From bcd320a40d0648dfe7cc53139866456646f69fa4 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 2 Jul 2024 16:04:48 -0700 Subject: [PATCH 01/66] Added formalization of NDEBUG (Debug Settings) --- .../io/parse/coe/DebugSettingsParser.java | 54 +++++++ .../io/parse/control/BaseControlParser.java | 3 +- .../bc/gov/nrs/vdyp/model/DebugSettings.java | 65 +++++++++ .../gov/nrs/vdyp/model/DebugSettingsTest.java | 61 ++++++++ ...ails.java => ForwardControlVariables.java} | 0 .../forward/model/ForwardDebugSettings.java | 138 ++++++++++++++++++ ...java => ForwardControlVariableParser.java} | 0 .../forward/ForwardDebugSettingsTest.java | 62 ++++++++ 8 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java create mode 100644 vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java rename vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/{VdypGrowthDetails.java => ForwardControlVariables.java} (100%) create mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java rename vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/{VdypControlVariableParser.java => ForwardControlVariableParser.java} (100%) create mode 100644 vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java new file mode 100644 index 000000000..5af35ebf3 --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java @@ -0,0 +1,54 @@ +package ca.bc.gov.nrs.vdyp.io.parse.coe; + +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; +import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; +import ca.bc.gov.nrs.vdyp.model.DebugSettings; + +public class DebugSettingsParser implements ValueParser { + + private static final Logger logger = LoggerFactory.getLogger(DebugSettingsParser.class); + + @Override + public DebugSettings parse(String string) throws ValueParseException { + + if (string == null) { + throw new ValueParseException(null, "VdypDebugSettingsParser: supplied string is null"); + } + + string = string.trim(); + + if (string.length() % 2 == 1) { + string += " "; + } + + List debugSettingsValues = new ArrayList<>(); + + while (string.length() > 0) { + + String settingText = string.substring(0, 2).trim(); + + try { + debugSettingsValues.add(Integer.parseInt(settingText)); + } catch (NumberFormatException e) { + throw new ValueParseException("Debug setting value \"" + settingText + "\" is not an integer"); + } + + string = string.substring(2); + } + + if (debugSettingsValues.size() < DebugSettings.MAX_DEBUG_SETTINGS) { + logger.warn( + "Only " + debugSettingsValues.size() + " debug values were supplied rather than the " + + DebugSettings.MAX_DEBUG_SETTINGS + " expected" + ); + } + + return new DebugSettings(debugSettingsValues.stream().toArray(Integer[]::new)); + } +} diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java index f7bb6f880..c0d1fd8d4 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java @@ -12,6 +12,7 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.io.FileResolver; +import ca.bc.gov.nrs.vdyp.io.parse.coe.DebugSettingsParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; @@ -64,7 +65,7 @@ protected void initialize() { controlParser.record(ControlKey.MINIMA, minimaParser()); - controlParser.record(ControlKey.DEBUG_SWITCHES, ValueParser.list(ValueParser.INTEGER)); // IPSJF155 + controlParser.record(ControlKey.DEBUG_SWITCHES, new DebugSettingsParser()); // IPSJF155 } protected abstract ValueParser> minimaParser(); diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java new file mode 100644 index 000000000..013e57db4 --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java @@ -0,0 +1,65 @@ +package ca.bc.gov.nrs.vdyp.model; + +import java.lang.reflect.Array; +import java.util.Arrays; + +/** + * Stores the debug flag values provided in key 199 of the control files. + *

+ * This class accepts an array of Integers (if null, or the default constructor + * is used, an empty integer array is used). The array cannot have more than + * 25 elements, but may have fewer. + *

+ * The class provides one operation: debugValue, which takes + * the number of debug setting whose value is needed. In keeping with the + * original FORTRAN code, these values are one-based - so, debug + * setting "5" is actually stored at settings[4]. + *

+ * It is an error to supply a setting number above 25. If 25 or less but + * higher than the number of elements in the array, the default value of + * "0" is returned. Otherwise, the value is read from the array. + *

+ * Instances of class are typically wrapped by an application-specific class + * that understands the settings in use by the application. + *

+ * See IPSJF155, appendix IX, details. + */ +public class DebugSettings { + + public static final int MAX_DEBUG_SETTINGS = 25; + protected static final int DEFAULT_DEBUG_SETTING = 0; + + protected final Integer[] settings; + + public DebugSettings(Integer[] settings) { + this.settings = settings == null ? new Integer[0] : Arrays.copyOf(settings, settings.length); + + if (this.settings.length > MAX_DEBUG_SETTINGS) { + throw new IllegalArgumentException("Debug settings array has length " + this.settings.length + + ", which exceeds the maximum length of " + MAX_DEBUG_SETTINGS); + } + + for (int i = 0; i < this.settings.length; i++) { + if (this.settings[i] == null) { + this.settings[i] = DEFAULT_DEBUG_SETTING; + } + } + } + + public DebugSettings() { + this(new Integer[0]); + } + + public int getValue(int settingNumber) { + if (settingNumber < 1 || settingNumber > MAX_DEBUG_SETTINGS) { + throw new IllegalArgumentException("Debug setting number " + settingNumber + " is out of range -" + + " must be between 1 and " + MAX_DEBUG_SETTINGS); + } + + if (settingNumber > settings.length) { + return DEFAULT_DEBUG_SETTING; + } + + return settings[settingNumber - 1]; + } +} diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java new file mode 100644 index 000000000..ccdf55da6 --- /dev/null +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java @@ -0,0 +1,61 @@ +package ca.bc.gov.nrs.vdyp.model; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +class DebugSettingsTest { + + @Test + void testNullArray() { + DebugSettings ds = new DebugSettings(null); + assertThat(ds.settings, Matchers.notNullValue()); + assertThat(ds.settings, Matchers.arrayWithSize(0)); + } + + @Test + void testEmptyArray() { + DebugSettings ds = new DebugSettings(new Integer[0]); + assertThat(ds.settings, Matchers.notNullValue()); + assertThat(ds.settings, Matchers.arrayWithSize(0)); + } + + @Test + void testSizeOneArray() { + DebugSettings ds = new DebugSettings(new Integer[] { 43 }); + assertThat(ds.settings, Matchers.notNullValue()); + assertThat(ds.settings, Matchers.arrayWithSize(1)); + assertThat(ds.settings[0], is(43)); + } + + @Test + void testTooLargeArray() { + assertThrows(IllegalArgumentException.class, () -> new DebugSettings(new Integer[DebugSettings.MAX_DEBUG_SETTINGS + 1])); + } + + @Test + void testValuesRecordedCorrectly() { + DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }); + for (int i = 0; i < 10; i++) { + assertThat(ds.getValue(i + 1), is(i + 1)); + } + } + + @Test + void testDefaultCorrectly() { + DebugSettings ds = new DebugSettings(new Integer[] { 1 }); + assertThat(ds.getValue(1), is(1)); + for (int i = 2; i <= DebugSettings.MAX_DEBUG_SETTINGS; i++) { + assertThat(ds.getValue(i), is(0)); + } + } + + @Test + void testOutOfBoundsRequest() { + DebugSettings ds = new DebugSettings(new Integer[] { 1 }); + assertThrows(IllegalArgumentException.class, () -> ds.getValue(DebugSettings.MAX_DEBUG_SETTINGS + 1)); + } +} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypGrowthDetails.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypGrowthDetails.java rename to vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java new file mode 100644 index 000000000..b23016e6d --- /dev/null +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java @@ -0,0 +1,138 @@ +package ca.bc.gov.nrs.vdyp.forward.model; + +import java.util.ArrayList; +import java.util.List; + +import ca.bc.gov.nrs.vdyp.model.DebugSettings; + +/** +(1) Species Dynamics +

    +
  • Value 0: Full species dynamics. Not recommended. +
  • Value 1: No species dynamics. Species percents in TPH and BA are constant. +
  • Value 2: Limited dynamics. Percents by BA are constant, but TPH %’s vary. +
+(2) Maximum Breast Height Age +
    +
  • Value 0: No upper age for application of BA and DQ yield equations. +
  • Value n: Maximum BH age for application of BA and DQ yields is 100 * n (years). +
+(3) Basal Area Growth Model +
    +
  • Value 0: BA growth comes from fiat model (approach to yield eqn’s). +
  • Value 1: BA growth from empirical model (older ages suspect). +
  • Value 2: Mixed fiat & empirical model. (See SEQ111 and IPSJF162). +
+(4) Maximum Breast Height Per Species and Region +
    +
  • Value 0: Will default to (2). Controls upper bounds in some models. +
  • Value 1: Limits from SEQ108 on control file, categorized by GRPBA1. +
  • Value 2: Limits from SEQ043 on control file, Coast Interior & Leading species. +
+(5) Messaging Level. See note (1), below +(6) Quadratic Mean Diameter growth model +
    +
  • Value 0: DQ growth comes from fiat model (approach to yield eqn’s). +
  • Value 1: DQ growth from empirical model (older ages suspect). +
  • Value 2: Mixed fiat & empirical model. (See SEQ117 and IPSJF178). +
+(8) Lorey Height change strategy +
    +
  • Value 0: Normal changes in Lorey height (HL), all species. +
  • Value 1: Force change to zero for nonprimary species if change in HD is zero. +
  • Value 2: Force change to zero for all species if change in HD is zero. + (option 2 precludes changes in primary sp HL due solely to change in TPH). +
+(9) Can limit BA if DQ has been limited (see Note 2, below.) +

+(11-21) HD/Age/SI fill-in controls (see Note 3, and IPSJF174.doc). +

+Note 1: for all programs the 5th debug switch should be zero except for program debugging. This will +prevent “SZERO” messages in the output and error messages produced by the MATH77 routines. Allowable +values: +

    +
  • Value 0: activates the MATH77 process to suppress messages AND furthermore totally deactivates the +messaging capability. +
  • Value 1: implements the MATH77 deactivation mechanism, but there will still be a few error messages. +
  • Value 2: allows for normal error messaging. +
+The usual underlying cause of the messages is that in reconciling results for the different species, the +program has been forced to violate a DQ/HL limit for a species. +

+Note 2: There has been a programming change to VDYP7 GROW, such that the behavior of the BA increment +may be altered subsequent to a projection having hit or exceeded a DQ limit. The configuration file +for VDYP7 GROW is affected, in that on sequence 199, Ndebug(9) is now defined. +

    +
  • Value 0: causes the program to operate as it always has to date (2009.03.24) +
  • Value 1: causes the indicated condition to be checked for, and may cause some predicted BA increments +to be smaller, or to be set to zero. +
+An explanation of the change, and the reason for it, are given in a document JFmemo_20090311.doc. Detailed +notes for code developers and those with detailed knowledge of VDYP7 are in JFmemo_20090318.doc. +

+Note 3: Valid values from Ndebug(11) through Ndebug(20): +

    +
  • 0: No action +
  • 1: Move SI from non-primary to primary using sitetools si conversions. Checks start with second high-BA + species, then ordered by ISP. If no conversions found, first attempted conversion redone 1:1. +
  • 2: Move SI from primary to non-primary using sitetools si conversions. +
  • 3: Complete (TOTAGE, BHAGE, YTBH) if 2 out of 3 present, all sp. +
  • 4: Move total age from non-primary to primary species (From second-most common species if present, else + 1st encountered). +
  • 5: Estimate dominant height of primary species from Lorey height. +
  • 6: Estimate dominant height of non-primary species from Lorey heights. +
  • 7: Estimate SI of primary species from HD and total age. (*) +
  • 8: Estimate SI of primary species from HD and BHAGE. (*) +
  • 9: Estimate SI of non-primary species from HD and total age. (*) +
  • 10: Estimate SI of non-primary species from HD and BHAGE. (*) +
  • 11: Estimate ages (total and BH and YTBH) of primary species from SI, HD +
  • 12: Estimate ages (total and BH and YTBH) of non-primary species from SI, HD. +
  • 13: Estimate YTBH of primary species from SI. +
  • 14: Estimate YTBH of non-primary species from SI. +
  • 15: Same as option 1, condition on total age (primary) < 30. +
+*/ +public class ForwardDebugSettings { + + public static final int MAX_FILL_INDEX_SETTINGS_INDEX = 20; + + public enum Vars { + SPECIES_DYNAMICS_1(1), + MAX_BREAST_HEIGHT_AGE_2(2), + BASAL_AREA_GROWTH_MODEL_3(3), + PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4(4), + MESSAGING_LEVEL_5(5), + DQ_GROWTH_MODEL_6(6), + LOREY_HEIGHT_CHANGE_STRATEGY_8(8), + DO_LIMIT_BA_WHEN_DQ_LIMITED_9(9); + + public final int settingNumber; + + Vars(int settingNumber) { + this.settingNumber = settingNumber; + } + } + + private final DebugSettings debugSettings; + + public ForwardDebugSettings(DebugSettings debugSettings) { + this.debugSettings = debugSettings; + } + + public int getValue(Vars v) { + return debugSettings.getValue(v.settingNumber); + } + + public Integer[] getFillInValues() { + + var result = new ArrayList(); + + int settingValue; + int index = 11; + while (index <= MAX_FILL_INDEX_SETTINGS_INDEX && (settingValue = debugSettings.getValue(index++)) != 0) { + result.add(settingValue); + } + + return result.toArray(Integer[]::new); + } +} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypControlVariableParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypControlVariableParser.java rename to vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java new file mode 100644 index 000000000..ac58e3309 --- /dev/null +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java @@ -0,0 +1,62 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import org.hamcrest.MatcherAssert; +import static org.hamcrest.Matchers.is; +import org.junit.jupiter.api.Test; + +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.model.DebugSettings; + +class ForwardDebugSettingsTest { + + @Test + void testNoSpecialActions() { + DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); + ForwardDebugSettings fs = new ForwardDebugSettings(ds); + + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1), is(1)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2), is(2)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3), is(3)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MESSAGING_LEVEL_5), is(5)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6), is(6)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8), is(8)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9), is(9)); + + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[0])); + } + + @Test + void testOneSpecialAction() { + DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 0 }); + ForwardDebugSettings fs = new ForwardDebugSettings(ds); + + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1), is(1)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2), is(2)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3), is(3)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MESSAGING_LEVEL_5), is(5)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6), is(6)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8), is(8)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9), is(9)); + + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 12 })); + } + + @Test + void testAllSpecialActions() { + DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 }); + ForwardDebugSettings fs = new ForwardDebugSettings(ds); + + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1), is(1)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2), is(2)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3), is(3)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MESSAGING_LEVEL_5), is(5)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6), is(6)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8), is(8)); + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9), is(9)); + + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 })); + } +} From 9ddd68348ad40f76f469c297ca2a50f3b7cc51bc Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 2 Jul 2024 16:13:24 -0700 Subject: [PATCH 02/66] Added formalization of NDEBUG (Debug Settings) --- .../forward/model/ForwardDebugSettings.java | 2 +- .../forward/ForwardDebugSettingsTest.java | 32 +++++++------------ 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java index b23016e6d..7a383546e 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java @@ -94,7 +94,7 @@ */ public class ForwardDebugSettings { - public static final int MAX_FILL_INDEX_SETTINGS_INDEX = 20; + public static final int MAX_FILL_INDEX_SETTINGS_INDEX = DebugSettings.MAX_DEBUG_SETTINGS; public enum Vars { SPECIES_DYNAMICS_1(1), diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java index ac58e3309..b15c7f51c 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java @@ -1,7 +1,9 @@ package ca.bc.gov.nrs.vdyp.forward; -import org.hamcrest.MatcherAssert; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; @@ -31,32 +33,22 @@ void testOneSpecialAction() { DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 0 }); ForwardDebugSettings fs = new ForwardDebugSettings(ds); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1), is(1)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2), is(2)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3), is(3)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MESSAGING_LEVEL_5), is(5)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6), is(6)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8), is(8)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9), is(9)); - MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 12 })); } @Test void testAllSpecialActions() { - DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 }); + DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }); ForwardDebugSettings fs = new ForwardDebugSettings(ds); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1), is(1)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2), is(2)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3), is(3)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MESSAGING_LEVEL_5), is(5)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6), is(6)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8), is(8)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9), is(9)); + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 })); + } + + @Test + void testAllSomeActions() { + DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107 }); + ForwardDebugSettings fs = new ForwardDebugSettings(ds); - MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109 })); + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107 })); } } From 08b8e8cbb89297b3d87d45e0af367e7b439aad0c Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 2 Jul 2024 17:07:22 -0700 Subject: [PATCH 03/66] Control Variable parser tests --- .../vdyp/forward/model/ControlVariable.java | 16 +++ .../model/ForwardControlVariables.java | 106 +++++++++++------- .../parsers/ForwardControlVariableParser.java | 22 +--- ...est.java => ForwardControlParserTest.java} | 2 +- .../forward/ForwardControlVariablesTest.java | 73 ++++++++++++ .../forward/ForwardDebugSettingsTest.java | 1 - ...dypForwardControlVariablesParserTest.java} | 0 7 files changed, 159 insertions(+), 61 deletions(-) create mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java rename vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{VdypForwardControlParserTest.java => ForwardControlParserTest.java} (99%) create mode 100644 vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java rename vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/{VdypGrowthDetailParserTest.java => VdypForwardControlVariablesParserTest.java} (100%) diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java new file mode 100644 index 000000000..a44bd3427 --- /dev/null +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java @@ -0,0 +1,16 @@ +package ca.bc.gov.nrs.vdyp.forward.model; + +public enum ControlVariable { + GROW_TARGET_1(1), + COMPAT_VAR_OUTPUT_2(2), + COMPAT_VAR_APPLICATION_3(3), + OUTPUT_FILES_4(4), + ALLOW_COMPAT_VAR_CALCS_5(5), + UPDATE_DURING_GROWTH_6(6); + + public final int variableNumber; + + ControlVariable(int variableNumber) { + this.variableNumber = variableNumber; + } +} \ No newline at end of file diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java index a42624058..91ea8c25c 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java @@ -3,6 +3,8 @@ import java.util.function.BiFunction; import java.util.function.BooleanSupplier; +import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; + /** * Control Variable values *

@@ -45,20 +47,14 @@ *

  • 1: Yes (normal) * */ -public class VdypGrowthDetails { +public class ForwardControlVariables { private static final int MAX_CONTROL_VARIABLE_VALUES = 10; - - private enum ControlVariables { - GROW_TARGET, COMPATIBILITY_VARIABLE_OUTPUT, COMPATIBILITY_VARIABLE_APPLICATION, OUTPUT_FILES, - ALLOW_COMPATIBILITY_VARIABLE_CALCULATIONS, UPDATE_DURING_GROWTH - } - - private Integer firstYear, currentYear, lastYear, yearCounter; + private static final int DEFAULT_CONTROL_VARIABLE_VALUE = 0; private final int[] controlVariables = new int[10]; - public VdypGrowthDetails(Integer[] controlVariableValues) { + public ForwardControlVariables(Integer[] controlVariableValues) throws ValueParseException { int index = 0; if (controlVariableValues != null) { @@ -67,61 +63,89 @@ public VdypGrowthDetails(Integer[] controlVariableValues) { } for (; index < MAX_CONTROL_VARIABLE_VALUES; index++) - this.controlVariables[index] = 0; - } - - public Integer getFirstYear() { - return firstYear; - } - - public void setFirstYear(Integer firstYear) { - this.firstYear = firstYear; - } - - public Integer getCurrentYear() { - return currentYear; + this.controlVariables[index] = DEFAULT_CONTROL_VARIABLE_VALUE; + + validate(); } + + private void validate() throws ValueParseException { + + // Validate the control variable values. + + var yearCounter = getControlVariable(ControlVariable.GROW_TARGET_1); + if (yearCounter != -1 && (yearCounter < 0 || yearCounter > 400 && yearCounter < 1920 || yearCounter > 2400)) { + throw new ValueParseException( + Integer.toString(yearCounter), + "VdypControlVariableParser: year counter (1) value \"" + yearCounter + "\" is out of range" + ); + } - public void setCurrentYear(Integer currentYear) { - this.currentYear = currentYear; - } + var compatibilityVariableOutputVariableValue = getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); + if (compatibilityVariableOutputVariableValue < 0 || compatibilityVariableOutputVariableValue > 2) { + throw new ValueParseException( + Integer.toString(compatibilityVariableOutputVariableValue), + "VdypControlVariableParser: compatibility variable output value \"" + compatibilityVariableOutputVariableValue + "\" is out of range [0-2]" + ); + } - public Integer getLastYear() { - return lastYear; - } + var compatibilityVariableApplicationVariableValue = getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); + if (compatibilityVariableApplicationVariableValue < 0 || compatibilityVariableApplicationVariableValue > 2) { + throw new ValueParseException( + Integer.toString(compatibilityVariableApplicationVariableValue), + "VdypControlVariableParser: compatibility variable application value \"" + compatibilityVariableApplicationVariableValue + "\" is out of range [0-2]" + ); + } - public void setLastYear(Integer lastYear) { - this.lastYear = lastYear; - } + var outputFileDirectiveVariableValue = getControlVariable(ControlVariable.OUTPUT_FILES_4); + if (outputFileDirectiveVariableValue < 0 || outputFileDirectiveVariableValue > 4) { + throw new ValueParseException( + Integer.toString(outputFileDirectiveVariableValue), + "VdypControlVariableParser: output file directive value \"" + outputFileDirectiveVariableValue + "\" is out of range [0-4]" + ); + } - public Integer getYearCounter() { - return yearCounter; - } + var allowCompatibilityVariableCalculationsVariableValue = getControlVariable(ControlVariable.ALLOW_COMPAT_VAR_CALCS_5); + if (allowCompatibilityVariableCalculationsVariableValue < 0 || allowCompatibilityVariableCalculationsVariableValue > 1) { + throw new ValueParseException( + Integer.toString(allowCompatibilityVariableCalculationsVariableValue), + "VdypControlVariableParser: compatibility variable calculations allowed value \"" + allowCompatibilityVariableCalculationsVariableValue + "\" is out of range [0-1]" + ); + } - public void setYearCounter(Integer yearCounter) { - this.yearCounter = yearCounter; + var updateDuringGrowthVariableValue = getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6); + if (updateDuringGrowthVariableValue < 0 || updateDuringGrowthVariableValue > 1) { + throw new ValueParseException( + Integer.toString(updateDuringGrowthVariableValue), + "VdypControlVariableParser: update site species and ITG during grow value \"" + updateDuringGrowthVariableValue + "\" is out of range [0-1]" + ); + } } public boolean allowCalculation(float value, float limit, BiFunction p) { - int cvValue = controlVariables[ControlVariables.ALLOW_COMPATIBILITY_VARIABLE_CALCULATIONS.ordinal()]; + int cvValue = controlVariables[ControlVariable.ALLOW_COMPAT_VAR_CALCS_5.ordinal()]; return cvValue == 0 && value > 0 || cvValue == 1 && p.apply(value, limit); } public boolean allowCalculation(BooleanSupplier p) { - int cvValue = controlVariables[ControlVariables.ALLOW_COMPATIBILITY_VARIABLE_CALCULATIONS.ordinal()]; + int cvValue = controlVariables[ControlVariable.ALLOW_COMPAT_VAR_CALCS_5.ordinal()]; return cvValue == 1 && p.getAsBoolean(); } + public int getControlVariable(ControlVariable controlVariable) { + + assert controlVariable.ordinal() == controlVariable.variableNumber - 1; + return controlVariables[controlVariable.ordinal()]; + } + int getControlVariable(int elementNumber) { - int index = elementNumber - 1; - if (index < 0 || index > MAX_CONTROL_VARIABLE_VALUES) { + if (elementNumber < 1 || elementNumber > MAX_CONTROL_VARIABLE_VALUES) { throw new IllegalArgumentException( "Element number (" + elementNumber + ") is out of range - must be from 1 to " + MAX_CONTROL_VARIABLE_VALUES ); } - return controlVariables[index]; + return controlVariables[elementNumber - 1]; } } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java index 44691f079..d596b98ae 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java @@ -2,14 +2,14 @@ import java.util.List; -import ca.bc.gov.nrs.vdyp.forward.model.VdypGrowthDetails; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; -public class VdypControlVariableParser implements ValueParser { +public class ForwardControlVariableParser implements ValueParser { @Override - public VdypGrowthDetails parse(String string) throws ValueParseException { + public ForwardControlVariables parse(String string) throws ValueParseException { if (string == null) { throw new ValueParseException(null, "VdypControlVariableParser: supplied string is null"); @@ -29,20 +29,6 @@ public VdypGrowthDetails parse(String string) throws ValueParseException { ); } - var a = new Integer[controlVariableValues.size()]; - - var details = new VdypGrowthDetails(controlVariableValues.toArray(a)); - - var yearCounter = a[0]; - if (yearCounter != -1 && (yearCounter < 0 || yearCounter > 400 && yearCounter < 1920)) { - throw new ValueParseException( - Integer.toString(yearCounter), - "VdypControlVariableParser: yearCounter value \"" + yearCounter + "\" is out of range" - ); - } - - details.setYearCounter(yearCounter); - - return details; + return new ForwardControlVariables(controlVariableValues.toArray(new Integer[controlVariableValues.size()])); } } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java similarity index 99% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java rename to vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java index fe8d1dd04..80643e24d 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java @@ -46,7 +46,7 @@ import ca.bc.gov.nrs.vdyp.test.TestUtils; @SuppressWarnings({ "unchecked", "rawtypes" }) -class VdypForwardControlParserTest { +class ForwardControlParserTest { @Test void testParseBec_9() throws Exception { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java new file mode 100644 index 000000000..1d5879769 --- /dev/null +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java @@ -0,0 +1,73 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; +import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; + +class ForwardControlVariablesTest { + + @Test + void testNull() throws ValueParseException { + ForwardControlVariables fcv = new ForwardControlVariables(null); + + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.GROW_TARGET_1), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.OUTPUT_FILES_4), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.ALLOW_COMPAT_VAR_CALCS_5), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6), Matchers.equalTo(0)); + } + + @Test + void testEmpty() throws ValueParseException { + ForwardControlVariables fcv = new ForwardControlVariables(new Integer[0]); + + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.GROW_TARGET_1), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.OUTPUT_FILES_4), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.ALLOW_COMPAT_VAR_CALCS_5), Matchers.equalTo(0)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6), Matchers.equalTo(0)); + } + + @Test + void testSimple() throws ValueParseException { + ForwardControlVariables fcv = new ForwardControlVariables(new Integer[] { 1, 1, 1, 1, 1, 1 }); + + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.GROW_TARGET_1), Matchers.equalTo(1)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2), Matchers.equalTo(1)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3), Matchers.equalTo(1)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.OUTPUT_FILES_4), Matchers.equalTo(1)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.ALLOW_COMPAT_VAR_CALCS_5), Matchers.equalTo(1)); + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6), Matchers.equalTo(1)); + } + + @Test + void testYearValues() throws ValueParseException { + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { -2, 0, 0, 0, 0, 0 })); + new ForwardControlVariables(new Integer[] { -1, 0, 0, 0, 0, 0 }); + new ForwardControlVariables(new Integer[] { 0, 0, 0, 0, 0, 0 }); + new ForwardControlVariables(new Integer[] { 1, 0, 0, 0, 0, 0 }); + new ForwardControlVariables(new Integer[] { 400, 0, 0, 0, 0, 0 }); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 401, 0, 0, 0, 0, 0 })); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 1919, 0, 0, 0, 0, 0 })); + new ForwardControlVariables(new Integer[] { 1920, 0, 0, 0, 0, 0 }); + new ForwardControlVariables(new Integer[] { 2400, 0, 0, 0, 0, 0 }); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 2401, 0, 0, 0, 0, 0 })); + } + + @Test + void testInvalidInput2To5() throws ValueParseException { + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 0, 3, 3, 4, 2, 2 })); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 0, 0, 3, 4, 2, 2 })); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 0, 0, 0, 4, 2, 2 })); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 0, 0, 0, 0, 2, 2 })); + assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 0, 0, 0, 0, 0, 2 })); + } +} diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java index b15c7f51c..964df58aa 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java @@ -1,7 +1,6 @@ package ca.bc.gov.nrs.vdyp.forward; import static org.hamcrest.Matchers.is; -import static org.junit.jupiter.api.Assertions.assertThrows; import org.hamcrest.MatcherAssert; import org.junit.jupiter.api.Test; diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypGrowthDetailParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypGrowthDetailParserTest.java rename to vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java From 23bec2e355736009c0062a7d1dbd355a69be1e7b Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 3 Jul 2024 17:39:49 -0700 Subject: [PATCH 04/66] GROW up to and including HDGROW --- .../vdyp/forward/ForwardControlParser.java | 9 +- .../vdyp/forward/ForwardDataStreamReader.java | 51 ++- .../vdyp/forward/ForwardProcessingEngine.java | 388 ++++++++++++++++-- .../vdyp/forward/ForwardProcessingState.java | 67 ++- .../nrs/vdyp/forward/ForwardProcessor.java | 25 +- .../vdyp/forward/PolygonProcessingState.java | 10 +- .../nrs/vdyp/forward/model/VdypPolygon.java | 13 +- .../forward/parsers/VdypSpeciesParser.java | 44 +- .../forward/ForwardProcessingEngineTest.java | 21 +- .../GeneralForwardProcessingEngineTest.java | 82 ++-- .../vdyp/forward/GrowDominantHeightTest.java | 84 ++++ .../forward/PolygonProcessingStateTest.java | 18 +- ...yVariablesForwardProcessingEngineTest.java | 20 +- .../forward/VdypForwardReadPolygonTest.java | 11 +- ...VdypForwardControlVariablesParserTest.java | 40 +- 15 files changed, 657 insertions(+), 226 deletions(-) create mode 100644 vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java index a8992ada7..457104afa 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java @@ -16,11 +16,11 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.parsers.ForwardControlVariableParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonDescriptionParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypSpeciesParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypUtilizationParser; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypControlVariableParser; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.BasalAreaGrowthEmpiricalParser; import ca.bc.gov.nrs.vdyp.io.parse.coe.BasalAreaGrowthFiatParser; @@ -84,8 +84,6 @@ public class ForwardControlParser extends BaseControlParser { public ForwardControlParser() { initialize(); - - controlParser.record(ControlKey.VTROL, new VdypControlVariableParser()); } @Override @@ -267,6 +265,8 @@ protected void initialize() { addInputParser(new VdypPolygonDescriptionParser()); // 101 - a literal value of type VdypGrowthDetails + + controlParser.record(ControlKey.VTROL, new ForwardControlVariableParser()); orderedControlKeys.add(ControlKey.VTROL); // 199 - debug switches @@ -319,8 +319,7 @@ protected void applyAllModifiers(Map map, FileResolver fileResol } // Report any control map items that are a) not included in orderedControlKeys - // or b) for which - // not parser was registered. + // or b) for which not parser was registered. // a Set parsersNotExecuted = new HashSet<>( diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 68550c0e3..b438ac348 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -15,6 +15,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; @@ -33,6 +34,7 @@ public class ForwardDataStreamReader { private final StreamingParser polygonStream; private final StreamingParser> layerSpeciesStream; private final StreamingParser> speciesUtilizationStream; + Optional> polygonDescriptionStream; @SuppressWarnings("unchecked") public ForwardDataStreamReader(Map controlMap) throws IOException { @@ -46,18 +48,26 @@ public ForwardDataStreamReader(Map controlMap) throws IOExceptio var speciesUtilizationStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()); speciesUtilizationStream = ((StreamingParserFactory>) speciesUtilizationStreamFactory) .get(); + + polygonDescriptionStream = Optional.empty(); + if (controlMap.containsKey(ControlKey.FORWARD_INPUT_GROWTO.name())) { + var polygonDescriptionStreamFactory = Utils.> + expectParsedControl(controlMap, ControlKey.FORWARD_INPUT_GROWTO, StreamingParserFactory.class); + + polygonDescriptionStream = Optional.of(polygonDescriptionStreamFactory.get()); + } else { + polygonDescriptionStream = Optional.empty(); + } } - public VdypPolygon readNextPolygon(VdypPolygonDescription polygonDescription) throws ProcessingException { + public Optional readNextPolygon() throws ProcessingException { // Advance all the streams until the definition for the polygon is found. - logger.debug("Looking for polygon {}", polygonDescription); - Optional thePolygon = Optional.empty(); try { - while (thePolygon.isEmpty() && polygonStream.hasNext()) { + if (polygonStream.hasNext()) { var polygon = polygonStream.next(); logger.debug("Reading polygon {}", polygon); @@ -71,6 +81,24 @@ public VdypPolygon readNextPolygon(VdypPolygonDescription polygonDescription) th utilizationsBySpeciesMap.putIfAbsent(key, new EnumMap<>(UtilizationClass.class)); utilizationsBySpeciesMap.get(key).put(utilization.getUcIndex(), utilization); } + + if (polygonDescriptionStream.isPresent()) { + var pdStream = polygonDescriptionStream.get(); + if (!pdStream.hasNext()) { + throw new ProcessingException(MessageFormat.format("Grow-to-year file at {0} in the control file does" + + " not contain a record for {1} as expected, but instead the end-of-file was reached" + , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getDescription().getName())); + } + var polygonDescription = pdStream.next(); + if (! polygonDescription.getName().equals(polygon.getDescription().getName())) { + throw new ProcessingException(MessageFormat.format("Grow-to-year file at {0} in the control file does" + + " not contain a record for {1} as expected, but instead contains a record for {2}" + , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getDescription().getName() + , polygonDescription.getName())); + } + + polygon.setTargetYear(polygonDescription.getYear()); + } var speciesCollection = layerSpeciesStream.next(); var primarySpecies = new HashMap(); @@ -139,23 +167,14 @@ public VdypPolygon readNextPolygon(VdypPolygonDescription polygonDescription) th polygon.setLayers(primaryLayer, veteranLayer); - if (polygonDescription.equals(polygon.getDescription())) { - thePolygon = Optional.of(polygon); - - adjustUtilizations(polygon); - } + thePolygon = Optional.of(polygon); + adjustUtilizations(polygon); } } catch (ResourceParseException | IOException e) { throw new ProcessingException(e); } - if (thePolygon.isEmpty()) { - throw new ProcessingException( - MessageFormat.format("Unable to find the definition of {0}", polygonDescription) - ); - } - - return thePolygon.get(); + return thePolygon; } /** diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index f554b7575..e9074a87b 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -20,6 +20,7 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; @@ -27,9 +28,12 @@ import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CurveErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.NoAnswerException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.SpeciesErrorException; +import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexAgeType; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; +import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypGrowthDetails; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; @@ -42,6 +46,7 @@ import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.MatrixMap3Impl; import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; import ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; @@ -78,6 +83,7 @@ public enum ExecutionStep { ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES, // CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX, // SET_COMPATIBILITY_VARIABLES, // + GROW, // // Must be last ALL; // @@ -113,10 +119,35 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStep) throws P // All of BANKCHK1 that we need validatePolygon(polygon); - executeForwardAlgorithm(lastStep); + // Determine the target year of the growth + int targetYear; + + int growTargetControlVariableValue = fps.getForwardControlVariables() + .getControlVariable(ControlVariable.GROW_TARGET_1); + if (growTargetControlVariableValue == -1) { + if (polygon.getTargetYear().isEmpty()) { + throw new ProcessingException( + "Control Variable 1 has the value -1, indicating that the grow-to years are" + + " to be read from a grow-to-year file (at " + ControlKey.FORWARD_INPUT_GROWTO.name() + + " in the" + + " control file), but no such file was specified." + ); + } + targetYear = polygon.getTargetYear().get(); + } else { + if (growTargetControlVariableValue <= 400) { + targetYear = polygon.getDescription().getYear() + growTargetControlVariableValue; + } else { + targetYear = growTargetControlVariableValue; + } + } + + // Run the forward algorithm for this polygon + + executeForwardAlgorithm(lastStep, targetYear); } - private void executeForwardAlgorithm(ExecutionStep lastStep) throws ProcessingException { + private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank bank = fps.getBank(0, LayerType.PRIMARY); @@ -133,7 +164,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep) throws ProcessingEx calculateMissingSiteCurves(bank, fps.getSiteCurveMap(), fps.getPolygonProcessingState()); } - // VPRIME, method == 1 + // VPRIME1, method == 1 if (lastStep.ordinal() >= ExecutionStep.CALCULATE_COVERAGES.ordinal()) { calculateCoverages(pps); } @@ -160,8 +191,282 @@ private void executeForwardAlgorithm(ExecutionStep lastStep) throws ProcessingEx if (lastStep.ordinal() >= ExecutionStep.SET_COMPATIBILITY_VARIABLES.ordinal()) { setCompatibilityVariables(pps); } - - fps.storeActive(2, LayerType.PRIMARY); + + if (lastStep.ordinal() >= ExecutionStep.GROW.ordinal()) { + int veteranLayerInstance = 1; + + int primaryLayerSourceInstance = 2; + fps.storeActive(primaryLayerSourceInstance, LayerType.PRIMARY); + + int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); + + writeLayers(primaryLayerSourceInstance, veteranLayerInstance, false); + + boolean createNewGroups = fps.debugSettings.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 + && fps.getPolygonProcessingState().getNSpecies() > 1; + + int primaryLayerTargetInstance = 3; + int currentYear = startingYear; + while (currentYear <= untilYear) { + + grow(primaryLayerSourceInstance, currentYear, primaryLayerTargetInstance, veteranLayerInstance); + + // Store polygon (both primary and veteran layers) to output + writeLayers(primaryLayerTargetInstance, veteranLayerInstance, createNewGroups); + + currentYear += 1; + + int newPrimaryLayerSourceInstance = primaryLayerTargetInstance; + primaryLayerTargetInstance = primaryLayerSourceInstance; + primaryLayerSourceInstance = newPrimaryLayerSourceInstance; + } + } + } + + private void grow( + int primaryLayerSourceInstance, int currentYear, int primaryLayerTargetInstance, int veteranLayerInstance + ) + throws ProcessingException { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + VdypPolygon polygon = pps.getPolygon(); + + logger.info( + "Performing grow of {} for year {} from instance {} to instance {}", polygon.getDescription() + .getName(), currentYear, primaryLayerSourceInstance, primaryLayerTargetInstance + ); + + // Call to BANKOUT1 unnecessary; pps.wallet already contains the primary layer + + // If update-during-growth is set, and this is not the starting year, update the + // context + int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); + if (currentYear > startingYear + && fps.getForwardControlVariables().getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { + // VPRIME1, method == 1 + calculateCoverages(pps); + + // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 + calculateDominantHeightAgeSiteIndex(pps, fps.getHl1Coefficients()); + } + + float dominantHeight = pps.getPrimarySpeciesDominantHeight(); + int siteCurveNumber = pps.getSiteCurveNumber(startingYear); + float siteIndex = pps.getPrimarySpeciesSiteIndex(); + float yearsToBreastHeight = pps.getPrimarySpeciesAgeToBreastHeight(); + + SiteCurveAgeMaximum scAgeMaximums = fps.maximumAgeBySiteCurveNumber.get(siteCurveNumber); + Region region = fps.getPolygonProcessingState().wallet.getBecZone().getRegion(); + + float newDominantHeight = growDominantHeight( + scAgeMaximums, region, dominantHeight, siteCurveNumber, siteIndex, yearsToBreastHeight + ); + } + + public static float + growDominantHeight( + SiteCurveAgeMaximum scAgeMaximums, Region region, float dominantHeight, int siteCurveNumber, + float siteIndex, float yearsToBreastHeight + ) throws ProcessingException { + + if (siteCurveNumber == VdypEntity.MISSING_INTEGER_VALUE) { + throw new ProcessingException("No SiteCurveNumber supplied"); + } + + var siteIndexEquation = SiteIndexEquation.getByIndex(siteCurveNumber); + + if (dominantHeight <= 1.3) { + throw new ProcessingException( + MessageFormat.format( + "(current) DominantHeight {0} is out of range (must be above 1.3)", dominantHeight + ) + ); + } + + final SiteIndexAgeType ageType = SiteIndexAgeType.SI_AT_TOTAL; + + double siteIndex_d = siteIndex; + double dominantHeight_d = dominantHeight; + double yearsToBreastHeight_d = yearsToBreastHeight; + + double currentAge; + try { + currentAge = SiteTool.heightAndSiteIndexToAge( + siteIndexEquation, dominantHeight_d, ageType, siteIndex_d, yearsToBreastHeight_d + ); + } catch (CommonCalculatorException e) { + throw new ProcessingException( + MessageFormat.format( + "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3})", siteIndexEquation, dominantHeight_d, null, siteIndex_d, yearsToBreastHeight_d + ), e + ); + } + + if (currentAge <= 0.0d) { + if (dominantHeight_d > siteIndex_d) { + return 0.0f /* no growth */; + } else { + throw new ProcessingException( + MessageFormat.format("currentBreastHeightAge value {0} must be positive", currentAge) + ); + } + } + + double nextAge = currentAge + 1.0f; + + // If we are past the total age limit for site curve, assign no growth. If we are almost there, go + // slightly past the limit (by .01 yr). Once there, we should stop growing. The TOTAL age limit was + // stored so we must calculate a BH age limit first... + + float ageLimitInYears = scAgeMaximums.getAgeMaximum(region); + + float breastHeightAgeLimitInYears = 0.0f; + if (ageLimitInYears > 0) { + breastHeightAgeLimitInYears = ageLimitInYears - yearsToBreastHeight; + } + + if (currentAge <= breastHeightAgeLimitInYears || scAgeMaximums.getT1() <= 0.0f) { + + float yearPart = 1.0f; + + if (scAgeMaximums.getT1() <= 0.0f) { + + if (breastHeightAgeLimitInYears > 0.0f && nextAge > breastHeightAgeLimitInYears) { + if (currentAge > breastHeightAgeLimitInYears) { + return 0.0f /* no growth */; + } + + yearPart = (float) (breastHeightAgeLimitInYears - currentAge + 0.01); + nextAge = currentAge + yearPart; + } + } + + // The above code to find ages allows errors up to .005 m. At high ages with some + // species this can correspond to a half year. Therefore, AGED1 can not be assumed to + // correspond to HDD1. Find a new HDD1 to at least get the increment correct. + + double currentDominantHeight; + try { + currentDominantHeight = SiteTool.ageAndSiteIndexToHeight( + siteIndexEquation, currentAge, ageType, siteIndex_d, yearsToBreastHeight_d + ); + } catch (CommonCalculatorException e) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, currentAge, ageType, siteIndex_d, yearsToBreastHeight_d + ), e + ); + } + + double nextDominantHeight; + try { + nextDominantHeight = SiteTool.ageAndSiteIndexToHeight( + siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d + ); + } catch (CommonCalculatorException e) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d + ), e + ); + } + + if (nextDominantHeight < 0.0) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) returned {5}", siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d, nextDominantHeight + ) + ); + } + + if (nextDominantHeight < currentDominantHeight && yearPart == 1.0) { + // Rounding error in site routines? + if (Math.abs(currentDominantHeight - nextDominantHeight) < 0.01) { + return 0.0f /* no growth */; + } else { + throw new ProcessingException( + MessageFormat.format( + "New dominant height {0} is less than the current dominant height {1}", nextDominantHeight, currentDominantHeight + ) + ); + } + } + + return (float) (nextDominantHeight - currentDominantHeight); + + } else { + // We are in a special extension of the curve. Derive the new curve form and then + // compute the answer. + + float a = FloatMath.log(0.5f) / scAgeMaximums.getT1(); + double breastHeightAgeLimitInYears_d = breastHeightAgeLimitInYears; + + double currentDominantHeight; + try { + currentDominantHeight = SiteTool.ageAndSiteIndexToHeight( + siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + ); + } catch (CommonCalculatorException e) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + ), e + ); + } + + breastHeightAgeLimitInYears_d += 1.0; + + double nextDominantHeight; + try { + nextDominantHeight = SiteTool.ageAndSiteIndexToHeight( + siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + ); + } catch (CommonCalculatorException e) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + ), e + ); + } + + float rate = (float) (nextDominantHeight - currentDominantHeight); + if (rate < 0.0005f) { + rate = 0.0005f; + } + + float y = (float) currentDominantHeight; + // Model is: + // Y = Y0 - RATE0/A*(1-exp(A* t)) where t = AGE - BHAGELIM + // Solve for T: + // 1 - exp(A * T) = (Y0 - Y) * A/RATE0 + // -exp(A * T) = (Y0 - Y) * A/RATE0 - 1 + // exp(A * T) = (Y - Y0) * A/RATE0 + 1 + // A * T = ln(1 + (Y - Y0) * A/RATE0) + // T = ln(1 + (Y - Y0) * A/RATE0) / A + float t; + if (dominantHeight > y) { + float term = 1.0f + (dominantHeight - y) * a / rate; + if (term <= 1.0e-7) { + return 0.0f; + } + t = FloatMath.log(term) / a; + } else { + t = 0.0f; + } + + if (t < scAgeMaximums.getT2()) { + return 0.0f; + } else { + return rate / a * (-FloatMath.exp(a * t) + FloatMath.exp(a * (t + 1.0f))); + } + } + } + + private void writeLayers(int primaryLayerInstance, int veteranLayerInstance, boolean b) { + + logger.info( + "Writing primary layer from instance {} and veteran layer from instance {}", primaryLayerInstance, veteranLayerInstance + ); } private static final float[] DEFAULT_QUAD_MEAN_DIAMETERS = new float[] { Float.NaN, 10.0f, 15.0f, 20.0f, 25.0f }; @@ -240,10 +545,10 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process // EMP094 EstimationMethods.estimateNetDecayAndWasteVolume( - pps.getBecZone().getRegion(), uc, aAdjust, pps.wallet.speciesNames[s], spLoreyHeight_All, - pps.getNetDecayWasteCoeMap(), pps.getWasteModifierMap(), quadMeanDiameters, - closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, - closeUtilizationVolumesNetOfDecayAndWaste + pps.getBecZone() + .getRegion(), uc, aAdjust, pps.wallet.speciesNames[s], spLoreyHeight_All, pps + .getNetDecayWasteCoeMap(), pps + .getWasteModifierMap(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste ); float actualVolume = pps.wallet.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; @@ -263,10 +568,9 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process // EMP093 int decayGroup = pps.decayEquationGroups[s]; EstimationMethods.estimateNetDecayVolume( - pps.wallet.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, - pps.getPrimarySpeciesAgeAtBreastHeight(), pps.getNetDecayCoeMap(), - pps.getDecayModifierMap(), quadMeanDiameters, closeUtilizationVolumes, - closeUtilizationVolumesNetOfDecay + pps.wallet.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, pps + .getPrimarySpeciesAgeAtBreastHeight(), pps.getNetDecayCoeMap(), pps + .getDecayModifierMap(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay ); float actualVolume = pps.wallet.cuVolumesMinusDecay[s][uc.ordinal()]; @@ -285,8 +589,8 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process // EMP092 int volumeGroup = pps.volumeEquationGroups[s]; EstimationMethods.estimateCloseUtilizationVolume( - uc, aAdjust, volumeGroup, spLoreyHeight_All, pps.getCloseUtilizationCoeMap(), - quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes + uc, aAdjust, volumeGroup, spLoreyHeight_All, pps + .getCloseUtilizationCoeMap(), quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes ); float actualVolume = pps.wallet.closeUtilizationVolumes[s][uc.ordinal()]; @@ -301,15 +605,15 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process float primarySpeciesQMDAll = pps.wallet.quadMeanDiameters[s][UTILIZATION_ALL_INDEX]; var wholeStemVolume = pps.wallet.treesPerHectare[s][UTILIZATION_ALL_INDEX] * EstimationMethods.estimateWholeStemVolumePerTree( - primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll, - pps.getTotalStandWholeStepVolumeCoeMap() + primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll, pps + .getTotalStandWholeStepVolumeCoeMap() ); wholeStemVolumes.setCoe(UTILIZATION_ALL_INDEX, wholeStemVolume); EstimationMethods.estimateWholeStemVolume( - UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, - pps.getWholeStemUtilizationComponentMap(), quadMeanDiameters, basalAreas, wholeStemVolumes + UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, pps + .getWholeStemUtilizationComponentMap(), quadMeanDiameters, basalAreas, wholeStemVolumes ); for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL_ALL) { @@ -329,16 +633,17 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process ); EstimationMethods.estimateBaseAreaByUtilization( - pps.getBecZone(), pps.getBasalAreaUtilizationComponentMap(), quadMeanDiameters, basalAreas, - genusName + pps.getBecZone(), pps + .getBasalAreaUtilizationComponentMap(), quadMeanDiameters, basalAreas, genusName ); // Calculate trees-per-hectare per utilization treesPerHectare.setCoe(UtilizationClass.ALL.index, pps.wallet.treesPerHectare[s][UTILIZATION_ALL_INDEX]); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { treesPerHectare.setCoe( - uc.index, - calculateTreesPerHectare(basalAreas.getCoe(uc.index), quadMeanDiameters.getCoe(uc.index)) + uc.index, calculateTreesPerHectare( + basalAreas.getCoe(uc.index), quadMeanDiameters.getCoe(uc.index) + ) ); } @@ -379,7 +684,7 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process * @throws ProcessingException */ private static HashMap - estimateSmallComponents(PolygonProcessingState pps, int speciesIndex, VdypGrowthDetails growthDetails) + estimateSmallComponents(PolygonProcessingState pps, int speciesIndex, ForwardControlVariables growthDetails) throws ProcessingException { Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); @@ -423,8 +728,8 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process if (growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { float spInputQuadMeanDiameter_Small = pps.wallet.quadMeanDiameters[speciesIndex][UTILIZATION_SMALL_INDEX]; cvSmall.put( - SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, - spInputQuadMeanDiameter_Small - cvQuadMeanDiameter_Small + SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small + - cvQuadMeanDiameter_Small ); } else { cvSmall.put(SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); @@ -650,8 +955,7 @@ static void calculateDominantHeightAgeSiteIndex( if (Float.isNaN(loreyHeight)) { throw new ProcessingException( MessageFormat.format( - "Neither dominant nor lorey height[All] is available for primary species {}", - state.wallet.speciesNames[primarySpeciesIndex] + "Neither dominant nor lorey height[All] is available for primary species {}", state.wallet.speciesNames[primarySpeciesIndex] ), 2 ); } @@ -849,15 +1153,13 @@ static void estimateMissingSiteIndices(PolygonProcessingState state) throws Proc } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion from curves {0} to {1}. Skipping species {3}", - siteCurveI, primarySiteCurve, i + "there is no conversion from curves {0} to {1}. Skipping species {3}", siteCurveI, primarySiteCurve, i ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", siteCurveI, - siteIndexI, primarySiteCurve + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", siteCurveI, siteIndexI, primarySiteCurve ), e ); } @@ -891,15 +1193,13 @@ static void estimateMissingSiteIndices(PolygonProcessingState state) throws Proc } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion between curves {0} and {1}. Skipping species {2}", - primarySiteCurve, siteCurveI, i + "there is no conversion between curves {0} and {1}. Skipping species {2}", primarySiteCurve, siteCurveI, i ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed. Skipping species {3}", - primarySiteCurve, primarySpeciesSiteIndex, siteCurveI, i + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed. Skipping species {3}", primarySiteCurve, primarySpeciesSiteIndex, siteCurveI, i ), e ); } @@ -1001,8 +1301,8 @@ private static void validatePolygon(VdypPolygon polygon) throws ProcessingExcept throw new ProcessingException( MessageFormat.format( - "Polygon {0}''s year value {1} is < 1900", polygon.getDescription().getName(), - polygon.getDescription().getYear() + "Polygon {0}''s year value {1} is < 1900", polygon.getDescription().getName(), polygon + .getDescription().getYear() ) ); } @@ -1020,8 +1320,8 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing if (state.getNSpecies() == 0) { throw new ProcessingException( MessageFormat.format( - "Polygon {0} layer 0 has no species with basal area above {1}", - state.getLayer().getParent().getDescription().getName(), MIN_BASAL_AREA + "Polygon {0} layer 0 has no species with basal area above {1}", state.getLayer().getParent() + .getDescription().getName(), MIN_BASAL_AREA ) ); } @@ -1080,7 +1380,8 @@ static void determinePolygonRankings(PolygonProcessingState state, Collection
  • secondaryGenusName = secondHighestPercentageIndex != -1 - ? Optional.of(state.wallet.speciesNames[secondHighestPercentageIndex]) : Optional.empty(); + ? Optional.of(state.wallet.speciesNames[secondHighestPercentageIndex]) + : Optional.empty(); try { int inventoryTypeGroup = findInventoryTypeGroup(primaryGenusName, secondaryGenusName, highestPercentage); @@ -1126,8 +1427,7 @@ static void combinePercentages(String[] speciesNames, List combinationGr if (speciesNames.length != percentages.length) { throw new IllegalArgumentException( MessageFormat.format( - "the length of speciesNames ({}) must match that of percentages ({}) but it doesn't", - speciesNames.length, percentages.length + "the length of speciesNames ({}) must match that of percentages ({}) but it doesn't", speciesNames.length, percentages.length ) ); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 1f8ce95f9..949d11be8 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -1,6 +1,5 @@ package ca.bc.gov.nrs.vdyp.forward; -import java.text.MessageFormat; import java.util.List; import java.util.Map; import java.util.Optional; @@ -9,17 +8,20 @@ import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.model.VdypGrowthDetails; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.DebugSettings; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; class ForwardProcessingState { @@ -28,20 +30,17 @@ class ForwardProcessingState { private static final int LAYERS_PER_INSTANCE = 2; /** An "instance" is the processing state of one polygon */ + @SuppressWarnings("unused") private static final int MAX_INSTANCES = 3; - /** - * We allocate one record for the Primary Layer and one record for the Veteran Layer of each instance. - */ - private static final int MAX_RECORDS = LAYERS_PER_INSTANCE * MAX_INSTANCES; - /** The control map defining the context of the execution */ private final Map controlMap; // Cached values from the controlMap final GenusDefinitionMap genusDefinitionMap; - final VdypGrowthDetails vdypGrowthDetails; + final ForwardControlVariables forwardGrowthDetails; + final ForwardDebugSettings debugSettings; final Map netDecayWasteCoeMap; final MatrixMap2> netDecayCoeMap; final MatrixMap2 wasteModifierMap; @@ -56,20 +55,25 @@ class ForwardProcessingState { final Map smallComponentQuadMeanDiameterCoefficients; final Map smallComponentBasalAreaCoefficients; final Map smallComponentProbabilityCoefficients; + final Map maximumAgeBySiteCurveNumber; /** The storage banks */ - private final Bank[] banks; + private final Bank[/* instances */][/* layers of instance */] banks; /** The active state */ private PolygonProcessingState pps; - // VDEBUG - NDEBUG - // TODO - public ForwardProcessingState(Map controlMap) { this.controlMap = controlMap; - banks = new Bank[MAX_RECORDS]; + banks = new Bank[][] { new Bank[LAYERS_PER_INSTANCE], new Bank[LAYERS_PER_INSTANCE], + new Bank[LAYERS_PER_INSTANCE] }; + + this.forwardGrowthDetails = Utils + .expectParsedControl(controlMap, ControlKey.VTROL, ForwardControlVariables.class); + this.debugSettings = new ForwardDebugSettings( + Utils.expectParsedControl(controlMap, ControlKey.DEBUG_SWITCHES, DebugSettings.class) + ); List genusDefinitions = Utils .>expectParsedControl(controlMap, ControlKey.SP0_DEF, List.class); @@ -90,7 +94,6 @@ public ForwardProcessingState(Map controlMap) { this.closeUtilizationCoeMap = Utils.>>expectParsedControl( controlMap, ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class ); - this.vdypGrowthDetails = Utils.expectParsedControl(controlMap, ControlKey.VTROL, VdypGrowthDetails.class); this.totalStandWholeStepVolumeCoeMap = Utils.>expectParsedControl( controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class ); @@ -117,6 +120,9 @@ public ForwardProcessingState(Map controlMap) { this.smallComponentProbabilityCoefficients = Utils.>expectParsedControl( controlMap, ControlKey.SMALL_COMP_PROBABILITY, Map.class ); + this.maximumAgeBySiteCurveNumber = Utils.>expectParsedControl( + controlMap, ControlKey.SITE_CURVE_AGE_MAX, Map.class + ); } public GenusDefinitionMap getGenusDefinitionMap() { @@ -139,21 +145,21 @@ public CompVarAdjustments getCompVarAdjustments() { return Utils.expectParsedControl(controlMap, ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); } - public VdypGrowthDetails getVdypGrowthDetails() { - return Utils.expectParsedControl(controlMap, ControlKey.VTROL, VdypGrowthDetails.class); + public ForwardControlVariables getForwardControlVariables() { + return Utils.expectParsedControl(controlMap, ControlKey.VTROL, ForwardControlVariables.class); } private static final float MIN_BASAL_AREA = 0.001f; public void setPolygon(VdypPolygon polygon) { // Move the primary layer of the given polygon to bank zero. - assert toIndex(0, LayerType.PRIMARY) == 0; - banks[0] = new Bank( + banks[0][0] = new Bank( polygon.getPrimaryLayer(), polygon.getBiogeoclimaticZone(), s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA : true + ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA + : true ); - pps = new PolygonProcessingState(this, polygon, banks[0], controlMap); + pps = new PolygonProcessingState(this, polygon, banks[0][0], controlMap); } public PolygonProcessingState getPolygonProcessingState() { @@ -165,29 +171,14 @@ public Map getControlMap() { } public void storeActive(int instanceNumber, LayerType layerType) { - banks[toIndex(instanceNumber, layerType)] = pps.wallet.copy(); + banks[instanceNumber][layerType.ordinal()] = pps.wallet.copy(); } public void transfer(int fromInstanceNumber, int toInstanceNumber, LayerType layerType) { - banks[toIndex(toInstanceNumber, layerType)] = banks[toIndex(fromInstanceNumber, layerType)].copy(); + banks[toInstanceNumber][layerType.ordinal()] = banks[fromInstanceNumber][layerType.ordinal()].copy(); } public Bank getBank(int instanceNumber, LayerType layerType) { - return banks[toIndex(instanceNumber, layerType)]; - } - - private static int toIndex(int instanceNumber, LayerType layerType) { - return instanceNumber * LAYERS_PER_INSTANCE + toLayerIndex(layerType); - } - - private static int toLayerIndex(LayerType layerType) { - switch (layerType) { - case PRIMARY: - return 0; - case VETERAN: - return 1; - default: - throw new IllegalStateException(MessageFormat.format("Unsupported LayerType {0}", layerType)); - } + return banks[instanceNumber][layerType.ordinal()]; } } \ No newline at end of file diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index 47618c5a4..0f50156cc 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -2,9 +2,11 @@ import java.io.IOException; import java.nio.file.Path; +import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.slf4j.Logger; @@ -12,10 +14,13 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; /** @@ -96,7 +101,6 @@ void run(FileResolver resolver, List controlFileNames, Set * * @throws ProcessingException */ - @SuppressWarnings("unchecked") public void process(Set vdypPassSet, Map controlMap) throws ProcessingException { logger.info("Beginning processing with given configuration"); @@ -119,17 +123,13 @@ public void process(Set vdypPassSet, Map controlMap if (vdypPassSet.contains(ForwardPass.PASS_3)) { try { - var polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap - .get(ControlKey.FORWARD_INPUT_GROWTO.name()); - var polygonDescriptionStream = polygonDescriptionStreamFactory.get(); - var fpe = new ForwardProcessingEngine(controlMap); var forwardDataStreamReader = new ForwardDataStreamReader(controlMap); // Fetch the next polygon to process. int nPolygonsProcessed = 0; - while (polygonDescriptionStream.hasNext()) { + while (true) { if (nPolygonsProcessed == maxPoly) { logger.info( @@ -138,14 +138,19 @@ public void process(Set vdypPassSet, Map controlMap ); } - var polygon = forwardDataStreamReader.readNextPolygon(polygonDescriptionStream.next()); - + var polygonHolder = forwardDataStreamReader.readNextPolygon(); + if (polygonHolder.isEmpty()) { + break; + } + + var polygon = polygonHolder.get(); + fpe.processPolygon(polygon); nPolygonsProcessed += 1; } - - } catch (ResourceParseException | IOException e) { + + } catch (IOException e) { throw new ProcessingException(e); } } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 0268bf1b9..725044425 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -9,8 +9,8 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypGrowthDetails; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; import ca.bc.gov.nrs.vdyp.model.BecDefinition; @@ -173,8 +173,8 @@ public VdypPolygonLayer getLayer() { return wallet.getLayer(); } - public VdypGrowthDetails getVdypGrowthDetails() { - return fps.vdypGrowthDetails; + public ForwardControlVariables getVdypGrowthDetails() { + return fps.forwardGrowthDetails; } public MatrixMap2> getNetDecayCoeMap() { @@ -255,6 +255,10 @@ public int getInventoryTypeGroup() { return inventoryTypeGroup; } + /** + * @param n index of species for whom the site curve number is to be returned. + * @return the site curve number of the given species. + */ public int getSiteCurveNumber(int n) { if (!areSiteCurveNumbersSet) { throw new IllegalStateException(UNSET_SITE_CURVE_NUMBERS); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java index 135f20464..81bda67c9 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java @@ -18,12 +18,13 @@ public class VdypPolygon extends VdypEntity { private final Optional inventoryTypeGroup; // ITG private final Optional basalAreaGroup; // GRPBA1 private final Optional fipMode; // MODE - + // Set after construction private VdypPolygonLayer primaryLayer; private Optional veteranLayer = Optional.empty(); private Set layers = new HashSet<>(); - + private Optional targetYear = Optional.empty(); + public VdypPolygon( VdypPolygonDescription vdypPolygonDescription, BecDefinition bec, Character fizId, float percentForestLand, Optional inventoryTypeGroup, Optional basalAreaGroup, Optional fipMode @@ -68,6 +69,14 @@ public Set getLayers() { return Collections.unmodifiableSet(layers); } + public Optional getTargetYear() { + return targetYear; + } + + public void setTargetYear(int targetYear) { + this.targetYear = Optional.of(targetYear); + } + public VdypPolygonDescription getDescription() { return description; } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 0c2bacabc..5507192cd 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.forward.parsers; import java.io.IOException; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -11,6 +12,7 @@ import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; +import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.io.EndOfRecord; @@ -23,6 +25,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.GroupingStreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.io.parse.value.ControlledValueParser; +import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDistribution; @@ -130,42 +133,57 @@ protected ValueOrMarker, EndOfRecord> convert(MapoptSafe(entry.get(IS_PRIMARY_SPECIES)); var siteCurveNumber = Utils.optSafe(entry.get(SITE_CURVE_NUMBER)) .orElse(VdypEntity.MISSING_INTEGER_VALUE); - - var builder = new ValueOrMarker.Builder, EndOfRecord>(); - return layerType.handle(l -> builder.value(l.map(lt -> { - + + GenusDistributionSet speciesDistributionSet; + + // Validation + if (layerType.isValue()) { List gdList = new ArrayList<>(); - + Utils.ifBothPresent( genusNameText0.filter(t -> genusDefinitionMap.contains(t)), percentGenus0, (s, p) -> gdList.add(new GenusDistribution(0, genusDefinitionMap.get(s), p)) ); - + Utils.ifBothPresent( genusNameText1.filter(t -> genusDefinitionMap.contains(t)), percentGenus1, (s, p) -> gdList.add(new GenusDistribution(1, genusDefinitionMap.get(s), p)) ); - + Utils.ifBothPresent( genusNameText2.filter(t -> genusDefinitionMap.contains(t)), percentGenus2, (s, p) -> gdList.add(new GenusDistribution(2, genusDefinitionMap.get(s), p)) ); - + Utils.ifBothPresent( genusNameText3.filter(t -> genusDefinitionMap.contains(t)), percentGenus3, (s, p) -> gdList.add(new GenusDistribution(3, genusDefinitionMap.get(s), p)) ); - + + speciesDistributionSet = new GenusDistributionSet(3, gdList); + try { GenusDistributionSet.validate(3, gdList); } catch (InvalidGenusDistributionSet e) { - new ResourceParseException(e); + throw new ResourceParseException(e); } - - GenusDistributionSet speciesDistributionSet = new GenusDistributionSet(3, gdList); + + if (siteCurveNumber != VdypEntity.MISSING_INTEGER_VALUE) { + try { + SiteIndexEquation.getByIndex(siteCurveNumber); + } catch (IllegalArgumentException e) { + throw new ResourceParseException(MessageFormat.format("{0} does not identify a known Site Curve", siteCurveNumber)); + } + } + } else { + speciesDistributionSet = null; + } + + var builder = new ValueOrMarker.Builder, EndOfRecord>(); + return layerType.handle(l -> builder.value(l.map(lt -> { var genus = optionalGenus.orElse(genusDefinitionMap.getByIndex(genusIndex).getAlias()); - + return new VdypLayerSpecies( polygonId, lt, genusIndex, genus, speciesDistributionSet, siteIndex, dominantHeight, totalAge, ageAtBreastHeight, yearsToBreastHeight, isPrimarySpecies, siteCurveNumber diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java index 78f15f44d..0c42d7d93 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java @@ -1,9 +1,10 @@ package ca.bc.gov.nrs.vdyp.forward; -import java.io.IOException; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; import org.junit.jupiter.api.Test; @@ -25,16 +26,16 @@ void test() throws IOException, ResourceParseException, ProcessingException { int nPolygonsProcessed = 0; while (polygonDescriptionStream.hasNext()) { - var polygonDescription = polygonDescriptionStream.next(); + var polygon = forwardDataStreamReader.readNextPolygon(); - var polygon = forwardDataStreamReader.readNextPolygon(polygonDescription); - - fpe.processPolygon(polygon); - - nPolygonsProcessed += 1; + if (polygon.isPresent()) { + fpe.processPolygon(polygon.get()); + nPolygonsProcessed += 1; + } else { + break; + } } - logger.info("{} polygons processed", nPolygonsProcessed); + assertEquals(10, nPolygonsProcessed); } - } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index a480164f7..3f2c107db 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; @@ -28,7 +29,6 @@ import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonDescriptionParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypSpeciesParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypUtilizationParser; @@ -76,27 +76,25 @@ void test() throws IOException, ResourceParseException, ProcessingException { assertThat(fpe.fps.getGenusDefinitionMap(), notNullValue()); assertThat(fpe.fps.getSiteCurveMap(), notNullValue()); - // Fetch the next polygon to process. int nPolygonsProcessed = 0; - while (polygonDescriptionStream.hasNext()) { - - var polygonDescription = polygonDescriptionStream.next(); - - var polygon = forwardDataStreamReader.readNextPolygon(polygonDescription); - - fpe.processPolygon(polygon); - - nPolygonsProcessed += 1; + while (true) { + var polygon = forwardDataStreamReader.readNextPolygon(); + + if (polygon.isPresent()) { + fpe.processPolygon(polygon.get()); + nPolygonsProcessed += 1; + } else { + break; + } } - logger.info("{} polygons processed", nPolygonsProcessed); + assertEquals(10, nPolygonsProcessed); } @Test void testFindPrimarySpecies() throws IOException, ResourceParseException, ProcessingException { - var polygonDescription = polygonDescriptionStream.next(); - var polygon = forwardDataStreamReader.readNextPolygon(polygonDescription); + var polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); { ForwardProcessingState fps = new ForwardProcessingState(controlMap); @@ -289,8 +287,7 @@ void testCalculateMissingSiteCurves() throws IOException, ResourceParseException var reader = new ForwardDataStreamReader(controlMap); - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_MISSING_SITE_CURVES); @@ -325,8 +322,7 @@ void testCalculateMissingSiteCurvesNoSiteCurveData() var reader = new ForwardDataStreamReader(controlMap); - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_MISSING_SITE_CURVES); @@ -365,8 +361,7 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti var reader = new ForwardDataStreamReader(controlMap); - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.ESTIMATE_MISSING_SITE_INDICES); @@ -384,27 +379,46 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti void testEstimateMissingSiteIndicesStep2() throws ProcessingException, IOException, ResourceParseException, CurveErrorException, SpeciesErrorException, NoAnswerException { - var targetDescription = VdypPolygonDescriptionParser.parse("01004 S000037 00 1957"); - var polygon = forwardDataStreamReader.readNextPolygon(targetDescription); + buildPolygonParserForStream("testPolygon.dat", "01002 S000001 00 1970 CWH A 99 37 1 1"); + + buildSpeciesParserForStream( + "testSpecies.dat", // + "01002 S000001 00 1970 P 3 B B 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // + "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // + "01002 S000001 00 1970 P 5 D D 100.0 0.0 0.0 0.0 13.40 28.90 265.0 253.9 11.1 1 12", // + "01002 S000001 00 1970 P 8 H H 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // + "01002 S000001 00 1970 P 15 S S 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // + "01002 S000001 00 1970" + ); + + buildUtilizationParserForStandardStream("testUtilizations.dat"); + + var siteCurveMap = new MatrixMap2Impl( + new ArrayList(), new ArrayList(), (k1, k2) -> SiteIndexEquation.SI_NO_EQUATION + ); + + controlMap.put(ControlKey.SITE_CURVE_NUMBERS.name(), siteCurveMap); + + var reader = new ForwardDataStreamReader(controlMap); + + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.ESTIMATE_MISSING_SITE_INDICES); - var sourceSiteCurve = SiteIndexEquation.SI_CWC_KURUCZ; + var sourceSiteCurve = SiteIndexEquation.SI_CWC_BARKER; var sourceSiteIndex = 13.4; - var targetSiteCurve = SiteIndexEquation.SI_CWC_BARKER; + var targetSiteCurve = SiteIndexEquation.SI_CWC_NIGH; double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getPolygonProcessingState().wallet.siteIndices[1], is((float) expectedValue)); + assertThat(fpe.fps.getPolygonProcessingState().wallet.siteIndices[2], is((float) expectedValue)); } @Test void testEstimateMissingYearsToBreastHeightValues() throws ProcessingException, IOException, ResourceParseException { - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); - buildSpeciesParserForStream( "testSpecies.dat", // "01002 S000001 00 1970 P 3 B B 100.0 0.0 0.0 0.0 -9.00 -9.00 15.0 11.0 -9.0 0 -9", // @@ -417,7 +431,7 @@ void testEstimateMissingYearsToBreastHeightValues() var reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon( @@ -433,8 +447,6 @@ void testEstimateMissingYearsToBreastHeightValues() @Test void testCalculateDominantHeightAgeSiteIndex() throws ProcessingException, IOException, ResourceParseException { - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); - buildSpeciesParserForStream( "testSpecies.dat", // // Polygon Year L? x G S1 % S2 % S3 % S4 % Sidx domH age agebh y2bh P? SC @@ -450,7 +462,7 @@ void testCalculateDominantHeightAgeSiteIndex() throws ProcessingException, IOExc var reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX); @@ -464,11 +476,9 @@ void testCalculateDominantHeightAgeSiteIndex() throws ProcessingException, IOExc @Test void testSetEquationGroups() throws ResourceParseException, IOException, ProcessingException { - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); var reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().get(); ForwardProcessingState fps = new ForwardProcessingState(controlMap); fps.setPolygon(polygon); @@ -491,8 +501,6 @@ void testSetEquationGroups() throws ResourceParseException, IOException, Process void testCalculateDominantHeightAgeSiteIndexNoSecondary() throws ProcessingException, IOException, ResourceParseException { - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); - buildSpeciesParserForStream( "testSpecies.dat", // "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 34.00 -9.00 22.0 -9.0 -9.0 0 -9", // @@ -518,7 +526,7 @@ void testCalculateDominantHeightAgeSiteIndexNoSecondary() var reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java new file mode 100644 index 000000000..65f37f89a --- /dev/null +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -0,0 +1,84 @@ +package ca.bc.gov.nrs.vdyp.forward; + +//import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe; +//import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.controlMapHasEntry; +//import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.hasBec; +//import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.mmEmpty; +//import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.mmHasEntry; +//import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; +import static org.hamcrest.MatcherAssert.assertThat; +//import static org.hamcrest.Matchers.allOf; +//import static org.hamcrest.Matchers.contains; +//import static org.hamcrest.Matchers.hasEntry; +//import static org.hamcrest.Matchers.hasItem; +//import static org.hamcrest.Matchers.hasKey; +//import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +//import static org.hamcrest.Matchers.isA; +//import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; + +class GrowDominantHeightTest { + + protected static final Logger logger = LoggerFactory.getLogger(GrowDominantHeightTest.class); + + protected static ForwardControlParser parser; + protected static Map controlMap; + + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; + + protected static ForwardDataStreamReader forwardDataStreamReader; + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeTest() throws IOException, ResourceParseException { + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + .get(ControlKey.FORWARD_INPUT_GROWTO.name()); + polygonDescriptionStream = polygonDescriptionStreamFactory.get(); + + forwardDataStreamReader = new ForwardDataStreamReader(controlMap); + } + + @Test + void test1() throws ProcessingException { + + var polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + float hd = 35.2999992f; + int sc = 13; + float si = 35; + float ytbh = 1.0f; + + Map map + = Utils.>optSafe(controlMap.get(ControlKey.SITE_CURVE_AGE_MAX.name())) + .orElseThrow(() -> new IllegalStateException()); + SiteCurveAgeMaximum maximums = map.get(sc); + + Region region = polygon.getBiogeoclimaticZone().getRegion(); + float gdh = ForwardProcessingEngine.growDominantHeight(maximums, region, hd, sc, si, ytbh); + + assertThat(gdh, is(0.173380271f)); + } +} diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index 6cdb027a1..2b8683df9 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -57,12 +57,9 @@ ControlKey.SP0_DEF, allOf(instanceOf(List.class), hasItem(instanceOf(GenusDefini @Test void testConstruction() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); assertThat(pLayer, notNullValue()); @@ -121,12 +118,9 @@ void testConstruction() throws IOException, ResourceParseException, ProcessingEx @Test void testSetCopy() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); assertThat(pLayer, notNullValue()); @@ -143,11 +137,9 @@ void testSetCopy() throws IOException, ResourceParseException, ProcessingExcepti @Test void testRemoveSmallLayers() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); assertThat(pLayer, notNullValue()); @@ -176,11 +168,9 @@ void testRemoveSmallLayers() throws IOException, ResourceParseException, Process @Test void testCopyConstructor() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); assertThat(pLayer, notNullValue()); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java index 8a7579dc7..c3c4263e7 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java @@ -1,5 +1,17 @@ package ca.bc.gov.nrs.vdyp.forward; +import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.BASAL_AREA; +import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.LOREY_HEIGHT; +import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER; +import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.WHOLE_STEM_VOLUME; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.OVER225; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.U125TO175; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.U175TO225; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.U75TO125; +import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.CLOSE_UTIL_VOL; +import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY; +import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE; +import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.WHOLE_STEM_VOL; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -10,22 +22,16 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonDescriptionParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.LayerType; -import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.*; -import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.*; -import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.*; class SetCompatibilityVariablesForwardProcessingEngineTest extends AbstractForwardProcessingEngineTest { @Test void testSetCompatibilityVariables() throws ResourceParseException, IOException, ProcessingException { - var testPolygonDescription = VdypPolygonDescriptionParser.parse("01002 S000001 00 1970"); var reader = new ForwardDataStreamReader(controlMap); - - var polygon = reader.readNextPolygon(testPolygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(); ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.SET_COMPATIBILITY_VARIABLES); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index 743341c04..98df45875 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -50,11 +50,12 @@ void testReadPolygons() throws Exception { while (polygonDescriptionStream.hasNext()) { - var polygonDescription = polygonDescriptionStream.next(); - - var polygon = reader.readNextPolygon(polygonDescription); - - polygons.add(polygon); + var polygon = reader.readNextPolygon(); + if (polygon.isPresent()) { + polygons.add(polygon.get()); + } else { + break; + } } assertThat(polygons, Matchers.hasSize(10)); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java index 4981caac4..28c652c29 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java @@ -4,19 +4,20 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypControlVariableParser; +import ca.bc.gov.nrs.vdyp.forward.parsers.ForwardControlVariableParser; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; -class VdypGrowthDetailParserTest { +class VdypForwardControlVariablesParserTest { @Test void testNullInput() throws Exception { try { - var parser = new VdypControlVariableParser(); + var parser = new ForwardControlVariableParser(); parser.parse(null); Assertions.fail(); } catch (ValueParseException e) { @@ -27,7 +28,7 @@ void testNullInput() throws Exception { @Test void testEmptyInput() throws Exception { try { - var parser = new VdypControlVariableParser(); + var parser = new ForwardControlVariableParser(); parser.parse(" "); Assertions.fail(); } catch (ValueParseException e) { @@ -38,7 +39,7 @@ void testEmptyInput() throws Exception { @Test void testInvalidInput() throws Exception { try { - var parser = new VdypControlVariableParser(); + var parser = new ForwardControlVariableParser(); parser.parse("a b c"); Assertions.fail(); } catch (ValueParseException e) { @@ -48,28 +49,23 @@ void testInvalidInput() throws Exception { @Test void testValidInput() throws Exception { - var parser = new VdypControlVariableParser(); - var details1 = parser.parse("-1"); - assertThat(details1, hasProperty("yearCounter", is(-1))); + var parser = new ForwardControlVariableParser(); - var details2 = parser.parse("1 2 3 4 5 6"); - assertThat(details2, hasProperty("yearCounter", is(1))); - assertThat(1, equalTo(details2.getControlVariable(1))); - assertThat(2, equalTo(details2.getControlVariable(2))); - assertThat(3, equalTo(details2.getControlVariable(3))); - assertThat(4, equalTo(details2.getControlVariable(4))); - assertThat(5, equalTo(details2.getControlVariable(5))); - assertThat(6, equalTo(details2.getControlVariable(6))); + var details = parser.parse("1 1 1 1 1 1"); + assertThat(1, equalTo(details.getControlVariable(ControlVariable.GROW_TARGET_1))); + assertThat(1, equalTo(details.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2))); + assertThat(1, equalTo(details.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3))); + assertThat(1, equalTo(details.getControlVariable(ControlVariable.OUTPUT_FILES_4))); + assertThat(1, equalTo(details.getControlVariable(ControlVariable.ALLOW_COMPAT_VAR_CALCS_5))); + assertThat(1, equalTo(details.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6))); } @Test void testExtraInputIgnored() throws Exception { - var parser = new VdypControlVariableParser(); - var details1 = parser.parse("-1"); - assertThat(details1, hasProperty("yearCounter", is(-1))); + var parser = new ForwardControlVariableParser(); - var details2 = parser.parse("1 2 3 4 5 6 7 8 9 10 11"); - assertThat(details2, hasProperty("yearCounter", is(1))); - assertThat(10, equalTo(details2.getControlVariable(10))); + var details = parser.parse("1 1 1 1 1 1 1 1 1 1 1"); + assertThat(1, equalTo(details.getControlVariable(10))); + assertThrows(IllegalArgumentException.class, () -> details.getControlVariable(11)); } } From 2072910500f031fdfb02136d365fa3b99accfb01 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 8 Jul 2024 13:18:12 -0700 Subject: [PATCH 05/66] Housekeeping --- .../vdyp/common_calculators/SiteIndex2Age.java | 10 ++-------- .../ca/bc/gov/nrs/vdyp/model/DebugSettings.java | 1 - .../gov/nrs/vdyp/forward/ForwardProcessor.java | 7 ------- .../forward/model/ForwardDebugSettings.java | 1 - .../forward/model/VdypSpeciesUtilization.java | 17 +++++++++++------ .../vdyp/forward/parsers/VdypSpeciesParser.java | 1 - 6 files changed, 13 insertions(+), 24 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java index ded2f17e8..0c7b6db62 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java @@ -523,7 +523,7 @@ public static double indexToAge( return (age); } - public static double iterate( + private static double iterate( SiteIndexEquation cuIndex, double siteHeight, SiteIndexAgeType ageType, double siteIndex, double yearsToBreastHeight ) throws CommonCalculatorException { @@ -538,12 +538,6 @@ public static double iterate( step = si2age / 2; err_count = 0; - /* do a preliminary test to catch some obvious errors */ - test_ht = SiteIndex2Height.indexToHeight( - cuIndex, si2age, SI_AT_TOTAL, siteIndex, yearsToBreastHeight, 0.5 /* may have to change */ - ); - // This would throw an illegal argument exception and move up the stack - /* loop until real close, or other end condition */ do { if (TEST) { @@ -603,7 +597,7 @@ public static double iterate( } /* see if we're close enough */ - if ( (test_ht - siteHeight > 0.005) || (test_ht - siteHeight < -0.005)) { + if (Math.abs(test_ht - siteHeight) > 0.005) { /* not close enough */ if (test_ht > siteHeight) { if (step > 0) { diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java index 013e57db4..b58adbd91 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java @@ -1,6 +1,5 @@ package ca.bc.gov.nrs.vdyp.model; -import java.lang.reflect.Array; import java.util.Arrays; /** diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index 0f50156cc..4cbbec657 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -2,11 +2,9 @@ import java.io.IOException; import java.nio.file.Path; -import java.text.MessageFormat; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import org.slf4j.Logger; @@ -14,14 +12,9 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; /** * diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java index 7a383546e..396d2fc20 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java @@ -1,7 +1,6 @@ package ca.bc.gov.nrs.vdyp.forward.model; import java.util.ArrayList; -import java.util.List; import ca.bc.gov.nrs.vdyp.model.DebugSettings; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java index 70cbce5f0..519957e19 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java @@ -215,30 +215,35 @@ private void adjustBasalAreaToMatchTreesPerHectare() throws ProcessingException float basalAreaUpperBound = ForwardProcessingEngine .calculateBasalArea(CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - DQ_EPS, this.liveTreesPerHectare); - float basalAreaError = 0.0f; + float basalAreaError; + float newBasalArea; String message = null; if (this.basalArea < basalAreaLowerBound) { basalAreaError = FloatMath.abs(this.basalArea - basalAreaLowerBound); - this.basalArea = basalAreaLowerBound; + newBasalArea = basalAreaLowerBound; message = MessageFormat.format( - "{0}: Error 6: basal area {1} is {2} below threshold, exceeding the maximum error {3}", this, + "{0}: Error 6: basal area {1} is {2} below threshold, exceeding the maximum error of {3}.", this, this.basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR ); } else if (this.basalArea > basalAreaUpperBound) { basalAreaError = FloatMath.abs(this.basalArea - basalAreaUpperBound); message = MessageFormat.format( - "{0}: Error 6: basal area {1} is {2} above threshold, exceeding the maximum error {3}", this, + "{0}: Error 6: basal area {1} is {2} above threshold, exceeding the maximum error of {3}.", this, this.basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR ); - this.basalArea = basalAreaUpperBound; + newBasalArea = basalAreaUpperBound; + } else { + basalAreaError = 0.0f; + newBasalArea = this.basalArea; } if (basalAreaError > MAX_ACCEPTABLE_BASAL_AREA_ERROR) { throw new ProcessingException(message); + } else { + this.basalArea = newBasalArea; } } - } /** diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 5507192cd..a5608cda6 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -25,7 +25,6 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.GroupingStreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.io.parse.value.ControlledValueParser; -import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDistribution; From 92eca3f2aae00508040e313063c84adc4cd85107 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 8 Jul 2024 13:20:13 -0700 Subject: [PATCH 06/66] Unit test extensions and improvements for Forward --- .../vdyp/io/parse/coe/UpperBoundsParser.java | 3 + .../ca/bc/gov/nrs/vdyp/model/LayerType.java | 17 +- .../vdyp/forward/ForwardProcessingEngine.java | 2 +- .../AbstractForwardProcessingEngineTest.java | 30 +-- .../vdyp/forward/ForwardGrowStepTests.java | 41 ++++ .../forward/ForwardProcessingEngineTest.java | 6 +- .../GeneralForwardProcessingEngineTest.java | 178 ++++++------------ .../vdyp/forward/GrowDominantHeightTest.java | 63 +++++-- 8 files changed, 184 insertions(+), 156 deletions(-) create mode 100644 vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java index fcd18466e..de60371c0 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java @@ -45,6 +45,9 @@ public class UpperBoundsParser implements ControlMapSubResourceParser ALL_USED = Collections.unmodifiableList(List.of(PRIMARY, VETERAN)); private final String alias; + private final Integer index; - private LayerType(String alias) { + LayerType(String alias, Integer index) { this.alias = alias; + this.index = index; } public String getAlias() { return alias; } + + public int getIndex() { + if (index == null) { + throw new UnsupportedOperationException("LayerType " + this.getAlias() + " is not supported"); + } + return index; + } } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index e9074a87b..6a362c78c 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -283,7 +283,7 @@ private void grow( ); } - final SiteIndexAgeType ageType = SiteIndexAgeType.SI_AT_TOTAL; + final SiteIndexAgeType ageType = SiteIndexAgeType.SI_AT_BREAST; double siteIndex_d = siteIndex; double dominantHeight_d = dominantHeight; diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java index 54a8894f6..05a0edc49 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java @@ -20,7 +20,8 @@ abstract class AbstractForwardProcessingEngineTest { - protected static final Logger logger = LoggerFactory.getLogger(AbstractForwardProcessingEngineTest.class); + @SuppressWarnings("unused") + private static final Logger logger = LoggerFactory.getLogger(AbstractForwardProcessingEngineTest.class); protected static ForwardControlParser parser; protected static Map controlMap; @@ -76,7 +77,8 @@ protected void buildUtilizationParserForStream(String fileName, String... stream protected void buildUtilizationParserForStandardStream(String fileName) throws ResourceParseException, IOException { buildUtilizationParserForStream( - fileName, // + fileName, + // polygon year P? I N UC BasalArea TPH Lorey H WhSt Vol CUtl Vol CU-Decay CU-DWst CU-DWBrk QMDBH "01002 S000001 00 1970 P 0 -1 0.01513 5.24 7.0166 0.0630 0.0000 0.0000 0.0000 0.0000 6.1", // "01002 S000001 00 1970 P 0 0 44.93259 595.32 30.9724 620.9775 592.2023 580.1681 577.6229 549.0159 31.0", // "01002 S000001 00 1970 P 0 1 0.53100 64.82 -9.0000 2.5979 0.3834 0.3794 0.3788 0.3623 10.2", // @@ -95,18 +97,18 @@ protected void buildUtilizationParserForStandardStream(String fileName) throws R "01002 S000001 00 1970 P 4 C 2 0.31003 17.87 -9.0000 1.9237 1.4103 1.3710 1.3628 1.2915 14.9", // "01002 S000001 00 1970 P 4 C 3 0.51339 16.55 -9.0000 3.8230 3.3162 3.2127 3.1859 3.0076 19.9", // "01002 S000001 00 1970 P 4 C 4 4.09434 32.92 -9.0000 37.1192 34.6019 31.5703 30.6352 28.5119 39.8", // - "01002 S000001 00 1970 P 5 D -1 0.00000 0.47 10.6033 0.0078 0.0000 0.0000 0.0000 0.0000 6.5", // - "01002 S000001 00 1970 P 5 D 0 5.81006 287.70 33.7440 459.5233 444.0844 436.5280 435.2818 413.6949 36.0", // - "01002 S000001 00 1970 P 5 D 1 0.36138 1.64 -9.0000 0.1091 0.0571 0.0566 0.0565 0.0541 10.5", // - "01002 S000001 00 1970 P 5 D 2 0.82449 2.69 -9.0000 0.5602 0.5048 0.5007 0.5005 0.4783 15.6", // - "01002 S000001 00 1970 P 5 D 3 1.07566 13.82 -9.0000 6.0129 5.6414 5.5975 5.5948 5.3383 20.5", // - "01002 S000001 00 1970 P 5 D 4 3.54853 269.56 -9.0000 452.8412 437.8810 430.3732 429.1300 407.8242 36.9", // - "01002 S000001 00 1970 P 8 H -1 0.00155 0.00 7.5464 0.0000 0.0000 0.0000 0.0000 0.0000 -9.0", // - "01002 S000001 00 1970 P 8 H 0 29.30249 167.90 22.7704 55.8878 49.8291 49.0742 48.8550 46.6828 21.0", // - "01002 S000001 00 1970 P 8 H 1 0.01412 43.57 -9.0000 1.7385 0.1925 0.1913 0.1911 0.1834 10.3", // - "01002 S000001 00 1970 P 8 H 2 0.05128 45.99 -9.0000 5.8666 4.4155 4.3846 4.3789 4.2023 15.1", // - "01002 S000001 00 1970 P 8 H 3 0.45736 33.93 -9.0000 9.6521 8.5752 8.5019 8.4827 8.1397 20.1", // - "01002 S000001 00 1970 P 8 H 4 28.77972 44.42 -9.0000 38.6306 36.6459 35.9963 35.8023 34.1574 31.9", // + "01002 S000001 00 1970 P 5 D -1 0.00155 0.47 10.6033 0.0078 0.0000 0.0000 0.0000 0.0000 6.5", // + "01002 S000001 00 1970 P 5 D 0 29.30249 287.70 33.7440 459.5233 444.0844 436.5280 435.2818 413.6949 36.0", // + "01002 S000001 00 1970 P 5 D 1 0.01412 1.64 -9.0000 0.1091 0.0571 0.0566 0.0565 0.0541 10.5", // + "01002 S000001 00 1970 P 5 D 2 0.05128 2.69 -9.0000 0.5602 0.5048 0.5007 0.5005 0.4783 15.6", // + "01002 S000001 00 1970 P 5 D 3 0.45736 13.82 -9.0000 6.0129 5.6414 5.5975 5.5948 5.3383 20.5", // + "01002 S000001 00 1970 P 5 D 4 28.77972 269.56 -9.0000 452.8412 437.8810 430.3732 429.1300 407.8242 36.9", // + "01002 S000001 00 1970 P 8 H -1 0.00000 0.00 7.5464 0.0000 0.0000 0.0000 0.0000 0.0000 -9.0", // + "01002 S000001 00 1970 P 8 H 0 5.81006 167.90 22.7704 55.8878 49.8291 49.0742 48.8550 46.6828 21.0", // + "01002 S000001 00 1970 P 8 H 1 0.36138 43.57 -9.0000 1.7385 0.1925 0.1913 0.1911 0.1834 10.3", // + "01002 S000001 00 1970 P 8 H 2 0.82449 45.99 -9.0000 5.8666 4.4155 4.3846 4.3789 4.2023 15.1", // + "01002 S000001 00 1970 P 8 H 3 1.07566 33.93 -9.0000 9.6521 8.5752 8.5019 8.4827 8.1397 20.1", // + "01002 S000001 00 1970 P 8 H 4 3.54853 44.42 -9.0000 38.6306 36.6459 35.9963 35.8023 34.1574 31.9", // "01002 S000001 00 1970 P 15 S -1 0.00115 0.36 8.2003 0.0045 0.0000 0.0000 0.0000 0.0000 6.3", // "01002 S000001 00 1970 P 15 S 0 4.37115 51.10 32.0125 55.8879 52.8895 52.4561 52.3768 50.2060 33.0", // "01002 S000001 00 1970 P 15 S 1 0.02225 2.73 -9.0000 0.1291 0.0213 0.0212 0.0212 0.0204 10.2", // diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java new file mode 100644 index 000000000..beddcb7d8 --- /dev/null +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java @@ -0,0 +1,41 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; + +class ForwardGrowStepTests extends AbstractForwardProcessingEngineTest { + + @SuppressWarnings("unused") + private static final Logger logger = LoggerFactory.getLogger(ForwardGrowStepTests.class); + + @Test + void testOnePolygon() throws IOException, ResourceParseException, ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + assertThat(fpe.fps.becLookup, notNullValue()); + assertThat(fpe.fps.genusDefinitionMap, notNullValue()); + assertThat(fpe.fps.siteCurveMap, notNullValue()); + + int nPolygonsProcessed = 0; + var polygon = forwardDataStreamReader.readNextPolygon(); + + if (polygon.isPresent()) { + fpe.processPolygon(polygon.get(), ExecutionStep.GROW); + nPolygonsProcessed += 1; + } + + assertEquals(1, nPolygonsProcessed); + } +} diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java index 0c42d7d93..addca791d 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java @@ -18,9 +18,9 @@ void test() throws IOException, ResourceParseException, ProcessingException { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - assertThat(fpe.fps.getBecLookup(), notNullValue()); - assertThat(fpe.fps.getGenusDefinitionMap(), notNullValue()); - assertThat(fpe.fps.getSiteCurveMap(), notNullValue()); + assertThat(fpe.fps.becLookup, notNullValue()); + assertThat(fpe.fps.genusDefinitionMap, notNullValue()); + assertThat(fpe.fps.siteCurveMap, notNullValue()); // Fetch the next polygon to process. int nPolygonsProcessed = 0; diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index 3f2c107db..1b14f04de 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -11,12 +11,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import org.hamcrest.Matchers; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,53 +26,25 @@ import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.SpeciesErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypSpeciesParser; -import ca.bc.gov.nrs.vdyp.forward.parsers.VdypUtilizationParser; -import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.CommonData; import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; -import ca.bc.gov.nrs.vdyp.test.TestUtils; -class GeneralForwardProcessingEngineTest { +class GeneralForwardProcessingEngineTest extends AbstractForwardProcessingEngineTest { - protected static final Logger logger = LoggerFactory.getLogger(GeneralForwardProcessingEngineTest.class); - - protected static ForwardControlParser parser; - protected static Map controlMap; - - protected static StreamingParserFactory polygonDescriptionStreamFactory; - protected static StreamingParser polygonDescriptionStream; - - protected static ForwardDataStreamReader forwardDataStreamReader; - - @SuppressWarnings("unchecked") - @BeforeEach - void beforeTest() throws IOException, ResourceParseException { - parser = new ForwardControlParser(); - controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - - polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap - .get(ControlKey.FORWARD_INPUT_GROWTO.name()); - polygonDescriptionStream = polygonDescriptionStreamFactory.get(); - - forwardDataStreamReader = new ForwardDataStreamReader(controlMap); - } + @SuppressWarnings("unused") + private static final Logger logger = LoggerFactory.getLogger(GeneralForwardProcessingEngineTest.class); @Test void test() throws IOException, ResourceParseException, ProcessingException { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - assertThat(fpe.fps.getBecLookup(), notNullValue()); - assertThat(fpe.fps.getGenusDefinitionMap(), notNullValue()); - assertThat(fpe.fps.getSiteCurveMap(), notNullValue()); + assertThat(fpe.fps.becLookup, notNullValue()); + assertThat(fpe.fps.genusDefinitionMap, notNullValue()); + assertThat(fpe.fps.siteCurveMap, notNullValue()); int nPolygonsProcessed = 0; while (true) { @@ -97,37 +67,76 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces var polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); { - ForwardProcessingState fps = new ForwardProcessingState(controlMap); - fps.setPolygon(polygon); + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + fpe.fps.setPolygon(polygon); - PolygonProcessingState pps = fps.getPolygonProcessingState(); + PolygonProcessingState pps = fpe.fps.getPolygonProcessingState(); - ForwardProcessingEngine.calculateCoverages(pps); - ForwardProcessingEngine.determinePolygonRankings(pps, CommonData.PRIMARY_SPECIES_TO_COMBINE); + fpe.calculateCoverages(); + fpe.determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); assertThat(pps.getPrimarySpeciesIndex(), is(3)); assertThat(pps.getSecondarySpeciesIndex(), is(4)); assertThat(pps.getInventoryTypeGroup(), is(37)); + assertThat(pps.getPrimarySpeciesGroupNumber(), is(1)); + assertThat(pps.getPrimarySpeciesStratumNumber(), is(1)); } { - ForwardProcessingState fps = new ForwardProcessingState(controlMap); - fps.setPolygon(polygon); - - PolygonProcessingState pps = fps.getPolygonProcessingState(); + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + fpe.fps.setPolygon(polygon); + PolygonProcessingState pps = fpe.fps.getPolygonProcessingState(); var speciesToCombine = Arrays.asList(Arrays.asList(pps.wallet.speciesNames[3], pps.wallet.speciesNames[4])); - ForwardProcessingEngine.calculateCoverages(pps); - ForwardProcessingEngine.determinePolygonRankings(pps, speciesToCombine); + fpe.calculateCoverages(); + fpe.determinePolygonRankings(speciesToCombine); // The test-specific speciesToCombine will combine 3 & 4 into 3 (leaving 4 at 0.0), promoting 2 to // secondary. assertThat(pps.getPrimarySpeciesIndex(), is(3)); assertThat(pps.getSecondarySpeciesIndex(), is(2)); assertThat(pps.getInventoryTypeGroup(), is(37)); + assertThat(pps.getPrimarySpeciesGroupNumber(), is(1)); + assertThat(pps.getPrimarySpeciesStratumNumber(), is(1)); } } + @Test + void testGroupAndStratumNumberSpecialCases() throws IOException, ResourceParseException, ProcessingException { + + // We want the + // "equationModifierGroup.isPresent()" + // and the + // " Region.INTERIOR.equals(pps.wallet.getBecZone().getRegion()) + // && exceptedSpeciesIndicies.contains(primarySpeciesIndex)" + // cases in determinePolygonRankings. + + buildPolygonParserForStream( + "testPolygon.dat", // + "01002 S000001 00 1970 IDF A 99 37 1 1", // + "" + ); + + buildSpeciesParserForStream( + "testSpecies.dat", // + "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 253.9 11.1 0 -9", // + "01002 S000001 00 1970" + ); + + var reader = new ForwardDataStreamReader(controlMap); + + var polygon = reader.readNextPolygon().orElseThrow(); + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.DETERMINE_POLYGON_RANKINGS); + + assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesIndex(), is(1)); + assertThrows(IllegalStateException.class, () -> fpe.fps.getPolygonProcessingState().getSecondarySpeciesIndex()); + assertThat(fpe.fps.getPolygonProcessingState().getInventoryTypeGroup(), is(10)); + assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(), is(35)); + assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesStratumNumber(), is(24)); + } + @Test void testCombinePercentages() { @@ -537,79 +546,4 @@ void testCalculateDominantHeightAgeSiteIndexNoSecondary() assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesAgeAtBreastHeight(), is(Float.NaN)); assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesAgeToBreastHeight(), is(4.7f)); } - - private void buildPolygonParserForStream(String fileName, String... streamContent) - throws ResourceParseException, IOException { - - controlMap.put(ControlKey.FORWARD_INPUT_VDYP_POLY.name(), fileName); - var polygonParser = new VdypPolygonParser(); - var polygonFileResolver = TestUtils.fileResolver(fileName, TestUtils.makeInputStream(streamContent)); - - polygonParser.modify(controlMap, polygonFileResolver); - } - - private void buildSpeciesParserForStream(String fileName, String... streamContent) - throws ResourceParseException, IOException { - - controlMap.put(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SPECIES.name(), fileName); - var speciesParser = new VdypSpeciesParser(); - var speciesFileResolver = TestUtils.fileResolver(fileName, TestUtils.makeInputStream(streamContent)); - - speciesParser.modify(controlMap, speciesFileResolver); - } - - private void buildUtilizationParserForStream(String fileName, String... streamContent) - throws ResourceParseException, IOException { - - controlMap.put(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), fileName); - var utilizationsParser = new VdypUtilizationParser(); - var utilizationsFileResolver = TestUtils.fileResolver(fileName, TestUtils.makeInputStream(streamContent)); - - utilizationsParser.modify(controlMap, utilizationsFileResolver); - } - - private void buildUtilizationParserForStandardStream(String fileName) throws ResourceParseException, IOException { - - buildUtilizationParserForStream( - fileName, // - // Polygon Year P? i S uc ba tph lh ws cu cu-d cu-d-w cu-d-w-b qmd - "01002 S000001 00 1970 P 0 -1 0.01513 5.24 7.0166 0.0630 0.0000 0.0000 0.0000 0.0000 6.1", - "01002 S000001 00 1970 P 0 0 44.93259 595.32 30.9724 620.9775 592.2023 580.1681 577.6229 549.0159 31.0", - "01002 S000001 00 1970 P 0 1 0.53100 64.82 -9.0000 2.5979 0.3834 0.3794 0.3788 0.3623 10.2", - "01002 S000001 00 1970 P 0 2 1.27855 71.93 -9.0000 9.1057 6.9245 6.8469 6.8324 6.5384 15.0", - "01002 S000001 00 1970 P 0 3 2.33020 73.60 -9.0000 22.4019 20.1244 19.8884 19.8375 18.9555 20.1", - "01002 S000001 00 1970 P 0 4 40.79285 384.98 -9.0000 586.8720 564.7699 553.0534 550.5741 523.1597 36.7", - "01002 S000001 00 1970 P 3 B -1 0.00000 0.00 8.0272 0.0000 0.0000 0.0000 0.0000 0.0000 6.1", - "01002 S000001 00 1970 P 3 B 0 0.40292 5.16 36.7553 6.2098 5.9592 5.8465 5.8163 5.5177 31.5", - "01002 S000001 00 1970 P 3 B 1 0.00502 0.76 -9.0000 0.0185 0.0009 0.0009 0.0009 0.0009 9.2", - "01002 S000001 00 1970 P 3 B 2 0.01363 0.93 -9.0000 0.0757 0.0498 0.0497 0.0496 0.0475 13.7", - "01002 S000001 00 1970 P 3 B 3 0.02284 0.88 -9.0000 0.1748 0.1521 0.1514 0.1512 0.1445 18.2", - "01002 S000001 00 1970 P 3 B 4 0.36143 2.60 -9.0000 5.9408 5.7564 5.6446 5.6146 5.3249 42.1", - "01002 S000001 00 1970 P 4 C -1 0.01243 4.40 6.4602 0.0507 0.0000 0.0000 0.0000 0.0000 6.0", - "01002 S000001 00 1970 P 4 C 0 5.04597 83.46 22.9584 43.4686 39.4400 36.2634 35.2930 32.9144 27.7", - "01002 S000001 00 1970 P 4 C 1 0.12822 16.12 -9.0000 0.6027 0.1116 0.1094 0.1090 0.1035 10.1", - "01002 S000001 00 1970 P 4 C 2 0.31003 17.87 -9.0000 1.9237 1.4103 1.3710 1.3628 1.2915 14.9", - "01002 S000001 00 1970 P 4 C 3 0.51339 16.55 -9.0000 3.8230 3.3162 3.2127 3.1859 3.0076 19.9", - "01002 S000001 00 1970 P 4 C 4 4.09434 32.92 -9.0000 37.1192 34.6019 31.5703 30.6352 28.5119 39.8", - "01002 S000001 00 1970 P 5 D -1 0.00155 0.47 10.6033 0.0078 0.0000 0.0000 0.0000 0.0000 6.5", - "01002 S000001 00 1970 P 5 D 0 29.30249 287.70 33.7440 459.5233 444.0844 436.5280 435.2818 413.6949 36.0", - "01002 S000001 00 1970 P 5 D 1 0.01412 1.64 -9.0000 0.1091 0.0571 0.0566 0.0565 0.0541 10.5", - "01002 S000001 00 1970 P 5 D 2 0.05128 2.69 -9.0000 0.5602 0.5048 0.5007 0.5005 0.4783 15.6", - "01002 S000001 00 1970 P 5 D 3 0.45736 13.82 -9.0000 6.0129 5.6414 5.5975 5.5948 5.3383 20.5", - "01002 S000001 00 1970 P 5 D 4 28.77972 269.56 -9.0000 452.8412 437.8810 430.3732 429.1300 407.8242 36.9", - "01002 S000001 00 1970 P 8 H -1 0.00000 0.00 7.5464 0.0000 0.0000 0.0000 0.0000 0.0000 -9.0", - "01002 S000001 00 1970 P 8 H 0 5.81006 167.90 22.7704 55.8878 49.8291 49.0742 48.8550 46.6828 21.0", - "01002 S000001 00 1970 P 8 H 1 0.36138 43.57 -9.0000 1.7385 0.1925 0.1913 0.1911 0.1834 10.3", - "01002 S000001 00 1970 P 8 H 2 0.82449 45.99 -9.0000 5.8666 4.4155 4.3846 4.3789 4.2023 15.1", - "01002 S000001 00 1970 P 8 H 3 1.07566 33.93 -9.0000 9.6521 8.5752 8.5019 8.4827 8.1397 20.1", - "01002 S000001 00 1970 P 8 H 4 3.54853 44.42 -9.0000 38.6306 36.6459 35.9963 35.8023 34.1574 31.9", - "01002 S000001 00 1970 P 15 S -1 0.00115 0.36 8.2003 0.0045 0.0000 0.0000 0.0000 0.0000 6.3", - "01002 S000001 00 1970 P 15 S 0 4.37115 51.10 32.0125 55.8879 52.8895 52.4561 52.3768 50.2060 33.0", - "01002 S000001 00 1970 P 15 S 1 0.02225 2.73 -9.0000 0.1291 0.0213 0.0212 0.0212 0.0204 10.2", - "01002 S000001 00 1970 P 15 S 2 0.07911 4.46 -9.0000 0.6795 0.5440 0.5410 0.5406 0.5189 15.0", - "01002 S000001 00 1970 P 15 S 3 0.26095 8.43 -9.0000 2.7391 2.4396 2.4250 2.4229 2.3254 19.9", - "01002 S000001 00 1970 P 15 S 4 4.00883 35.49 -9.0000 52.3402 49.8846 49.4689 49.3920 47.3414 37.9", - "01002 S000001 00 1970 " - ); - } } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java index 65f37f89a..39f1870d6 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -27,14 +27,12 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; -import ca.bc.gov.nrs.vdyp.model.Region; -import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; class GrowDominantHeightTest { @@ -62,23 +60,64 @@ void beforeTest() throws IOException, ResourceParseException { } @Test - void test1() throws ProcessingException { + void testNormalCurve() throws ProcessingException { - var polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + ForwardProcessingState fps = new ForwardProcessingState(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + fps.setPolygon(forwardDataStreamReader.readNextPolygon().orElseThrow()); float hd = 35.2999992f; int sc = 13; float si = 35; float ytbh = 1.0f; - Map map - = Utils.>optSafe(controlMap.get(ControlKey.SITE_CURVE_AGE_MAX.name())) - .orElseThrow(() -> new IllegalStateException()); - SiteCurveAgeMaximum maximums = map.get(sc); - - Region region = polygon.getBiogeoclimaticZone().getRegion(); - float gdh = ForwardProcessingEngine.growDominantHeight(maximums, region, hd, sc, si, ytbh); + float gdh = ForwardProcessingEngine.growDominantHeight(fps, hd, sc, si, ytbh); assertThat(gdh, is(0.173380271f)); } + + @Test + void testCurveExtension1() throws ProcessingException { + + // Select polygon 01003AS000001 00(1953) - triggers curve extension code + VdypPolygon polygon; + do { + polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + } while (! polygon.getDescription().getName().equals("01003AS000001 00")); + + ForwardProcessingState fps = new ForwardProcessingState(controlMap); + fps.setPolygon(polygon); + + float hd = 29.5f; + int sc = 11; + float si = 14.8000002f; + float ytbh = 10.8000002f; + + float gdh = ForwardProcessingEngine.growDominantHeight(fps, hd, sc, si, ytbh); + + assertThat(gdh, is(0.0f)); + } + + @Test + void testCurveExtension2() throws ProcessingException { + + // Select polygon 01003AS000001 00(1953) - triggers curve extension code + VdypPolygon polygon; + do { + polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + } while (! polygon.getDescription().getName().equals("01003AS000001 00")); + + ForwardProcessingState fps = new ForwardProcessingState(controlMap); + fps.setPolygon(polygon); + + float hd = 26.5f; + int sc = 11; + float si = 14.8000002f; + float ytbh = 5.8000002f; + + float gdh = ForwardProcessingEngine.growDominantHeight(fps, hd, sc, si, ytbh); + + assertThat(gdh, is(0.045883115f)); + } } From f7900cbdb2c39da19ce948cb038b4f3014e58427 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 8 Jul 2024 13:20:41 -0700 Subject: [PATCH 07/66] Changes needed for BA growth calculation --- .../vdyp/forward/ForwardProcessingEngine.java | 317 +++++++++++------- .../vdyp/forward/ForwardProcessingState.java | 71 ++-- .../vdyp/forward/PolygonProcessingState.java | 126 ++++++- .../vdyp/forward/SpeciesRankingDetails.java | 3 +- 4 files changed, 364 insertions(+), 153 deletions(-) diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 6a362c78c..de77f82b9 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -15,6 +15,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +36,7 @@ import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; +import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperBoundsParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; @@ -56,8 +58,8 @@ public class ForwardProcessingEngine { private static final Logger logger = LoggerFactory.getLogger(ForwardProcessor.class); - private static final int UTILIZATION_ALL_INDEX = UtilizationClass.ALL.ordinal(); - private static final int UTILIZATION_SMALL_INDEX = UtilizationClass.SMALL.ordinal(); + private static final int UC_ALL_INDEX = UtilizationClass.ALL.ordinal(); + private static final int UC_SMALL_INDEX = UtilizationClass.SMALL.ordinal(); private static final float MIN_BASAL_AREA = 0.001f; @@ -122,7 +124,7 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStep) throws P // Determine the target year of the growth int targetYear; - int growTargetControlVariableValue = fps.getForwardControlVariables() + int growTargetControlVariableValue = fps.forwardControlVariables .getControlVariable(ControlVariable.GROW_TARGET_1); if (growTargetControlVariableValue == -1) { if (polygon.getTargetYear().isEmpty()) { @@ -161,16 +163,16 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro // SCINXSET - note these are calculated directly from the Primary bank of instance 1 if (lastStep.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { - calculateMissingSiteCurves(bank, fps.getSiteCurveMap(), fps.getPolygonProcessingState()); + calculateMissingSiteCurves(bank, fps.siteCurveMap, fps.getPolygonProcessingState()); } // VPRIME1, method == 1 if (lastStep.ordinal() >= ExecutionStep.CALCULATE_COVERAGES.ordinal()) { - calculateCoverages(pps); + calculateCoverages(); } if (lastStep.ordinal() >= ExecutionStep.DETERMINE_POLYGON_RANKINGS.ordinal()) { - determinePolygonRankings(pps, CommonData.PRIMARY_SPECIES_TO_COMBINE); + determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); } // SITEADD (TODO: SITEADDU when NDEBUG 11 > 0) @@ -184,7 +186,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 if (lastStep.ordinal() >= ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX.ordinal()) { - calculateDominantHeightAgeSiteIndex(pps, fps.getHl1Coefficients()); + calculateDominantHeightAgeSiteIndex(pps, fps.hl1Coefficients); } // CVSET1 @@ -193,7 +195,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro } if (lastStep.ordinal() >= ExecutionStep.GROW.ordinal()) { - int veteranLayerInstance = 1; + int veteranLayerInstance = 0; int primaryLayerSourceInstance = 2; fps.storeActive(primaryLayerSourceInstance, LayerType.PRIMARY); @@ -205,7 +207,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro boolean createNewGroups = fps.debugSettings.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 && fps.getPolygonProcessingState().getNSpecies() > 1; - int primaryLayerTargetInstance = 3; + int primaryLayerTargetInstance = 2; int currentYear = startingYear; while (currentYear <= untilYear) { @@ -238,37 +240,89 @@ private void grow( // Call to BANKOUT1 unnecessary; pps.wallet already contains the primary layer + Bank primaryBank = fps.getBank(primaryLayerSourceInstance, LayerType.PRIMARY); + Optional veteranBank = Optional.ofNullable(fps.getBank(veteranLayerInstance, LayerType.VETERAN)); + // If update-during-growth is set, and this is not the starting year, update the // context int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); if (currentYear > startingYear - && fps.getForwardControlVariables().getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { + && fps.forwardControlVariables.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { // VPRIME1, method == 1 - calculateCoverages(pps); + calculateCoverages(); // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 - calculateDominantHeightAgeSiteIndex(pps, fps.getHl1Coefficients()); + calculateDominantHeightAgeSiteIndex(pps, fps.hl1Coefficients); } float dominantHeight = pps.getPrimarySpeciesDominantHeight(); - int siteCurveNumber = pps.getSiteCurveNumber(startingYear); + int siteCurveNumber = pps.getSiteCurveNumber(pps.getPrimarySpeciesIndex()); float siteIndex = pps.getPrimarySpeciesSiteIndex(); float yearsToBreastHeight = pps.getPrimarySpeciesAgeToBreastHeight(); + float yearsAtBreastHeight = pps.getPrimarySpeciesAgeAtBreastHeight(); - SiteCurveAgeMaximum scAgeMaximums = fps.maximumAgeBySiteCurveNumber.get(siteCurveNumber); - Region region = fps.getPolygonProcessingState().wallet.getBecZone().getRegion(); + // Calculate change in dominant height - float newDominantHeight = growDominantHeight( - scAgeMaximums, region, dominantHeight, siteCurveNumber, siteIndex, yearsToBreastHeight + float growthInDominantHeight = growDominantHeight( + fps, dominantHeight, siteCurveNumber, siteIndex, yearsToBreastHeight ); + + // Calculate change in basal area + + final float veteranLayerBasalArea; + if (veteranBank.isPresent()) + veteranLayerBasalArea = veteranBank.get().basalAreas[0][UC_ALL_INDEX]; + else { + veteranLayerBasalArea = 0.0f; + } + + float[] speciesProportionByBasalArea = new float[pps.getNSpecies() + 1]; + for (int i = 1; i <= pps.getNSpecies(); i++) { + speciesProportionByBasalArea[i] = primaryBank.basalAreas[i][UC_ALL_INDEX] + / primaryBank.basalAreas[0][UC_ALL_INDEX]; + } + + float growthInBasalArea = growBasalArea( + fps, yearsAtBreastHeight, dominantHeight, primaryBank.basalAreas[0][UC_ALL_INDEX], veteranLayerBasalArea, growthInDominantHeight + ); + } + + private float growBasalArea( + ForwardProcessingState fps, float yearsAtBreastHeight, float dominantHeight, float primaryLayerBasalArea, + float veteranLayerBasalArea, float growthInDominantHeight + ) { + // UPPERGEN( 1, BATOP98, DQTOP98) + var baUpperBound = growBasalAreaUpperBound(fps); + var dqUpperBound = growQuadraticMeanDiameterUpperBound(fps); + + return 0; + } + + /** + * UPPERGEN( 1, BATOP98, DQTOP98) for basal area + */ + private float growBasalAreaUpperBound(ForwardProcessingState fps) { + var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + return fps.upperBounds.get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); + } + + /** + * UPPERGEN( 1, BATOP98, DQTOP98) for quad-mean-diameter + */ + private float growQuadraticMeanDiameterUpperBound(ForwardProcessingState fps) { + var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + return fps.upperBounds.get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); } public static float growDominantHeight( - SiteCurveAgeMaximum scAgeMaximums, Region region, float dominantHeight, int siteCurveNumber, + ForwardProcessingState fps, float dominantHeight, int siteCurveNumber, float siteIndex, float yearsToBreastHeight ) throws ProcessingException { + SiteCurveAgeMaximum scAgeMaximums = fps.maximumAgeBySiteCurveNumber.get(siteCurveNumber); + Region region = fps.getPolygonProcessingState().wallet.getBecZone().getRegion(); + if (siteCurveNumber == VdypEntity.MISSING_INTEGER_VALUE) { throw new ProcessingException("No SiteCurveNumber supplied"); } @@ -297,7 +351,7 @@ private void grow( } catch (CommonCalculatorException e) { throw new ProcessingException( MessageFormat.format( - "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3})", siteIndexEquation, dominantHeight_d, null, siteIndex_d, yearsToBreastHeight_d + "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3}, {4})", siteIndexEquation, dominantHeight_d, ageType, siteIndex_d, yearsToBreastHeight_d ), e ); } @@ -326,11 +380,11 @@ private void grow( } if (currentAge <= breastHeightAgeLimitInYears || scAgeMaximums.getT1() <= 0.0f) { - + float yearPart = 1.0f; if (scAgeMaximums.getT1() <= 0.0f) { - + if (breastHeightAgeLimitInYears > 0.0f && nextAge > breastHeightAgeLimitInYears) { if (currentAge > breastHeightAgeLimitInYears) { return 0.0f /* no growth */; @@ -345,39 +399,13 @@ private void grow( // species this can correspond to a half year. Therefore, AGED1 can not be assumed to // correspond to HDD1. Find a new HDD1 to at least get the increment correct. - double currentDominantHeight; - try { - currentDominantHeight = SiteTool.ageAndSiteIndexToHeight( - siteIndexEquation, currentAge, ageType, siteIndex_d, yearsToBreastHeight_d - ); - } catch (CommonCalculatorException e) { - throw new ProcessingException( - MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, currentAge, ageType, siteIndex_d, yearsToBreastHeight_d - ), e - ); - } - - double nextDominantHeight; - try { - nextDominantHeight = SiteTool.ageAndSiteIndexToHeight( - siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d - ); - } catch (CommonCalculatorException e) { - throw new ProcessingException( - MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d - ), e - ); - } + double currentDominantHeight = ageAndSiteIndexToHeight( + siteIndexEquation, currentAge, ageType, siteIndex_d, yearsToBreastHeight_d + ); - if (nextDominantHeight < 0.0) { - throw new ProcessingException( - MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) returned {5}", siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d, nextDominantHeight - ) - ); - } + double nextDominantHeight = ageAndSiteIndexToHeight( + siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d, r -> r >= 0.0 + ); if (nextDominantHeight < currentDominantHeight && yearPart == 1.0) { // Rounding error in site routines? @@ -398,51 +426,33 @@ private void grow( // We are in a special extension of the curve. Derive the new curve form and then // compute the answer. - float a = FloatMath.log(0.5f) / scAgeMaximums.getT1(); double breastHeightAgeLimitInYears_d = breastHeightAgeLimitInYears; - double currentDominantHeight; - try { - currentDominantHeight = SiteTool.ageAndSiteIndexToHeight( - siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d - ); - } catch (CommonCalculatorException e) { - throw new ProcessingException( - MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d - ), e - ); - } + double currentDominantHeight = ageAndSiteIndexToHeight( + siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + ); breastHeightAgeLimitInYears_d += 1.0; - double nextDominantHeight; - try { - nextDominantHeight = SiteTool.ageAndSiteIndexToHeight( - siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d - ); - } catch (CommonCalculatorException e) { - throw new ProcessingException( - MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d - ), e - ); - } + double nextDominantHeight = ageAndSiteIndexToHeight( + siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + ); float rate = (float) (nextDominantHeight - currentDominantHeight); if (rate < 0.0005f) { rate = 0.0005f; } + float a = FloatMath.log(0.5f) / scAgeMaximums.getT1(); float y = (float) currentDominantHeight; // Model is: - // Y = Y0 - RATE0/A*(1-exp(A* t)) where t = AGE - BHAGELIM - // Solve for T: - // 1 - exp(A * T) = (Y0 - Y) * A/RATE0 - // -exp(A * T) = (Y0 - Y) * A/RATE0 - 1 - // exp(A * T) = (Y - Y0) * A/RATE0 + 1 - // A * T = ln(1 + (Y - Y0) * A/RATE0) - // T = ln(1 + (Y - Y0) * A/RATE0) / A + // Y = y - rate/a * (1 - exp(a * t)) where t = AGE - BHAGELIM + // Solve for t: + // 1 - exp(a * t) = (y - dominantHeight) * a/rate + // -exp(a * t) = (y - dominantHeight) * a/rate - 1 + // exp(a * t) = (dominantHeight - y) * a/rate + 1 + // a * t = ln(1 + (dominantHeight - y) * a/rate) + // t = ln(1 + (dominantHeight - y) * a/rate) / a float t; if (dominantHeight > y) { float term = 1.0f + (dominantHeight - y) * a / rate; @@ -454,7 +464,7 @@ private void grow( t = 0.0f; } - if (t < scAgeMaximums.getT2()) { + if (t > scAgeMaximums.getT2()) { return 0.0f; } else { return rate / a * (-FloatMath.exp(a * t) + FloatMath.exp(a * (t + 1.0f))); @@ -462,6 +472,38 @@ private void grow( } } + private static double ageAndSiteIndexToHeight( + SiteIndexEquation curve, double age, SiteIndexAgeType ageType, double siteIndex, double years2BreastHeight, + Function checkResultValidity + ) throws ProcessingException { + Double r = ageAndSiteIndexToHeight(curve, age, ageType, siteIndex, years2BreastHeight); + if (!checkResultValidity.apply(r)) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) returned {5}", curve, age, ageType, siteIndex, years2BreastHeight, r + ) + ); + } + + return r; + } + + private static double ageAndSiteIndexToHeight( + SiteIndexEquation curve, double age, SiteIndexAgeType ageType, double siteIndex, double years2BreastHeight + ) throws ProcessingException { + try { + return SiteTool.ageAndSiteIndexToHeight( + curve, age, ageType, siteIndex, years2BreastHeight + ); + } catch (CommonCalculatorException e) { + throw new ProcessingException( + MessageFormat.format( + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", curve, age, ageType, siteIndex, years2BreastHeight + ), e + ); + } + } + private void writeLayers(int primaryLayerInstance, int veteranLayerInstance, boolean b) { logger.info( @@ -602,14 +644,14 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process } int primarySpeciesVolumeGroup = pps.volumeEquationGroups[s]; - float primarySpeciesQMDAll = pps.wallet.quadMeanDiameters[s][UTILIZATION_ALL_INDEX]; - var wholeStemVolume = pps.wallet.treesPerHectare[s][UTILIZATION_ALL_INDEX] + float primarySpeciesQMDAll = pps.wallet.quadMeanDiameters[s][UC_ALL_INDEX]; + var wholeStemVolume = pps.wallet.treesPerHectare[s][UC_ALL_INDEX] * EstimationMethods.estimateWholeStemVolumePerTree( primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll, pps .getTotalStandWholeStepVolumeCoeMap() ); - wholeStemVolumes.setCoe(UTILIZATION_ALL_INDEX, wholeStemVolume); + wholeStemVolumes.setCoe(UC_ALL_INDEX, wholeStemVolume); EstimationMethods.estimateWholeStemVolume( UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, pps @@ -638,7 +680,7 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process ); // Calculate trees-per-hectare per utilization - treesPerHectare.setCoe(UtilizationClass.ALL.index, pps.wallet.treesPerHectare[s][UTILIZATION_ALL_INDEX]); + treesPerHectare.setCoe(UtilizationClass.ALL.index, pps.wallet.treesPerHectare[s][UC_ALL_INDEX]); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { treesPerHectare.setCoe( uc.index, calculateTreesPerHectare( @@ -690,12 +732,12 @@ uc.index, calculateTreesPerHectare( Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); String speciesName = pps.wallet.speciesNames[speciesIndex]; - float spLoreyHeight_All = pps.wallet.loreyHeights[speciesIndex][UTILIZATION_ALL_INDEX]; // HLsp - float spQuadMeanDiameter_All = pps.wallet.quadMeanDiameters[speciesIndex][UTILIZATION_ALL_INDEX]; // DQsp + float spLoreyHeight_All = pps.wallet.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp + float spQuadMeanDiameter_All = pps.wallet.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp // this WHOLE operation on Actual BA's, not 100% occupancy. // TODO: verify this: float fractionAvailable = polygon.getPercentForestLand(); - float spBaseArea_All = pps.wallet.basalAreas[speciesIndex][UTILIZATION_ALL_INDEX] /* * fractionAvailable */; // BAsp + float spBaseArea_All = pps.wallet.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp // EMP080 float cvSmallComponentProbability = smallComponentProbability(pps, speciesName, spLoreyHeight_All, region); // PROBsp @@ -722,11 +764,11 @@ uc.index, calculateTreesPerHectare( var cvSmall = new HashMap(); - float spInputBasalArea_Small = pps.wallet.basalAreas[speciesIndex][UTILIZATION_SMALL_INDEX]; + float spInputBasalArea_Small = pps.wallet.basalAreas[speciesIndex][UC_SMALL_INDEX]; cvSmall.put(SmallUtilizationClassVariable.BASAL_AREA, spInputBasalArea_Small - cvBasalArea_Small); if (growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { - float spInputQuadMeanDiameter_Small = pps.wallet.quadMeanDiameters[speciesIndex][UTILIZATION_SMALL_INDEX]; + float spInputQuadMeanDiameter_Small = pps.wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; cvSmall.put( SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - cvQuadMeanDiameter_Small @@ -735,7 +777,7 @@ uc.index, calculateTreesPerHectare( cvSmall.put(SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); } - float spInputLoreyHeight_Small = pps.wallet.loreyHeights[speciesIndex][UTILIZATION_SMALL_INDEX]; + float spInputLoreyHeight_Small = pps.wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX]; if (spInputLoreyHeight_Small > 1.3f && cvLoreyHeight_Small > 1.3f && spInputBasalArea_Small > 0.0f) { float cvLoreyHeight = FloatMath.log( (spInputLoreyHeight_Small - 1.3f) / (cvLoreyHeight_Small - 1.3f)); cvSmall.put(SmallUtilizationClassVariable.LOREY_HEIGHT, cvLoreyHeight); @@ -743,11 +785,11 @@ uc.index, calculateTreesPerHectare( cvSmall.put(SmallUtilizationClassVariable.LOREY_HEIGHT, 0.0f); } - float spInputWholeStemVolume_Small = pps.wallet.wholeStemVolumes[speciesIndex][UTILIZATION_SMALL_INDEX]; + float spInputWholeStemVolume_Small = pps.wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; if (spInputWholeStemVolume_Small > 0.0f && cvMeanVolume_Small > 0.0f && growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l >= r)) { - float spInputTreePerHectare_Small = pps.wallet.treesPerHectare[speciesIndex][UTILIZATION_SMALL_INDEX]; + float spInputTreePerHectare_Small = pps.wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; var cvWholeStemVolume = FloatMath .log(spInputWholeStemVolume_Small / spInputTreePerHectare_Small / cvMeanVolume_Small); @@ -941,6 +983,13 @@ private static float calculateWholeStemVolume(float actualVolume, float basalAre return actualLogit - staticLogit; } + /** + * VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 + * + * @param state + * @param hl1Coefficients + * @throws ProcessingException + */ static void calculateDominantHeightAgeSiteIndex( PolygonProcessingState state, MatrixMap2 hl1Coefficients ) throws ProcessingException { @@ -951,7 +1000,7 @@ static void calculateDominantHeightAgeSiteIndex( // (1) Dominant Height float primarySpeciesDominantHeight = state.wallet.dominantHeights[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesDominantHeight)) { - float loreyHeight = state.wallet.loreyHeights[primarySpeciesIndex][UTILIZATION_ALL_INDEX]; + float loreyHeight = state.wallet.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; if (Float.isNaN(loreyHeight)) { throw new ProcessingException( MessageFormat.format( @@ -969,7 +1018,7 @@ static void calculateDominantHeightAgeSiteIndex( float a1 = coefficients.getCoe(2); float a2 = coefficients.getCoe(3); - float treesPerHectare = state.wallet.treesPerHectare[primarySpeciesIndex][UTILIZATION_ALL_INDEX]; + float treesPerHectare = state.wallet.treesPerHectare[primarySpeciesIndex][UC_ALL_INDEX]; float hMult = a0 - a1 + a1 * FloatMath.exp(a2 * (treesPerHectare - 100.0f)); primarySpeciesDominantHeight = 1.3f + (loreyHeight - 1.3f) / hMult; @@ -1036,7 +1085,7 @@ static void calculateDominantHeightAgeSiteIndex( SiteIndexEquation siteCurve2 = SiteIndexEquation.getByIndex(state.getSiteCurveNumber(0)); try { - double newSI = SiteTool.convertSiteIndexBetweenCurves(siteCurve1, activeIndex.get(), siteCurve2); + double newSI = SiteTool.convertSiteIndexBetweenCurves(siteCurve1, primarySpeciesSiteIndex, siteCurve2); if (newSI > 1.3) { primarySpeciesSiteIndex = (float) newSI; } @@ -1217,19 +1266,21 @@ static void estimateMissingSiteIndices(PolygonProcessingState state) throws Proc * * @param state the bank in which the calculations are performed */ - static void calculateCoverages(PolygonProcessingState state) { + void calculateCoverages() { + + PolygonProcessingState pps = this.fps.getPolygonProcessingState(); - logger.atDebug().addArgument(state.getNSpecies()).addArgument(state.wallet.basalAreas[0][0]).log( + logger.atDebug().addArgument(pps.getNSpecies()).addArgument(pps.wallet.basalAreas[0][0]).log( "Calculating coverages as a ratio of Species BA over Total BA. # species: {}; Layer total 7.5cm+ basal area: {}" ); - for (int i : state.getIndices()) { - state.wallet.percentagesOfForestedLand[i] = state.wallet.basalAreas[i][UTILIZATION_ALL_INDEX] - / state.wallet.basalAreas[0][UTILIZATION_ALL_INDEX] * 100.0f; + for (int i : pps.getIndices()) { + pps.wallet.percentagesOfForestedLand[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] + / pps.wallet.basalAreas[0][UC_ALL_INDEX] * 100.0f; - logger.atDebug().addArgument(i).addArgument(state.wallet.speciesIndices[i]) - .addArgument(state.wallet.speciesNames[i]).addArgument(state.wallet.basalAreas[i][0]) - .addArgument(state.wallet.percentagesOfForestedLand[i]) + logger.atDebug().addArgument(i).addArgument(pps.wallet.speciesIndices[i]) + .addArgument(pps.wallet.speciesNames[i]).addArgument(pps.wallet.basalAreas[i][0]) + .addArgument(pps.wallet.percentagesOfForestedLand[i]) .log("Species {}: SP0 {}, Name {}, Species 7.5cm+ BA {}, Calculated Percent {}"); } } @@ -1327,6 +1378,10 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing } } + /** Default Equation Group, by species. Indexed by the species number, a one-based value. */ + private static final int[] defaultEquationGroups = { 0 /* placeholder */, 1, 2, 3, 4, 1, 2, 5, 6, 7, 1, 9, 8, 9, 9, 10, 4 }; + private static final Set exceptedSpeciesIndicies = new HashSet<>(List.of(3, 4, 5, 6, 10)); + // PRIMFIND /** * Returns a {@code SpeciesRankingDetails} instance giving: @@ -1336,27 +1391,29 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing *
  • the percentage of forested land occupied by the primary species * * - * @param state the bank on which to operate + * @param pps the bank on which to operate * @return as described */ - static void determinePolygonRankings(PolygonProcessingState state, Collection> speciesToCombine) { + void determinePolygonRankings(Collection> speciesToCombine) { - if (state.getNSpecies() == 0) { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + if (pps.getNSpecies() == 0) { throw new IllegalArgumentException("Can not find primary species as there are no species"); } float[] percentages = Arrays - .copyOf(state.wallet.percentagesOfForestedLand, state.wallet.percentagesOfForestedLand.length); + .copyOf(pps.wallet.percentagesOfForestedLand, pps.wallet.percentagesOfForestedLand.length); for (var speciesPair : speciesToCombine) { - combinePercentages(state.wallet.speciesNames, speciesPair, percentages); + combinePercentages(pps.wallet.speciesNames, speciesPair, percentages); } float highestPercentage = 0.0f; int highestPercentageIndex = -1; float secondHighestPercentage = 0.0f; int secondHighestPercentageIndex = -1; - for (int i : state.getIndices()) { + for (int i : pps.getIndices()) { if (percentages[i] > highestPercentage) { @@ -1378,20 +1435,42 @@ static void determinePolygonRankings(PolygonProcessingState state, Collection
  • 0"); } - String primaryGenusName = state.wallet.speciesNames[highestPercentageIndex]; + String primaryGenusName = pps.wallet.speciesNames[highestPercentageIndex]; Optional secondaryGenusName = secondHighestPercentageIndex != -1 - ? Optional.of(state.wallet.speciesNames[secondHighestPercentageIndex]) + ? Optional.of(pps.wallet.speciesNames[secondHighestPercentageIndex]) : Optional.empty(); try { int inventoryTypeGroup = findInventoryTypeGroup(primaryGenusName, secondaryGenusName, highestPercentage); - state.setSpeciesRankingDetails( + int basalAreaGroup1 = 0; + + String primarySpeciesName = pps.wallet.speciesNames[highestPercentageIndex]; + String becZoneAlias = pps.wallet.getBecZone().getAlias(); + + int defaultEquationGroup = fps.defaultEquationGroup.get(primarySpeciesName, becZoneAlias); + Optional equationModifierGroup = fps.equationModifierGroup.get(defaultEquationGroup, inventoryTypeGroup); + if (equationModifierGroup.isPresent()) { + basalAreaGroup1 = equationModifierGroup.get(); + } else { + basalAreaGroup1 = defaultEquationGroup; + } + + int primarySpeciesIndex = pps.wallet.speciesIndices[highestPercentageIndex]; + int basalAreaGroup3 = defaultEquationGroups[primarySpeciesIndex]; + if (Region.INTERIOR.equals(pps.wallet.getBecZone().getRegion()) + && exceptedSpeciesIndicies.contains(primarySpeciesIndex)) { + basalAreaGroup3 += 20; + } + + pps.setSpeciesRankingDetails( new SpeciesRankingDetails( highestPercentageIndex, secondHighestPercentageIndex != -1 ? Optional.of(secondHighestPercentageIndex) : Optional.empty(), - inventoryTypeGroup + inventoryTypeGroup, + basalAreaGroup1, + basalAreaGroup3 ) ); } catch (ProcessingException e) { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 949d11be8..aa3831c0d 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -56,13 +56,23 @@ class ForwardProcessingState { final Map smallComponentBasalAreaCoefficients; final Map smallComponentProbabilityCoefficients; final Map maximumAgeBySiteCurveNumber; - + final Map upperBounds; + final MatrixMap2 defaultEquationGroup; + final MatrixMap2> equationModifierGroup; + final MatrixMap2 hl1Coefficients; + final CompVarAdjustments compVarAdjustments; + final ForwardControlVariables forwardControlVariables; + /** The storage banks */ private final Bank[/* instances */][/* layers of instance */] banks; /** The active state */ private PolygonProcessingState pps; + final BecLookup becLookup; + final MatrixMap2 siteCurveMap; + + public ForwardProcessingState(Map controlMap) { this.controlMap = controlMap; @@ -123,43 +133,44 @@ public ForwardProcessingState(Map controlMap) { this.maximumAgeBySiteCurveNumber = Utils.>expectParsedControl( controlMap, ControlKey.SITE_CURVE_AGE_MAX, Map.class ); - } - - public GenusDefinitionMap getGenusDefinitionMap() { - return genusDefinitionMap; - } - - public BecLookup getBecLookup() { - return Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); - } - - public MatrixMap2 getSiteCurveMap() { - return Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); - } - - public MatrixMap2 getHl1Coefficients() { - return Utils.expectParsedControl(controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); - } - - public CompVarAdjustments getCompVarAdjustments() { - return Utils.expectParsedControl(controlMap, ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); - } - - public ForwardControlVariables getForwardControlVariables() { - return Utils.expectParsedControl(controlMap, ControlKey.VTROL, ForwardControlVariables.class); + this.upperBounds = Utils.>expectParsedControl( + controlMap, ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); + this.defaultEquationGroup = Utils.>expectParsedControl( + controlMap, ControlKey.DEFAULT_EQ_NUM, MatrixMap2.class); + this.equationModifierGroup = Utils.>>expectParsedControl( + controlMap, ControlKey.EQN_MODIFIERS, MatrixMap2.class); + + this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); + + this.siteCurveMap = Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); + + this.hl1Coefficients = Utils.expectParsedControl(controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); + + this.compVarAdjustments = Utils.expectParsedControl(controlMap, ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); + + this.forwardControlVariables = Utils.expectParsedControl(controlMap, ControlKey.VTROL, ForwardControlVariables.class); } private static final float MIN_BASAL_AREA = 0.001f; public void setPolygon(VdypPolygon polygon) { + // Move the primary layer of the given polygon to bank zero. - banks[0][0] = new Bank( + Bank primaryBank = banks[0][LayerType.PRIMARY.getIndex()] = new Bank( polygon.getPrimaryLayer(), polygon.getBiogeoclimaticZone(), s -> s.getUtilizations().isPresent() ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA : true ); - pps = new PolygonProcessingState(this, polygon, banks[0][0], controlMap); + + polygon.getVeteranLayer().ifPresent(l -> + banks[0][LayerType.VETERAN.getIndex()] = new Bank( + l, polygon.getBiogeoclimaticZone(), + s -> s.getUtilizations().isPresent() + ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA + : true)); + + pps = new PolygonProcessingState(this, polygon, primaryBank, controlMap); } public PolygonProcessingState getPolygonProcessingState() { @@ -171,14 +182,14 @@ public Map getControlMap() { } public void storeActive(int instanceNumber, LayerType layerType) { - banks[instanceNumber][layerType.ordinal()] = pps.wallet.copy(); + banks[instanceNumber][layerType.getIndex()] = pps.wallet.copy(); } public void transfer(int fromInstanceNumber, int toInstanceNumber, LayerType layerType) { - banks[toInstanceNumber][layerType.ordinal()] = banks[fromInstanceNumber][layerType.ordinal()].copy(); + banks[toInstanceNumber][layerType.getIndex()] = banks[fromInstanceNumber][layerType.getIndex()].copy(); } public Bank getBank(int instanceNumber, LayerType layerType) { - return banks[instanceNumber][layerType.ordinal()]; + return banks[instanceNumber][layerType.getIndex()]; } } \ No newline at end of file diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 725044425..1d2407431 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -9,6 +9,7 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; @@ -78,9 +79,7 @@ class PolygonProcessingState { // PCTP = wallet.percentagesOfForestedLand[primarySpeciesIndex] private Optional secondarySpeciesIndex; // => ISPS (species name) and PCTS (percentage) private int inventoryTypeGroup; // ITG - @SuppressWarnings("unused") private int primarySpeciesGroupNumber; // GRPBA1 - @SuppressWarnings("unused") private int primarySpeciesStratumNumber; // GRPBA3 // Site Curve Numbers - encompasses INXSCV @@ -255,6 +254,122 @@ public int getInventoryTypeGroup() { return inventoryTypeGroup; } + public static String getCompatibilityVariablesSetCanBeSetOnceOnly() { + return COMPATIBILITY_VARIABLES_SET_CAN_BE_SET_ONCE_ONLY; + } + + public static String getPrimarySpeciesDetailsCanBeSetOnceOnly() { + return PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY; + } + + public static String getSiteCurveNumbersCanBeSetOnceOnly() { + return SITE_CURVE_NUMBERS_CAN_BE_SET_ONCE_ONLY; + } + + public static String getSpeciesRankingDetailsCanBeSetOnceOnly() { + return SPECIES_RANKING_DETAILS_CAN_BE_SET_ONCE_ONLY; + } + + public static String getUnsetPrimarySpeciesAgeToBreastHeight() { + return UNSET_PRIMARY_SPECIES_AGE_TO_BREAST_HEIGHT; + } + + public static String getUnsetPrimarySpeciesAgeAtBreastHeight() { + return UNSET_PRIMARY_SPECIES_AGE_AT_BREAST_HEIGHT; + } + + public static String getUnsetPrimarySpeciesDominantHeight() { + return UNSET_PRIMARY_SPECIES_DOMINANT_HEIGHT; + } + + public static String getUnsetCvVolumes() { + return UNSET_CV_VOLUMES; + } + + public static String getUnsetCvBasalAreas() { + return UNSET_CV_BASAL_AREAS; + } + + public static String getUnsetRankingDetails() { + return UNSET_RANKING_DETAILS; + } + + public static String getUnsetSiteCurveNumbers() { + return UNSET_SITE_CURVE_NUMBERS; + } + + public static String getUnsetInventoryTypeGroup() { + return UNSET_INVENTORY_TYPE_GROUP; + } + + public static Logger getLogger() { + return logger; + } + + public ForwardProcessingState getFps() { + return fps; + } + + public Bank getWallet() { + return wallet; + } + + public int[] getVolumeEquationGroups() { + return volumeEquationGroups; + } + + public int[] getDecayEquationGroups() { + return decayEquationGroups; + } + + public int[] getBreakageEquationGroups() { + return breakageEquationGroups; + } + + public boolean isAreRankingDetailsSet() { + return areRankingDetailsSet; + } + + public int getPrimarySpeciesGroupNumber() { + return primarySpeciesGroupNumber; + } + + public int getPrimarySpeciesStratumNumber() { + return primarySpeciesStratumNumber; + } + + public boolean isAreSiteCurveNumbersSet() { + return areSiteCurveNumbersSet; + } + + public int[] getSiteCurveNumbers() { + return siteCurveNumbers; + } + + public boolean isArePrimarySpeciesDetailsSet() { + return arePrimarySpeciesDetailsSet; + } + + public boolean isAreCompatibilityVariablesSet() { + return areCompatibilityVariablesSet; + } + + public MatrixMap3[] getCvVolume() { + return cvVolume; + } + + public MatrixMap2[] getCvBasalArea() { + return cvBasalArea; + } + + public MatrixMap2[] getCvQuadraticMeanDiameter() { + return cvQuadraticMeanDiameter; + } + + public Map[] getCvPrimaryLayerSmall() { + return cvPrimaryLayerSmall; + } + /** * @param n index of species for whom the site curve number is to be returned. * @return the site curve number of the given species. @@ -316,6 +431,8 @@ public void setSpeciesRankingDetails(SpeciesRankingDetails rankingDetails) { this.primarySpeciesIndex = rankingDetails.primarySpeciesIndex(); this.secondarySpeciesIndex = rankingDetails.secondarySpeciesIndex(); this.inventoryTypeGroup = rankingDetails.inventoryTypeGroup(); + this.primarySpeciesGroupNumber = rankingDetails.basalAreaGroup1(); + this.primarySpeciesStratumNumber = rankingDetails.basalAreaGroup3(); this.areRankingDetailsSet = true; } @@ -331,7 +448,10 @@ public void setSiteCurveNumbers(int[] siteCurveNumbers) { } public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { - if (this.arePrimarySpeciesDetailsSet) { + + // Normally, these values may only be set only once. However, during grow(), if the + // control variable UPDATE_DURING_GROWTH_6 has value "1" then updates are allowed. + if (this.arePrimarySpeciesDetailsSet && fps.forwardControlVariables.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) != 1) { throw new IllegalStateException(PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java index 41392d714..60788beb6 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java @@ -3,6 +3,7 @@ import java.util.Optional; public record SpeciesRankingDetails( - int primarySpeciesIndex, Optional secondarySpeciesIndex, int inventoryTypeGroup + int primarySpeciesIndex, Optional secondarySpeciesIndex, int inventoryTypeGroup, + int basalAreaGroup1, int basalAreaGroup3 ) { } \ No newline at end of file From a106b4db65f5f8a4f7b2034ea1acab756d9c4b8e Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 8 Jul 2024 13:26:40 -0700 Subject: [PATCH 08/66] Merge branch 'feature/VDYP-305' into feature/VDYP-363-grow # Conflicts: # vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java # vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java --- .../vdyp/forward/ForwardProcessingEngine.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index de77f82b9..72cdd0363 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -278,8 +278,8 @@ private void grow( float[] speciesProportionByBasalArea = new float[pps.getNSpecies() + 1]; for (int i = 1; i <= pps.getNSpecies(); i++) { - speciesProportionByBasalArea[i] = primaryBank.basalAreas[i][UC_ALL_INDEX] - / primaryBank.basalAreas[0][UC_ALL_INDEX]; + speciesProportionByBasalArea[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] + / pps.wallet.basalAreas[0][UC_ALL_INDEX]; } float growthInBasalArea = growBasalArea( @@ -287,6 +287,19 @@ private void grow( ); } + private static final float EMPIRICAL_OCCUPANCY = 0.85f; + + /** + * EMP111A - Basal area growth for the primary layer. + * + * @param fps current processing state + * @param yearsAtBreastHeight at the start of the year + * @param dominantHeight primary species dominant height at start of year + * @param primaryLayerBasalArea at the start of the year + * @param veteranLayerBasalArea at the start of the year + * @param growthInDominantHeight during the year + * @return the growth in the basal area for the year + */ private float growBasalArea( ForwardProcessingState fps, float yearsAtBreastHeight, float dominantHeight, float primaryLayerBasalArea, float veteranLayerBasalArea, float growthInDominantHeight @@ -295,11 +308,13 @@ private float growBasalArea( var baUpperBound = growBasalAreaUpperBound(fps); var dqUpperBound = growQuadraticMeanDiameterUpperBound(fps); + baUpperBound = baUpperBound / EMPIRICAL_OCCUPANCY; + var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); return 0; } /** - * UPPERGEN( 1, BATOP98, DQTOP98) for basal area + * UPPERGEN(1, BATOP98, DQTOP98) for basal area */ private float growBasalAreaUpperBound(ForwardProcessingState fps) { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); @@ -307,7 +322,7 @@ private float growBasalAreaUpperBound(ForwardProcessingState fps) { } /** - * UPPERGEN( 1, BATOP98, DQTOP98) for quad-mean-diameter + * UPPERGEN(1, BATOP98, DQTOP98) for quad-mean-diameter */ private float growQuadraticMeanDiameterUpperBound(ForwardProcessingState fps) { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); From d0eb5405554ad013838c77c5a722e5a691f04041 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 9 Jul 2024 10:12:25 -0700 Subject: [PATCH 09/66] Implementation of Caching Control Map wrapper --- .../application/VdypStartApplication.java | 39 +- ...EstimationMethods.java => Estimators.java} | 667 +++++------------- .../nrs/vdyp/common/GenusDefinitionMap.java | 4 + .../CachingResolvedControlMapImpl.java | 175 +++++ .../vdyp/controlmap/ResolvedControlMap.java | 59 ++ .../controlmap/ResolvedControlMapImpl.java | 149 ++++ .../vdyp/io/parse/coe/UpperBoundsParser.java | 4 +- .../application/VdypStartApplicationTest.java | 1 - .../vdyp/common/EstimationMethodsTest.java | 79 +-- .../vdyp/common/ReconcilationMethodsTest.java | 1 - .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 52 +- .../vdyp/forward/ForwardProcessingEngine.java | 164 ++--- .../vdyp/forward/ForwardProcessingState.java | 132 +--- .../vdyp/forward/PolygonProcessingState.java | 79 +-- .../controlmap/ForwardResolvedControlMap.java | 20 + .../ForwardResolvedControlMapImpl.java | 52 ++ .../vdyp/forward/ForwardGrowStepTests.java | 6 +- .../forward/ForwardProcessingEngineTest.java | 6 +- .../GeneralForwardProcessingEngineTest.java | 6 +- .../vdyp/forward/GrowDominantHeightTest.java | 20 +- .../forward/PolygonProcessingStateTest.java | 9 - .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 110 +-- .../ca/bc/gov/nrs/vdyp/vri/VriStartTest.java | 223 +++--- 23 files changed, 970 insertions(+), 1087 deletions(-) rename vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/{EstimationMethods.java => Estimators.java} (60%) create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java create mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java create mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index e735618f5..d1f9d2b6b 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -1,12 +1,10 @@ package ca.bc.gov.nrs.vdyp.application; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.abs; import static ca.bc.gov.nrs.vdyp.math.FloatMath.clamp; import static ca.bc.gov.nrs.vdyp.math.FloatMath.exp; import static ca.bc.gov.nrs.vdyp.math.FloatMath.floor; import static ca.bc.gov.nrs.vdyp.math.FloatMath.log; import static ca.bc.gov.nrs.vdyp.math.FloatMath.pow; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.sqrt; import static java.lang.Math.max; import static java.lang.Math.min; @@ -37,11 +35,12 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods; +import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperCoefficientParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -168,7 +167,7 @@ protected static void doMain(VdypStartApplication app, final String. protected Map controlMap = new HashMap<>(); - public EstimationMethods estimationMethods; + protected Estimators estimators; static final Comparator PERCENT_GENUS_DESCENDING = Utils .compareUsing(BaseVdypSpecies::getPercentGenus).reversed(); @@ -240,7 +239,7 @@ void closeVriWriter() throws IOException { protected void setControlMap(Map controlMap) { this.controlMap = controlMap; - this.estimationMethods = new EstimationMethods(controlMap); + this.estimators = new Estimators(new ResolvedControlMapImpl(controlMap)); } protected StreamingParser getStreamingParser(ControlKey key) throws ProcessingException { @@ -1152,10 +1151,10 @@ public void computeUtilizationComponentsPrimary( var adjustDecayWasteUtil = Utils.utilizationVector(); // ADJVDW // EMP071 - estimationMethods.estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec.getGenus()); + estimators.estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec.getGenus()); // EMP070 - estimationMethods.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus()); + estimators.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus()); // Calculate tree density components for (var uc : VdypStartApplication.UTIL_CLASSES) { @@ -1196,7 +1195,7 @@ public void computeUtilizationComponentsPrimary( } else { // EMP091 - estimationMethods.estimateWholeStemVolume( + estimators.estimateWholeStemVolume( UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil ); @@ -1212,48 +1211,48 @@ public void computeUtilizationComponentsPrimary( } // EMP092 - estimationMethods.estimateCloseUtilizationVolume( + estimators.estimateCloseUtilizationVolume( UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil ); // EMP093 - estimationMethods.estimateNetDecayVolume( + estimators.estimateNetDecayVolume( spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil ); // EMP094 - estimationMethods.estimateNetDecayAndWasteVolume( + estimators.estimateNetDecayAndWasteVolume( bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil ); if (this.getId().isStart()) { // EMP095 - estimationMethods.estimateNetDecayWasteAndBreakageVolume( + estimators.estimateNetDecayWasteAndBreakageVolume( UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil ); } } - spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, EstimationMethods.COPY_IF_BAND); - spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, EstimationMethods.COPY_IF_BAND); + spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, Estimators.COPY_IF_BAND); + spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, Estimators.COPY_IF_BAND); spec.getQuadraticMeanDiameterByUtilization() - .pairwiseInPlace(quadMeanDiameterUtil, EstimationMethods.COPY_IF_BAND); + .pairwiseInPlace(quadMeanDiameterUtil, Estimators.COPY_IF_BAND); spec.getWholeStemVolumeByUtilization() - .pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_TOTAL); + .pairwiseInPlace(wholeStemVolumeUtil, Estimators.COPY_IF_NOT_TOTAL); spec.getCloseUtilizationVolumeByUtilization() - .pairwiseInPlace(closeVolumeUtil, EstimationMethods.COPY_IF_NOT_TOTAL); + .pairwiseInPlace(closeVolumeUtil, Estimators.COPY_IF_NOT_TOTAL); spec.getCloseUtilizationVolumeNetOfDecayByUtilization() - .pairwiseInPlace(closeVolumeNetDecayUtil, EstimationMethods.COPY_IF_NOT_TOTAL); + .pairwiseInPlace(closeVolumeNetDecayUtil, Estimators.COPY_IF_NOT_TOTAL); spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_TOTAL); + .pairwiseInPlace(closeVolumeNetDecayWasteUtil, Estimators.COPY_IF_NOT_TOTAL); spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_TOTAL); + .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, Estimators.COPY_IF_NOT_TOTAL); } computeLayerUtilizationComponentsFromSpecies(vdypLayer); diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java similarity index 60% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java rename to vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index 6e1353eaf..b99d6159e 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -19,10 +19,11 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.application.StandProcessingException; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.io.parse.coe.GenusDefinitionParser; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; -import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; +import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; @@ -32,13 +33,15 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; -public class EstimationMethods { +public class Estimators { - public static final Logger log = LoggerFactory.getLogger(EstimationMethods.class); + public static final Logger log = LoggerFactory.getLogger(Estimators.class); private static final int UTIL_ALL = UtilizationClass.ALL.index; private static final int UTIL_LARGEST = UtilizationClass.OVER225.index; + private static final float EMPIRICAL_OCCUPANCY = 0.85f; + /** * Returns the new value if the index is that of a utilization class that represents a size band, otherwise the old * value @@ -50,36 +53,21 @@ public class EstimationMethods { */ public static final IndexedFloatBinaryOperator COPY_IF_NOT_TOTAL = (oldX, newX, i) -> i < UTIL_ALL ? oldX : newX; - Map controlMap; + ResolvedControlMap controlMap; - public EstimationMethods(Map controlMap) { - this.controlMap = controlMap; + public Estimators(ResolvedControlMap resolvedControlMap) { + this.controlMap = resolvedControlMap; } - private static float heightMultiplier( - Map controlMap, String genus, Region region, float treesPerHectarePrimary + private float heightMultiplier( + String genus, Region region, float treesPerHectarePrimary ) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class - ); + final var coeMap = controlMap + .>get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); var coe = coeMap.get(genus, region).reindex(0); return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); } - /** - * EMP050 Method 1: Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return - */ - public float - primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - return primaryHeightFromLeadHeight(controlMap, leadHeight, genus, region, treesPerHectarePrimary); - } - /** * EMP050 Method 1: Return the lorey height of the primary species based on the dominant height of the lead species. * @@ -90,10 +78,10 @@ private static float heightMultiplier( * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species * @return */ - public static float primaryHeightFromLeadHeight( - Map controlMap, float leadHeight, String genus, Region region, float treesPerHectarePrimary + public float primaryHeightFromLeadHeight( + float leadHeight, String genus, Region region, float treesPerHectarePrimary ) { - return 1.3f + (leadHeight - 1.3f) * heightMultiplier(controlMap, genus, region, treesPerHectarePrimary); + return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); } /** @@ -107,23 +95,7 @@ public static float primaryHeightFromLeadHeight( public float leadHeightFromPrimaryHeight( float primaryHeight, String genus, Region region, float treesPerHectarePrimary ) { - return leadHeightFromPrimaryHeight(controlMap, primaryHeight, genus, region, treesPerHectarePrimary); - } - - /** - * EMP050 Method 2: Return the dominant height of the lead species based on the lorey height of the primary species. - * - * @param controlMap Control map containing coefficients - * @param primaryHeight lorey height of the primary species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - */ - public static float leadHeightFromPrimaryHeight( - Map controlMap, float primaryHeight, String genus, Region region, - float treesPerHectarePrimary - ) { - return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(controlMap, genus, region, treesPerHectarePrimary); + return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(genus, region, treesPerHectarePrimary); } /** @@ -134,22 +106,8 @@ public static float leadHeightFromPrimaryHeight( * @param region Region of the polygon */ public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { - return primaryHeightFromLeadHeightInitial(controlMap, leadHeight, genus, region); - } - - /** - * EMP051 Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param controlMap Control map containing coefficients - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - */ - public float primaryHeightFromLeadHeightInitial( - Map controlMap, float leadHeight, String genus, Region region - ) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class + final var coeMap = controlMap.>get( + ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class ); var coe = coeMap.get(genus, region); return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); @@ -167,35 +125,18 @@ public float primaryHeightFromLeadHeightInitial( * @param primaryHeight height of the primary species * @throws ProcessingException */ - public float estimateNonPrimaryLoreyHeight( - BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight - ) throws ProcessingException { - return estimateNonPrimaryLoreyHeight(vspec.getGenus(), vspecPrime.getGenus(), bec, leadHeight, primaryHeight); - } - - /** - * EMP053 Estimate the lorey height of a non-primary species of a primary layer. - *

    - * Using eqns N1 and N2 from ipsjf124.doc - * - * @param vspec The species. - * @param vspecPrime The primary species. - * @param leadHeight lead height of the layer - * @param primaryHeight height of the primary species - * @throws ProcessingException - */ public float estimateNonPrimaryLoreyHeight( String vspec, String vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight ) throws ProcessingException { - var coeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.HL_NONPRIMARY, MatrixMap3.class + var coeMap = controlMap.>>get( + ControlKey.HL_NONPRIMARY, MatrixMap3.class ); var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( () -> new ProcessingException( String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, - bec.getRegion() + "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, bec + .getRegion() ) ) ); @@ -239,9 +180,8 @@ public float estimateQuadMeanDiameterForSpecies( return standQuadMeanDiameter; } - var coeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BY_SPECIES_DQ, Map.class); - var specAliases = GenusDefinitionParser.getSpeciesAliases(controlMap); + var coeMap = controlMap.>get(ControlKey.BY_SPECIES_DQ, Map.class); + var specAliases = controlMap.getGenusDefinitionMap().getAliases(); // TODO we can probably remove these as they seem to only be used for debugging // in VDYP7 @@ -369,8 +309,8 @@ public static record Limits( // EMP061 public Limits getLimitsForHeightAndDiameter(String genus, Region region) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class + var coeMap = controlMap.>get( + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class ); var coe = coeMap.get(genus, region); @@ -390,47 +330,10 @@ public Limits getLimitsForHeightAndDiameter(String genus, Region region) { public void estimateBaseAreaByUtilization( BecDefinition bec, Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, String genus ) throws ProcessingException { - - estimateBaseAreaByUtilization(controlMap, bec, quadMeanDiameterUtil, baseAreaUtil, genus); - } - - /** - * EMP070. Estimate basal area by utilization class from the given parameters, after getting the estimation - * coefficients map from the control map. - * - * @param controlMap - * @param bec - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateBaseAreaByUtilization( - Map controlMap, BecDefinition bec, Coefficients quadMeanDiameterUtil, - Coefficients baseAreaUtil, String genus - ) throws ProcessingException { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_BA, MatrixMap3.class + final var basalAreaUtilCompCoeMap = controlMap.>get( + ControlKey.UTIL_COMP_BA, MatrixMap3.class ); - estimateBaseAreaByUtilization(bec, coeMap, quadMeanDiameterUtil, baseAreaUtil, genus); - } - - /** - * EMP070: estimate basal area by utilization class from the given parameters - * - * @param bec - * @param basalAreaUtilCompCoeMap - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateBaseAreaByUtilization( - BecDefinition bec, MatrixMap3 basalAreaUtilCompCoeMap, - Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, String genus - ) throws ProcessingException { - float dq = quadMeanDiameterUtil.getCoe(UTIL_ALL); var b = Utils.utilizationVector(); b.setCoe(0, baseAreaUtil.getCoe(UTIL_ALL)); @@ -473,42 +376,10 @@ public static void estimateBaseAreaByUtilization( estimateQuadMeanDiameterByUtilization(BecDefinition bec, Coefficients quadMeanDiameterUtil, String genus) throws ProcessingException { - estimateQuadMeanDiameterByUtilization(controlMap, bec, quadMeanDiameterUtil, genus); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param controlMap - * @param bec - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateQuadMeanDiameterByUtilization( - Map controlMap, BecDefinition bec, Coefficients quadMeanDiameterUtil, String genus - ) throws ProcessingException { - - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_DQ, MatrixMap3.class + final var coeMap = controlMap.>get( + ControlKey.UTIL_COMP_DQ, MatrixMap3.class ); - estimateQuadMeanDiameterByUtilization(bec, coeMap, quadMeanDiameterUtil, genus); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param bec - * @param coeMap - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateQuadMeanDiameterByUtilization( - BecDefinition bec, MatrixMap3 coeMap, - Coefficients quadMeanDiameterUtil, String genus - ) throws ProcessingException { log.atTrace().setMessage("Estimate DQ by utilization class for {} in BEC {}. DQ for all >7.5 is {}") .addArgument(genus).addArgument(bec.getName()).addArgument(quadMeanDiameterUtil.getCoe(UTIL_ALL)); @@ -575,7 +446,6 @@ public static void estimateQuadMeanDiameterByUtilization( () -> UtilizationClass.UTIL_CLASSES.stream() .map(uc -> String.format("%s: %d", uc.className, quadMeanDiameterUtil.getCoe(uc.index))) ); - } /** @@ -588,46 +458,10 @@ public static void estimateQuadMeanDiameterByUtilization( * @return as described */ public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - - return estimateWholeStemVolumePerTree(controlMap, volumeGroup, loreyHeight, quadMeanDiameter); - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param controlMap the control map from which the total stand whole stem volume equation coefficients are - * retrieved - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public static float estimateWholeStemVolumePerTree( - Map controlMap, int volumeGroup, float loreyHeight, float quadMeanDiameter - ) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class + var totalStandWholeStemVolumeCoeMap = controlMap.>get( + ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class ); - return estimateWholeStemVolumePerTree(volumeGroup, loreyHeight, quadMeanDiameter, coeMap); - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param controlMap the control map from which the total stand whole stem volume equation coefficients are - * retrieved - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public static float estimateWholeStemVolumePerTree( - int volumeGroup, float loreyHeight, float quadMeanDiameter, - Map totalStandWholeStemVolumeCoeMap - ) { var coe = totalStandWholeStemVolumeCoeMap.get(volumeGroup).reindex(0); var logMeanVolume = // @@ -644,30 +478,6 @@ public static float estimateWholeStemVolumePerTree( return exp(logMeanVolume); } - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values, getting wholeStemUtilizationComponentMap from the - * given controlMap. - * - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public void estimateWholeStemVolume( - UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, Coefficients wholeStemVolumeUtil - ) throws ProcessingException { - - estimateWholeStemVolume( - controlMap, utilizationClass, adjustCloseUtil, volumeGroup, hlSp, quadMeanDiameterUtil, baseAreaUtil, - wholeStemVolumeUtil - ); - } - /** * EMP091. Updates wholeStemVolumeUtil with estimated values, getting wholeStemUtilizationComponentMap from the * given controlMap. @@ -682,39 +492,15 @@ public void estimateWholeStemVolume( * @param wholeStemVolumeUtil * @throws ProcessingException */ - public static void estimateWholeStemVolume( - Map controlMap, UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, + public void estimateWholeStemVolume( + UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, Coefficients wholeStemVolumeUtil ) throws ProcessingException { - final var wholeStemUtilizationComponentMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class + final var wholeStemUtilizationComponentMap = controlMap + .>>get( + ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class ); - estimateWholeStemVolume( - utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, - quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - } - - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values. - * - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param wholeStemUtilizationComponentMap - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public static void estimateWholeStemVolume( - UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - MatrixMap2> wholeStemUtilizationComponentMap, - Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, Coefficients wholeStemVolumeUtil - ) throws ProcessingException { var dqSp = quadMeanDiameterUtil.getCoe(UTIL_ALL); estimateUtilization(baseAreaUtil, wholeStemVolumeUtil, utilizationClass, (uc, ba) -> { @@ -764,58 +550,11 @@ public void estimateCloseUtilizationVolume( UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, float hlSp, Coefficients quadMeanDiameterUtil, Coefficients wholeStemVolumeUtil, Coefficients closeUtilizationVolumeUtil ) throws ProcessingException { - estimateCloseUtilizationVolume( - controlMap, utilizationClass, aAdjust, volumeGroup, hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, - closeUtilizationVolumeUtil - ); - } - - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param controlMap - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public static void estimateCloseUtilizationVolume( - Map controlMap, UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, - float hlSp, Coefficients quadMeanDiameterUtil, Coefficients wholeStemVolumeUtil, - Coefficients closeUtilizationVolumeUtil - ) throws ProcessingException { - final var closeUtilizationCoeMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class + final var closeUtilizationCoeMap = controlMap + .>>get( + ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class ); - estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, - wholeStemVolumeUtil, closeUtilizationVolumeUtil - ); - } - - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param closeUtilizationCoeMap - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public static void estimateCloseUtilizationVolume( - UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, float hlSp, - MatrixMap2> closeUtilizationCoeMap, - Coefficients quadMeanDiameterUtil, Coefficients wholeStemVolumeUtil, Coefficients closeUtilizationVolumeUtil - ) throws ProcessingException { + estimateUtilization(wholeStemVolumeUtil, closeUtilizationVolumeUtil, utilizationClass, (uc, ws) -> { Coefficients closeUtilCoe = closeUtilizationCoeMap.get(uc.index, volumeGroup).orElseThrow( () -> new ProcessingException( @@ -857,68 +596,13 @@ public void estimateNetDecayVolume( float ageBreastHeight, Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayUtil ) throws ProcessingException { - - estimateNetDecayVolume( - controlMap, genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, quadMeanDiameterUtil, - closeUtilizationUtil, closeUtilizationNetOfDecayUtil + final var netDecayCoeMap = controlMap.>>get( + ControlKey.VOLUME_NET_DECAY, MatrixMap2.class ); - } - - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param controlMap - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @throws ProcessingException - */ - public static void estimateNetDecayVolume( - Map controlMap, String genus, Region region, UtilizationClass utilizationClass, - Coefficients aAdjust, int decayGroup, float ageBreastHeight, Coefficients quadMeanDiameterUtil, - Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayUtil - ) throws ProcessingException { - final var netDecayCoeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY, MatrixMap2.class + final var decayModifierMap = controlMap.>get( + ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class ); - final var decayModifierMap = Utils.>expectParsedControl( - controlMap, ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class - ); - estimateNetDecayVolume( - genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, - quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil - ); - } - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param netDecayCoeMap - * @param decayModifierMap - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param lore // EMP053 Using eqns N1 and N2 from ipsjf124.doc yHeight - * @throws ProcessingException - */ - public static void estimateNetDecayVolume( - String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - float ageBreastHeight, MatrixMap2> netDecayCoeMap, - MatrixMap2 decayModifierMap, Coefficients quadMeanDiameterUtil, - Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayUtil - ) throws ProcessingException { var dqSp = quadMeanDiameterUtil.getCoe(UTIL_ALL); final var ageTr = (float) Math.log(Math.max(20.0, ageBreastHeight)); @@ -969,72 +653,17 @@ public void estimateNetDecayAndWasteVolume( Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayUtil, Coefficients closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { - - estimateNetDecayAndWasteVolume( - controlMap, region, utilizationClass, aAdjust, genus, loreyHeight, quadMeanDiameterUtil, - closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil + final var netDecayWasteCoeMap = controlMap.>get( + ControlKey.VOLUME_NET_DECAY_WASTE, Map.class ); - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param controlMap - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public static void estimateNetDecayAndWasteVolume( - Map controlMap, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, - String genus, float loreyHeight, Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, - Coefficients closeUtilizationNetOfDecayUtil, Coefficients closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { - final var netDecayWasteCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - - estimateNetDecayAndWasteVolume( - region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, - quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, - closeUtilizationNetOfDecayAndWasteUtil + final var wasteModifierMap = controlMap.>get( + ControlKey.WASTE_MODIFIERS, MatrixMap2.class ); - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param netDecayWasteCoeMap - * @param wasteModifierMap - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public static void estimateNetDecayAndWasteVolume( - Region region, UtilizationClass utilizationClass, Coefficients aAdjust, String genus, float loreyHeight, - Map netDecayWasteCoeMap, MatrixMap2 wasteModifierMap, - Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, - Coefficients closeUtilizationNetOfDecayUtil, Coefficients closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { + estimateUtilization( - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, - (i, netDecay) -> { + closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( + i, netDecay + ) -> { if (Float.isNaN(netDecay) || netDecay <= 0f) { return 0f; } @@ -1107,58 +736,9 @@ public void estimateNetDecayWasteAndBreakageVolume( Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayAndWasteUtil, Coefficients closeUtilizationNetOfDecayWasteAndBreakageUtil ) throws ProcessingException { + final var netBreakageCoeMap = controlMap + .>get(ControlKey.BREAKAGE, Map.class); - estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, breakageGroup, quadMeanDiameterUtil, closeUtilizationUtil, - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil - ); - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public static void estimateNetDecayWasteAndBreakageVolume( - Map controlMap, UtilizationClass utilizationClass, int breakageGroup, - Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, - Coefficients closeUtilizationNetOfDecayAndWasteUtil, - Coefficients closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { - final var netBreakageCoeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BREAKAGE, Map.class); - - estimateNetDecayWasteAndBreakageVolume( - utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil - ); - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public static void estimateNetDecayWasteAndBreakageVolume( - UtilizationClass utilizationClass, int breakageGroup, Map netBreakageCoeMap, - Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, - Coefficients closeUtilizationNetOfDecayAndWasteUtil, - Coefficients closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { final var coefficients = netBreakageCoeMap.get(breakageGroup); if (coefficients == null) { throw new ProcessingException("Could not find net breakage coefficients for group " + breakageGroup); @@ -1170,8 +750,9 @@ public static void estimateNetDecayWasteAndBreakageVolume( final var a4 = coefficients.getCoe(4); estimateUtilization( - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, - utilizationClass, (uc, netWaste) -> { + closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, utilizationClass, ( + uc, netWaste + ) -> { if (netWaste <= 0f) { return 0f; @@ -1230,6 +811,134 @@ private static void estimateUtilization( } } + /** + * EMP106 + * + * @param estimateBaseAreaYieldCoefficients + * @param dominantHeight + * @param breastHeightAge + * @param baseAreaOverstory + * @param fullOccupancy + * @param bec + * @param baseAreaGroup + * @return + * @throws StandProcessingException + */ + public float estimateBaseAreaYield( + Coefficients estimateBaseAreaYieldCoefficients, float dominantHeight, float breastHeightAge, + Optional baseAreaOverstory, boolean fullOccupancy, + BecDefinition bec, int baseAreaGroup + ) throws StandProcessingException { + float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); + + /* + * The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea + * (BATOP98). I have included them here. + */ + + /* + * And one POSSIBLY one last vestage of grouping by ITG That limit applies to full occupancy and Empirical + * occupancy. They were derived as the 98th percentile of Empirical stocking, though adjusted PSP's were + * included. If the ouput of this routine is bumped up from empirical to full, MIGHT adjust this limit DOWN + * here, so that at end, it is correct. Tentatively decide NOT to do this. + */ + + // if (fullOccupancy) + // upperBoundsBaseArea *= EMPOC; + + float ageToUse = breastHeightAge; + + // TODO getDebugMode(2)==1 + + if (ageToUse <= 0f) { + throw new StandProcessingException("Age was not positive"); + } + + float trAge = FloatMath.log(ageToUse); + + float a00 = Math.max( + estimateBaseAreaYieldCoefficients.getCoe(0) + estimateBaseAreaYieldCoefficients.getCoe(1) * trAge, 0f + ); + float ap = Math.max( + estimateBaseAreaYieldCoefficients.getCoe(3) + estimateBaseAreaYieldCoefficients.getCoe(4) * trAge, 0f + ); + + float bap; + if (dominantHeight <= estimateBaseAreaYieldCoefficients.getCoe(2)) { + bap = 0f; + } else { + bap = a00 * FloatMath.pow(dominantHeight - estimateBaseAreaYieldCoefficients.getCoe(2), ap) + * FloatMath.exp( + estimateBaseAreaYieldCoefficients.getCoe(5) * dominantHeight + + estimateBaseAreaYieldCoefficients.getCoe(6) * baseAreaOverstory.orElse(0f) + ); + bap = Math.min(bap, upperBoundBaseArea); + } + + if (fullOccupancy) + bap /= EMPIRICAL_OCCUPANCY; + + return bap; + } + + /** + * EMP107 + * + * @param dominantHeight Dominant height (m) + * @param breastHeightAge breast height age + * @param veteranBaseArea Basal area of overstory (>= 0) + * @param bec BEC of the polygon + * @param baseAreaGroup Index of the base area group + * @return DQ of primary layer (w DBH >= 7.5) + * @throws StandProcessingException + */ + public float estimateQuadMeanDiameterYield( + Coefficients coefficientsWeightedBySpeciesAndDecayBec, float dominantHeight, float breastHeightAge, + Optional veteranBaseArea, BecDefinition bec, int baseAreaGroup + ) throws StandProcessingException { + + // TODO handle getDebugMode(2) case + final float ageUse = breastHeightAge; + + final float upperBoundsQuadMeanDiameter = upperBoundsQuadMeanDiameter(baseAreaGroup); + + if (ageUse <= 0f) { + throw new StandProcessingException("Primary breast height age must be positive but was " + ageUse); + } + + final float trAge = FloatMath.log(ageUse); + + final float c0 = coefficientsWeightedBySpeciesAndDecayBec.getCoe(0); + final float c1 = Math.max( + coefficientsWeightedBySpeciesAndDecayBec.getCoe(1) + + coefficientsWeightedBySpeciesAndDecayBec.getCoe(2) * trAge, 0f + ); + final float c2 = Math.max( + coefficientsWeightedBySpeciesAndDecayBec.getCoe(3) + + coefficientsWeightedBySpeciesAndDecayBec.getCoe(4) * trAge, 0f + ); + + return FloatMath.clamp(c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2), 7.6f, upperBoundsQuadMeanDiameter); + + } + + // UPPERGEN Method 1 + Coefficients upperBounds(int baseAreaGroup) { + var upperBoundsMap = controlMap + .>get(ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); + return Utils.optSafe(upperBoundsMap.get(baseAreaGroup)).orElseThrow( + () -> new IllegalStateException("Could not find limits for base area group " + baseAreaGroup) + ); + } + + private float upperBoundsBaseArea(int baseAreaGroup) { + return upperBounds(baseAreaGroup).getCoe(1); + } + + private float upperBoundsQuadMeanDiameter(int baseAreaGroup) { + return upperBounds(baseAreaGroup).getCoe(2); + } + /** * Estimate values for one utilization vector from another * diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java index b81c2f103..31583f5b9 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java @@ -34,6 +34,10 @@ public GenusDefinitionMap(List genusDefinitionList) { public boolean contains(String alias) { return genusByAliasMap.get(alias) != null; } + + public List getAliases() { + return genusByAliasMap.values().stream().map(GenusDefinition::getAlias).toList(); + } public GenusDefinition get(String alias) { GenusDefinition g = genusByAliasMap.get(alias); diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java new file mode 100644 index 000000000..ff3aaadde --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -0,0 +1,175 @@ +package ca.bc.gov.nrs.vdyp.controlmap; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; + +public class CachingResolvedControlMapImpl extends ResolvedControlMapImpl implements ResolvedControlMap { + + final GenusDefinitionMap genusDefinitionMap; + final Map netDecayWasteCoeMap; + final MatrixMap2> netDecayCoeMap; + final MatrixMap2 wasteModifierMap; + final MatrixMap2 decayModifierMap; + final MatrixMap2> closeUtilizationCoeMap; + final Map totalStandWholeStepVolumeCoeMap; + final MatrixMap2> wholeStemUtilizationComponentMap; + final MatrixMap3 quadMeanDiameterUtilizationComponentMap; + final MatrixMap3 basalAreaDiameterUtilizationComponentMap; + final Map smallComponentWholeStemVolumeCoefficients; + final Map smallComponentLoreyHeightCoefficients; + final Map smallComponentQuadMeanDiameterCoefficients; + final Map smallComponentBasalAreaCoefficients; + final Map smallComponentProbabilityCoefficients; + final Map maximumAgeBySiteCurveNumber; + final Map upperBounds; + final MatrixMap2 defaultEquationGroup; + final MatrixMap2> equationModifierGroup; + final MatrixMap2 hl1Coefficients; + final CompVarAdjustments compVarAdjustments; + + public CachingResolvedControlMapImpl(Map controlMap) { + + super(controlMap); + + List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); + this.genusDefinitionMap = new GenusDefinitionMap(genusDefinitions); + + this.netDecayWasteCoeMap = this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); + this.netDecayCoeMap = this.get(ControlKey.VOLUME_NET_DECAY, MatrixMap2.class); + this.wasteModifierMap = this.get(ControlKey.WASTE_MODIFIERS, MatrixMap2.class); + this.decayModifierMap = this.get(ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class); + this.closeUtilizationCoeMap = this.get(ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class); + this.totalStandWholeStepVolumeCoeMap = this.get(ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class); + this.wholeStemUtilizationComponentMap = this.get(ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class); + this.quadMeanDiameterUtilizationComponentMap = this.get(ControlKey.UTIL_COMP_DQ, MatrixMap3.class); + this.basalAreaDiameterUtilizationComponentMap = this.get(ControlKey.UTIL_COMP_BA, MatrixMap3.class); + this.smallComponentWholeStemVolumeCoefficients = this.get(ControlKey.SMALL_COMP_WS_VOLUME, Map.class); + this.smallComponentLoreyHeightCoefficients = this.get(ControlKey.SMALL_COMP_HL, Map.class); + this.smallComponentQuadMeanDiameterCoefficients = this.get(ControlKey.SMALL_COMP_DQ, Map.class); + this.smallComponentBasalAreaCoefficients = this.get(ControlKey.SMALL_COMP_BA, Map.class); + this.smallComponentProbabilityCoefficients = this.get(ControlKey.SMALL_COMP_PROBABILITY, Map.class); + this.maximumAgeBySiteCurveNumber = this.get(ControlKey.SITE_CURVE_AGE_MAX, Map.class); + this.defaultEquationGroup = this.get(ControlKey.DEFAULT_EQ_NUM, MatrixMap2.class); + this.hl1Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); + this.compVarAdjustments = this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); + this.upperBounds = this.get(ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); + this.equationModifierGroup = this.get(ControlKey.EQN_MODIFIERS, MatrixMap2.class); + } + + @Override + public GenusDefinitionMap getGenusDefinitionMap() { + return genusDefinitionMap; + } + + @Override + public Map getNetDecayWasteCoeMap() { + return netDecayWasteCoeMap; + } + + @Override + public MatrixMap2> getNetDecayCoeMap() { + return netDecayCoeMap; + } + + @Override + public MatrixMap2 getWasteModifierMap() { + return wasteModifierMap; + } + + @Override + public MatrixMap2 getDecayModifierMap() { + return decayModifierMap; + } + + @Override + public MatrixMap2> getCloseUtilizationCoeMap() { + return closeUtilizationCoeMap; + } + + @Override + public Map getTotalStandWholeStepVolumeCoeMap() { + return totalStandWholeStepVolumeCoeMap; + } + + @Override + public MatrixMap2> getWholeStemUtilizationComponentMap() { + return wholeStemUtilizationComponentMap; + } + + @Override + public MatrixMap3 getQuadMeanDiameterUtilizationComponentMap() { + return quadMeanDiameterUtilizationComponentMap; + } + + @Override + public MatrixMap3 getBasalAreaDiameterUtilizationComponentMap() { + return basalAreaDiameterUtilizationComponentMap; + } + + @Override + public Map getSmallComponentWholeStemVolumeCoefficients() { + return smallComponentWholeStemVolumeCoefficients; + } + + @Override + public Map getSmallComponentLoreyHeightCoefficients() { + return smallComponentLoreyHeightCoefficients; + } + + @Override + public Map getSmallComponentQuadMeanDiameterCoefficients() { + return smallComponentQuadMeanDiameterCoefficients; + } + + @Override + public Map getSmallComponentBasalAreaCoefficients() { + return smallComponentBasalAreaCoefficients; + } + + @Override + public Map getSmallComponentProbabilityCoefficients() { + return smallComponentProbabilityCoefficients; + } + + @Override + public Map getMaximumAgeBySiteCurveNumber() { + return maximumAgeBySiteCurveNumber; + } + + @Override + public Map getUpperBounds() { + return upperBounds; + } + + @Override + public MatrixMap2 getDefaultEquationGroup() { + return defaultEquationGroup; + } + + @Override + public MatrixMap2> getEquationModifierGroup() { + return equationModifierGroup; + } + + @Override + public MatrixMap2 getHl1Coefficients() { + return hl1Coefficients; + } + + @Override + public CompVarAdjustments getCompVarAdjustments() { + return compVarAdjustments; + } +} diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java new file mode 100644 index 000000000..73f722a97 --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -0,0 +1,59 @@ +package ca.bc.gov.nrs.vdyp.controlmap; + +import java.util.Map; +import java.util.Optional; + +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; + +public interface ResolvedControlMap { + U get(ControlKey key, Class clazz); + + GenusDefinitionMap getGenusDefinitionMap(); + + Map getNetDecayWasteCoeMap(); + + MatrixMap2> getNetDecayCoeMap(); + + MatrixMap2 getWasteModifierMap(); + + MatrixMap2 getDecayModifierMap(); + + MatrixMap2> getCloseUtilizationCoeMap(); + + Map getTotalStandWholeStepVolumeCoeMap(); + + MatrixMap2> getWholeStemUtilizationComponentMap(); + + MatrixMap3 getQuadMeanDiameterUtilizationComponentMap(); + + MatrixMap3 getBasalAreaDiameterUtilizationComponentMap(); + + Map getSmallComponentWholeStemVolumeCoefficients(); + + Map getSmallComponentLoreyHeightCoefficients(); + + Map getSmallComponentQuadMeanDiameterCoefficients(); + + Map getSmallComponentBasalAreaCoefficients(); + + Map getSmallComponentProbabilityCoefficients(); + + Map getMaximumAgeBySiteCurveNumber(); + + Map getUpperBounds(); + + MatrixMap2 getDefaultEquationGroup(); + + MatrixMap2> getEquationModifierGroup(); + + MatrixMap2 getHl1Coefficients(); + + CompVarAdjustments getCompVarAdjustments(); +} diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java new file mode 100644 index 000000000..198a0ecdf --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -0,0 +1,149 @@ +package ca.bc.gov.nrs.vdyp.controlmap; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; + +public class ResolvedControlMapImpl implements ResolvedControlMap { + + private final Map controlMap; + + private final Map entityCache = new HashMap<>(); + + public ResolvedControlMapImpl(Map controlMap) { + this.controlMap = controlMap; + } + + @SuppressWarnings("unchecked") + @Override + public U get(ControlKey key, Class clazz) { + + U entity = (U) entityCache.get(key); + if (entity == null) { + entity = (U) Utils.expectParsedControl(controlMap, key.name(), clazz); + entityCache.put(key, entity); + } + + return entity; + } + + @Override + public GenusDefinitionMap getGenusDefinitionMap() { + List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); + return new GenusDefinitionMap(genusDefinitions); + } + + @Override + public Map getNetDecayWasteCoeMap() { + return this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); + + } + + @Override + public MatrixMap2> getNetDecayCoeMap() { + return this.get(ControlKey.VOLUME_NET_DECAY, MatrixMap2.class); + } + + @Override + public MatrixMap2 getWasteModifierMap() { + return this.get(ControlKey.WASTE_MODIFIERS, MatrixMap2.class); + } + + @Override + public MatrixMap2 getDecayModifierMap() { + return this.get(ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class); + } + + @Override + public MatrixMap2> getCloseUtilizationCoeMap() { + return this.get(ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class); + } + + @Override + public Map getTotalStandWholeStepVolumeCoeMap() { + return this.get(ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class); + } + + @Override + public MatrixMap2> getWholeStemUtilizationComponentMap() { + return this.get(ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class); + } + + @Override + public MatrixMap3 getQuadMeanDiameterUtilizationComponentMap() { + return this.get(ControlKey.UTIL_COMP_DQ, MatrixMap3.class); + } + + @Override + public MatrixMap3 getBasalAreaDiameterUtilizationComponentMap() { + return this.get(ControlKey.UTIL_COMP_BA, MatrixMap3.class); + } + + @Override + public Map getSmallComponentWholeStemVolumeCoefficients() { + return this.get(ControlKey.SMALL_COMP_WS_VOLUME, Map.class); + } + + @Override + public Map getSmallComponentLoreyHeightCoefficients() { + return this.get(ControlKey.SMALL_COMP_HL, Map.class); + } + + @Override + public Map getSmallComponentQuadMeanDiameterCoefficients() { + return this.get(ControlKey.SMALL_COMP_DQ, Map.class); + } + + @Override + public Map getSmallComponentBasalAreaCoefficients() { + return this.get(ControlKey.SMALL_COMP_BA, Map.class); + } + + @Override + public Map getSmallComponentProbabilityCoefficients() { + return this.get(ControlKey.SMALL_COMP_PROBABILITY, Map.class); + } + + @Override + public Map getMaximumAgeBySiteCurveNumber() { + return this.get(ControlKey.SITE_CURVE_AGE_MAX, Map.class); + } + + @Override + public Map getUpperBounds() { + return this.get(ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); + } + + @Override + public MatrixMap2 getDefaultEquationGroup() { + return this.get(ControlKey.DEFAULT_EQ_NUM, Map.class); + } + + @Override + public MatrixMap2> getEquationModifierGroup() { + return this.get(ControlKey.BA_MODIFIERS, MatrixMap2.class); + } + + @Override + public MatrixMap2 getHl1Coefficients() { + return this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); + } + + @Override + public CompVarAdjustments getCompVarAdjustments() { + return this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); + } +} diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java index de60371c0..83e6f212d 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java @@ -46,8 +46,8 @@ public class UpperBoundsParser implements ControlMapSubResourceParser controlMap; BecLookup becLookup; - EstimationMethods emp; + Estimators estimators; @BeforeEach void setup() { controlMap = TestUtils.loadControlMap(); - emp = new EstimationMethods(controlMap); + estimators = new Estimators(new CachingResolvedControlMapImpl(controlMap)); becLookup = (BecLookup) controlMap.get(ControlKey.BEC_DEF.name()); } @@ -59,8 +56,8 @@ void testWhenBasalAreaAllIsZero() throws ProcessingException { Coefficients quadMeanDiameterByUtilization = Utils.utilizationVector(0.0f); Coefficients basalAreaByUtilization = Utils.utilizationVector(0.0f); - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() + estimators.estimateBaseAreaByUtilization( + becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() ); for (var c : basalAreaByUtilization) { @@ -79,8 +76,8 @@ void testWhenBasalAreaAllIsTenAndQuadMeanDiametersAreAllZero() throws Processing Coefficients quadMeanDiameterByUtilization = Utils.utilizationVector(0.0f); Coefficients basalAreaByUtilization = Utils.utilizationVector(10.0f); - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() + estimators.estimateBaseAreaByUtilization( + becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() ); assertThat(basalAreaByUtilization.getCoe(UtilizationClass.SMALL.index), is(0.0f)); @@ -103,8 +100,8 @@ void testTypical() throws ProcessingException { Coefficients quadMeanDiameterByUtilization = Utils.utilizationVector(31.5006275f); Coefficients basalAreaByUtilization = Utils.utilizationVector(0.406989872f); - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() + estimators.estimateBaseAreaByUtilization( + becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() ); // Result of run in FORTRAN VDYP7 with the above parameters. @@ -128,7 +125,7 @@ void testWithInstantiatedControlMap() throws ProcessingException { var bec = Utils.getBec("CWH", controlMap); - emp.estimateBaseAreaByUtilization(bec, dq, ba, "B"); + estimators.estimateBaseAreaByUtilization(bec, dq, ba, "B"); assertThat( ba, @@ -163,8 +160,8 @@ void testWhenWholeStemVolumeIsZero() throws ProcessingException { Coefficients closeUtilizationVolume = Utils.utilizationVector(0.0f); float loreyHeight = 30.0f; - EstimationMethods.estimateCloseUtilizationVolume( - controlMap, UtilizationClass.U75TO125, aAdjust, volumeGroup, loreyHeight, + estimators.estimateCloseUtilizationVolume( + UtilizationClass.U75TO125, aAdjust, volumeGroup, loreyHeight, quadMeanDiameterByUtilization, wholeStemVolumeByUtilization, closeUtilizationVolume ); @@ -193,8 +190,8 @@ void testTypical() throws ProcessingException { Coefficients closeUtilizationVolume = Utils.utilizationVector(0.0f); float loreyHeight = 36.7552986f; - EstimationMethods.estimateCloseUtilizationVolume( - controlMap, UtilizationClass.U175TO225, aAdjust, volumeGroup, loreyHeight, + estimators.estimateCloseUtilizationVolume( + UtilizationClass.U175TO225, aAdjust, volumeGroup, loreyHeight, quadMeanDiameterByUtilization, wholeStemVolumeByUtilization, closeUtilizationVolume ); @@ -215,7 +212,7 @@ void testVeteran() throws Exception { var closeUtilizationUtil = Utils.utilizationVector(0f, 0f, 0f, 0f, 0f); - emp.estimateCloseUtilizationVolume( + estimators.estimateCloseUtilizationVolume( utilizationClass, aAdjust, volumeGroup, lorieHeight, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationUtil ); @@ -246,8 +243,8 @@ void testWhenCloseUtilizationIsZero() throws ProcessingException { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayVolume( - controlMap, genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, + estimators.estimateNetDecayVolume( + genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, volumeGroup, 0.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay ); @@ -275,8 +272,8 @@ void testTypical() throws ProcessingException { ); int decayGroup = decayEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayVolume( - controlMap, genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, + estimators.estimateNetDecayVolume( + genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, decayGroup, 54.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay ); @@ -302,8 +299,8 @@ void testWhenCloseUtilizationLessDecayIsZero() throws ProcessingException { Coefficients closeUtilizationNetOfDecay = Utils.utilizationVector(0.0f); Coefficients closeUtilizationNetOfDecayAndWastage = Utils.utilizationVector(0.0f); - EstimationMethods.estimateNetDecayAndWasteVolume( - controlMap, becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 0.0f, + estimators.estimateNetDecayAndWasteVolume( + becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 0.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay, closeUtilizationNetOfDecayAndWastage ); @@ -329,8 +326,8 @@ void testTypical() throws ProcessingException { .utilizationVector(0.0f, 5.90565634f, 0.000909090857f, 0.0502020158f, 0.152929291f, 5.70161581f); Coefficients closeUtilizationNetOfDecayAndWastage = Utils.utilizationVector(0.0f); - EstimationMethods.estimateNetDecayAndWasteVolume( - controlMap, becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), + estimators.estimateNetDecayAndWasteVolume( + becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 36.7552986f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay, closeUtilizationNetOfDecayAndWastage ); @@ -362,8 +359,8 @@ void testWhenCloseUtilizationLessDecayAndWastageIsZero() throws ProcessingExcept ); int breakageGroup = breakageEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, + estimators.estimateNetDecayWasteAndBreakageVolume( + UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage ); @@ -392,8 +389,8 @@ void testTypical() throws ProcessingException { ); int breakageGroup = breakageEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, + estimators.estimateNetDecayWasteAndBreakageVolume( + UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage ); @@ -417,7 +414,7 @@ void testTest1() throws Exception { var bec = Utils.getBec("CWH", controlMap); - emp.estimateQuadMeanDiameterByUtilization(bec, coe, "B"); + estimators.estimateQuadMeanDiameterByUtilization(bec, coe, "B"); assertThat(coe, utilization(0f, 31.6622887f, 10.0594692f, 14.966774f, 19.9454956f, 46.1699982f)); } @@ -431,7 +428,7 @@ void testTest2() throws Exception { var bec = Utils.getBec("MH", controlMap); - emp.estimateQuadMeanDiameterByUtilization(bec, coe, "L"); + estimators.estimateQuadMeanDiameterByUtilization(bec, coe, "L"); assertThat(coe, utilization(0f, 13.4943399f, 10.2766619f, 14.67033f, 19.4037666f, 25.719244f)); } @@ -511,7 +508,7 @@ void testEstimateQuadMeanDiameterForSpecies() throws Exception { specs.put(spec4.getGenus(), spec4); specs.put(spec5.getGenus(), spec5); - float dq = emp.estimateQuadMeanDiameterForSpecies( + float dq = estimators.estimateQuadMeanDiameterForSpecies( spec1, specs, Region.COASTAL, 30.2601795f, 44.6249847f, 620.504883f, 31.6603775f ); @@ -543,8 +540,8 @@ void testPrimary() throws ProcessingException { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateWholeStemVolume( - controlMap, UtilizationClass.ALL, 0.0f, volumeGroup, 36.7552986f, quadMeanDiameterByUtilization, + estimators.estimateWholeStemVolume( + UtilizationClass.ALL, 0.0f, volumeGroup, 36.7552986f, quadMeanDiameterByUtilization, basalAreaByUtilization, wholeStemVolumeByUtilization ); @@ -565,15 +562,13 @@ void testVeteran() throws Exception { var baseAreaUtil = Utils.utilizationVector(0.492921442f, 0f, 0f, 0f, 0.492921442f); var wholeStemVolumeUtil = Utils.utilizationVector(); - emp.estimateWholeStemVolume( + estimators.estimateWholeStemVolume( utilizationClass, aAdjust, volumeGroup, lorieHeight, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil ); assertThat(wholeStemVolumeUtil, utilization(0f, 0f, 0f, 0f, 0f, 6.11904192f)); - } - } @Test @@ -590,8 +585,8 @@ void testWholeStemVolumePerTreeEstimation() { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - float result = EstimationMethods - .estimateWholeStemVolumePerTree(controlMap, volumeGroup, 36.7552986f, 31.5006275f); + float result = estimators + .estimateWholeStemVolumePerTree(volumeGroup, 36.7552986f, 31.5006275f); // Result of run in FORTRAN VDYP7 with the above parameters. assertThat(result, is(1.2011181f)); @@ -624,7 +619,7 @@ void testEqn1() throws Exception { builder.breakageGroup(-1); }); - var result = emp.estimateNonPrimaryLoreyHeight(spec, specPrime, bec, 24.2999992f, 20.5984688f); + var result = estimators.estimateNonPrimaryLoreyHeight(spec.getGenus(), specPrime.getGenus(), bec, 24.2999992f, 20.5984688f); assertThat(result, closeTo(21.5356998f)); @@ -654,7 +649,7 @@ void testEqn2() throws Exception { builder.breakageGroup(-1); }); - var result = emp.estimateNonPrimaryLoreyHeight(spec, specPrime, bec, 35.2999992f, 33.6889763f); + var result = estimators.estimateNonPrimaryLoreyHeight(spec.getGenus(), specPrime.getGenus(), bec, 35.2999992f, 33.6889763f); assertThat(result, closeTo(38.7456512f)); diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java index 4b9716f03..85e5e242c 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java @@ -1,7 +1,6 @@ package ca.bc.gov.nrs.vdyp.common; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; import org.junit.jupiter.api.Test; diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index c1631285c..647f984b4 100644 --- a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -46,7 +46,6 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; @@ -333,14 +332,14 @@ VdypLayer processLayerAsPrimary(FipPolygon fipPolygon, FipLayerPrimary fipLayer, } // Estimate lorey height for primary species if (iPass == 1 && vdypSpecies.size() == 1) { - primaryHeight = estimationMethods.primaryHeightFromLeadHeight( + primaryHeight = estimators.primaryHeightFromLeadHeight( leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), tphTotal ); } else if (iPass == 1) { - primaryHeight = estimationMethods + primaryHeight = estimators .primaryHeightFromLeadHeightInitial(leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion()); } else { - primaryHeight = estimationMethods.primaryHeightFromLeadHeight( + primaryHeight = estimators.primaryHeightFromLeadHeight( leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), vdypPrimarySpecies.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) ); @@ -355,8 +354,8 @@ VdypLayer processLayerAsPrimary(FipPolygon fipPolygon, FipLayerPrimary fipLayer, // EMP053 vspec.getLoreyHeightByUtilization().setCoe( UTIL_ALL, - estimationMethods.estimateNonPrimaryLoreyHeight( - vspec, vdypPrimarySpecies, bec, leadHeight, primaryHeight + estimators.estimateNonPrimaryLoreyHeight( + vspec.getGenus(), vdypPrimarySpecies.getGenus(), bec, leadHeight, primaryHeight ) ); } @@ -411,7 +410,7 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, // Multiple Species for (var spec : result.getSpecies().values()) { - var limits = estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); + var limits = estimators.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); final float maxHeightMultiplier = fipLayer.getPrimaryGenus() .orElseThrow(() -> new IllegalStateException("primaryGenus has not been set")) @@ -461,7 +460,7 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, for (var spec : result.getSpecies().values()) { // EMP061 - var limits = estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); + var limits = estimators.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); var dqMin = limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); var dqMax = max( @@ -471,7 +470,7 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, // EMP060 float quadMeanDiameter = clamp( - estimationMethods.estimateQuadMeanDiameterForSpecies( + estimators.estimateQuadMeanDiameterForSpecies( spec, result.getSpecies(), bec.getRegion(), quadMeanDiameterTotal, baseAreaTotal, treesPerHectareTotal, loreyHeightTotal ), // @@ -544,8 +543,8 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, for (var spec : result.getSpecies().values()) { // EMP090 var wholeStemVolume = spec.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - * EstimationMethods.estimateWholeStemVolumePerTree( - controlMap, spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL), + * estimators.estimateWholeStemVolumePerTree( + spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL), spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL) ); spec.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, wholeStemVolume); @@ -735,44 +734,37 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit var adjust = new Coefficients(new float[] { 0f, 0f, 0f, 0f }, 1); // EMP091 - EstimationMethods.estimateWholeStemVolume( - controlMap, utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, + estimators.estimateWholeStemVolume( + 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, + estimators.estimateCloseUtilizationVolume( + utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil ); adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); // EMP093 - EstimationMethods.estimateNetDecayVolume( - controlMap, vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, + estimators.estimateNetDecayVolume( + 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.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - EstimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, netDecayCoeMap, - wasteModifierMap, quadMeanDiameterUtil, closeUtilizationVolumeUtil, - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil - ); + estimators.estimateNetDecayAndWasteVolume( + bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, + quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, + closeUtilizationNetOfDecayAndWasteUtil); if (getId().isStart()) { // EMP095 - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, + estimators.estimateNetDecayWasteAndBreakageVolume( + utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 72cdd0363..a44e74cfd 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -22,7 +22,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods; +import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CommonCalculatorException; @@ -67,10 +67,12 @@ public class ForwardProcessingEngine { public static final float PI_40K = (float) (Math.PI / 40_000); /* pp */ final ForwardProcessingState fps; + /* pp */ final Estimators estimators; public ForwardProcessingEngine(Map controlMap) { this.fps = new ForwardProcessingState(controlMap); + this.estimators = new Estimators(fps.fcm); } public enum ExecutionStep { @@ -124,7 +126,7 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStep) throws P // Determine the target year of the growth int targetYear; - int growTargetControlVariableValue = fps.forwardControlVariables + int growTargetControlVariableValue = fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.GROW_TARGET_1); if (growTargetControlVariableValue == -1) { if (polygon.getTargetYear().isEmpty()) { @@ -163,7 +165,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro // SCINXSET - note these are calculated directly from the Primary bank of instance 1 if (lastStep.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { - calculateMissingSiteCurves(bank, fps.siteCurveMap, fps.getPolygonProcessingState()); + calculateMissingSiteCurves(bank, fps.fcm.getSiteCurveMap(), fps.getPolygonProcessingState()); } // VPRIME1, method == 1 @@ -186,7 +188,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 if (lastStep.ordinal() >= ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX.ordinal()) { - calculateDominantHeightAgeSiteIndex(pps, fps.hl1Coefficients); + calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); } // CVSET1 @@ -204,7 +206,8 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro writeLayers(primaryLayerSourceInstance, veteranLayerInstance, false); - boolean createNewGroups = fps.debugSettings.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 + boolean createNewGroups = fps.fcm.getDebugSettings() + .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 && fps.getPolygonProcessingState().getNSpecies() > 1; int primaryLayerTargetInstance = 2; @@ -247,12 +250,13 @@ private void grow( // context int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); if (currentYear > startingYear - && fps.forwardControlVariables.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { + && fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { // VPRIME1, method == 1 calculateCoverages(); // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 - calculateDominantHeightAgeSiteIndex(pps, fps.hl1Coefficients); + calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); } float dominantHeight = pps.getPrimarySpeciesDominantHeight(); @@ -264,7 +268,7 @@ private void grow( // Calculate change in dominant height float growthInDominantHeight = growDominantHeight( - fps, dominantHeight, siteCurveNumber, siteIndex, yearsToBreastHeight + dominantHeight, siteCurveNumber, siteIndex, yearsToBreastHeight ); // Calculate change in basal area @@ -288,7 +292,7 @@ private void grow( } private static final float EMPIRICAL_OCCUPANCY = 0.85f; - + /** * EMP111A - Basal area growth for the primary layer. * @@ -305,8 +309,8 @@ private float growBasalArea( float veteranLayerBasalArea, float growthInDominantHeight ) { // UPPERGEN( 1, BATOP98, DQTOP98) - var baUpperBound = growBasalAreaUpperBound(fps); - var dqUpperBound = growQuadraticMeanDiameterUpperBound(fps); + var baUpperBound = growBasalAreaUpperBound(); + var dqUpperBound = growQuadraticMeanDiameterUpperBound(); baUpperBound = baUpperBound / EMPIRICAL_OCCUPANCY; var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); @@ -316,26 +320,25 @@ private float growBasalArea( /** * UPPERGEN(1, BATOP98, DQTOP98) for basal area */ - private float growBasalAreaUpperBound(ForwardProcessingState fps) { + private float growBasalAreaUpperBound() { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - return fps.upperBounds.get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); + return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); } - + /** * UPPERGEN(1, BATOP98, DQTOP98) for quad-mean-diameter */ - private float growQuadraticMeanDiameterUpperBound(ForwardProcessingState fps) { + private float growQuadraticMeanDiameterUpperBound() { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - return fps.upperBounds.get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); + return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); } - public static float - growDominantHeight( - ForwardProcessingState fps, float dominantHeight, int siteCurveNumber, - float siteIndex, float yearsToBreastHeight + public float growDominantHeight( + float dominantHeight, int siteCurveNumber, float siteIndex, + float yearsToBreastHeight ) throws ProcessingException { - SiteCurveAgeMaximum scAgeMaximums = fps.maximumAgeBySiteCurveNumber.get(siteCurveNumber); + SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); Region region = fps.getPolygonProcessingState().wallet.getBecZone().getRegion(); if (siteCurveNumber == VdypEntity.MISSING_INTEGER_VALUE) { @@ -531,10 +534,10 @@ private void writeLayers(int primaryLayerInstance, int veteranLayerInstance, boo private static final float B_BASE_MIN = 0.01f; @SuppressWarnings("unchecked") - static void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingException { + void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingException { Coefficients aAdjust = new Coefficients(new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, 1); - var growthDetails = pps.getVdypGrowthDetails(); + var growthDetails = pps.getFps().fcm.getForwardControlVariables(); // Note: L1COM2 (INL1VGRP, INL1DGRP, INL1BGRP) is initialized when // PolygonProcessingState (volumeEquationGroups, decayEquationGroups @@ -601,11 +604,9 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP094 - EstimationMethods.estimateNetDecayAndWasteVolume( + estimators.estimateNetDecayAndWasteVolume( pps.getBecZone() - .getRegion(), uc, aAdjust, pps.wallet.speciesNames[s], spLoreyHeight_All, pps - .getNetDecayWasteCoeMap(), pps - .getWasteModifierMap(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste + .getRegion(), uc, aAdjust, pps.wallet.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste ); float actualVolume = pps.wallet.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; @@ -624,10 +625,9 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process // EMP093 int decayGroup = pps.decayEquationGroups[s]; - EstimationMethods.estimateNetDecayVolume( + estimators.estimateNetDecayVolume( pps.wallet.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, pps - .getPrimarySpeciesAgeAtBreastHeight(), pps.getNetDecayCoeMap(), pps - .getDecayModifierMap(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay + .getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay ); float actualVolume = pps.wallet.cuVolumesMinusDecay[s][uc.ordinal()]; @@ -645,9 +645,8 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process // EMP092 int volumeGroup = pps.volumeEquationGroups[s]; - EstimationMethods.estimateCloseUtilizationVolume( - uc, aAdjust, volumeGroup, spLoreyHeight_All, pps - .getCloseUtilizationCoeMap(), quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes + estimators.estimateCloseUtilizationVolume( + uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes ); float actualVolume = pps.wallet.closeUtilizationVolumes[s][uc.ordinal()]; @@ -661,16 +660,14 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process int primarySpeciesVolumeGroup = pps.volumeEquationGroups[s]; float primarySpeciesQMDAll = pps.wallet.quadMeanDiameters[s][UC_ALL_INDEX]; var wholeStemVolume = pps.wallet.treesPerHectare[s][UC_ALL_INDEX] - * EstimationMethods.estimateWholeStemVolumePerTree( - primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll, pps - .getTotalStandWholeStepVolumeCoeMap() + * estimators.estimateWholeStemVolumePerTree( + primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll ); wholeStemVolumes.setCoe(UC_ALL_INDEX, wholeStemVolume); - EstimationMethods.estimateWholeStemVolume( - UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, pps - .getWholeStemUtilizationComponentMap(), quadMeanDiameters, basalAreas, wholeStemVolumes + estimators.estimateWholeStemVolume( + UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, quadMeanDiameters, basalAreas, wholeStemVolumes ); for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL_ALL) { @@ -685,13 +682,12 @@ static void setCompatibilityVariables(PolygonProcessingState pps) throws Process cvVolume[s].put(uc, VolumeVariable.WHOLE_STEM_VOL, LayerType.PRIMARY, adjustment); } - EstimationMethods.estimateQuadMeanDiameterByUtilization( - pps.getBecZone(), pps.getQuadMeanDiameterUtilizationComponentMap(), quadMeanDiameters, genusName + estimators.estimateQuadMeanDiameterByUtilization( + pps.getBecZone(), quadMeanDiameters, genusName ); - EstimationMethods.estimateBaseAreaByUtilization( - pps.getBecZone(), pps - .getBasalAreaUtilizationComponentMap(), quadMeanDiameters, basalAreas, genusName + estimators.estimateBaseAreaByUtilization( + pps.getBecZone(), quadMeanDiameters, basalAreas, genusName ); // Calculate trees-per-hectare per utilization @@ -727,7 +723,7 @@ uc.index, calculateTreesPerHectare( // Small components - cvSmall[s] = estimateSmallComponents(pps, s, growthDetails); + cvSmall[s] = estimateSmallComponents(s, growthDetails); } pps.setCompatibilityVariableDetails(cvVolume, cvBasalArea, cvQuadraticMeanDiameter, cvSmall); @@ -735,31 +731,33 @@ uc.index, calculateTreesPerHectare( /** * Estimate small component utilization values for primary layer - * * @param allowCompatibilitySetting * * @throws ProcessingException */ - private static HashMap - estimateSmallComponents(PolygonProcessingState pps, int speciesIndex, ForwardControlVariables growthDetails) + private HashMap + estimateSmallComponents(int speciesIndex, ForwardControlVariables growthDetails) throws ProcessingException { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank wallet = pps.wallet; + Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); - String speciesName = pps.wallet.speciesNames[speciesIndex]; + String speciesName = wallet.speciesNames[speciesIndex]; - float spLoreyHeight_All = pps.wallet.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp - float spQuadMeanDiameter_All = pps.wallet.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp + float spLoreyHeight_All = wallet.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp + float spQuadMeanDiameter_All = wallet.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp // this WHOLE operation on Actual BA's, not 100% occupancy. // TODO: verify this: float fractionAvailable = polygon.getPercentForestLand(); - float spBaseArea_All = pps.wallet.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp + float spBaseArea_All = wallet.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp // EMP080 - float cvSmallComponentProbability = smallComponentProbability(pps, speciesName, spLoreyHeight_All, region); // PROBsp + float cvSmallComponentProbability = smallComponentProbability(speciesName, spLoreyHeight_All, region); // PROBsp // EMP081 float conditionalExpectedBaseArea = conditionalExpectedBaseArea( - pps, speciesName, spBaseArea_All, spLoreyHeight_All, region + speciesName, spBaseArea_All, spLoreyHeight_All, region ); // BACONDsp // TODO (see previous TODO): conditionalExpectedBaseArea /= fractionAvailable; @@ -767,23 +765,23 @@ uc.index, calculateTreesPerHectare( float cvBasalArea_Small = cvSmallComponentProbability * conditionalExpectedBaseArea; // EMP082 - float cvQuadMeanDiameter_Small = smallComponentQuadMeanDiameter(pps, speciesName, spLoreyHeight_All); // DQSMsp + float cvQuadMeanDiameter_Small = smallComponentQuadMeanDiameter(speciesName, spLoreyHeight_All); // DQSMsp // EMP085 float cvLoreyHeight_Small = smallComponentLoreyHeight( - pps, speciesName, spLoreyHeight_All, cvQuadMeanDiameter_Small, spQuadMeanDiameter_All + speciesName, spLoreyHeight_All, cvQuadMeanDiameter_Small, spQuadMeanDiameter_All ); // HLSMsp // EMP086 - float cvMeanVolume_Small = meanVolumeSmall(pps, speciesName, cvQuadMeanDiameter_Small, cvLoreyHeight_Small); // VMEANSMs + float cvMeanVolume_Small = meanVolumeSmall(speciesName, cvQuadMeanDiameter_Small, cvLoreyHeight_Small); // VMEANSMs var cvSmall = new HashMap(); - float spInputBasalArea_Small = pps.wallet.basalAreas[speciesIndex][UC_SMALL_INDEX]; + float spInputBasalArea_Small = wallet.basalAreas[speciesIndex][UC_SMALL_INDEX]; cvSmall.put(SmallUtilizationClassVariable.BASAL_AREA, spInputBasalArea_Small - cvBasalArea_Small); if (growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { - float spInputQuadMeanDiameter_Small = pps.wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; + float spInputQuadMeanDiameter_Small = wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; cvSmall.put( SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - cvQuadMeanDiameter_Small @@ -792,7 +790,7 @@ uc.index, calculateTreesPerHectare( cvSmall.put(SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); } - float spInputLoreyHeight_Small = pps.wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX]; + float spInputLoreyHeight_Small = wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX]; if (spInputLoreyHeight_Small > 1.3f && cvLoreyHeight_Small > 1.3f && spInputBasalArea_Small > 0.0f) { float cvLoreyHeight = FloatMath.log( (spInputLoreyHeight_Small - 1.3f) / (cvLoreyHeight_Small - 1.3f)); cvSmall.put(SmallUtilizationClassVariable.LOREY_HEIGHT, cvLoreyHeight); @@ -800,11 +798,11 @@ uc.index, calculateTreesPerHectare( cvSmall.put(SmallUtilizationClassVariable.LOREY_HEIGHT, 0.0f); } - float spInputWholeStemVolume_Small = pps.wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; + float spInputWholeStemVolume_Small = wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; if (spInputWholeStemVolume_Small > 0.0f && cvMeanVolume_Small > 0.0f && growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l >= r)) { - float spInputTreePerHectare_Small = pps.wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; + float spInputTreePerHectare_Small = wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; var cvWholeStemVolume = FloatMath .log(spInputWholeStemVolume_Small / spInputTreePerHectare_Small / cvMeanVolume_Small); @@ -818,10 +816,12 @@ uc.index, calculateTreesPerHectare( } // EMP080 - private static float smallComponentProbability( - PolygonProcessingState pps, String speciesName, float loreyHeight, Region region + private float smallComponentProbability( + String speciesName, float loreyHeight, Region region ) { - Coefficients coe = pps.getSmallComponentProbabilityCoefficients().get(speciesName); + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + Coefficients coe = fps.fcm.getSmallComponentProbabilityCoefficients().get(speciesName); // EQN 1 in IPSJF118.doc @@ -841,10 +841,10 @@ private static float smallComponentProbability( } // EMP081 - private static float conditionalExpectedBaseArea( - PolygonProcessingState pps, String speciesName, float basalArea, float loreyHeight, Region region + private float conditionalExpectedBaseArea( + String speciesName, float basalArea, float loreyHeight, Region region ) { - Coefficients coe = pps.getSmallComponentBasalAreaCoefficients().get(speciesName); + Coefficients coe = fps.fcm.getSmallComponentBasalAreaCoefficients().get(speciesName); // EQN 3 in IPSJF118.doc @@ -866,9 +866,9 @@ private static float conditionalExpectedBaseArea( } // EMP082 - private static float - smallComponentQuadMeanDiameter(PolygonProcessingState pps, String speciesName, float loreyHeight) { - Coefficients coe = pps.getSmallComponentQuadMeanDiameterCoefficients().get(speciesName); + private float + smallComponentQuadMeanDiameter(String speciesName, float loreyHeight) { + Coefficients coe = fps.fcm.getSmallComponentQuadMeanDiameterCoefficients().get(speciesName); // EQN 5 in IPSJF118.doc @@ -881,11 +881,11 @@ private static float conditionalExpectedBaseArea( } // EMP085 - private static float smallComponentLoreyHeight( - PolygonProcessingState pps, String speciesName, float speciesLoreyHeight_All, - float quadMeanDiameterSpecSmall, float speciesQuadMeanDiameter_All + private float smallComponentLoreyHeight( + String speciesName, float speciesLoreyHeight_All, float quadMeanDiameterSpecSmall, + float speciesQuadMeanDiameter_All ) { - Coefficients coe = pps.getSmallComponentLoreyHeightCoefficients().get(speciesName); + Coefficients coe = fps.fcm.getSmallComponentLoreyHeightCoefficients().get(speciesName); // EQN 1 in IPSJF119.doc @@ -897,10 +897,10 @@ private static float smallComponentLoreyHeight( } // EMP086 - private static float meanVolumeSmall( - PolygonProcessingState pps, String speciesName, float quadMeanDiameterSpecSmall, float loreyHeightSpecSmall + private float meanVolumeSmall( + String speciesName, float quadMeanDiameterSpecSmall, float loreyHeightSpecSmall ) { - Coefficients coe = pps.getSmallComponentWholeStemVolumeCoefficients().get(speciesName); + Coefficients coe = fps.fcm.getSmallComponentWholeStemVolumeCoefficients().get(speciesName); // EQN 1 in IPSJF119.doc @@ -1394,7 +1394,8 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing } /** Default Equation Group, by species. Indexed by the species number, a one-based value. */ - private static final int[] defaultEquationGroups = { 0 /* placeholder */, 1, 2, 3, 4, 1, 2, 5, 6, 7, 1, 9, 8, 9, 9, 10, 4 }; + private static final int[] defaultEquationGroups = { 0 /* placeholder */, 1, 2, 3, 4, 1, 2, 5, 6, 7, 1, 9, 8, 9, 9, + 10, 4 }; private static final Set exceptedSpeciesIndicies = new HashSet<>(List.of(3, 4, 5, 6, 10)); // PRIMFIND @@ -1463,8 +1464,9 @@ void determinePolygonRankings(Collection> speciesToCombine) { String primarySpeciesName = pps.wallet.speciesNames[highestPercentageIndex]; String becZoneAlias = pps.wallet.getBecZone().getAlias(); - int defaultEquationGroup = fps.defaultEquationGroup.get(primarySpeciesName, becZoneAlias); - Optional equationModifierGroup = fps.equationModifierGroup.get(defaultEquationGroup, inventoryTypeGroup); + int defaultEquationGroup = fps.fcm.getDefaultEquationGroup().get(primarySpeciesName, becZoneAlias); + Optional equationModifierGroup = fps.fcm.getEquationModifierGroup() + .get(defaultEquationGroup, inventoryTypeGroup); if (equationModifierGroup.isPresent()) { basalAreaGroup1 = equationModifierGroup.get(); } else { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index aa3831c0d..0c2057523 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -1,27 +1,11 @@ package ca.bc.gov.nrs.vdyp.forward; -import java.util.List; import java.util.Map; -import java.util.Optional; -import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; -import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; -import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; +import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; -import ca.bc.gov.nrs.vdyp.model.BecLookup; -import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; -import ca.bc.gov.nrs.vdyp.model.DebugSettings; -import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; -import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -import ca.bc.gov.nrs.vdyp.model.Region; -import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; class ForwardProcessingState { @@ -34,34 +18,7 @@ class ForwardProcessingState { private static final int MAX_INSTANCES = 3; /** The control map defining the context of the execution */ - private final Map controlMap; - - // Cached values from the controlMap - - final GenusDefinitionMap genusDefinitionMap; - final ForwardControlVariables forwardGrowthDetails; - final ForwardDebugSettings debugSettings; - final Map netDecayWasteCoeMap; - final MatrixMap2> netDecayCoeMap; - final MatrixMap2 wasteModifierMap; - final MatrixMap2 decayModifierMap; - final MatrixMap2> closeUtilizationCoeMap; - final Map totalStandWholeStepVolumeCoeMap; - final MatrixMap2> wholeStemUtilizationComponentMap; - final MatrixMap3 quadMeanDiameterUtilizationComponentMap; - final MatrixMap3 basalAreaDiameterUtilizationComponentMap; - final Map smallComponentWholeStemVolumeCoefficients; - final Map smallComponentLoreyHeightCoefficients; - final Map smallComponentQuadMeanDiameterCoefficients; - final Map smallComponentBasalAreaCoefficients; - final Map smallComponentProbabilityCoefficients; - final Map maximumAgeBySiteCurveNumber; - final Map upperBounds; - final MatrixMap2 defaultEquationGroup; - final MatrixMap2> equationModifierGroup; - final MatrixMap2 hl1Coefficients; - final CompVarAdjustments compVarAdjustments; - final ForwardControlVariables forwardControlVariables; + final ForwardResolvedControlMap fcm; /** The storage banks */ private final Bank[/* instances */][/* layers of instance */] banks; @@ -69,86 +26,11 @@ class ForwardProcessingState { /** The active state */ private PolygonProcessingState pps; - final BecLookup becLookup; - final MatrixMap2 siteCurveMap; - - public ForwardProcessingState(Map controlMap) { - this.controlMap = controlMap; - banks = new Bank[][] { new Bank[LAYERS_PER_INSTANCE], new Bank[LAYERS_PER_INSTANCE], new Bank[LAYERS_PER_INSTANCE] }; - this.forwardGrowthDetails = Utils - .expectParsedControl(controlMap, ControlKey.VTROL, ForwardControlVariables.class); - this.debugSettings = new ForwardDebugSettings( - Utils.expectParsedControl(controlMap, ControlKey.DEBUG_SWITCHES, DebugSettings.class) - ); - - List genusDefinitions = Utils - .>expectParsedControl(controlMap, ControlKey.SP0_DEF, List.class); - this.genusDefinitionMap = new GenusDefinitionMap(genusDefinitions); - - this.netDecayWasteCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - this.netDecayCoeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY, MatrixMap2.class - ); - this.wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - this.decayModifierMap = Utils.>expectParsedControl( - controlMap, ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class - ); - this.closeUtilizationCoeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class - ); - this.totalStandWholeStepVolumeCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class - ); - this.wholeStemUtilizationComponentMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class - ); - this.quadMeanDiameterUtilizationComponentMap = Utils - .>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_DQ, MatrixMap3.class - ); - this.basalAreaDiameterUtilizationComponentMap = Utils - .>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_BA, MatrixMap3.class - ); - this.smallComponentWholeStemVolumeCoefficients = Utils - .>expectParsedControl(controlMap, ControlKey.SMALL_COMP_WS_VOLUME, Map.class); - this.smallComponentLoreyHeightCoefficients = Utils - .>expectParsedControl(controlMap, ControlKey.SMALL_COMP_HL, Map.class); - this.smallComponentQuadMeanDiameterCoefficients = Utils - .>expectParsedControl(controlMap, ControlKey.SMALL_COMP_DQ, Map.class); - this.smallComponentBasalAreaCoefficients = Utils - .>expectParsedControl(controlMap, ControlKey.SMALL_COMP_BA, Map.class); - this.smallComponentProbabilityCoefficients = Utils.>expectParsedControl( - controlMap, ControlKey.SMALL_COMP_PROBABILITY, Map.class - ); - this.maximumAgeBySiteCurveNumber = Utils.>expectParsedControl( - controlMap, ControlKey.SITE_CURVE_AGE_MAX, Map.class - ); - this.upperBounds = Utils.>expectParsedControl( - controlMap, ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); - this.defaultEquationGroup = Utils.>expectParsedControl( - controlMap, ControlKey.DEFAULT_EQ_NUM, MatrixMap2.class); - this.equationModifierGroup = Utils.>>expectParsedControl( - controlMap, ControlKey.EQN_MODIFIERS, MatrixMap2.class); - - this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); - - this.siteCurveMap = Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); - - this.hl1Coefficients = Utils.expectParsedControl(controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); - - this.compVarAdjustments = Utils.expectParsedControl(controlMap, ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); - - this.forwardControlVariables = Utils.expectParsedControl(controlMap, ControlKey.VTROL, ForwardControlVariables.class); + this.fcm = new ForwardResolvedControlMapImpl(controlMap); } private static final float MIN_BASAL_AREA = 0.001f; @@ -170,17 +52,13 @@ public void setPolygon(VdypPolygon polygon) { ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA : true)); - pps = new PolygonProcessingState(this, polygon, primaryBank, controlMap); + pps = new PolygonProcessingState(this, polygon, primaryBank); } public PolygonProcessingState getPolygonProcessingState() { return pps; } - public Map getControlMap() { - return controlMap; - } - public void storeActive(int instanceNumber, LayerType layerType) { banks[instanceNumber][layerType.getIndex()] = pps.wallet.copy(); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 1d2407431..13867b0f7 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -8,18 +8,14 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; -import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; @@ -113,7 +109,7 @@ class PolygonProcessingState { // TODO public PolygonProcessingState( - ForwardProcessingState fps, VdypPolygon polygon, Bank bank, Map controlMap + ForwardProcessingState fps, VdypPolygon polygon, Bank bank ) { this.fps = fps; @@ -121,14 +117,14 @@ public PolygonProcessingState( this.wallet = bank.copy(); - var volumeEquationGroupMatrix = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_EQN_GROUPS, MatrixMap2.class + var volumeEquationGroupMatrix = this.fps.fcm.>get( + ControlKey.VOLUME_EQN_GROUPS, MatrixMap2.class ); - var decayEquationGroupMatrix = Utils.>expectParsedControl( - controlMap, ControlKey.DECAY_GROUPS, MatrixMap2.class + var decayEquationGroupMatrix = this.fps.fcm.>get( + ControlKey.DECAY_GROUPS, MatrixMap2.class ); - var breakageEquationGroupMatrix = Utils.>expectParsedControl( - controlMap, ControlKey.BREAKAGE_GROUPS, MatrixMap2.class + var breakageEquationGroupMatrix = this.fps.fcm.>get( + ControlKey.BREAKAGE_GROUPS, MatrixMap2.class ); this.volumeEquationGroups = new int[this.wallet.getNSpecies() + 1]; @@ -172,65 +168,6 @@ public VdypPolygonLayer getLayer() { return wallet.getLayer(); } - public ForwardControlVariables getVdypGrowthDetails() { - return fps.forwardGrowthDetails; - } - - public MatrixMap2> getNetDecayCoeMap() { - return fps.netDecayCoeMap; - } - - public Map getNetDecayWasteCoeMap() { - return fps.netDecayWasteCoeMap; - } - - public MatrixMap2 getWasteModifierMap() { - return fps.wasteModifierMap; - } - - public MatrixMap2 getDecayModifierMap() { - return fps.decayModifierMap; - } - - public MatrixMap2> getCloseUtilizationCoeMap() { - return fps.closeUtilizationCoeMap; - } - - public Map getTotalStandWholeStepVolumeCoeMap() { - return fps.totalStandWholeStepVolumeCoeMap; - } - - public MatrixMap2> getWholeStemUtilizationComponentMap() { - return fps.wholeStemUtilizationComponentMap; - } - - public MatrixMap3 getQuadMeanDiameterUtilizationComponentMap() { - return fps.quadMeanDiameterUtilizationComponentMap; - } - - public MatrixMap3 getBasalAreaUtilizationComponentMap() { - return fps.basalAreaDiameterUtilizationComponentMap; - } - - public Map getSmallComponentWholeStemVolumeCoefficients() { - return fps.smallComponentWholeStemVolumeCoefficients; - } - - public Map getSmallComponentLoreyHeightCoefficients() { - return fps.smallComponentLoreyHeightCoefficients; - } - - public Map getSmallComponentQuadMeanDiameterCoefficients() { - return fps.smallComponentQuadMeanDiameterCoefficients; - } - - public Map getSmallComponentBasalAreaCoefficients() { - return fps.smallComponentBasalAreaCoefficients; - } - - public Map getSmallComponentProbabilityCoefficients() { - return fps.smallComponentProbabilityCoefficients; - } public int getPrimarySpeciesIndex() { if (!areRankingDetailsSet) { @@ -451,7 +388,7 @@ public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { // Normally, these values may only be set only once. However, during grow(), if the // control variable UPDATE_DURING_GROWTH_6 has value "1" then updates are allowed. - if (this.arePrimarySpeciesDetailsSet && fps.forwardControlVariables.getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) != 1) { + if (this.arePrimarySpeciesDetailsSet && fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) != 1) { throw new IllegalStateException(PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java new file mode 100644 index 000000000..acdbbf899 --- /dev/null +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -0,0 +1,20 @@ +package ca.bc.gov.nrs.vdyp.forward.controlmap; + +import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.Region; + +public interface ForwardResolvedControlMap extends ResolvedControlMap { + + ForwardDebugSettings getDebugSettings(); + + ForwardControlVariables getForwardControlVariables(); + + BecLookup getBecLookup(); + + MatrixMap2 getSiteCurveMap(); +} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java new file mode 100644 index 000000000..9decaec9f --- /dev/null +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -0,0 +1,52 @@ +package ca.bc.gov.nrs.vdyp.forward.controlmap; + +import java.util.Map; + +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; +import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.DebugSettings; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.Region; + +public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl implements ForwardResolvedControlMap { + + final ForwardDebugSettings debugSettings; + final ForwardControlVariables forwardControlVariables; + final BecLookup becLookup; + final MatrixMap2 siteCurveMap; + + public ForwardResolvedControlMapImpl(Map controlMap) { + + super(controlMap); + + this.debugSettings = new ForwardDebugSettings(get(ControlKey.DEBUG_SWITCHES, DebugSettings.class)); + this.forwardControlVariables = get(ControlKey.VTROL, ForwardControlVariables.class); + this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); + this.siteCurveMap = Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); + } + + @Override + public ForwardDebugSettings getDebugSettings() { + return debugSettings; + } + + @Override + public ForwardControlVariables getForwardControlVariables() { + return forwardControlVariables; + } + + @Override + public BecLookup getBecLookup() { + return becLookup; + } + + @Override + public MatrixMap2 getSiteCurveMap() { + return siteCurveMap; + } +} diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java index beddcb7d8..d16299021 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java @@ -24,9 +24,9 @@ void testOnePolygon() throws IOException, ResourceParseException, ProcessingExce ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - assertThat(fpe.fps.becLookup, notNullValue()); - assertThat(fpe.fps.genusDefinitionMap, notNullValue()); - assertThat(fpe.fps.siteCurveMap, notNullValue()); + assertThat(fpe.fps.fcm.getBecLookup(), notNullValue()); + assertThat(fpe.fps.fcm.getGenusDefinitionMap(), notNullValue()); + assertThat(fpe.fps.fcm.getSiteCurveMap(), notNullValue()); int nPolygonsProcessed = 0; var polygon = forwardDataStreamReader.readNextPolygon(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java index addca791d..eec438527 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java @@ -18,9 +18,9 @@ void test() throws IOException, ResourceParseException, ProcessingException { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - assertThat(fpe.fps.becLookup, notNullValue()); - assertThat(fpe.fps.genusDefinitionMap, notNullValue()); - assertThat(fpe.fps.siteCurveMap, notNullValue()); + assertThat(fpe.fps.fcm.getBecLookup(), notNullValue()); + assertThat(fpe.fps.fcm.getGenusDefinitionMap(), notNullValue()); + assertThat(fpe.fps.fcm.getSiteCurveMap(), notNullValue()); // Fetch the next polygon to process. int nPolygonsProcessed = 0; diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index ce20cd687..90780cc6d 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -42,9 +42,9 @@ void test() throws IOException, ResourceParseException, ProcessingException { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - assertThat(fpe.fps.becLookup, notNullValue()); - assertThat(fpe.fps.genusDefinitionMap, notNullValue()); - assertThat(fpe.fps.siteCurveMap, notNullValue()); + assertThat(fpe.fps.fcm.getBecLookup(), notNullValue()); + assertThat(fpe.fps.fcm.getGenusDefinitionMap(), notNullValue()); + assertThat(fpe.fps.fcm.getSiteCurveMap(), notNullValue()); int nPolygonsProcessed = 0; while (true) { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java index 39f1870d6..62dfbb2ee 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -62,17 +62,17 @@ void beforeTest() throws IOException, ResourceParseException { @Test void testNormalCurve() throws ProcessingException { - ForwardProcessingState fps = new ForwardProcessingState(controlMap); + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); // Select the first polygon - 01002 S000001 00(1970) - fps.setPolygon(forwardDataStreamReader.readNextPolygon().orElseThrow()); + fpe.fps.setPolygon(forwardDataStreamReader.readNextPolygon().orElseThrow()); float hd = 35.2999992f; int sc = 13; float si = 35; float ytbh = 1.0f; - float gdh = ForwardProcessingEngine.growDominantHeight(fps, hd, sc, si, ytbh); + float gdh = fpe.growDominantHeight(hd, sc, si, ytbh); assertThat(gdh, is(0.173380271f)); } @@ -80,21 +80,22 @@ void testNormalCurve() throws ProcessingException { @Test void testCurveExtension1() throws ProcessingException { + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + // Select polygon 01003AS000001 00(1953) - triggers curve extension code VdypPolygon polygon; do { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); } while (! polygon.getDescription().getName().equals("01003AS000001 00")); - ForwardProcessingState fps = new ForwardProcessingState(controlMap); - fps.setPolygon(polygon); + fpe.fps.setPolygon(polygon); float hd = 29.5f; int sc = 11; float si = 14.8000002f; float ytbh = 10.8000002f; - float gdh = ForwardProcessingEngine.growDominantHeight(fps, hd, sc, si, ytbh); + float gdh = fpe.growDominantHeight(hd, sc, si, ytbh); assertThat(gdh, is(0.0f)); } @@ -102,21 +103,22 @@ void testCurveExtension1() throws ProcessingException { @Test void testCurveExtension2() throws ProcessingException { + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + // Select polygon 01003AS000001 00(1953) - triggers curve extension code VdypPolygon polygon; do { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); } while (! polygon.getDescription().getName().equals("01003AS000001 00")); - ForwardProcessingState fps = new ForwardProcessingState(controlMap); - fps.setPolygon(polygon); + fpe.fps.setPolygon(polygon); float hd = 26.5f; int sc = 11; float si = 14.8000002f; float ytbh = 5.8000002f; - float gdh = ForwardProcessingEngine.growDominantHeight(fps, hd, sc, si, ytbh); + float gdh = fpe.growDominantHeight(hd, sc, si, ytbh); assertThat(gdh, is(0.045883115f)); } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index 2b8683df9..21859a0e3 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -19,13 +19,10 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; @@ -34,8 +31,6 @@ class PolygonProcessingStateTest { private ForwardControlParser parser; private Map controlMap; - private StreamingParser polygonDescriptionStream; - @SuppressWarnings({ "unchecked", "rawtypes" }) @BeforeEach void before() throws IOException, ResourceParseException { @@ -48,10 +43,6 @@ void before() throws IOException, ResourceParseException { ControlKey.SP0_DEF, allOf(instanceOf(List.class), hasItem(instanceOf(GenusDefinition.class))) ) ); - - var polygonDescriptionStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_GROWTO.name()); - polygonDescriptionStream = ((StreamingParserFactory) polygonDescriptionStreamFactory) - .get(); } @Test diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index 9d335d712..e6e24f4ef 100644 --- a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.vri; -import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.*; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.quadMeanDiameter; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.treesPerHectare; import java.io.Closeable; import java.io.IOException; @@ -22,6 +23,7 @@ import org.apache.commons.math3.exception.TooManyEvaluationsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.RuntimeProcessingException; import ca.bc.gov.nrs.vdyp.application.RuntimeStandProcessingException; @@ -29,7 +31,7 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods.Limits; +import ca.bc.gov.nrs.vdyp.common.Estimators.Limits; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.SiteIndex2Height; @@ -40,8 +42,6 @@ import ca.bc.gov.nrs.vdyp.io.parse.control.BaseControlParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; -import ca.bc.gov.nrs.vdyp.model.PolygonMode; -import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.BaseVdypSite; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies.Builder; @@ -53,6 +53,8 @@ import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.ModelClassBuilder; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; +import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.VdypLayer; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; @@ -68,8 +70,6 @@ public class VriStart extends VdypStartApplication processPolygon(int polygonsRead, VriPolygon polygon) throw } } + @SuppressWarnings("unused") void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws ProcessingException { var primaryLayer = polygon.getLayers().get(LayerType.PRIMARY); var bec = Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap); @@ -429,7 +430,7 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws var leadHeight = requirePositive(primarySiteIn.getHeight(), "Primary layer lead species height"); // HLPL1 - var primaryHeight = estimationMethods.primaryHeightFromLeadHeight( + var primaryHeight = estimators.primaryHeightFromLeadHeight( leadHeight, primarySiteIn.getSiteGenus(), bec.getRegion(), primarySpeciesDensity ); @@ -450,14 +451,14 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws float loreyHeight = vriSite.getHeight().filter((x) -> getDebugMode(2) == 1).map(height -> { float speciesQuadMeanDiameter = Math.max(7.5f, height / leadHeight * layerQuadMeanDiameter); float speciesDensity = treesPerHectare(primaryBaseArea, layerQuadMeanDiameter); - float speciesLoreyHeight = estimationMethods.primaryHeightFromLeadHeight( + float speciesLoreyHeight = estimators.primaryHeightFromLeadHeight( vriSite.getHeight().get(), vriSite.getSiteGenus(), bec.getRegion(), speciesDensity ); return 0f; }).orElseGet(() -> { try { - return estimationMethods.estimateNonPrimaryLoreyHeight( + return estimators.estimateNonPrimaryLoreyHeight( vriSite.getSiteGenus(), primarySiteIn.getSiteGenus(), bec, leadHeight, primaryHeight ); } catch (ProcessingException e) { @@ -465,7 +466,7 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws } }); - float maxHeight = estimationMethods.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) + float maxHeight = estimators.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) .maxLoreyHeight(); loreyHeight = Math.min(loreyHeight, maxHeight); sBuilder.height(loreyHeight); @@ -557,7 +558,7 @@ void getDqBySpeciesInitial( Map minPerSpecies, Map maxPerSpecies ) throws ProcessingException { for (var spec : layer.getSpecies().values()) { - float specDq = estimationMethods.estimateQuadMeanDiameterForSpecies( + float specDq = estimators.estimateQuadMeanDiameterForSpecies( spec, layer.getSpecies(), region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, loreyHeightTotal ); @@ -585,7 +586,7 @@ protected Limits getLimitsForSpecies(VdypSpecies spec, Region region) { // TODO for JPROGRAM = 7 implement this differently, see ROOTV01 L91-L99 // EMP061 - return estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), region); + return estimators.getLimitsForHeightAndDiameter(spec.getGenus(), region); } float quadMeanDiameterFractionalError( @@ -612,6 +613,7 @@ float quadMeanDiameterSpeciesAdjust(float x, float initialDq, float min, float m } private void processVeteranLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws StandProcessingException { + @SuppressWarnings("unused") var veteranLayer = polygon.getLayers().get(LayerType.VETERAN); // TODO @@ -622,7 +624,7 @@ PolygonMode checkPolygon(VriPolygon polygon) throws ProcessingException { BecDefinition bec = Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap); - var primaryLayer = requireLayer(polygon, LayerType.PRIMARY); + requireLayer(polygon, LayerType.PRIMARY); // At this point the Fortran implementation nulled the BA and TPH of Primary // layers if the BA and TPH were present and resulted in a DQ <7.5 @@ -771,23 +773,6 @@ void validateMinimum(String fieldName, Optional value, float minimum, boo ); } - // UPPERGEN Method 1 - Coefficients upperBounds(int baseAreaGroup) { - var upperBoundsMap = Utils - .>expectParsedControl(controlMap, ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); - return Utils.optSafe(upperBoundsMap.get(baseAreaGroup)).orElseThrow( - () -> new IllegalStateException("Could not find limits for base area group " + baseAreaGroup) - ); - } - - float upperBoundsBaseArea(int baseAreaGroup) { - return upperBounds(baseAreaGroup).getCoe(1); - } - - float upperBoundsQuadMeanDiameter(int baseAreaGroup) { - return upperBounds(baseAreaGroup).getCoe(2); - } - // EMP106 float estimateBaseAreaYield( float dominantHeight, float breastHeightAge, Optional baseAreaOverstory, boolean fullOccupancy, @@ -795,49 +780,7 @@ float estimateBaseAreaYield( ) throws StandProcessingException { var coe = estimateBaseAreaYieldCoefficients(species, bec); - float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); - - /* - * The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea - * (BATOP98). I have included them here. - */ - - /* - * And one POSSIBLY one last vestage of grouping by ITG That limit applies to full occupancy and Empirical - * occupancy. They were derived as the 98th percentile of Empirical stocking, though adjusted PSP's were - * included. If the ouput of this routine is bumped up from empirical to full, MIGHT adjust this limit DOWN - * here, so that at end, it is correct. Tentatively decide NOT to do this. - */ - - // if (fullOccupancy) - // upperBoundsBaseArea *= EMPOC; - - float ageToUse = breastHeightAge; - - // TODO getDebugMode(2)==1 - - if (ageToUse <= 0f) { - throw new StandProcessingException("Age was not positive"); - } - - float trAge = FloatMath.log(ageToUse); - - float a00 = Math.max(coe.getCoe(0) + coe.getCoe(1) * trAge, 0f); - float ap = Math.max(coe.getCoe(3) + coe.getCoe(4) * trAge, 0f); - - float bap; - if (dominantHeight <= coe.getCoe(2)) { - bap = 0f; - } else { - bap = a00 * FloatMath.pow(dominantHeight - coe.getCoe(2), ap) - * FloatMath.exp(coe.getCoe(5) * dominantHeight + coe.getCoe(6) * baseAreaOverstory.orElse(0f)); - bap = Math.min(bap, upperBoundBaseArea); - } - - if (fullOccupancy) - bap /= EMPOC; - - return bap; + return estimators.estimateBaseAreaYield(coe, dominantHeight, breastHeightAge, baseAreaOverstory, fullOccupancy, bec, baseAreaGroup); } Coefficients estimateBaseAreaYieldCoefficients(Collection species, BecDefinition bec) { @@ -883,23 +826,7 @@ float estimateQuadMeanDiameterYield( ) throws StandProcessingException { final var coe = sumCoefficientsWeightedBySpeciesAndDecayBec(species, bec, ControlKey.DQ_YIELD, 6); - // TODO handle getDebugMode(2) case - final float ageUse = breastHeightAge; - - final float upperBoundsQuadMeanDiameter = upperBoundsQuadMeanDiameter(baseAreaGroup); - - if (ageUse <= 0f) { - throw new StandProcessingException("Primary breast height age must be positive but was " + ageUse); - } - - final float trAge = FloatMath.log(ageUse); - - final float c0 = coe.getCoe(0); - final float c1 = Math.max(coe.getCoe(1) + coe.getCoe(2) * trAge, 0f); - final float c2 = Math.max(coe.getCoe(3) + coe.getCoe(4) * trAge, 0f); - - return FloatMath.clamp(c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2), 7.6f, upperBoundsQuadMeanDiameter); - + return estimators.estimateQuadMeanDiameterYield(coe, dominantHeight, breastHeightAge, veteranBaseArea, bec, baseAreaGroup); } PolygonMode findDefaultPolygonMode( @@ -1356,7 +1283,7 @@ float findRootForQuadMeanDiameterFractionalError( if (tol > 0.0 && Math.abs(lastFs[0]) < tol / 2) { - double f = errorFunc.value(lastXes[0]); + errorFunc.value(lastXes[0]); if (Math.abs(lastFs[0]) < tol) { // Decide if we want to propagate the exception or try to use the last result. @@ -1437,7 +1364,6 @@ public static record Interval(double start, double end) { Interval evaluate(UnivariateFunction func) { return new Interval(func.value(start()), func.value(end())); } - } /** diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java b/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java index a5c41cc20..e7906bfa7 100644 --- a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java +++ b/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java @@ -768,93 +768,88 @@ resultPerSpecies, allOf( @Nested class ExpandIntervalOfRootFinder { @Test - void testNoChange() throws StandProcessingException { + void testNoChange() throws StandProcessingException, IOException { UnivariateFunction errorFunc = x -> x; var xInterval = new VriStart.Interval(-1, 1); - VriStart app = new VriStart(); - - var result = app.findInterval(xInterval, errorFunc); - - assertThat(result, equalTo(xInterval)); - + try (var app = new VriStart()) { + var result = app.findInterval(xInterval, errorFunc); + + assertThat(result, equalTo(xInterval)); + } } @Test - void testSimpleChange() throws StandProcessingException { + void testSimpleChange() throws StandProcessingException, IOException { UnivariateFunction errorFunc = x -> x; var xInterval = new VriStart.Interval(-2, -1); - VriStart app = new VriStart(); - - var result = app.findInterval(xInterval, errorFunc); - - var evaluated = result.evaluate(errorFunc); - assertTrue( - evaluated.start() * evaluated.end() <= 0, - () -> "F(" + result + ") should have mixed signs but was " + evaluated - ); - + try (VriStart app = new VriStart()) { + + var result = app.findInterval(xInterval, errorFunc); + + var evaluated = result.evaluate(errorFunc); + assertTrue( + evaluated.start() * evaluated.end() <= 0, + () -> "F(" + result + ") should have mixed signs but was " + evaluated + ); + } } @ParameterizedTest @CsvSource({ "1, 1", "-1, 1", "1, -1", "-1, -1" }) - void testDifficultChange(float a, float b) throws StandProcessingException { + void testDifficultChange(float a, float b) throws StandProcessingException, IOException { UnivariateFunction errorFunc = x -> a * (Math.exp(b * x) - 0.000001); var xInterval = new VriStart.Interval(-1, 1); - VriStart app = new VriStart(); - - var result = app.findInterval(xInterval, errorFunc); - - var evaluated = result.evaluate(errorFunc); - assertTrue( - evaluated.start() * evaluated.end() <= 0, - () -> "F(" + result + ") should have mixed signs but was " + evaluated - ); - + try (VriStart app = new VriStart()) { + var result = app.findInterval(xInterval, errorFunc); + + var evaluated = result.evaluate(errorFunc); + assertTrue( + evaluated.start() * evaluated.end() <= 0, + () -> "F(" + result + ") should have mixed signs but was " + evaluated + ); + } } @ParameterizedTest @ValueSource(floats = { 1, -1, 20, -20 }) - void testTwoRoots(float a) throws StandProcessingException { + void testTwoRoots(float a) throws StandProcessingException, IOException { UnivariateFunction errorFunc = x -> a * (x * x - 0.5); var xInterval = new VriStart.Interval(-1, 1); - VriStart app = new VriStart(); - - var result = app.findInterval(xInterval, errorFunc); - - var evaluated = result.evaluate(errorFunc); - assertTrue( - evaluated.start() * evaluated.end() <= 0, - () -> "F(" + result + ") should have mixed signs but was " + evaluated - ); - + try (VriStart app = new VriStart()) { + var result = app.findInterval(xInterval, errorFunc); + + var evaluated = result.evaluate(errorFunc); + assertTrue( + evaluated.start() * evaluated.end() <= 0, + () -> "F(" + result + ") should have mixed signs but was " + evaluated + ); + } } @ParameterizedTest @CsvSource({ "1, 1", "-1, 1", "1, -1", "-1, -1" }) - void testImpossible(float a, float b) throws StandProcessingException { + void testImpossible(float a, float b) throws StandProcessingException, IOException { UnivariateFunction errorFunc = x -> a * (Math.exp(b * x) + 1); var xInterval = new VriStart.Interval(-1, 1); - VriStart app = new VriStart(); - - var ex = assertThrows(NoBracketingException.class, () -> app.findInterval(xInterval, errorFunc)); - + try (VriStart app = new VriStart()) { + assertThrows(NoBracketingException.class, () -> app.findInterval(xInterval, errorFunc)); + } } - } @Nested @@ -1639,79 +1634,78 @@ void testDontSkip(PolygonMode mode) throws Exception { var control = EasyMock.createControl(); - VriStart app = EasyMock.createMockBuilder(VriStart.class) // + try (VriStart app = EasyMock.createMockBuilder(VriStart.class) // .addMockedMethod("processYoung") // .addMockedMethod("processBatc") // .addMockedMethod("processBatn") // .addMockedMethod("checkPolygon") // .addMockedMethod("processPrimaryLayer") // .addMockedMethod("getDebugMode") // - .createMock(control); - - MockFileResolver resolver = dummyInput(); - - var poly = VriPolygon.build(pb -> { - pb.polygonIdentifier("TestPoly", 2024); - pb.biogeoclimaticZone("IDF"); - pb.yieldFactor(1.0f); - pb.mode(mode); - pb.addLayer(lb -> { - lb.layerType(LayerType.PRIMARY); - lb.crownClosure(80f); - lb.utilization(0.6f); - }); - }); - - var polyYoung = VriPolygon.build(pb -> { - pb.polygonIdentifier("TestPolyYoung", 2024); - pb.biogeoclimaticZone("IDF"); - pb.yieldFactor(1.0f); - pb.mode(mode); - pb.addLayer(lb -> { - lb.layerType(LayerType.PRIMARY); - lb.crownClosure(80f); - lb.utilization(0.6f); - }); - }); - var polyBatc = VriPolygon.build(pb -> { - pb.polygonIdentifier("TestPolyBatc", 2024); - pb.biogeoclimaticZone("IDF"); - pb.yieldFactor(1.0f); - pb.mode(mode); - pb.addLayer(lb -> { - lb.layerType(LayerType.PRIMARY); - lb.crownClosure(80f); - lb.utilization(0.6f); - }); - }); - var polyBatn = VriPolygon.build(pb -> { - pb.polygonIdentifier("TestPolyBatn", 2024); - pb.biogeoclimaticZone("IDF"); - pb.yieldFactor(1.0f); - pb.mode(mode); - pb.addLayer(lb -> { - lb.layerType(LayerType.PRIMARY); - lb.crownClosure(80f); - lb.utilization(0.6f); - }); - }); - - EasyMock.expect(app.checkPolygon(poly)).andReturn(mode).once(); - EasyMock.expect(app.processYoung(poly)).andReturn(polyYoung).times(0, 1); - EasyMock.expect(app.processBatc(poly)).andReturn(polyBatc).times(0, 1); - EasyMock.expect(app.processBatn(poly)).andReturn(polyBatn).times(0, 1); - app.processPrimaryLayer(EasyMock.anyObject(VriPolygon.class), EasyMock.anyObject(VdypLayer.Builder.class)); - EasyMock.expectLastCall().once(); - EasyMock.expect(app.getDebugMode(9)).andStubReturn(0); - EasyMock.expect(app.getDebugMode(1)).andStubReturn(0); - - control.replay(); - - app.init(resolver, controlMap); - - var result = app.processPolygon(0, poly); - - app.close(); + .createMock(control)) { + + MockFileResolver resolver = dummyInput(); + + var poly = VriPolygon.build(pb -> { + pb.polygonIdentifier("TestPoly", 2024); + pb.biogeoclimaticZone("IDF"); + pb.yieldFactor(1.0f); + pb.mode(mode); + pb.addLayer(lb -> { + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(80f); + lb.utilization(0.6f); + }); + }); + + var polyYoung = VriPolygon.build(pb -> { + pb.polygonIdentifier("TestPolyYoung", 2024); + pb.biogeoclimaticZone("IDF"); + pb.yieldFactor(1.0f); + pb.mode(mode); + pb.addLayer(lb -> { + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(80f); + lb.utilization(0.6f); + }); + }); + var polyBatc = VriPolygon.build(pb -> { + pb.polygonIdentifier("TestPolyBatc", 2024); + pb.biogeoclimaticZone("IDF"); + pb.yieldFactor(1.0f); + pb.mode(mode); + pb.addLayer(lb -> { + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(80f); + lb.utilization(0.6f); + }); + }); + var polyBatn = VriPolygon.build(pb -> { + pb.polygonIdentifier("TestPolyBatn", 2024); + pb.biogeoclimaticZone("IDF"); + pb.yieldFactor(1.0f); + pb.mode(mode); + pb.addLayer(lb -> { + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(80f); + lb.utilization(0.6f); + }); + }); + + EasyMock.expect(app.checkPolygon(poly)).andReturn(mode).once(); + EasyMock.expect(app.processYoung(poly)).andReturn(polyYoung).times(0, 1); + EasyMock.expect(app.processBatc(poly)).andReturn(polyBatc).times(0, 1); + EasyMock.expect(app.processBatn(poly)).andReturn(polyBatn).times(0, 1); + app.processPrimaryLayer(EasyMock.anyObject(VriPolygon.class), EasyMock.anyObject(VdypLayer.Builder.class)); + EasyMock.expectLastCall().once(); + EasyMock.expect(app.getDebugMode(9)).andStubReturn(0); + EasyMock.expect(app.getDebugMode(1)).andStubReturn(0); + + control.replay(); + + app.init(resolver, controlMap); + + app.processPolygon(0, poly); + } control.verify(); } @@ -1859,6 +1853,7 @@ void testProcessIgnored() throws Exception { control.verify(); } + @SuppressWarnings("unused") @Test void testStandExceptionProcessingPrimaryLayer() throws Exception { @@ -1932,7 +1927,7 @@ void testStandExceptionProcessingPrimaryLayer() throws Exception { app.init(resolver, controlMap); - var ex = assertThrows(StandProcessingException.class, () -> app.processPolygon(0, poly)); + assertThrows(StandProcessingException.class, () -> app.processPolygon(0, poly)); app.close(); From b9a9326c175c0653de773f5a7ea402149fbb4e72 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 9 Jul 2024 10:34:23 -0700 Subject: [PATCH 10/66] Pushed this.compVarAdjustments down to ForwardResolvedControlMapImpl, since only in Forward control map. --- .../vdyp/controlmap/CachingResolvedControlMapImpl.java | 8 -------- .../forward/controlmap/ForwardResolvedControlMapImpl.java | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index ff3aaadde..35c087bff 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -37,8 +37,6 @@ public class CachingResolvedControlMapImpl extends ResolvedControlMapImpl implem final MatrixMap2 defaultEquationGroup; final MatrixMap2> equationModifierGroup; final MatrixMap2 hl1Coefficients; - final CompVarAdjustments compVarAdjustments; - public CachingResolvedControlMapImpl(Map controlMap) { super(controlMap); @@ -63,7 +61,6 @@ public CachingResolvedControlMapImpl(Map controlMap) { this.maximumAgeBySiteCurveNumber = this.get(ControlKey.SITE_CURVE_AGE_MAX, Map.class); this.defaultEquationGroup = this.get(ControlKey.DEFAULT_EQ_NUM, MatrixMap2.class); this.hl1Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); - this.compVarAdjustments = this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); this.upperBounds = this.get(ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); this.equationModifierGroup = this.get(ControlKey.EQN_MODIFIERS, MatrixMap2.class); } @@ -167,9 +164,4 @@ public MatrixMap2> getEquationModifierGroup( public MatrixMap2 getHl1Coefficients() { return hl1Coefficients; } - - @Override - public CompVarAdjustments getCompVarAdjustments() { - return compVarAdjustments; - } } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index 9decaec9f..0a6d11c65 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -9,6 +9,7 @@ import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.DebugSettings; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -19,6 +20,7 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl final ForwardControlVariables forwardControlVariables; final BecLookup becLookup; final MatrixMap2 siteCurveMap; + final CompVarAdjustments compVarAdjustments; public ForwardResolvedControlMapImpl(Map controlMap) { @@ -28,6 +30,7 @@ public ForwardResolvedControlMapImpl(Map controlMap) { this.forwardControlVariables = get(ControlKey.VTROL, ForwardControlVariables.class); this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); this.siteCurveMap = Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); + this.compVarAdjustments = this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); } @Override @@ -49,4 +52,9 @@ public BecLookup getBecLookup() { public MatrixMap2 getSiteCurveMap() { return siteCurveMap; } + + @Override + public CompVarAdjustments getCompVarAdjustments() { + return compVarAdjustments; + } } From 6bbbc6fbe3f80d96757877b4aac31047fac32981 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 9 Jul 2024 13:55:35 -0700 Subject: [PATCH 11/66] Refer now to common EMPIRICAL_OCCUPANCY --- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 4 +- .../vdyp/forward/ForwardProcessingEngine.java | 39 ++++++++++++------- .../controlmap/ForwardResolvedControlMap.java | 12 ++++-- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index b99d6159e..9e9995aa3 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -37,11 +37,11 @@ public class Estimators { public static final Logger log = LoggerFactory.getLogger(Estimators.class); + public static final float EMPIRICAL_OCCUPANCY = 0.85f; + private static final int UTIL_ALL = UtilizationClass.ALL.index; private static final int UTIL_LARGEST = UtilizationClass.OVER225.index; - private static final float EMPIRICAL_OCCUPANCY = 0.85f; - /** * Returns the new value if the index is that of a utilization class that represents a size band, otherwise the old * value diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index a44e74cfd..9c12a9038 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.application.StandProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; @@ -196,6 +197,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro setCompatibilityVariables(pps); } + // VGROW1 if (lastStep.ordinal() >= ExecutionStep.GROW.ordinal()) { int veteranLayerInstance = 0; @@ -273,11 +275,11 @@ private void grow( // Calculate change in basal area - final float veteranLayerBasalArea; + final Optional veteranLayerBasalArea; if (veteranBank.isPresent()) - veteranLayerBasalArea = veteranBank.get().basalAreas[0][UC_ALL_INDEX]; + veteranLayerBasalArea = Optional.of(veteranBank.get().basalAreas[0][UC_ALL_INDEX]); else { - veteranLayerBasalArea = 0.0f; + veteranLayerBasalArea = Optional.empty(); } float[] speciesProportionByBasalArea = new float[pps.getNSpecies() + 1]; @@ -287,34 +289,42 @@ private void grow( } float growthInBasalArea = growBasalArea( - fps, yearsAtBreastHeight, dominantHeight, primaryBank.basalAreas[0][UC_ALL_INDEX], veteranLayerBasalArea, growthInDominantHeight + speciesProportionByBasalArea, yearsAtBreastHeight, dominantHeight, primaryBank.basalAreas[0][UC_ALL_INDEX], veteranLayerBasalArea, growthInDominantHeight ); } - private static final float EMPIRICAL_OCCUPANCY = 0.85f; - /** * EMP111A - Basal area growth for the primary layer. - * - * @param fps current processing state + * @param speciesProportionByBasalArea the proportion by basal area of each of the polygon's species * @param yearsAtBreastHeight at the start of the year * @param dominantHeight primary species dominant height at start of year * @param primaryLayerBasalArea at the start of the year * @param veteranLayerBasalArea at the start of the year * @param growthInDominantHeight during the year + * * @return the growth in the basal area for the year + * @throws StandProcessingException */ private float growBasalArea( - ForwardProcessingState fps, float yearsAtBreastHeight, float dominantHeight, float primaryLayerBasalArea, - float veteranLayerBasalArea, float growthInDominantHeight - ) { + float[] speciesProportionByBasalArea, float yearsAtBreastHeight, float dominantHeight, float primaryLayerBasalArea, + Optional veteranLayerBasalArea, float growthInDominantHeight + ) throws StandProcessingException { + // UPPERGEN( 1, BATOP98, DQTOP98) var baUpperBound = growBasalAreaUpperBound(); var dqUpperBound = growQuadraticMeanDiameterUpperBound(); - baUpperBound = baUpperBound / EMPIRICAL_OCCUPANCY; + baUpperBound = baUpperBound / Estimators.EMPIRICAL_OCCUPANCY; var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); - return 0; + + var baYield = fps.fcm + + boolean isFullOccupancy = true; + int primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + float basalAreaYield = estimators.estimateBaseAreaYield(null, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, + isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber); + + return basalAreaYield; } /** @@ -866,8 +876,7 @@ private float conditionalExpectedBaseArea( } // EMP082 - private float - smallComponentQuadMeanDiameter(String speciesName, float loreyHeight) { + private float smallComponentQuadMeanDiameter(String speciesName, float loreyHeight) { Coefficients coe = fps.fcm.getSmallComponentQuadMeanDiameterCoefficients().get(speciesName); // EQN 5 in IPSJF118.doc diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index acdbbf899..106a6005d 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -10,11 +10,15 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { - ForwardDebugSettings getDebugSettings(); - - ForwardControlVariables getForwardControlVariables(); - + /** 9 */ BecLookup getBecLookup(); + /** 25 */ MatrixMap2 getSiteCurveMap(); + + /** 101 */ + ForwardControlVariables getForwardControlVariables(); + + /** 199 */ + ForwardDebugSettings getDebugSettings(); } From ca247945c158442c9df98dfdfb0f1546471649b9 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 9 Jul 2024 13:58:31 -0700 Subject: [PATCH 12/66] Removing python tools from this branch - now on feature/python-tools --- vdyp-tools/src/browse_usages.py | 60 -------- vdyp-tools/src/call_tree.py | 195 -------------------------- vdyp-tools/src/commons.py | 195 -------------------------- vdyp-tools/src/util.py | 19 --- vdyp-tools/src/vdyp-browse-usages.bat | 1 - vdyp-tools/src/vdyp-call-tree.bat | 1 - vdyp-tools/src/vdyp-commons.bat | 1 - 7 files changed, 472 deletions(-) delete mode 100644 vdyp-tools/src/browse_usages.py delete mode 100644 vdyp-tools/src/call_tree.py delete mode 100644 vdyp-tools/src/commons.py delete mode 100644 vdyp-tools/src/util.py delete mode 100644 vdyp-tools/src/vdyp-browse-usages.bat delete mode 100644 vdyp-tools/src/vdyp-call-tree.bat delete mode 100644 vdyp-tools/src/vdyp-commons.bat diff --git a/vdyp-tools/src/browse_usages.py b/vdyp-tools/src/browse_usages.py deleted file mode 100644 index ef8b9c287..000000000 --- a/vdyp-tools/src/browse_usages.py +++ /dev/null @@ -1,60 +0,0 @@ -import os -import sys -import re -import util - -keywords = ['INTEGER', 'REAL', 'CHARACTER', 'LOGICAL', 'DIMENSION'] - - -def browse_usages(block_name, member_name): - - print('searching for usages of block ' + block_name + ' and member ' + member_name) - - source_files = util.collect_source_files() - - common_re = re.compile(r'^\s+COMMON.*/\s*' + block_name + r'\s*/') - keyword_re = re.compile(r'^\s+([A-Z]+)(\*[0-9]+|\s)') - assignment_re = re.compile(r'[^A-Z0-9_]' + member_name.upper() + r'([^A-Z0-9_].*=|=)') - usage_re = re.compile(r'[^A-Z0-9_]' + member_name.upper() + r'[^A-Z0-9_]') - - for s in source_files: - sf = open(s) - block_declarations = [] - usages = [] - assignments = [] - for line in sf.readlines(): - line = line.upper() - if line[0] == 'C' or line[0] == '#': - continue - if common_re.search(line): - block_declarations.append(line) - else: - m = re.search(keyword_re, line) - if m is not None and m.group(1) in keywords: - pass - elif assignment_re.search(line): - assignments.append(line) - elif line.strip().startswith('&'): - pass - elif usage_re.search(line): - usages.append(line) - - if len(block_declarations) > 0 and (len(assignments) > 0 or len(usages) > 0): - print(s.name) - if len(assignments) > 0: - for l in assignments: - print(' A ' + l.strip()) - if len(usages) > 0: - for l in usages: - print(' U ' + l.strip()) - - sf.close() - - -if __name__ == '__main__': - - if len(sys.argv) != 3: - print('usage: browse_usages ') - sys.exit(0) - - browse_usages(sys.argv[1], sys.argv[2]) diff --git a/vdyp-tools/src/call_tree.py b/vdyp-tools/src/call_tree.py deleted file mode 100644 index f2a7cb8ed..000000000 --- a/vdyp-tools/src/call_tree.py +++ /dev/null @@ -1,195 +0,0 @@ -import os -import sys -import re -import commons -import argparse -import util - -subroutine_declaration_re = re.compile(r'^\s+SUBROUTINE\s+([A-Z][A-Z0-9_]*)\s*\(') -end_subroutine_declaration_re = re.compile(r'^\s+END SUBROUTINE') -token_re = re.compile(r'CALL\s+([A-Z][A-Z0-9_]*)') - -subroutines = {} - - -def collect_symbols(source_files): - - for s in source_files: - commons_details = commons.gather_commons_details(s) - sf = open(s) - for line in sf.readlines(): - line = line.upper() - if line[0] == 'C': - continue - m = re.search(subroutine_declaration_re, line) - if m is not None: - routine_name = m.group(1) - subroutines[routine_name] = { - "name": routine_name, - "file": s, - "has_been_traversed": False, - "commons_usages": commons.gather_commons_usages(s, commons_details, routine_name), - "callees": set() - } - - sf.close() - - -def generate_call_tree(routines_to_scan): - if len(routines_to_scan) == 0: - return - - routine_name = routines_to_scan.pop() - - if subroutines[routine_name]["has_been_traversed"]: - # already scanned - return - - subroutine = subroutines[routine_name] - - subroutine["has_been_traversed"] = True - - file = subroutine["file"] - sf = open(file) - - in_routine = False - for line in sf.readlines(): - line = line.upper() - if len(line.strip()) == 0 or line[0] == 'C' or line[0] == '#': - continue - m = re.search(subroutine_declaration_re, line) - if m is not None and m.group(1) == routine_name: - in_routine = True - else: - m = re.search(end_subroutine_declaration_re, line) - if m is not None: - in_routine = False - elif in_routine: - # tokenize the line, looking for nested calls - m = re.search(token_re, line) - while m is not None: - token = m.group(1) - if token in subroutines: - subroutine["callees"].add(token) - if not subroutines[token]["has_been_traversed"]: - routines_to_scan.append(token) - line = line[m.end():] - m = re.search(token_re, line) - - -ignored_commons = {'UNITS', 'UNITS3', 'UNITS4', 'LIBCOMMON'} - - -def uses_only_ignored_commons(commons_usages, args): - for a in commons_usages["block_assignments"]: - if a not in ignored_commons: - return False - if not args.assignments_only: - for u in commons_usages["block_usages"]: - if u not in ignored_commons: - return False - - return True - - -def has_commons_usages(subroutine, args): - for callee in subroutine["callees"]: - if has_commons_usages(subroutines[callee], args): - return True - commons_usages = subroutine["commons_usages"] - if uses_only_ignored_commons(commons_usages, args): - return False - return True - - -def print_call_tree(subroutine, args, indent): - name = subroutine["name"] - commons_usages = subroutine["commons_usages"] - - if args.exclude_no_commons_usages and not has_commons_usages(subroutine, args): - return - - assignments = "" - assignments_per_block = {} - for c in commons_usages["block_assignments"]: - if c not in ignored_commons: - assignments_per_block[c] = [] - for m in commons_usages["member_assignments"]: - c = m[0:m.find('.')] - if c not in ignored_commons: - assignments_per_block[c].append(m[len(c) + 1:]) - for c in assignments_per_block.keys(): - assignments += c + '(' - if not args.blocks_only: - for m in assignments_per_block[c]: - assignments += m + ', ' - assignments = assignments[0:len(assignments) - 2] - assignments += '), ' - assignments = ' assignments: ' + assignments[0:len(assignments) - 2] if len(assignments) > 0 else '' - - usages = "" - if not args.assignments_only: - usages_per_block = {} - for c in commons_usages["block_usages"]: - if c not in ignored_commons: - usages_per_block[c] = [] - for m in commons_usages["member_usages"]: - c = m[0:m.find('.')] - if c not in ignored_commons: - usages_per_block[c].append(m[len(c) + 1:]) - for c in usages_per_block.keys(): - usages += c + '(' - if not args.blocks_only: - for m in usages_per_block[c]: - usages += m + ', ' - usages = usages[0:len(usages) - 2] - usages += '), ' - usages = ' usages: ' + usages[0:len(usages) - 2] if len(usages) > 0 else '' - - if len(assignments) > 60 or len(usages) > 60 or len(assignments + usages) > 90: - print((' ' * indent if indent > 0 else '') + name) - if len(assignments) > 0: - print((' ' * (indent + 7)) + assignments) - if len(usages) > 0: - print((' ' * (indent + 7)) + usages) - else: - print((' ' * indent if indent > 0 else '') + name + assignments + usages) - - for callee in subroutine["callees"]: - print_call_tree(subroutines[callee], args, indent + 4) - - -def call_tree(routine_name, args): - - routine_name = routine_name.upper() - - source_files = util.collect_source_files() - collect_symbols(source_files) - - if routine_name not in subroutines: - print('Subroutine "' + routine_name + '" not found in the source code') - return - - print('Listing call tree rooted at ' + routine_name) - - routines_to_scan = [routine_name] - - while len(routines_to_scan) > 0: - generate_call_tree(routines_to_scan) - - print_call_tree(subroutines[routine_name], args, 0) - - -if __name__ == '__main__': - - parser = argparse.ArgumentParser('Lists the call tree rooted at the given subroutine name' - ' and, for each method, common block usage') - parser.add_argument('-b', '--blocks-only', action='store_true', help='display block level information only') - parser.add_argument('-a', '--assignments-only', action='store_true', help='display assignment information only') - parser.add_argument('-x', '--exclude-no-commons-usages', action='store_true' - , help="exclude from call tree subroutines whose call tree doesn't use commons") - parser.add_argument('subroutine_name', nargs=1) - - params = parser.parse_args(sys.argv[1:]) - - call_tree(params.subroutine_name[0], params) diff --git a/vdyp-tools/src/commons.py b/vdyp-tools/src/commons.py deleted file mode 100644 index ad25af1d5..000000000 --- a/vdyp-tools/src/commons.py +++ /dev/null @@ -1,195 +0,0 @@ -import os -import sys -import re - -declaration_keywords = ['INTEGER', 'REAL', 'CHARACTER', 'LOGICAL', 'DIMENSION'] -common_re = re.compile(r'^\s*COMMON.*/\s*([A-Z][A-Z0-9_]*)\s*/(.*)') -declaration_re = re.compile(r"^\s*([A-Z]+)(\*[0-9]+|\s)") -member_name_re = re.compile(r'(^\s*[A-Z][A-Z0-9_]*)(\([^)]+\))?\s*(,|$)') -subroutine_declaration_re = re.compile(r'^\s+SUBROUTINE\s+([A-Z][A-Z0-9_]*)\s*\(') -end_subroutine_declaration_re = re.compile(r'^\s+END SUBROUTINE') -token_re = re.compile(r'([A-Z][A-Z0-9_]*)') - - -def find_file(file_name): - - file_name = file_name.lower() - if not file_name.endswith('.for'): - file_name = file_name + '.for' - - folders = ['C:/source/vdyp/VDYP_Master/Source'] - source_file = None - while source_file is None and len(folders) > 0: - current_directory = folders.pop() - entities = os.scandir(current_directory) - for e in entities: - if e.is_dir(): - folders.append(e) - elif e.is_file(): - if e.name == file_name: - return e - - -def gather_commons_details(file): - - commons_details = { - "block_members": [], - "member_block": {}, - "common_blocks": {} - } - - sf = open(file) - common_block_name = None - for line in sf.readlines(): - line = line.upper() - lstripped_line = line.lstrip() - if len(lstripped_line) == 0 or line[0] == 'C' or line[0] == '#': - continue - is_continuation_line = lstripped_line.startswith('&') - - m = common_re.search(line) - members = None - if m is not None: - common_block_name = m.group(1) - commons_details["common_blocks"][common_block_name] = [] - members = find_members(m.group(2)) - elif is_continuation_line and common_block_name is not None: - members = find_members(lstripped_line[1:]) - else: - common_block_name = None - - if members is not None: - commons_details["common_blocks"][common_block_name].extend(members) - commons_details["block_members"].extend(members) - for m in members: - commons_details["member_block"][m] = common_block_name - - sf.close() - - return commons_details - - -def gather_commons_usages(file_name, commons_details, routine_name): - - block_usages = set() - block_assignments = set() - member_usages = set() - member_assignments = set() - - commons_usages = { - "block_usages": block_usages, - "block_assignments": block_assignments, - "member_usages": member_usages, - "member_assignments": member_assignments - } - - in_routine = routine_name is None - in_commons_declaration = False - - sf = open(file_name) - for line in sf.readlines(): - line = line.upper() - lstripped_line = line.lstrip() - if len(lstripped_line) == 0 or line[0] == 'C' or line[0] == '#': - continue - - if not in_routine: - m = re.search(subroutine_declaration_re, line) - if m is not None and m.group(1) == routine_name: - in_routine = True - else: - if in_routine and routine_name is not None: - m = re.search(end_subroutine_declaration_re, line) - if m is not None: - break - - if common_re.search(line) is not None: - in_commons_declaration = True - elif in_commons_declaration and lstripped_line.startswith('&'): - continue - else: - m = re.search(declaration_re, line) - if m is not None and m.group(1) in declaration_keywords: - continue - - if line.find('CALL DBG') >= 0: - continue - - # we're in the routine (if one is specified) and this is not a comment line - # or a commons block declaration. Tokenize the line and look for assignments - # and usages. Also, ignore usages during calls to DBG subroutines. - assignment_seen_this_line = False - - m = re.search(token_re, line) - while m is not None: - token = m.group(1) - line = line[m.end():] - if token in commons_details["member_block"]: - if not assignment_seen_this_line and line.find('=') >= 0: - block_assignments.add(commons_details["member_block"][token]) - member_assignments.add(commons_details["member_block"][token] + '.' + token) - assignment_seen_this_line = True - else: - block_usages.add(commons_details["member_block"][token]) - member_usages.add(commons_details["member_block"][token] + '.' + token) - m = re.search(token_re, line) - sf.close() - - return commons_usages - - -def print_commons_usages(commons_usages): - - block_assignments = commons_usages["block_assignments"] - block_usages = commons_usages["block_usages"] - member_assignments = commons_usages["member_assignments"] - member_usages = commons_usages["member_usages"] - - if len(commons_usages["member_usages"]) == 0 and len(member_assignments) == 0: - print('No usages or assignments of common block variables') - else: - print('Common blocks assigned: ' + str(sorted(block_assignments))) - assignment_list = sorted(member_assignments) - while len(assignment_list) > 0: - print('Assignments: ' + str(assignment_list[0:8])) - assignment_list = assignment_list[8:] - - print('Common blocks used: ' + str(sorted(block_usages))) - usages_list = sorted(member_usages) - while len(usages_list) > 0: - print('Usages: ' + str(usages_list[0:8])) - usages_list = usages_list[8:] - - -def find_members(s): - members = [] - - s = s.strip() - m = re.search(member_name_re, s) - while m is not None: - members.append(m.group(1)) - s = s[m.end():].strip() - m = re.search(member_name_re, s) - - return members - - -def execute(file_name, routine_name): - - print('Listing common usages in ' + file_name) - - file = find_file(file_name) - commons_details = gather_commons_details(file) - commons_usages = gather_commons_usages(file, commons_details, routine_name) - print_commons_usages(commons_usages) - - -if __name__ == '__main__': - - if len(sys.argv) < 2 or len(sys.argv) > 3: - print('usage: list_common_usages []') - print(' where file_name is the plain name of the file, with or without ".for"') - print(' and routine_name (optional) is the name of a subroutine in that file') - sys.exit(0) - - execute(sys.argv[1], sys.argv[2] if len(sys.argv) == 3 else None) diff --git a/vdyp-tools/src/util.py b/vdyp-tools/src/util.py deleted file mode 100644 index a14c911a8..000000000 --- a/vdyp-tools/src/util.py +++ /dev/null @@ -1,19 +0,0 @@ -import os - - -def collect_source_files(): - folders = ['C:/source/vdyp/VDYP_Master/Source'] - source_files = [] - while len(folders) > 0: - current_directory = folders.pop() - entities = os.scandir(current_directory) - for e in entities: - if e.is_dir(): - folders.append(e) - elif e.is_file(): - if e.name.endswith('.for'): - source_files.append(e) - - print('Saw ' + str(len(source_files)) + ' source files') - - return source_files diff --git a/vdyp-tools/src/vdyp-browse-usages.bat b/vdyp-tools/src/vdyp-browse-usages.bat deleted file mode 100644 index cae5b2b8b..000000000 --- a/vdyp-tools/src/vdyp-browse-usages.bat +++ /dev/null @@ -1 +0,0 @@ -C:\Users\mjunkin\AppData\Local\Programs\Python\Python312\python.exe C:\Users\mjunkin\PycharmProjects\vdyp\browse_usages.py %~1 %~2 \ No newline at end of file diff --git a/vdyp-tools/src/vdyp-call-tree.bat b/vdyp-tools/src/vdyp-call-tree.bat deleted file mode 100644 index ce2ebdc3d..000000000 --- a/vdyp-tools/src/vdyp-call-tree.bat +++ /dev/null @@ -1 +0,0 @@ -C:\Users\mjunkin\AppData\Local\Programs\Python\Python312\python.exe C:\Users\mjunkin\PycharmProjects\vdyp\call_tree.py %1 %2 %3 %4 %5 %6 \ No newline at end of file diff --git a/vdyp-tools/src/vdyp-commons.bat b/vdyp-tools/src/vdyp-commons.bat deleted file mode 100644 index dac2c3e6a..000000000 --- a/vdyp-tools/src/vdyp-commons.bat +++ /dev/null @@ -1 +0,0 @@ -C:\Users\mjunkin\AppData\Local\Programs\Python\Python312\python.exe C:\Users\mjunkin\PycharmProjects\vdyp\commons.py %~1 \ No newline at end of file From 03fc6dc6f76739f1812578ca774098f6aac3f206 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 10 Jul 2024 09:07:57 -0700 Subject: [PATCH 13/66] growBasalArea - next steps --- .../CachingResolvedControlMapImpl.java | 11 ++- .../vdyp/controlmap/ResolvedControlMap.java | 91 ++++++++++++------- .../controlmap/ResolvedControlMapImpl.java | 13 ++- .../io/parse/coe/base/GrowthFiatParser.java | 2 +- .../gov/nrs/vdyp/model/GrowthFiatDetails.java | 46 ++++++---- .../parse/BasalAreaGrowthFiatParserTest.java | 11 ++- .../vdyp/io/parse/DqGrowthFiatParserTest.java | 11 ++- .../vdyp/forward/ForwardProcessingEngine.java | 70 +++++++++++++- .../controlmap/ForwardResolvedControlMap.java | 24 +++-- .../ForwardResolvedControlMapImpl.java | 26 ++++-- 10 files changed, 216 insertions(+), 89 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index 35c087bff..e0140a4c5 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -6,9 +6,10 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; +import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; @@ -17,6 +18,7 @@ public class CachingResolvedControlMapImpl extends ResolvedControlMapImpl implements ResolvedControlMap { + final BecLookup becLookup; final GenusDefinitionMap genusDefinitionMap; final Map netDecayWasteCoeMap; final MatrixMap2> netDecayCoeMap; @@ -41,6 +43,8 @@ public CachingResolvedControlMapImpl(Map controlMap) { super(controlMap); + this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); + List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); this.genusDefinitionMap = new GenusDefinitionMap(genusDefinitions); @@ -65,6 +69,11 @@ public CachingResolvedControlMapImpl(Map controlMap) { this.equationModifierGroup = this.get(ControlKey.EQN_MODIFIERS, MatrixMap2.class); } + @Override + public BecLookup getBecLookup() { + return becLookup; + } + @Override public GenusDefinitionMap getGenusDefinitionMap() { return genusDefinitionMap; diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index 73f722a97..72d3ce54f 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -5,8 +5,8 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; @@ -15,45 +15,66 @@ public interface ResolvedControlMap { U get(ControlKey key, Class clazz); + /** 9 - BEC_DEF */ + BecLookup getBecLookup(); + + /** 10 - SP0_DEF */ GenusDefinitionMap getGenusDefinitionMap(); - - Map getNetDecayWasteCoeMap(); - - MatrixMap2> getNetDecayCoeMap(); - - MatrixMap2 getWasteModifierMap(); - - MatrixMap2 getDecayModifierMap(); - - MatrixMap2> getCloseUtilizationCoeMap(); - - Map getTotalStandWholeStepVolumeCoeMap(); - - MatrixMap2> getWholeStemUtilizationComponentMap(); - - MatrixMap3 getQuadMeanDiameterUtilizationComponentMap(); - + + /** 26 - SITE_CURVE_AGE_MAX */ + Map getMaximumAgeBySiteCurveNumber(); + + /** 30 - DEFAULT_EQ_NUM */ + MatrixMap2 getDefaultEquationGroup(); + + /** 31 - EQN_MODIFIERS */ + MatrixMap2> getEquationModifierGroup(); + + /** 50 - HL_PRIMARY_SP_EQN_P1 */ + MatrixMap2 getHl1Coefficients(); + + /** 70 - UTIL_COMP_BA */ MatrixMap3 getBasalAreaDiameterUtilizationComponentMap(); - - Map getSmallComponentWholeStemVolumeCoefficients(); - - Map getSmallComponentLoreyHeightCoefficients(); - - Map getSmallComponentQuadMeanDiameterCoefficients(); - - Map getSmallComponentBasalAreaCoefficients(); - + + /** 71 - UTIL_COMP_DQ */ + MatrixMap3 getQuadMeanDiameterUtilizationComponentMap(); + + /** 80 - SMALL_COMP_PROBABILITY */ Map getSmallComponentProbabilityCoefficients(); + + /** 81 - SMALL_COMP_BA */ + Map getSmallComponentBasalAreaCoefficients(); + + /** 82 - SMALL_COMP_DQ */ + Map getSmallComponentQuadMeanDiameterCoefficients(); + + /** 85 - SMALL_COMP_HL */ + Map getSmallComponentLoreyHeightCoefficients(); + + /** 86 - SMALL_COMP_WS_VOLUME */ + Map getSmallComponentWholeStemVolumeCoefficients(); + + /** 90 - TOTAL_STAND_WHOLE_STEM_VOL*/ + Map getTotalStandWholeStepVolumeCoeMap(); + + /** 91 - UTIL_COMP_WS_VOLUME */ + MatrixMap2> getWholeStemUtilizationComponentMap(); + + /** 92 - CLOSE_UTIL_VOLUME */ + MatrixMap2> getCloseUtilizationCoeMap(); + + /** 93 - VOLUME_NET_DECAY */ + MatrixMap2> getNetDecayCoeMap(); - Map getMaximumAgeBySiteCurveNumber(); - + /** 94 - VOLUME_NET_DECAY_WASTE */ + Map getNetDecayWasteCoeMap(); + + /** 108 - BA_DQ_UPPER_BOUNDS */ Map getUpperBounds(); - MatrixMap2 getDefaultEquationGroup(); - - MatrixMap2> getEquationModifierGroup(); - - MatrixMap2 getHl1Coefficients(); + /** 198 - MODIFIER_FILE */ + MatrixMap2 getWasteModifierMap(); - CompVarAdjustments getCompVarAdjustments(); + /** 198 - MODIFIER_FILE */ + MatrixMap2 getDecayModifierMap(); } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 198a0ecdf..0b8607a98 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -9,8 +9,8 @@ import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; +import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; @@ -46,10 +46,14 @@ public GenusDefinitionMap getGenusDefinitionMap() { return new GenusDefinitionMap(genusDefinitions); } + @Override + public BecLookup getBecLookup() { + return this.get(ControlKey.BEC_DEF, BecLookup.class); + } + @Override public Map getNetDecayWasteCoeMap() { return this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); - } @Override @@ -141,9 +145,4 @@ public MatrixMap2> getEquationModifierGroup( public MatrixMap2 getHl1Coefficients() { return this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); } - - @Override - public CompVarAdjustments getCompVarAdjustments() { - return this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); - } } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java index 34e7668bb..463e53964 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java @@ -56,7 +56,7 @@ public Map parse(InputStream is, Map GrowthFiatDetails details = new GrowthFiatDetails(regionId, coefficients); - if (details.getNAges() == 0) { + if (details.getNAgesSupplied() == 0) { throw new ValueParseException("0", "Region Id " + regionId + " contains no age ranges"); } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java index b5c370239..ba73e651d 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java @@ -3,7 +3,12 @@ import java.util.List; public class GrowthFiatDetails { + private static final int N_AGES = 4; + private static final int N_MIXED_COEFFICIENTS = 3; + private final Region region; + + private int nAgesSupplied; private final Float[] ages; private final Float[] coefficients; private final Float[] mixedCoefficients; @@ -12,32 +17,32 @@ public class GrowthFiatDetails { * Describes a GrowthFiat model. * * @param regionId either 1 (coast) or 2 (interior) - * @param coefficients (11: 0-3 ages, 4-7 coefficients, 8-10 mixed coefficients) + * @param coefficients (11: 0-7 N_AGES pairs of (age, coefficient), 8-10 mixed coefficients) */ public GrowthFiatDetails(int regionId, List numbers) { region = regionId == 1 ? Region.COASTAL : Region.INTERIOR; - int agesSupplied = 4; - for (int i = 0; i < 4; i++) - if (numbers.get(i) == 0.0) { - agesSupplied = i; + nAgesSupplied = N_AGES; + for (int i = 0; i < N_AGES; i++) + if (numbers.get(i * 2) == 0.0) { + nAgesSupplied = i; break; } - ages = new Float[agesSupplied]; - for (int i = 0; i < agesSupplied; i++) { - ages[i] = numbers.get(i); + ages = new Float[N_AGES]; + for (int i = 0; i < N_AGES; i++) { + ages[i] = numbers.get(i * 2); } - coefficients = new Float[agesSupplied]; - for (int i = 0; i < agesSupplied; i++) { - coefficients[i] = numbers.get(4 + i); + coefficients = new Float[N_AGES]; + for (int i = 0; i < N_AGES; i++) { + coefficients[i] = numbers.get(i * 2 + 1); } - mixedCoefficients = new Float[3]; - for (int i = 0; i < 3; i++) { - mixedCoefficients[i] = numbers.get(8 + i); + mixedCoefficients = new Float[N_MIXED_COEFFICIENTS]; + for (int i = 0; i < N_MIXED_COEFFICIENTS; i++) { + mixedCoefficients[i] = numbers.get(2 * N_AGES + i); } } @@ -45,19 +50,28 @@ public Region getRegion() { return region; } - public int getNAges() { - return ages.length; + public int getNAgesSupplied() { + return nAgesSupplied; } public Float getAge(int index) { + if (index < 0 || index >= N_AGES) { + throw new IllegalArgumentException("GrowthFiatDetails.getAge: index"); + } return ages[index]; } public Float getCoefficient(int index) { + if (index < 0 || index >= N_AGES) { + throw new IllegalArgumentException("GrowthFiatDetails.getCoefficient: index"); + } return coefficients[index]; } public Float getMixedCoefficient(int index) { + if (index < 0 || index >= N_MIXED_COEFFICIENTS) { + throw new IllegalArgumentException("GrowthFiatDetails.getMixedCoefficient: index"); + } return mixedCoefficients[index]; } diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java index fbc7f6c5a..07eaf0375 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java @@ -33,19 +33,22 @@ void testParseSimple() throws Exception { .get(ControlKey.BA_GROWTH_FIAT.name()); assertThat(m, Matchers.aMapWithSize(2)); + assertThat( + m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3) + ); assertThat( m.get(Region.COASTAL), Matchers.allOf( - Matchers.hasProperty("ages", Matchers.arrayContaining(1.0f, 0.02f, 100.0f, 0.01f)), - Matchers.hasProperty("coefficients", Matchers.arrayContaining(200f, 0.0f, 0.0f, 0.0f)), + Matchers.hasProperty("ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f)), + Matchers.hasProperty("coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f)), Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) ) ); assertThat( m.get(Region.INTERIOR), Matchers.allOf( - Matchers.hasProperty("ages", Matchers.arrayContaining(1.0f, 0.02f, 100.0f, 0.01f)), - Matchers.hasProperty("coefficients", Matchers.arrayContaining(200f, 0.0f, 0.0f, 0.0f)), + Matchers.hasProperty("ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f)), + Matchers.hasProperty("coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f)), Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) ) ); diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java index 4dff50c24..59d22baba 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java @@ -35,19 +35,22 @@ void testParseSimple() throws Exception { .get(ControlKey.DQ_GROWTH_FIAT.name()); assertThat(m, Matchers.aMapWithSize(2)); + assertThat( + m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3) + ); assertThat( m.get(Region.COASTAL), Matchers.allOf( - Matchers.hasProperty("ages", Matchers.arrayContaining(1.0f, 0.02f, 100.0f, 0.01f)), - Matchers.hasProperty("coefficients", Matchers.arrayContaining(200f, 0.0f, 0.0f, 0.0f)), + Matchers.hasProperty("ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f)), + Matchers.hasProperty("coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f)), Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) ) ); assertThat( m.get(Region.INTERIOR), Matchers.allOf( - Matchers.hasProperty("ages", Matchers.arrayContaining(1.0f, 0.02f, 100.0f, 0.01f)), - Matchers.hasProperty("coefficients", Matchers.arrayContaining(200f, 0.0f, 0.0f, 0.0f)), + Matchers.hasProperty("ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f)), + Matchers.hasProperty("coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f)), Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) ) ); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 9c12a9038..3374b21f6 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -295,7 +295,7 @@ private void grow( /** * EMP111A - Basal area growth for the primary layer. - * @param speciesProportionByBasalArea the proportion by basal area of each of the polygon's species + * @param speciesProportionsByBasalArea the proportion by basal area of each of the polygon's species * @param yearsAtBreastHeight at the start of the year * @param dominantHeight primary species dominant height at start of year * @param primaryLayerBasalArea at the start of the year @@ -306,7 +306,7 @@ private void grow( * @throws StandProcessingException */ private float growBasalArea( - float[] speciesProportionByBasalArea, float yearsAtBreastHeight, float dominantHeight, float primaryLayerBasalArea, + float[] speciesProportionsByBasalArea, float yearsAtBreastHeight, float dominantHeight, float primaryLayerBasalArea, Optional veteranLayerBasalArea, float growthInDominantHeight ) throws StandProcessingException { @@ -317,14 +317,74 @@ private float growBasalArea( baUpperBound = baUpperBound / Estimators.EMPIRICAL_OCCUPANCY; var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); - var baYield = fps.fcm + var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); + var becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); + Coefficients estimateBaseAreaYieldCoefficients = Coefficients.empty(7, 0); + for (int i = 0; i < 7; i++) { + float sum = 0.0f; + for (String speciesAlias: fps.getPolygonProcessingState().wallet.speciesNames) { + sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i); + } + estimateBaseAreaYieldCoefficients.setCoe(i, sum); + } + if (estimateBaseAreaYieldCoefficients.getCoe(5) > 0.0f) { + estimateBaseAreaYieldCoefficients.setCoe(5, 0.0f); + } boolean isFullOccupancy = true; int primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - float basalAreaYield = estimators.estimateBaseAreaYield(null, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, + float basalAreaYieldAtStart = estimators.estimateBaseAreaYield(estimateBaseAreaYieldCoefficients, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber); - return basalAreaYield; + float dominantHeightEnd = dominantHeight + growthInDominantHeight; + float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; + + float basalAreaYieldAtEnd = estimators.estimateBaseAreaYield(estimateBaseAreaYieldCoefficients, dominantHeightEnd, yearsAtBreastHeightEnd, + veteranLayerBasalArea, isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber); + + var basalAreaGrowthFiatDetails = fps.fcm.getBasalAreaGrowthFiatDetails(); + var growthFaitDetails = basalAreaGrowthFiatDetails.get(fps.getPolygonProcessingState().getBecZone().getRegion()); + var convergenceCoefficient = growthFaitDetails.getCoefficient(0); + int nAges = growthFaitDetails.getNAgesSupplied(); + if (yearsAtBreastHeight > growthFaitDetails.getAge(0) && nAges > 1) { + if (yearsAtBreastHeight >= growthFaitDetails.getAge(nAges - 1)) { + convergenceCoefficient = growthFaitDetails.getAge(nAges - 1); + } else { + // Must interpolate (between pair1 & pair2) + int pair1, pair2; + if (yearsAtBreastHeight < growthFaitDetails.getAge(0)) { + pair1 = 0; + } else if (yearsAtBreastHeight < growthFaitDetails.getAge(1)) { + pair1 = 1; + } else { + pair1 = 2; + } + pair2 = pair1 + 1; + + convergenceCoefficient = growthFaitDetails.getCoefficient(pair1) + + (growthFaitDetails.getCoefficient(pair2) - growthFaitDetails.getCoefficient(pair1)) + * (yearsAtBreastHeight - growthFaitDetails.getAge(pair1)) + / (growthFaitDetails.getAge(pair2) - growthFaitDetails.getAge(pair1)); + } + } + + var grow = basalAreaYieldAtEnd - basalAreaYieldAtStart; + var adjust = -convergenceCoefficient * (primaryLayerBasalArea - basalAreaYieldAtStart); + grow += adjust; + + // Special check at young ages. + if (yearsAtBreastHeight < 40.0f && primaryLayerBasalArea > 5.0f * basalAreaYieldAtStart) { + // This stand started MUCH faster than base yield model. We'll let it keep going like + // this for a while. + grow = Math.min(basalAreaYieldAtStart / yearsAtBreastHeight, Math.min(0.5f, grow)); + } + + if (fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3) >= 1) { + var growFiat = grow; + // ... + } + + return basalAreaYieldAtEnd; } /** diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index 106a6005d..0b9522be2 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -1,24 +1,34 @@ package ca.bc.gov.nrs.vdyp.forward.controlmap; +import java.util.Map; + import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; -import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.GrowthFiatDetails; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; public interface ForwardResolvedControlMap extends ResolvedControlMap { - /** 9 */ - BecLookup getBecLookup(); - - /** 25 */ + /** 25 - SITE_CURVE_NUMBERS */ MatrixMap2 getSiteCurveMap(); - /** 101 */ + /** 28 - PARAM_ADJUSTMENTS */ + CompVarAdjustments getCompVarAdjustments(); + + /** 101 - VTROL */ ForwardControlVariables getForwardControlVariables(); - /** 199 */ + /** 106 - BA_YIELD */ + MatrixMap2 getBasalAreaYieldCoefficients(); + + /** 111 - BA_GROWTH_FIAT */ + Map getBasalAreaGrowthFiatDetails(); + + /** 199 - DEBUG_SWITCHES */ ForwardDebugSettings getDebugSettings(); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index 0a6d11c65..7b4fb62f1 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -8,9 +8,10 @@ import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; -import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.DebugSettings; +import ca.bc.gov.nrs.vdyp.model.GrowthFiatDetails; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -18,19 +19,21 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl final ForwardDebugSettings debugSettings; final ForwardControlVariables forwardControlVariables; - final BecLookup becLookup; final MatrixMap2 siteCurveMap; final CompVarAdjustments compVarAdjustments; - + final MatrixMap2 basalAreaYieldCoefficients; + final Map basalAreaGrowthFiatDetails; + public ForwardResolvedControlMapImpl(Map controlMap) { super(controlMap); this.debugSettings = new ForwardDebugSettings(get(ControlKey.DEBUG_SWITCHES, DebugSettings.class)); this.forwardControlVariables = get(ControlKey.VTROL, ForwardControlVariables.class); - this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); this.siteCurveMap = Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); this.compVarAdjustments = this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); + this.basalAreaYieldCoefficients = this.get(ControlKey.BA_YIELD, MatrixMap2.class); + this.basalAreaGrowthFiatDetails = this.get(ControlKey.BA_GROWTH_FIAT, Map.class); } @Override @@ -43,11 +46,6 @@ public ForwardControlVariables getForwardControlVariables() { return forwardControlVariables; } - @Override - public BecLookup getBecLookup() { - return becLookup; - } - @Override public MatrixMap2 getSiteCurveMap() { return siteCurveMap; @@ -57,4 +55,14 @@ public MatrixMap2 getSiteCurveMap() { public CompVarAdjustments getCompVarAdjustments() { return compVarAdjustments; } + + @Override + public MatrixMap2 getBasalAreaYieldCoefficients() { + return basalAreaYieldCoefficients; + } + + @Override + public Map getBasalAreaGrowthFiatDetails() { + return basalAreaGrowthFiatDetails; + } } From 053c4d0d6b8f7593614287e52683b29ff7dd4fca Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 10 Jul 2024 17:13:50 -0700 Subject: [PATCH 14/66] BA Growth - code complete; common path testing complete. --- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 12 +- .../coe/BasalAreaGrowthEmpiricalParser.java | 84 ++++++- .../io/parse/coe/BasalAreaYieldParser.java | 15 -- .../coe/QuadraticMeanDiameterYieldParser.java | 15 -- .../BecZoneBySpeciesCoefficientParser.java | 47 ++-- .../vdyp/forward/ForwardProcessingEngine.java | 223 ++++++++++++++---- .../controlmap/ForwardResolvedControlMap.java | 7 + .../ForwardResolvedControlMapImpl.java | 17 +- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 4 +- 9 files changed, 313 insertions(+), 111 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index 9e9995aa3..66a43d284 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -815,6 +815,7 @@ private static void estimateUtilization( * EMP106 * * @param estimateBaseAreaYieldCoefficients + * @param debugSetting2Value * @param dominantHeight * @param breastHeightAge * @param baseAreaOverstory @@ -825,9 +826,9 @@ private static void estimateUtilization( * @throws StandProcessingException */ public float estimateBaseAreaYield( - Coefficients estimateBaseAreaYieldCoefficients, float dominantHeight, float breastHeightAge, - Optional baseAreaOverstory, boolean fullOccupancy, - BecDefinition bec, int baseAreaGroup + Coefficients estimateBaseAreaYieldCoefficients, int debugSetting2Value, float dominantHeight, + float breastHeightAge, Optional baseAreaOverstory, boolean fullOccupancy, BecDefinition bec, + int baseAreaGroup ) throws StandProcessingException { float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); @@ -848,7 +849,10 @@ public float estimateBaseAreaYield( float ageToUse = breastHeightAge; - // TODO getDebugMode(2)==1 + if (debugSetting2Value > 0) { + // Cap ageToUse to at most 100 * debugSetting2Value + ageToUse = Math.min(ageToUse, debugSetting2Value * 100.0f); + } if (ageToUse <= 0f) { throw new StandProcessingException("Age was not positive"); diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java index 49fe0e0c2..32d8b248b 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java @@ -1,7 +1,21 @@ package ca.bc.gov.nrs.vdyp.io.parse.coe; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; + import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.coe.base.BecZoneBySpeciesCoefficientParser; +import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.control.ControlMapSubResourceParser; +import ca.bc.gov.nrs.vdyp.io.parse.value.ControlledValueParser; +import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; /** * Parses a mapping from a BEC Zone Alias and Species to a list of eight coefficients. Each row contains @@ -13,7 +27,10 @@ * * All lines are parsed. A BEC Zone Alias value, trimmed, of "" results in the line being skipped. *

    - * The result of the parse is a map from BEC Zone Alias and Species to a (zero-based) eight-element coefficient array. + * The result of the parse is a map from BEC Zone Alias and Species to a (zero-based) eight-element coefficient + * array. If, for a given line "indicator" is zero, only the first coefficient is recorded (for species 0) and + * all others are set to zero. If "indicator" is one, all coefficients on the line are assigned to their respective + * species. *

    * Control index: 121 *

    @@ -22,14 +39,75 @@ * @author Michael Junkin, Vivid Solutions * @see BecZoneBySpeciesCoefficientParser */ -public class BasalAreaGrowthEmpiricalParser extends BecZoneBySpeciesCoefficientParser { +public class BasalAreaGrowthEmpiricalParser implements ControlMapSubResourceParser> { + private static final int NUM_SPECIES = 16; private static final int NUM_COEFFICIENTS = 8; + public static final String BEC_ZONE_ID_KEY = "BecId"; + public static final String INDEX_KEY = "index"; + public static final String INDICATOR_KEY = "indicator"; + public static final String COEFFICIENTS_KEY = "coefficients"; + public BasalAreaGrowthEmpiricalParser() { - super(NUM_COEFFICIENTS); + + this.lineParser = new LineParser() { + @Override + public boolean isIgnoredLine(String line) { + return Utils.nullOrPrefixBlank(line, 4); + } + + } // + .value(4, BEC_ZONE_ID_KEY, ControlledValueParser.BEC) // + .space(2) // + .value(1, INDEX_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, NUM_COEFFICIENTS, false, "Index value")) // + .value(2, INDICATOR_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, 1, true, "Indicator value")) // + .multiValue(NUM_SPECIES, 8, COEFFICIENTS_KEY, ValueParser.FLOAT); } + private LineParser lineParser; + + @Override + public MatrixMap2 parse(InputStream is, Map control) + throws IOException, ResourceParseException { + + var becAliases = BecDefinitionParser.getBecs(control).getBecAliases(); + var sp0Aliases = GenusDefinitionParser.getSpeciesAliases(control); + MatrixMap2 result = new MatrixMap2Impl<>( + becAliases, sp0Aliases, (k1, k2) -> Coefficients.empty(NUM_COEFFICIENTS, 0) + ); + + lineParser.parse(is, result, (value, r, lineNumber) -> { + var becZoneId = (String) value.get(BEC_ZONE_ID_KEY); + var index = (int) value.get(INDEX_KEY); + var indicator = (int) value.get(INDICATOR_KEY); + + @SuppressWarnings("unchecked") + var specCoefficients = (List) value.get(COEFFICIENTS_KEY); + + var specIt = sp0Aliases.iterator(); + + int coefficientIndex = 0; + while (specIt.hasNext()) { + var spec = specIt.next(); + Coefficients coefficients = r.get(becZoneId, spec); + Float coe = specCoefficients.get(coefficientIndex); + + if (indicator == 0) { + coefficients.setCoe(index, coefficientIndex == 0 ? coe : 0.0f); + } else { + coefficients.setCoe(index, coe); + } + + coefficientIndex += 1; + } + + return r; + }, control); + + return result; + } + @Override public ControlKey getControlKey() { return ControlKey.BA_GROWTH_EMPIRICAL; diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java index e60e70103..fc1d79732 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java @@ -1,7 +1,5 @@ package ca.bc.gov.nrs.vdyp.io.parse.coe; -import java.util.Optional; - import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.io.parse.coe.base.BecZoneBySpeciesCoefficientParser; @@ -36,17 +34,4 @@ public BasalAreaYieldParser() { public ControlKey getControlKey() { return ControlKey.BA_YIELD; } - - // Values after the first are offsets from the first. - @Override - protected float value(float current, Optional first) { - return first.map(x -> x + current).orElse(current); - } - - // Duplicate first value to other species if shared instead of setting to 0. - @Override - protected float valueShared(float current, Optional first) { - return first.orElse(current); - } - } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java index 3fcda60e8..2c3d668d7 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java @@ -1,7 +1,5 @@ package ca.bc.gov.nrs.vdyp.io.parse.coe; -import java.util.Optional; - import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.io.parse.coe.base.BecZoneBySpeciesCoefficientParser; @@ -36,17 +34,4 @@ public QuadraticMeanDiameterYieldParser() { public ControlKey getControlKey() { return ControlKey.DQ_YIELD; } - - // Values after the first are offsets from the first. - @Override - protected float value(float current, Optional first) { - return first.map(x -> x + current).orElse(current); - } - - // Duplicate first value to other species if shared instead of setting to 0. - @Override - protected float valueShared(float current, Optional first) { - return first.orElse(current); - } - } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java index 8218ce1f4..713b69748 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java @@ -4,9 +4,7 @@ import java.io.InputStream; import java.util.List; import java.util.Map; -import java.util.Optional; -import ca.bc.gov.nrs.vdyp.common.HoldFirst; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.coe.BecDefinitionParser; import ca.bc.gov.nrs.vdyp.io.parse.coe.GenusDefinitionParser; @@ -25,6 +23,9 @@ * Zone Alias and then sp0 Alias, one per index. * * Indices range from 0 to a parameterized value (7, for example). + * + * If, for a given input line, indicator is "one", coe i, i = 1 - 15, is set to coe 0 plus coe i. + * Otherwise (indicator is "zero"), coe i is set to the ith coe supplied in the input file. * * @author Michael Junkin, Vivid Solutions * @see ControlMapSubResourceParser @@ -51,26 +52,15 @@ public boolean isIgnoredLine(String line) { } } // - .value(4, BEC_ZONE_ID_KEY, ControlledValueParser.BEC) // - .space(2) // - .value( - 1, INDEX_KEY, - ValueParser.range(ValueParser.INTEGER, 0, true, nCoefficients, false, "Index value") - ) // - .value(2, INDICATOR_KEY, ValueParser.LOGICAL_0_1) // - .multiValue(NUM_SPECIES, 8, COEFFICIENTS_KEY, ValueParser.FLOAT); + .value(4, BEC_ZONE_ID_KEY, ControlledValueParser.BEC) // + .space(2) // + .value(1, INDEX_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, nCoefficients, false, "Index value")) // + .value(2, INDICATOR_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, 1, true, "Indicator value")) // + .multiValue(NUM_SPECIES, 8, COEFFICIENTS_KEY, ValueParser.FLOAT); } private LineParser lineParser; - protected float value(float current, Optional first) { - return current; - } - - protected float valueShared(float current, Optional first) { - return first.isPresent() ? 0f : current; - } - @Override public MatrixMap2 parse(InputStream is, Map control) throws IOException, ResourceParseException { @@ -84,28 +74,32 @@ public MatrixMap2 parse(InputStream is, Map { var becZoneId = (String) value.get(BEC_ZONE_ID_KEY); var index = (int) value.get(INDEX_KEY); - var valueAppliesToAllSpecies = (!(boolean) value.get(INDICATOR_KEY)); + var indicator = (int) value.get(INDICATOR_KEY); @SuppressWarnings("unchecked") var specCoefficients = (List) value.get(COEFFICIENTS_KEY); var specIt = sp0Aliases.iterator(); - + + Float first = null; int coefficientIndex = 0; - var first = new HoldFirst(); while (specIt.hasNext()) { var spec = specIt.next(); - Coefficients coefficients = r.get(becZoneId, spec); + Float coe = specCoefficients.get(coefficientIndex); - if (valueAppliesToAllSpecies) { - coefficients.setCoe(index, valueShared(coe, first.get())); + Coefficients coefficients = r.get(becZoneId, spec); + if (indicator == 1 && coefficientIndex > 0) { + coefficients.setCoe(index, coe + first); } else { - coefficients.setCoe(index, value(coe, first.get())); + coefficients.setCoe(index, coe); + } + + if (coefficientIndex == 0) { + first = coe; } coefficientIndex += 1; - first.set(coe); } return r; @@ -113,5 +107,4 @@ public MatrixMap2 parse(InputStream is, Map veteranLayerBasalArea, float growthInDominantHeight + float[] speciesProportionsByBasalArea, float yearsAtBreastHeight, float dominantHeight, + float primaryLayerBasalArea, Optional veteranLayerBasalArea, float growthInDominantHeight ) throws StandProcessingException { - - // UPPERGEN( 1, BATOP98, DQTOP98) - var baUpperBound = growBasalAreaUpperBound(); - var dqUpperBound = growQuadraticMeanDiameterUpperBound(); - baUpperBound = baUpperBound / Estimators.EMPIRICAL_OCCUPANCY; - var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); - var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); var becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); Coefficients estimateBaseAreaYieldCoefficients = Coefficients.empty(7, 0); for (int i = 0; i < 7; i++) { float sum = 0.0f; - for (String speciesAlias: fps.getPolygonProcessingState().wallet.speciesNames) { - sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i); + for (int speciesIndex = 1; speciesIndex <= fps.getPolygonProcessingState().wallet.getNSpecies(); speciesIndex++) { + String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; + sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; } estimateBaseAreaYieldCoefficients.setCoe(i, sum); } if (estimateBaseAreaYieldCoefficients.getCoe(5) > 0.0f) { estimateBaseAreaYieldCoefficients.setCoe(5, 0.0f); } - + boolean isFullOccupancy = true; int primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - float basalAreaYieldAtStart = estimators.estimateBaseAreaYield(estimateBaseAreaYieldCoefficients, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, - isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber); + int debugSetting2Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); + + float basalAreaYieldAtStart = estimators.estimateBaseAreaYield( + estimateBaseAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, + isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber + ); float dominantHeightEnd = dominantHeight + growthInDominantHeight; float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; - - float basalAreaYieldAtEnd = estimators.estimateBaseAreaYield(estimateBaseAreaYieldCoefficients, dominantHeightEnd, yearsAtBreastHeightEnd, - veteranLayerBasalArea, isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber); - var basalAreaGrowthFiatDetails = fps.fcm.getBasalAreaGrowthFiatDetails(); - var growthFaitDetails = basalAreaGrowthFiatDetails.get(fps.getPolygonProcessingState().getBecZone().getRegion()); + float basalAreaYieldAtEnd = estimators.estimateBaseAreaYield( + estimateBaseAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, + isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber + ); + + var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() + .get(fps.getPolygonProcessingState().getBecZone().getRegion()); + var convergenceCoefficient = growthFaitDetails.getCoefficient(0); int nAges = growthFaitDetails.getNAgesSupplied(); if (yearsAtBreastHeight > growthFaitDetails.getAge(0) && nAges > 1) { @@ -352,61 +354,192 @@ private float growBasalArea( } else { // Must interpolate (between pair1 & pair2) int pair1, pair2; - if (yearsAtBreastHeight < growthFaitDetails.getAge(0)) { + if (yearsAtBreastHeight < growthFaitDetails.getAge(1)) { pair1 = 0; - } else if (yearsAtBreastHeight < growthFaitDetails.getAge(1)) { + } else if (yearsAtBreastHeight < growthFaitDetails.getAge(2)) { pair1 = 1; } else { pair1 = 2; } pair2 = pair1 + 1; - + convergenceCoefficient = growthFaitDetails.getCoefficient(pair1) - + (growthFaitDetails.getCoefficient(pair2) - growthFaitDetails.getCoefficient(pair1)) - * (yearsAtBreastHeight - growthFaitDetails.getAge(pair1)) - / (growthFaitDetails.getAge(pair2) - growthFaitDetails.getAge(pair1)); + + (growthFaitDetails.getCoefficient(pair2) - growthFaitDetails.getCoefficient(pair1)) + * (yearsAtBreastHeight - growthFaitDetails.getAge(pair1)) + / (growthFaitDetails.getAge(pair2) - growthFaitDetails.getAge(pair1)); } } - - var grow = basalAreaYieldAtEnd - basalAreaYieldAtStart; + + float baGrowth = basalAreaYieldAtEnd - basalAreaYieldAtStart; var adjust = -convergenceCoefficient * (primaryLayerBasalArea - basalAreaYieldAtStart); - grow += adjust; - + baGrowth += adjust; + // Special check at young ages. if (yearsAtBreastHeight < 40.0f && primaryLayerBasalArea > 5.0f * basalAreaYieldAtStart) { // This stand started MUCH faster than base yield model. We'll let it keep going like // this for a while. - grow = Math.min(basalAreaYieldAtStart / yearsAtBreastHeight, Math.min(0.5f, grow)); + baGrowth = Math.min(basalAreaYieldAtStart / yearsAtBreastHeight, Math.min(0.5f, baGrowth)); + } + + int debugSetting3Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3); + + if (debugSetting3Value >= 1) { + float baGrowthFiatModel = baGrowth; + + float baGrowthEmpiricalModel = calculateBasalAreaGrowthEmpirical( + speciesProportionsByBasalArea, primaryLayerBasalArea, yearsAtBreastHeight, dominantHeight, basalAreaYieldAtStart, basalAreaYieldAtEnd + ); + + baGrowth = baGrowthEmpiricalModel; + + if (debugSetting3Value == 2) { + float c = 1.0f; + if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { + c = 0.0f; + } else if (yearsAtBreastHeight > growthFaitDetails.getMixedCoefficient(0)) { + float t1 = yearsAtBreastHeight - growthFaitDetails.getMixedCoefficient(0); + float t2 = growthFaitDetails.getMixedCoefficient(1) - growthFaitDetails.getMixedCoefficient(0); + float t3 = growthFaitDetails.getMixedCoefficient(2); + c = 1.0f - FloatMath.pow(t1 / t2, t3); + } + baGrowth = c * baGrowthEmpiricalModel + (1.0f - c) * baGrowthFiatModel; + } + } + + // UPPERGEN( 1, BATOP98, DQTOP98) + var baUpperBound = growBasalAreaUpperBound(); + + baUpperBound = baUpperBound / Estimators.EMPIRICAL_OCCUPANCY; + var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); + + // Enforce upper limit on growth + if (primaryLayerBasalArea + baGrowth > baLimit) { + baGrowth = Math.max(baLimit - primaryLayerBasalArea, 0.0f); } - if (fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3) >= 1) { - var growFiat = grow; - // ... + // Undocumented check to prevent negative growth that causes BA to go to less than + // 1.0. It is doubtful that this condition will ever occur... + if (baGrowth < 0.0f && primaryLayerBasalArea + baGrowth < 1.0f) { + baGrowth = -primaryLayerBasalArea + 1.0f; } - return basalAreaYieldAtEnd; + return baGrowth; + } + + /** + * EMP121. Calculate basal area growth using the empirical model. + * + * @param speciesProportionsByBasalArea the proportion by basal area of each of the polygon's species + * @param primaryLayerBasalArea basal area of primary layer + * @param yearsAtBreastHeight primary species years at breast height or more + * @param dominantHeight primary species dominant height + * @param basalAreaYieldAtStart basal area yield at start of period + * @param basalAreaYieldAtEnd basal area yield at end of period + * + * @return the change in primary layer basal area from start to start + 1 year + */ + private float calculateBasalAreaGrowthEmpirical(float[] speciesProportionsByBasalArea, float primaryLayerBasalArea, float yearsAtBreastHeight, + float dominantHeight, float basalAreaYieldAtStart, float basalAreaYieldAtEnd) { + + yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); + if (yearsAtBreastHeight > 999.0f) { + yearsAtBreastHeight = 999.0f; + } + + var basalAreaGrowthEmpiricalCoefficients = fps.fcm.getBasalAreaGrowthEmpiricalCoefficients(); + + String becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); + String firstSpecies = fps.fcm.getGenusDefinitionMap().getByIndex(1).getAlias(); + var firstSpeciesBaGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, firstSpecies); + + float b0 = firstSpeciesBaGrowthCoe.get(0); + float b1 = firstSpeciesBaGrowthCoe.get(1); + float b2 = firstSpeciesBaGrowthCoe.get(2); + float b3 = firstSpeciesBaGrowthCoe.get(3); + float b4 = 0.0f; + float b5 = 0.0f; + float b6 = firstSpeciesBaGrowthCoe.get(6); + float b7 = firstSpeciesBaGrowthCoe.get(7); + + for (int i = 1; i <= fps.getPolygonProcessingState().wallet.getNSpecies(); i++) { + String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[i]; + var baGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, speciesAlias); + b4 += speciesProportionsByBasalArea[i] * baGrowthCoe.getCoe(4); + b5 += speciesProportionsByBasalArea[i] * baGrowthCoe.getCoe(5); + } + + b4 = Math.max(b4, 0.0f); + b5 = Math.min(b5, 0.0f); + + float term1; + if (dominantHeight > b0) { + term1 = 1.0f - FloatMath.exp(b1 * (dominantHeight - b0)); + } else { + term1 = 0.0f; + } + + float fLogIt = -0.05f * (yearsAtBreastHeight - 350.0f); + float term2a = FloatMath.exp(fLogIt) / (1.0f + FloatMath.exp(fLogIt)); + float term2 = b2 * FloatMath.pow(dominantHeight / 20.0f, b3) * term2a; + float term3 = b4 * FloatMath.exp(b5 * yearsAtBreastHeight); + + float term4; + float basalAreaYieldDelta = basalAreaYieldAtEnd - basalAreaYieldAtStart; + if (basalAreaYieldDelta > 0.0) { + term4 = b6 * FloatMath.pow(basalAreaYieldDelta, b7); + } else { + term4 = 0.0f; + } + + float basalAreaDelta = term1 * (term2 + term3) + term4; + + // An undocumented check to prevent negative growth that causes BA to go to + // less than 1.0. It is doubtful that this condition will ever occur. + if (basalAreaDelta < 0.0 && primaryLayerBasalArea + basalAreaDelta < 1.0f) { + basalAreaDelta = -primaryLayerBasalArea + 1.0f; + } + + return basalAreaDelta; } /** * UPPERGEN(1, BATOP98, DQTOP98) for basal area */ private float growBasalAreaUpperBound() { - var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); + + int debugSetting4Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); + if (debugSetting4Value > 0) { + var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); + Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); + int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + return upperBoundsCoefficients.get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 1); + } else { + var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); + } } /** * UPPERGEN(1, BATOP98, DQTOP98) for quad-mean-diameter */ private float growQuadraticMeanDiameterUpperBound() { - var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); + + int debugSetting4Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); + if (debugSetting4Value > 0) { + var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); + Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); + int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + return upperBoundsCoefficients.get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 2); + } else { + var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); + } } public float growDominantHeight( - float dominantHeight, int siteCurveNumber, float siteIndex, - float yearsToBreastHeight - ) throws ProcessingException { + float dominantHeight, int siteCurveNumber, float siteIndex, + float yearsToBreastHeight + ) throws ProcessingException { SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); Region region = fps.getPolygonProcessingState().wallet.getBecZone().getRegion(); @@ -811,7 +944,7 @@ uc.index, calculateTreesPerHectare( PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank wallet = pps.wallet; - + Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); String speciesName = wallet.speciesNames[speciesIndex]; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index 0b9522be2..0f7c53bdc 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -10,6 +10,7 @@ import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.GrowthFiatDetails; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; public interface ForwardResolvedControlMap extends ResolvedControlMap { @@ -20,6 +21,9 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 28 - PARAM_ADJUSTMENTS */ CompVarAdjustments getCompVarAdjustments(); + /** 43 - UPPER_BA_BY_CI_S0_P */ + MatrixMap3 getUpperBoundsCoefficients(); + /** 101 - VTROL */ ForwardControlVariables getForwardControlVariables(); @@ -29,6 +33,9 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 111 - BA_GROWTH_FIAT */ Map getBasalAreaGrowthFiatDetails(); + /** 121 - BA_GROWTH_EMPIRICAL */ + MatrixMap2 getBasalAreaGrowthEmpiricalCoefficients(); + /** 199 - DEBUG_SWITCHES */ ForwardDebugSettings getDebugSettings(); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index 7b4fb62f1..5d1314c5e 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -13,6 +13,7 @@ import ca.bc.gov.nrs.vdyp.model.DebugSettings; import ca.bc.gov.nrs.vdyp.model.GrowthFiatDetails; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl implements ForwardResolvedControlMap { @@ -23,7 +24,9 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl final CompVarAdjustments compVarAdjustments; final MatrixMap2 basalAreaYieldCoefficients; final Map basalAreaGrowthFiatDetails; - + final MatrixMap2 basalAreaGrowthEmpiricalCoefficients; + final MatrixMap3 upperBoundCoefficients; + public ForwardResolvedControlMapImpl(Map controlMap) { super(controlMap); @@ -34,6 +37,8 @@ public ForwardResolvedControlMapImpl(Map controlMap) { this.compVarAdjustments = this.get(ControlKey.PARAM_ADJUSTMENTS, CompVarAdjustments.class); this.basalAreaYieldCoefficients = this.get(ControlKey.BA_YIELD, MatrixMap2.class); this.basalAreaGrowthFiatDetails = this.get(ControlKey.BA_GROWTH_FIAT, Map.class); + this.basalAreaGrowthEmpiricalCoefficients = this.get(ControlKey.BA_GROWTH_EMPIRICAL, MatrixMap2.class); + this.upperBoundCoefficients = this.get(ControlKey.UPPER_BA_BY_CI_S0_P, MatrixMap3.class); } @Override @@ -65,4 +70,14 @@ public MatrixMap2 getBasalAreaYieldCoefficients() public Map getBasalAreaGrowthFiatDetails() { return basalAreaGrowthFiatDetails; } + + @Override + public MatrixMap2 getBasalAreaGrowthEmpiricalCoefficients() { + return basalAreaGrowthEmpiricalCoefficients; + } + + @Override + public MatrixMap3 getUpperBoundsCoefficients() { + return upperBoundCoefficients; + } } diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index e6e24f4ef..a64a317ff 100644 --- a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -780,7 +780,9 @@ float estimateBaseAreaYield( ) throws StandProcessingException { var coe = estimateBaseAreaYieldCoefficients(species, bec); - return estimators.estimateBaseAreaYield(coe, dominantHeight, breastHeightAge, baseAreaOverstory, fullOccupancy, bec, baseAreaGroup); + // TODO - switch to use the configured value. + int debugSetting2Value = 0; + return estimators.estimateBaseAreaYield(coe, debugSetting2Value, dominantHeight, breastHeightAge, baseAreaOverstory, fullOccupancy, bec, baseAreaGroup); } Coefficients estimateBaseAreaYieldCoefficients(Collection species, BecDefinition bec) { From 53d8f252ec1caf81b288f599ffab63d1dc34ced4 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 12 Jul 2024 11:18:15 -0700 Subject: [PATCH 15/66] Grow basal area (of primary layer) --- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 7 +- .../controlmap/ResolvedControlMapImpl.java | 2 +- .../io/parse/coe/base/GrowthFiatParser.java | 7 +- .../bc/gov/nrs/vdyp/model/DebugSettings.java | 47 +++-- .../gov/nrs/vdyp/model/GrowthFiatDetails.java | 72 +++++++- .../gov/nrs/vdyp/model/DebugSettingsTest.java | 7 +- .../vdyp/model/GrowthFiatDetailsTests.java | 98 +++++++++++ .../vdyp/forward/ForwardProcessingEngine.java | 164 +++++++++--------- .../vdyp/forward/ForwardProcessingState.java | 7 +- .../forward/model/ForwardDebugSettings.java | 23 ++- .../nrs/vdyp/forward/GrowBasalAreaTest.java | 114 ++++++++++++ 11 files changed, 440 insertions(+), 108 deletions(-) create mode 100644 vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java create mode 100644 vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index 66a43d284..c841b0232 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -10,6 +10,7 @@ import static java.lang.Math.max; import static java.lang.Math.min; +import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -830,7 +831,7 @@ public float estimateBaseAreaYield( float breastHeightAge, Optional baseAreaOverstory, boolean fullOccupancy, BecDefinition bec, int baseAreaGroup ) throws StandProcessingException { - float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); + float upperBoundBasalArea = upperBoundsBaseArea(baseAreaGroup); /* * The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea @@ -855,7 +856,7 @@ public float estimateBaseAreaYield( } if (ageToUse <= 0f) { - throw new StandProcessingException("Age was not positive"); + throw new StandProcessingException(MessageFormat.format("Age ({0}) was not positive", ageToUse)); } float trAge = FloatMath.log(ageToUse); @@ -876,7 +877,7 @@ public float estimateBaseAreaYield( estimateBaseAreaYieldCoefficients.getCoe(5) * dominantHeight + estimateBaseAreaYieldCoefficients.getCoe(6) * baseAreaOverstory.orElse(0f) ); - bap = Math.min(bap, upperBoundBaseArea); + bap = Math.min(bap, upperBoundBasalArea); } if (fullOccupancy) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 0b8607a98..7a62f22cc 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -42,7 +42,7 @@ public U get(ControlKey key, Class clazz) { @Override public GenusDefinitionMap getGenusDefinitionMap() { - List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); + List genusDefinitions = this.>get(ControlKey.SP0_DEF, List.class); return new GenusDefinitionMap(genusDefinitions); } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java index 463e53964..5fee04a3c 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java @@ -54,7 +54,12 @@ public Map parse(InputStream is, Map @SuppressWarnings("unchecked") var coefficients = (List) value.get(COEFFICIENTS_KEY); - GrowthFiatDetails details = new GrowthFiatDetails(regionId, coefficients); + GrowthFiatDetails details; + try { + details = new GrowthFiatDetails(regionId, coefficients); + } catch (ResourceParseException e) { + throw new ValueParseException(String.valueOf(regionId), "Error constructing GrowthFiatDetails instance", e); + } if (details.getNAgesSupplied() == 0) { throw new ValueParseException("0", "Region Id " + regionId + " contains no age ranges"); diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java index b58adbd91..5727fb043 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java @@ -26,39 +26,64 @@ public class DebugSettings { public static final int MAX_DEBUG_SETTINGS = 25; - protected static final int DEFAULT_DEBUG_SETTING = 0; + private static final int DEFAULT_DEBUG_SETTING = 0; - protected final Integer[] settings; + final int[] settings; + /** + * Create a DebugSettings instance from the given values. If settings is null, this + * is equivalent to calling DebugSettings(new Integer[0]). If an entry in settings + * is null, the default value (0) is assigned to that variable. If more than + * MAX_DEBUG_SETTINGS are supplied, those in excess are ignored. + */ public DebugSettings(Integer[] settings) { - this.settings = settings == null ? new Integer[0] : Arrays.copyOf(settings, settings.length); + + if (settings == null) { + settings = new Integer[0]; + } - if (this.settings.length > MAX_DEBUG_SETTINGS) { - throw new IllegalArgumentException("Debug settings array has length " + this.settings.length + if (settings.length > MAX_DEBUG_SETTINGS) { + throw new IllegalArgumentException("Debug settings array has length " + settings.length + ", which exceeds the maximum length of " + MAX_DEBUG_SETTINGS); } - for (int i = 0; i < this.settings.length; i++) { - if (this.settings[i] == null) { + this.settings = new int[MAX_DEBUG_SETTINGS]; + + for (int i = 0; i < MAX_DEBUG_SETTINGS; i++) { + if (i < settings.length && settings[i] != null) { + this.settings[i] = settings[i]; + } else { this.settings[i] = DEFAULT_DEBUG_SETTING; } } } + /** + * Create a DebugSettings instance with all settings set to zero. + */ public DebugSettings() { this(new Integer[0]); } + /** + * Return the value of the debug variable with setting number settingNumber. This is a + * one-based value. + * @param settingNumber the number of the debug variable whose value is to be returned. + * @return as described. + */ public int getValue(int settingNumber) { if (settingNumber < 1 || settingNumber > MAX_DEBUG_SETTINGS) { throw new IllegalArgumentException("Debug setting number " + settingNumber + " is out of range -" + " must be between 1 and " + MAX_DEBUG_SETTINGS); } - if (settingNumber > settings.length) { - return DEFAULT_DEBUG_SETTING; - } - return settings[settingNumber - 1]; } + + /** + * @return a copy of the values array, useful when the debug settings need to be modified. + */ + public int[] getValues() { + return Arrays.copyOf(settings, settings.length); + } } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java index ba73e651d..f7f88743f 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java @@ -1,10 +1,14 @@ package ca.bc.gov.nrs.vdyp.model; +import java.text.MessageFormat; import java.util.List; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; + public class GrowthFiatDetails { private static final int N_AGES = 4; private static final int N_MIXED_COEFFICIENTS = 3; + private static final int N_ENTRIES = N_AGES * 2 + N_MIXED_COEFFICIENTS; private final Region region; @@ -14,30 +18,61 @@ public class GrowthFiatDetails { private final Float[] mixedCoefficients; /** - * Describes a GrowthFiat model. + * Create a GrowthFiat model. The first 8 values is a list of four pairs of (age, coefficient.) The list + * may be terminated by supplying 0 as the age value in entries that are not to be considered part of + * the list. The ages in all previous entries must be monatonically increasing. The coefficients of all + * pairs whose age is 0 must be 0, too. * * @param regionId either 1 (coast) or 2 (interior) * @param coefficients (11: 0-7 N_AGES pairs of (age, coefficient), 8-10 mixed coefficients) + * + * @throws ResourceParseException */ - public GrowthFiatDetails(int regionId, List numbers) { + public GrowthFiatDetails(int regionId, List numbers) throws ResourceParseException { - region = regionId == 1 ? Region.COASTAL : Region.INTERIOR; + if (numbers == null || numbers.size() != N_ENTRIES) { + throw new ResourceParseException("numbers is null or does not contain " + N_ENTRIES + " entries"); + } + + if (regionId == 1) { + region = Region.COASTAL; + } else if (regionId == 2) { + region = Region.INTERIOR; + } else { + throw new ResourceParseException("region must have the value \"1\" or \"2\"; instead, saw \"" + regionId + "\""); + } nAgesSupplied = N_AGES; - for (int i = 0; i < N_AGES; i++) - if (numbers.get(i * 2) == 0.0) { + for (int i = 0; i < N_AGES; i++) { + if (nAgesSupplied < N_AGES) { + if (numbers.get(i * 2) != 0.0) { + throw new ResourceParseException(MessageFormat.format("All ages after the first 0 must be 0, too. Instead, saw \"{0}\"", + numbers.get(i * 2))); + } + } else if (numbers.get(i * 2) == 0.0) { nAgesSupplied = i; - break; } + } ages = new Float[N_AGES]; - for (int i = 0; i < N_AGES; i++) { + ages[0] = numbers.get(0); + for (int i = 1; i < N_AGES; i++) { ages[i] = numbers.get(i * 2); + if (i < nAgesSupplied && ages[i] < ages[i - 1]) { + throw new ResourceParseException(MessageFormat.format("Non-zero age values must be monatonically increasing" + + " Instead, saw \"{0}\" followed by \"{1}\"", + ages[i - 1], ages[i])); + } } coefficients = new Float[N_AGES]; - for (int i = 0; i < N_AGES; i++) { + coefficients[0] = numbers.get(0); + for (int i = 1; i < N_AGES; i++) { coefficients[i] = numbers.get(i * 2 + 1); + if (i >= nAgesSupplied && coefficients[i] != 0.0f) { + throw new ResourceParseException(MessageFormat.format("Coefficients of ages with value 0 must also have value 0" + + " Instead, saw \"{0}\"", coefficients[i])); + } } mixedCoefficients = new Float[N_MIXED_COEFFICIENTS]; @@ -86,4 +121,25 @@ public Float[] getCoefficients() { public Float[] getMixedCoefficients() { return mixedCoefficients; } + + public float calculateCoefficient(float age) { + + if (nAgesSupplied == 0 || age <= ages[0]) { + return getCoefficient(0); + } else if (age >= ages[nAgesSupplied - 1]) { + return getCoefficient(nAgesSupplied - 1); + } else { + for (int j = nAgesSupplied - 1, i = j - 1; i >= 0; i--, j--) { + if (age >= ages[i] && age < ages[j]) { + + return getCoefficient(i) + + (getCoefficient(j) - getCoefficient(i)) + * (age - ages[i]) + / (ages[j] - ages[i]); + } + } + } + + throw new IllegalStateException(MessageFormat.format("age {} was not found to be in range ", age)); + } } diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java index ccdf55da6..1dc6c4782 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; @@ -13,21 +14,21 @@ class DebugSettingsTest { void testNullArray() { DebugSettings ds = new DebugSettings(null); assertThat(ds.settings, Matchers.notNullValue()); - assertThat(ds.settings, Matchers.arrayWithSize(0)); + assertTrue(ds.settings.length == DebugSettings.MAX_DEBUG_SETTINGS); } @Test void testEmptyArray() { DebugSettings ds = new DebugSettings(new Integer[0]); assertThat(ds.settings, Matchers.notNullValue()); - assertThat(ds.settings, Matchers.arrayWithSize(0)); + assertTrue(ds.settings.length == DebugSettings.MAX_DEBUG_SETTINGS); } @Test void testSizeOneArray() { DebugSettings ds = new DebugSettings(new Integer[] { 43 }); assertThat(ds.settings, Matchers.notNullValue()); - assertThat(ds.settings, Matchers.arrayWithSize(1)); + assertTrue(ds.settings.length == DebugSettings.MAX_DEBUG_SETTINGS); assertThat(ds.settings[0], is(43)); } diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java new file mode 100644 index 000000000..0e85e1316 --- /dev/null +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java @@ -0,0 +1,98 @@ +package ca.bc.gov.nrs.vdyp.model; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; + +public class GrowthFiatDetailsTests { + + @Test + void test0Ages() { + try { + GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f)); + Assertions.assertTrue(details.getNAgesSupplied() == 0); + assertThat(details.getAges(), arrayContaining(0.0f, 0.0f, 0.0f, 0.0f)); + assertThat(details.getCoefficients(), arrayContaining(0.0f, 0.0f, 0.0f, 0.0f)); + assertThat(details.getMixedCoefficients(), arrayContaining(0.1f, 0.2f, 0.3f)); + } catch (ResourceParseException e) { + fail(); + } + } + + @Test + void test4Ages() { + try { + GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f)); + Assertions.assertTrue(details.getNAgesSupplied() == 4); + assertThat(details.getAges(), arrayContaining(1.0f, 2.0f, 3.0f, 4.0f)); + assertThat(details.getCoefficients(), arrayContaining(1.0f, 2.0f, 3.0f, 4.0f)); + assertThat(details.getMixedCoefficients(), arrayContaining(0.1f, 0.2f, 0.3f)); + } catch (ResourceParseException e) { + fail(); + } + } + + @Test + void test3Ages() { + try { + GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f)); + Assertions.assertTrue(details.getNAgesSupplied() == 3); + assertThat(details.getAges(), arrayContaining(1.0f, 2.0f, 3.0f, 0.0f)); + assertThat(details.getCoefficients(), arrayContaining(1.0f, 2.0f, 3.0f, 0.0f)); + assertThat(details.getMixedCoefficients(), arrayContaining(0.1f, 0.2f, 0.3f)); + } catch (ResourceParseException e) { + fail(); + } + } + + + @Test + void testInterpolation() { + try { + GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f)); + Assertions.assertTrue(details.getNAgesSupplied() == 3); + assertThat(details.calculateCoefficient(0.5f), is(1.0f)); + assertThat(details.calculateCoefficient(1.0f), is(1.0f)); + assertThat(details.calculateCoefficient(1.5f), is(1.5f)); + assertThat(details.calculateCoefficient(2.0f), is(2.0f)); + assertThat(details.calculateCoefficient(2.5f), is(2.5f)); + assertThat(details.calculateCoefficient(3.0f), is(3.0f)); + assertThat(details.calculateCoefficient(3.5f), is(3.0f)); + } catch (ResourceParseException e) { + fail(); + } + } + + @Test + void testAgeListNotEndedProperly() { + assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 0.0f, 0.0f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + } + + @Test + void testBadCoefficient() { + assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + } + + @Test + void testAgesNotMonatonicallyIncreasing() { + assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 2.5f, 4.0f, 0.1f, 0.2f, 0.3f))); + } + + @Test + void testCoefficientsNotMonatonicallyIncreasing() { + assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(2, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 1.5f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + } + + @Test + void testRegionValueNot1Or2() { + assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(0, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 1.5f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + } +} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 8b1496797..9b0d62e1f 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -68,12 +68,10 @@ public class ForwardProcessingEngine { public static final float PI_40K = (float) (Math.PI / 40_000); /* pp */ final ForwardProcessingState fps; - /* pp */ final Estimators estimators; public ForwardProcessingEngine(Map controlMap) { this.fps = new ForwardProcessingState(controlMap); - this.estimators = new Estimators(fps.fcm); } public enum ExecutionStep { @@ -230,6 +228,18 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro } } + /** + * VGROW1 - "grow" the primary layer, located in primaryLayerSourceInstance, starting at the + * given year, and write the results to primaryLayerTargetInstance. The veteran layer instance + * is supplied but at this point is ignored. + * + * @param primaryLayerSourceInstance + * @param currentYear + * @param primaryLayerTargetInstance + * @param veteranLayerInstance + * + * @throws ProcessingException + */ private void grow( int primaryLayerSourceInstance, int currentYear, int primaryLayerTargetInstance, int veteranLayerInstance ) @@ -282,15 +292,23 @@ private void grow( veteranLayerBasalArea = Optional.empty(); } - float[] speciesProportionByBasalArea = new float[pps.getNSpecies() + 1]; + float growthInBasalArea = growBasalArea( + primarySpeciesYearsAtBreastHeight, fps.fcm.getDebugSettings(), dominantHeight, primaryBank.basalAreas[0][UC_ALL_INDEX], veteranLayerBasalArea, growthInDominantHeight + ); + } + + private float[] getSpeciesProportionsByBasalArea() { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; + for (int i = 1; i <= pps.getNSpecies(); i++) { - speciesProportionByBasalArea[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] + speciesProportionsByBasalArea[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] / pps.wallet.basalAreas[0][UC_ALL_INDEX]; } - - float growthInBasalArea = growBasalArea( - speciesProportionByBasalArea, primarySpeciesYearsAtBreastHeight, dominantHeight, primaryBank.basalAreas[0][UC_ALL_INDEX], veteranLayerBasalArea, growthInDominantHeight - ); + + return speciesProportionsByBasalArea; } /** @@ -306,69 +324,51 @@ private void grow( * @return the growth in the basal area for the year * @throws StandProcessingException in the event of an error */ - private float growBasalArea( - float[] speciesProportionsByBasalArea, float yearsAtBreastHeight, float dominantHeight, + float growBasalArea( + float yearsAtBreastHeight, ForwardDebugSettings debugSettings, float dominantHeight, float primaryLayerBasalArea, Optional veteranLayerBasalArea, float growthInDominantHeight ) throws StandProcessingException { + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); + var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); var becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); - Coefficients estimateBaseAreaYieldCoefficients = Coefficients.empty(7, 0); + Coefficients estimateBasalAreaYieldCoefficients = Coefficients.empty(7, 0); for (int i = 0; i < 7; i++) { float sum = 0.0f; - for (int speciesIndex = 1; speciesIndex <= fps.getPolygonProcessingState().wallet.getNSpecies(); speciesIndex++) { + for (int speciesIndex = 1; speciesIndex <= fps.getPolygonProcessingState().wallet + .getNSpecies(); speciesIndex++) { String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; - sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; + sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) + * speciesProportionsByBasalArea[speciesIndex]; } - estimateBaseAreaYieldCoefficients.setCoe(i, sum); + estimateBasalAreaYieldCoefficients.setCoe(i, sum); } - if (estimateBaseAreaYieldCoefficients.getCoe(5) > 0.0f) { - estimateBaseAreaYieldCoefficients.setCoe(5, 0.0f); + if (estimateBasalAreaYieldCoefficients.getCoe(5) > 0.0f) { + estimateBasalAreaYieldCoefficients.setCoe(5, 0.0f); } boolean isFullOccupancy = true; int primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - int debugSetting2Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); + int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); - float basalAreaYieldAtStart = estimators.estimateBaseAreaYield( - estimateBaseAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, + float basalAreaYieldAtStart = fps.estimators.estimateBaseAreaYield( + estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber ); float dominantHeightEnd = dominantHeight + growthInDominantHeight; float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; - float basalAreaYieldAtEnd = estimators.estimateBaseAreaYield( - estimateBaseAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, + float basalAreaYieldAtEnd = fps.estimators.estimateBaseAreaYield( + estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() .get(fps.getPolygonProcessingState().getBecZone().getRegion()); - - var convergenceCoefficient = growthFaitDetails.getCoefficient(0); - int nAges = growthFaitDetails.getNAgesSupplied(); - if (yearsAtBreastHeight > growthFaitDetails.getAge(0) && nAges > 1) { - if (yearsAtBreastHeight >= growthFaitDetails.getAge(nAges - 1)) { - convergenceCoefficient = growthFaitDetails.getAge(nAges - 1); - } else { - // Must interpolate (between pair1 & pair2) - int pair1, pair2; - if (yearsAtBreastHeight < growthFaitDetails.getAge(1)) { - pair1 = 0; - } else if (yearsAtBreastHeight < growthFaitDetails.getAge(2)) { - pair1 = 1; - } else { - pair1 = 2; - } - pair2 = pair1 + 1; - convergenceCoefficient = growthFaitDetails.getCoefficient(pair1) - + (growthFaitDetails.getCoefficient(pair2) - growthFaitDetails.getCoefficient(pair1)) - * (yearsAtBreastHeight - growthFaitDetails.getAge(pair1)) - / (growthFaitDetails.getAge(pair2) - growthFaitDetails.getAge(pair1)); - } - } + var convergenceCoefficient = growthFaitDetails.calculateCoefficient(yearsAtBreastHeight); float baGrowth = basalAreaYieldAtEnd - basalAreaYieldAtStart; var adjust = -convergenceCoefficient * (primaryLayerBasalArea - basalAreaYieldAtStart); @@ -381,17 +381,17 @@ private float growBasalArea( baGrowth = Math.min(basalAreaYieldAtStart / yearsAtBreastHeight, Math.min(0.5f, baGrowth)); } - int debugSetting3Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3); - + int debugSetting3Value = debugSettings.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3); + if (debugSetting3Value >= 1) { float baGrowthFiatModel = baGrowth; - + float baGrowthEmpiricalModel = calculateBasalAreaGrowthEmpirical( speciesProportionsByBasalArea, primaryLayerBasalArea, yearsAtBreastHeight, dominantHeight, basalAreaYieldAtStart, basalAreaYieldAtEnd ); - + baGrowth = baGrowthEmpiricalModel; - + if (debugSetting3Value == 2) { float c = 1.0f; if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { @@ -416,13 +416,13 @@ private float growBasalArea( if (primaryLayerBasalArea + baGrowth > baLimit) { baGrowth = Math.max(baLimit - primaryLayerBasalArea, 0.0f); } - + // Undocumented check to prevent negative growth that causes BA to go to less than // 1.0. It is doubtful that this condition will ever occur... if (baGrowth < 0.0f && primaryLayerBasalArea + baGrowth < 1.0f) { baGrowth = -primaryLayerBasalArea + 1.0f; } - + return baGrowth; } @@ -438,20 +438,22 @@ private float growBasalArea( * * @return the change in primary layer basal area from start to start + 1 year */ - private float calculateBasalAreaGrowthEmpirical(float[] speciesProportionsByBasalArea, float primaryLayerBasalArea, float yearsAtBreastHeight, - float dominantHeight, float basalAreaYieldAtStart, float basalAreaYieldAtEnd) { - + private float calculateBasalAreaGrowthEmpirical( + float[] speciesProportionsByBasalArea, float primaryLayerBasalArea, float yearsAtBreastHeight, + float dominantHeight, float basalAreaYieldAtStart, float basalAreaYieldAtEnd + ) { + yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); if (yearsAtBreastHeight > 999.0f) { yearsAtBreastHeight = 999.0f; } - + var basalAreaGrowthEmpiricalCoefficients = fps.fcm.getBasalAreaGrowthEmpiricalCoefficients(); - + String becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); String firstSpecies = fps.fcm.getGenusDefinitionMap().getByIndex(1).getAlias(); var firstSpeciesBaGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, firstSpecies); - + float b0 = firstSpeciesBaGrowthCoe.get(0); float b1 = firstSpeciesBaGrowthCoe.get(1); float b2 = firstSpeciesBaGrowthCoe.get(2); @@ -460,29 +462,29 @@ private float calculateBasalAreaGrowthEmpirical(float[] speciesProportionsByBasa float b5 = 0.0f; float b6 = firstSpeciesBaGrowthCoe.get(6); float b7 = firstSpeciesBaGrowthCoe.get(7); - + for (int i = 1; i <= fps.getPolygonProcessingState().wallet.getNSpecies(); i++) { String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[i]; var baGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, speciesAlias); b4 += speciesProportionsByBasalArea[i] * baGrowthCoe.getCoe(4); b5 += speciesProportionsByBasalArea[i] * baGrowthCoe.getCoe(5); } - + b4 = Math.max(b4, 0.0f); b5 = Math.min(b5, 0.0f); - + float term1; if (dominantHeight > b0) { term1 = 1.0f - FloatMath.exp(b1 * (dominantHeight - b0)); } else { term1 = 0.0f; } - + float fLogIt = -0.05f * (yearsAtBreastHeight - 350.0f); float term2a = FloatMath.exp(fLogIt) / (1.0f + FloatMath.exp(fLogIt)); float term2 = b2 * FloatMath.pow(dominantHeight / 20.0f, b3) * term2a; float term3 = b4 * FloatMath.exp(b5 * yearsAtBreastHeight); - + float term4; float basalAreaYieldDelta = basalAreaYieldAtEnd - basalAreaYieldAtStart; if (basalAreaYieldDelta > 0.0) { @@ -490,15 +492,15 @@ private float calculateBasalAreaGrowthEmpirical(float[] speciesProportionsByBasa } else { term4 = 0.0f; } - + float basalAreaDelta = term1 * (term2 + term3) + term4; - + // An undocumented check to prevent negative growth that causes BA to go to // less than 1.0. It is doubtful that this condition will ever occur. if (basalAreaDelta < 0.0 && primaryLayerBasalArea + basalAreaDelta < 1.0f) { basalAreaDelta = -primaryLayerBasalArea + 1.0f; } - + return basalAreaDelta; } @@ -506,16 +508,18 @@ private float calculateBasalAreaGrowthEmpirical(float[] speciesProportionsByBasa * UPPERGEN(1, BATOP98, DQTOP98) for basal area */ private float growBasalAreaUpperBound() { - - int debugSetting4Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); + + int debugSetting4Value = fps.fcm.getDebugSettings() + .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); - return upperBoundsCoefficients.get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 1); + return upperBoundsCoefficients + .get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 1); } else { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); + return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); } } @@ -524,19 +528,21 @@ private float growBasalAreaUpperBound() { */ private float growQuadraticMeanDiameterUpperBound() { - int debugSetting4Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); + int debugSetting4Value = fps.fcm.getDebugSettings() + .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); - return upperBoundsCoefficients.get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 2); + return upperBoundsCoefficients + .get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 2); } else { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); } } - public float growDominantHeight( + float growDominantHeight( float dominantHeight, int siteCurveNumber, float siteIndex, float yearsToBreastHeight ) throws ProcessingException { @@ -807,7 +813,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP094 - estimators.estimateNetDecayAndWasteVolume( + fps.estimators.estimateNetDecayAndWasteVolume( pps.getBecZone() .getRegion(), uc, aAdjust, pps.wallet.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste ); @@ -828,7 +834,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce // EMP093 int decayGroup = pps.decayEquationGroups[s]; - estimators.estimateNetDecayVolume( + fps.estimators.estimateNetDecayVolume( pps.wallet.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, pps .getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay ); @@ -848,7 +854,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce // EMP092 int volumeGroup = pps.volumeEquationGroups[s]; - estimators.estimateCloseUtilizationVolume( + fps.estimators.estimateCloseUtilizationVolume( uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes ); @@ -863,13 +869,13 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce int primarySpeciesVolumeGroup = pps.volumeEquationGroups[s]; float primarySpeciesQMDAll = pps.wallet.quadMeanDiameters[s][UC_ALL_INDEX]; var wholeStemVolume = pps.wallet.treesPerHectare[s][UC_ALL_INDEX] - * estimators.estimateWholeStemVolumePerTree( + * fps.estimators.estimateWholeStemVolumePerTree( primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll ); wholeStemVolumes.setCoe(UC_ALL_INDEX, wholeStemVolume); - estimators.estimateWholeStemVolume( + fps.estimators.estimateWholeStemVolume( UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, quadMeanDiameters, basalAreas, wholeStemVolumes ); @@ -885,11 +891,11 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce cvVolume[s].put(uc, VolumeVariable.WHOLE_STEM_VOL, LayerType.PRIMARY, adjustment); } - estimators.estimateQuadMeanDiameterByUtilization( + fps.estimators.estimateQuadMeanDiameterByUtilization( pps.getBecZone(), quadMeanDiameters, genusName ); - estimators.estimateBaseAreaByUtilization( + fps.estimators.estimateBaseAreaByUtilization( pps.getBecZone(), quadMeanDiameters, basalAreas, genusName ); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 0c2057523..d660ad37c 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -2,6 +2,7 @@ import java.util.Map; +import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; @@ -19,7 +20,10 @@ class ForwardProcessingState { /** The control map defining the context of the execution */ final ForwardResolvedControlMap fcm; - + + /** The estimators instance used by this engine */ + final Estimators estimators; + /** The storage banks */ private final Bank[/* instances */][/* layers of instance */] banks; @@ -31,6 +35,7 @@ public ForwardProcessingState(Map controlMap) { new Bank[LAYERS_PER_INSTANCE] }; this.fcm = new ForwardResolvedControlMapImpl(controlMap); + this.estimators = new Estimators(this.fcm); } private static final float MIN_BASAL_AREA = 0.001f; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java index 396d2fc20..aec3173d9 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java @@ -112,7 +112,7 @@ public enum Vars { } } - private final DebugSettings debugSettings; + private DebugSettings debugSettings; public ForwardDebugSettings(DebugSettings debugSettings) { this.debugSettings = debugSettings; @@ -121,6 +121,27 @@ public ForwardDebugSettings(DebugSettings debugSettings) { public int getValue(Vars v) { return debugSettings.getValue(v.settingNumber); } + + /** + * For testing purposes sometimes it's useful to change the value of a debug setting. + * It is not expected that this method would be used for any other purpose. + * + * @param v the variable to change + * @param value the new value the variable is to have + */ + public void setValue(Vars v, int value) { + + int[] currentSettings = debugSettings.getValues(); + Integer[] updatedSettings = new Integer[currentSettings.length]; + for (int i = 0; i < currentSettings.length; i++) { + if (i == v.settingNumber - 1) { + updatedSettings[i] = value; + } else { + updatedSettings[i] = currentSettings[i]; + } + } + debugSettings = new DebugSettings(updatedSettings); + } public Integer[] getFillInValues() { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java new file mode 100644 index 000000000..0dc37652e --- /dev/null +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java @@ -0,0 +1,114 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; +import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; +import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; + +class GrowBasalAreaTest { + + protected static final Logger logger = LoggerFactory.getLogger(GrowBasalAreaTest.class); + + protected static ForwardControlParser parser; + protected static Map controlMap; + + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; + + protected static ForwardDataStreamReader forwardDataStreamReader; + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeTest() throws IOException, ResourceParseException { + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + .get(ControlKey.FORWARD_INPUT_GROWTO.name()); + polygonDescriptionStream = polygonDescriptionStreamFactory.get(); + + forwardDataStreamReader = new ForwardDataStreamReader(controlMap); + } + + @Test + void testStandardPath() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + float yabh = 54.0f; + float hd = 35.2999992f; + float ba = 45.3864441f; + float growthInHd = 0.173380271f; + + float gba = fpe.growBasalArea(yabh, fpe.fps.fcm.getDebugSettings(), hd, ba, Optional.empty(), growthInHd); + + assertThat(gba, is(0.35185286f)); + } + + @Test + void testYoungPath() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + float yabh = 30.0f; + float hd = 10.0f; + float ba = 200.0f; + float growthInHd = 0.173380271f; + + float gba = fpe.growBasalArea(yabh, fpe.fps.fcm.getDebugSettings(), hd, ba, Optional.empty(), growthInHd); + + assertThat(gba, is(0.0f)); + } + + @Test + void testDebugSettings2EqualsZeroPath() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + float yabh = 54.0f; + float hd = 35.2999992f; + float ba = 45.3864441f; + float growthInHd = 0.173380271f; + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.BASAL_AREA_GROWTH_MODEL_3, 0); + + float gba = fpe.growBasalArea(yabh, debugSettings, hd, ba, Optional.empty(), growthInHd); + + assertThat(gba, is(3.7865982f)); + } +} From b0088326dbbe0f6307dd15b5d3b051f6a4d9dec3 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 15 Jul 2024 11:40:29 -0700 Subject: [PATCH 16/66] Grow: quad-mean-diameter implementation and testing --- .../ca/bc/gov/nrs/vdyp/common}/Reference.java | 2 +- .../gov/nrs/vdyp/model/GrowthFiatDetails.java | 2 +- .../vdyp/forward/ForwardProcessingEngine.java | 222 ++++++++++++++++- .../controlmap/ForwardResolvedControlMap.java | 14 +- .../ForwardResolvedControlMapImpl.java | 28 +++ .../forward/GrowQuadMeanDiameterTest.java | 227 ++++++++++++++++++ .../bc/gov/nrs/vdyp/si32/site/SiteTool.java | 2 +- .../ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java | 2 +- .../ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java | 1 + .../bc/gov/nrs/vdyp/sindex/SindxdllTest.java | 1 + 10 files changed, 486 insertions(+), 15 deletions(-) rename {vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex => vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common}/Reference.java (93%) create mode 100644 vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java diff --git a/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java similarity index 93% rename from vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java rename to vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java index 062789391..026e7ace3 100644 --- a/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java @@ -1,4 +1,4 @@ -package ca.bc.gov.nrs.vdyp.sindex; +package ca.bc.gov.nrs.vdyp.common; import java.util.Optional; diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java index f7f88743f..25ab17534 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java @@ -66,7 +66,7 @@ public GrowthFiatDetails(int regionId, List numbers) throws ResourceParse } coefficients = new Float[N_AGES]; - coefficients[0] = numbers.get(0); + coefficients[0] = numbers.get(1); for (int i = 1; i < N_AGES; i++) { coefficients[i] = numbers.get(i * 2 + 1); if (i >= nAgesSupplied && coefficients[i] != 0.0f) { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 9b0d62e1f..7bdbb7f96 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -25,6 +25,7 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; +import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CommonCalculatorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CurveErrorException; @@ -292,22 +293,223 @@ private void grow( veteranLayerBasalArea = Optional.empty(); } + float basalAreaAtStartOfPeriod = primaryBank.basalAreas[0][UC_ALL_INDEX]; float growthInBasalArea = growBasalArea( - primarySpeciesYearsAtBreastHeight, fps.fcm.getDebugSettings(), dominantHeight, primaryBank.basalAreas[0][UC_ALL_INDEX], veteranLayerBasalArea, growthInDominantHeight + primarySpeciesYearsAtBreastHeight, fps.fcm + .getDebugSettings(), dominantHeight, basalAreaAtStartOfPeriod, veteranLayerBasalArea, growthInDominantHeight + ); + + float qmdAtStartOfGrowthPeriod = primaryBank.quadMeanDiameters[0][UC_ALL_INDEX]; + float primaryLayerBasalArea = primaryBank.basalAreas[0][UC_ALL_INDEX]; + Reference dqGrowthLimitApplied = new Reference<>(); + float growthInQuadMeanDiameter = growQuadMeanDiameter( + yearsToBreastHeight, primaryLayerBasalArea, dominantHeight, qmdAtStartOfGrowthPeriod, veteranLayerBasalArea, + veteranLayerBasalArea, growthInDominantHeight, dqGrowthLimitApplied ); } + + /** + * EMP117 - Quad Mean Diameter growth for the primary layer. + * + * @param yearsAtBreastHeight + * @param dominantHeight + * @param dqAtStart + * @param veteranBasalAreaStart + * @param veteranBasalAreaEnd + * @param hdGrowth + * @return + * + * @throws StandProcessingException + */ + float growQuadMeanDiameter( + float yearsAtBreastHeight, float primaryLayerBasalArea, float dominantHeight, float dqAtStart, + Optional veteranBasalAreaStart, Optional veteranBasalAreaEnd, float hdGrowth, + Reference dqGrowthLimitApplied + ) + throws StandProcessingException { + + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); + + var dqYieldCoefficients = fps.fcm.getQuadMeanDiameterYieldCoefficients(); + var decayBecZoneAlias = fps.getPolygonProcessingState().getBecZone().getDecayBec().getAlias(); + Coefficients coefficientsWeightedBySpeciesAndDecayBec = Coefficients.empty(6, 0); + for (int i = 0; i < 6; i++) { + float sum = 0.0f; + for (int speciesIndex = 1; speciesIndex <= fps.getPolygonProcessingState().wallet + .getNSpecies(); speciesIndex++) { + String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; + sum += dqYieldCoefficients.get(decayBecZoneAlias, speciesAlias).getCoe(i) + * speciesProportionsByBasalArea[speciesIndex]; + } + coefficientsWeightedBySpeciesAndDecayBec.setCoe(i, sum); + } + + float dqYieldAtStart = fps.estimators.estimateQuadMeanDiameterYield( + coefficientsWeightedBySpeciesAndDecayBec, dominantHeight, yearsAtBreastHeight, veteranBasalAreaStart, fps + .getPolygonProcessingState() + .getBecZone(), fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber() + ); + + float dominantHeightAtEnd = dominantHeight + hdGrowth; + float yearsAtBreastHeightAtEnd = yearsAtBreastHeight + 1.0f; + + float dqYieldAtEnd = fps.estimators.estimateQuadMeanDiameterYield( + coefficientsWeightedBySpeciesAndDecayBec, dominantHeightAtEnd, yearsAtBreastHeightAtEnd, veteranBasalAreaEnd, fps + .getPolygonProcessingState() + .getBecZone(), fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber() + ); + + float dqYieldGrowth = dqYieldAtEnd - dqYieldAtStart; + + int debugSetting6Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6); + + var growthFaitDetails = fps.fcm.getQuadMeanDiameterGrowthFiatDetails() + .get(fps.getPolygonProcessingState().getBecZone().getRegion()); + + Optional dqGrowthFiat = Optional.empty(); + if (debugSetting6Value != 1) { + var convergenceCoefficient = growthFaitDetails.calculateCoefficient(yearsAtBreastHeight); + + float adjust = -convergenceCoefficient * (dqAtStart - dqYieldAtStart); + dqGrowthFiat = Optional.of(dqYieldGrowth + adjust); + } + + Optional dqGrowthEmpirical = Optional.empty(); + if (debugSetting6Value != 0) { + dqGrowthEmpirical = Optional.of( + calculateQuadMeanDiameterGrowthEmpirical( + yearsAtBreastHeight, dominantHeight, primaryLayerBasalArea, dqAtStart, hdGrowth, dqYieldAtStart, dqYieldAtEnd + ) + ); + } + + float dqGrowth; + + switch (debugSetting6Value) { + case 0: + dqGrowth = dqGrowthFiat.orElseThrow(); + break; + + case 1: + dqGrowth = dqGrowthEmpirical.orElseThrow(); + break; + + case 2: { + float c = 1.0f; + if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { + c = 0.0f; + } else if (yearsAtBreastHeight > growthFaitDetails.getMixedCoefficient(0)) { + float t1 = yearsAtBreastHeight - growthFaitDetails.getMixedCoefficient(0); + float t2 = growthFaitDetails.getMixedCoefficient(1) - growthFaitDetails.getMixedCoefficient(0); + float t3 = growthFaitDetails.getMixedCoefficient(2); + c = 1.0f - FloatMath.pow(t1 / t2, t3); + } + dqGrowth = c * dqGrowthEmpirical.orElseThrow() + (1.0f - c) * dqGrowthFiat.orElseThrow(); + break; + } + + default: + throw new IllegalStateException("debugSetting6Value of " + debugSetting6Value + " is not supported"); + } - private float[] getSpeciesProportionsByBasalArea() { + float dqUpperBound = growQuadraticMeanDiameterUpperBound(); + float dqLimit = Math.max(dqUpperBound, dqAtStart); + + if (dqAtStart + dqGrowth < 7.6f) { + dqGrowth = 7.6f - dqAtStart; + } - PolygonProcessingState pps = fps.getPolygonProcessingState(); + if (dqAtStart + dqGrowth > dqLimit - 0.001f) { + dqGrowthLimitApplied.set(true); + dqGrowth = Math.max(dqLimit - dqAtStart, 0.0f); + } else { + dqGrowthLimitApplied.set(false); + } - float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; + // TODO: Must note if limited by maximum!!! + return dqGrowth; + } + + /** + * EMP122. Calculate quad mean diameter growth using the empirical model. + * + * @param yearsAtBreastHeight primary species years at breast height or more + * @param dominantHeight primary species dominant height + * @param primaryLayerBasalArea basal area of primary layer + * @param dqAtStart quad mean diameter at start of growth period + * @param hdGrowth growth in dominant height + * @param dqYieldAtStart quad mean diameter yield at start of growth period + * @param dqYieldAtEnd quad mean diameter yield at end of growth period + * + * @return the change in primary layer basal area from start to start + 1 year + */ + private float calculateQuadMeanDiameterGrowthEmpirical( + float yearsAtBreastHeight, float dominantHeight, + float primaryLayerBasalArea, float dqAtStart, float hdGrowth, float dqYieldAtStart, + float dqYieldAtEnd + ) { + // Compute the growth in quadratic mean diameter + + var dqGrowthEmpiricalCoefficients = fps.fcm.getQuadMeanDiameterGrowthEmpiricalCoefficients(); + + Integer stratumNumber = fps.getPolygonProcessingState().getPrimarySpeciesStratumNumber(); + var firstSpeciesDqGrowthCoe = dqGrowthEmpiricalCoefficients.get(stratumNumber); + + float a0 = firstSpeciesDqGrowthCoe.get(0); + float a1 = firstSpeciesDqGrowthCoe.get(1); + float a2 = firstSpeciesDqGrowthCoe.get(2); + float a3 = firstSpeciesDqGrowthCoe.get(3); + float a4 = firstSpeciesDqGrowthCoe.get(4); + float a5 = firstSpeciesDqGrowthCoe.get(5); + float a6 = firstSpeciesDqGrowthCoe.get(6); + + yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); + float dqYieldGrowth = dqYieldAtEnd - dqYieldAtStart; + + float dqDelta = FloatMath.exp( + a0 + a2 * FloatMath.log(yearsAtBreastHeight) + a3 * dqAtStart + + a4 * dominantHeight + a5 * primaryLayerBasalArea + a6 * hdGrowth) + + a1 * dqYieldGrowth; + + dqDelta = Math.max(dqDelta, 0.0f); + + // Compute min/max growth in quadratic mean diameter + + Map quadMeanDiameterGrowthEmpiricalLimits = fps.fcm + .getQuadMeanDiameterGrowthEmpiricalLimits(); + float[] l = new float[8]; + for (int i = 0; i < 8; i++) { + l[i] = quadMeanDiameterGrowthEmpiricalLimits.get(stratumNumber).getCoe(i); + } + + float x = dqAtStart - 7.5f; + float xsq = x * x; + + var dqGrowthMin = Math.max(l[0] + l[1] * x + l[2] * xsq / 100.0f, l[6]); + var dqGrowthMax = Math.min(l[3] + l[4] * x + l[5] * xsq / 100.0f, l[7]); + + dqGrowthMax = Math.max(dqGrowthMax, dqGrowthMin); + + // Apply the just-computed limits to the previously computed value. + + dqDelta = Math.max(dqDelta, dqGrowthMin); + dqDelta = Math.min(dqDelta, dqGrowthMax); + + return dqDelta; + } + + private float[] getSpeciesProportionsByBasalArea() { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; + for (int i = 1; i <= pps.getNSpecies(); i++) { speciesProportionsByBasalArea[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] / pps.wallet.basalAreas[0][UC_ALL_INDEX]; } - + return speciesProportionsByBasalArea; } @@ -330,7 +532,7 @@ float growBasalArea( ) throws StandProcessingException { float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); - + var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); var becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); Coefficients estimateBasalAreaYieldCoefficients = Coefficients.empty(7, 0); @@ -353,16 +555,16 @@ float growBasalArea( int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); float basalAreaYieldAtStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, - isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber + estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, isFullOccupancy, fps + .getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber ); float dominantHeightEnd = dominantHeight + growthInDominantHeight; float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; float basalAreaYieldAtEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, - isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber + estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, isFullOccupancy, fps + .getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index 0f7c53bdc..06c3d1a57 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -30,12 +30,24 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 106 - BA_YIELD */ MatrixMap2 getBasalAreaYieldCoefficients(); + /** 107 - DQ_YIELD */ + MatrixMap2 getQuadMeanDiameterYieldCoefficients(); + /** 111 - BA_GROWTH_FIAT */ Map getBasalAreaGrowthFiatDetails(); - + + /** 117 - DQ_GROWTH_FIAT */ + Map getQuadMeanDiameterGrowthFiatDetails(); + /** 121 - BA_GROWTH_EMPIRICAL */ MatrixMap2 getBasalAreaGrowthEmpiricalCoefficients(); + /** 122 - DQ_GROWTH_EMPIRICAL */ + Map getQuadMeanDiameterGrowthEmpiricalCoefficients(); + + /** 123 - DQ_GROWTH_EMPIRICAL_LIMITS */ + Map getQuadMeanDiameterGrowthEmpiricalLimits(); + /** 199 - DEBUG_SWITCHES */ ForwardDebugSettings getDebugSettings(); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index 5d1314c5e..0979971d2 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -26,6 +26,10 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl final Map basalAreaGrowthFiatDetails; final MatrixMap2 basalAreaGrowthEmpiricalCoefficients; final MatrixMap3 upperBoundCoefficients; + final MatrixMap2 quadMeanDiameterYieldCoefficients; + final Map quadMeanDiameterGrowthFiatDetails; + final Map quadMeanDiameterGrowthEmpiricalCoefficients; + final Map quadMeanDiameterGrowthEmpiricalLimits; public ForwardResolvedControlMapImpl(Map controlMap) { @@ -39,6 +43,10 @@ public ForwardResolvedControlMapImpl(Map controlMap) { this.basalAreaGrowthFiatDetails = this.get(ControlKey.BA_GROWTH_FIAT, Map.class); this.basalAreaGrowthEmpiricalCoefficients = this.get(ControlKey.BA_GROWTH_EMPIRICAL, MatrixMap2.class); this.upperBoundCoefficients = this.get(ControlKey.UPPER_BA_BY_CI_S0_P, MatrixMap3.class); + this.quadMeanDiameterYieldCoefficients = this.get(ControlKey.DQ_YIELD, MatrixMap2.class); + this.quadMeanDiameterGrowthFiatDetails = this.get(ControlKey.DQ_GROWTH_FIAT, Map.class); + this.quadMeanDiameterGrowthEmpiricalCoefficients = this.get(ControlKey.DQ_GROWTH_EMPIRICAL, Map.class); + this.quadMeanDiameterGrowthEmpiricalLimits = this.get(ControlKey.DQ_GROWTH_EMPIRICAL_LIMITS, Map.class); } @Override @@ -65,6 +73,11 @@ public CompVarAdjustments getCompVarAdjustments() { public MatrixMap2 getBasalAreaYieldCoefficients() { return basalAreaYieldCoefficients; } + + @Override + public MatrixMap2 getQuadMeanDiameterYieldCoefficients() { + return quadMeanDiameterYieldCoefficients; + } @Override public Map getBasalAreaGrowthFiatDetails() { @@ -80,4 +93,19 @@ public MatrixMap2 getBasalAreaGrowthEmpiricalCoeff public MatrixMap3 getUpperBoundsCoefficients() { return upperBoundCoefficients; } + + @Override + public Map getQuadMeanDiameterGrowthFiatDetails() { + return quadMeanDiameterGrowthFiatDetails; + } + + @Override + public Map getQuadMeanDiameterGrowthEmpiricalCoefficients() { + return quadMeanDiameterGrowthEmpiricalCoefficients; + } + + @Override + public Map getQuadMeanDiameterGrowthEmpiricalLimits() { + return quadMeanDiameterGrowthEmpiricalLimits; + } } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java new file mode 100644 index 000000000..264d7df02 --- /dev/null +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java @@ -0,0 +1,227 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Reference; +import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; +import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; +import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; + +class GrowQuadMeanDiameterTest { + + protected static final Logger logger = LoggerFactory.getLogger(GrowQuadMeanDiameterTest.class); + + protected static ForwardControlParser parser; + protected static Map controlMap; + + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; + + protected static ForwardDataStreamReader forwardDataStreamReader; + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeTest() throws IOException, ResourceParseException { + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + .get(ControlKey.FORWARD_INPUT_GROWTO.name()); + polygonDescriptionStream = polygonDescriptionStreamFactory.get(); + + forwardDataStreamReader = new ForwardDataStreamReader(controlMap); + } + + @Test + void testMixedModel() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 2); + + float yabh = 54.0f; + float hd = 35.2999992f; + float ba = 45.3864441f; + float dq = 30.9988747f; + float growthInHd = 0.173380271f; + Optional v_ba_start = Optional.empty(); + Optional v_ba_end = Optional.empty(); + Reference dqGrowthLimitApplied = new Reference<>(); + + float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); + + assertThat(gba, is(0.30947846f)); + assertTrue(dqGrowthLimitApplied.isPresent()); + assertThat(dqGrowthLimitApplied.get(), is(false)); + } + + @Test + void testFiatOnlyModel() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 0); /* this value will force the fiat only calculations. */ + + float yabh = 54.0f; + float hd = 35.2999992f; + float ba = 45.3864441f; + float dq = 30.9988747f; + float growthInHd = 0.173380271f; + Optional v_ba_start = Optional.empty(); + Optional v_ba_end = Optional.empty(); + Reference dqGrowthLimitApplied = new Reference<>(); + + float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); + + assertThat(gba, is(0.3194551f)); + assertTrue(dqGrowthLimitApplied.isPresent()); + assertThat(dqGrowthLimitApplied.get(), is(false)); + } + + @Test + void testEmpiricalOnlyModel() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 1); /* this value will force the empirical only calculations. */ + + float yabh = 54.0f; + float hd = 35.2999992f; + float ba = 45.3864441f; + float dq = 30.9988747f; + float growthInHd = 0.173380271f; + Optional v_ba_start = Optional.empty(); + Optional v_ba_end = Optional.empty(); + Reference dqGrowthLimitApplied = new Reference<>(); + + float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); + + assertThat(gba, is(0.30947846f)); + assertTrue(dqGrowthLimitApplied.isPresent()); + assertThat(dqGrowthLimitApplied.get(), is(false)); + } + + @Test + void testMixedModelWithInterpolation() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 2); + + float yabh = 104.0f; /* this value will force interpolation. */ + float hd = 35.2999992f; + float ba = 45.3864441f; + float dq = 30.9988747f; + float growthInHd = 0.173380271f; + Optional v_ba_start = Optional.empty(); + Optional v_ba_end = Optional.empty(); + Reference dqGrowthLimitApplied = new Reference<>(); + + float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); + + assertThat(gba, is(0.28309992f)); + assertTrue(dqGrowthLimitApplied.isPresent()); + assertThat(dqGrowthLimitApplied.get(), is(false)); + } + + @Test + void testMinimumApplied() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 0); + + float yabh = 54.0f; + float hd = 35.3f; + float ba = 45.3864441f; + float dq = 3.0f; /* this value will force the minimum test to kick in. */ + float growthInHd = 0.173380271f; + Optional v_ba_start = Optional.empty(); + Optional v_ba_end = Optional.empty(); + Reference dqGrowthLimitApplied = new Reference<>(); + + float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); + + assertThat(gba, is(4.6f)); + assertTrue(dqGrowthLimitApplied.isPresent()); + assertThat(dqGrowthLimitApplied.get(), is(false)); + } + + @Test + void testLimitApplied() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); + debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 0); + + float yabh = 54.0f; + float hd = 35.3f; + float ba = 45.3864441f; + float dq = 50.0f; /* this value will force the limit test to kick in. */ + float growthInHd = 0.173380271f; + Optional v_ba_start = Optional.empty(); + Optional v_ba_end = Optional.empty(); + Reference dqGrowthLimitApplied = new Reference<>(); + + float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); + + assertThat(gba, is(0.0f)); + assertTrue(dqGrowthLimitApplied.isPresent()); + assertThat(dqGrowthLimitApplied.get(), is(true)); + } +} diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java b/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java index 4ad1febc6..5b8ad767a 100644 --- a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java +++ b/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CommonCalculatorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CurveErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.NoAnswerException; @@ -22,7 +23,6 @@ import ca.bc.gov.nrs.vdyp.si32.enumerations.SpeciesRegion; import ca.bc.gov.nrs.vdyp.si32.vdyp.SP64Name; import ca.bc.gov.nrs.vdyp.si32.vdyp.VdypMethods; -import ca.bc.gov.nrs.vdyp.sindex.Reference; import ca.bc.gov.nrs.vdyp.sindex.Sindxdll; public class SiteTool { diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java b/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java index 5170a5a7e..4126c48ab 100644 --- a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java +++ b/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common_calculators.SiteIndexNames; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CommonCalculatorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.LessThan13Exception; @@ -32,7 +33,6 @@ import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; import ca.bc.gov.nrs.vdyp.si32.vdyp.SP64Name; import ca.bc.gov.nrs.vdyp.si32.vdyp.SpeciesTable; -import ca.bc.gov.nrs.vdyp.sindex.Reference; class SiteToolTest { diff --git a/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java b/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java index 681feca20..c1250ed18 100644 --- a/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java +++ b/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java @@ -26,6 +26,7 @@ import static ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexSpecies.SI_SPEC_SS; import static ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexSpecies.SI_SPEC_SW; +import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common_calculators.AgeToAge; import ca.bc.gov.nrs.vdyp.common_calculators.Height2SiteIndex; import ca.bc.gov.nrs.vdyp.common_calculators.SiteClassCode2SiteIndex; diff --git a/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java b/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java index 970907675..26aa01546 100644 --- a/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java +++ b/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java @@ -15,6 +15,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common_calculators.SiteIndexUtilities; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.AgeTypeErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.ClassErrorException; From c14532054263acd5a481fe2b516a08fd1eb361b3 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 23 Jul 2024 10:51:51 -0700 Subject: [PATCH 17/66] Component size parsing and representation changes --- .../io/parse/coe/ComponentSizeParser.java | 49 +++++++++++++++++-- .../coe/HLNonprimaryCoefficientParser.java | 32 ++++++++---- .../coe/base/SimpleCoefficientParser2.java | 2 - .../nrs/vdyp/model/ComponentSizeLimits.java | 9 ++++ .../vdyp/model/NonprimaryHLCoefficients.java | 5 ++ .../io/parse/coe/ComponentSizeParserTest.java | 4 +- 6 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java index 3485087b9..d1386d8cb 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java @@ -1,8 +1,15 @@ package ca.bc.gov.nrs.vdyp.io.parse.coe; +import java.util.Collection; +import java.util.List; + import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.io.parse.coe.base.SimpleCoefficientParser2; +import ca.bc.gov.nrs.vdyp.io.parse.coe.base.BaseCoefficientParser; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseValidException; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; import ca.bc.gov.nrs.vdyp.model.Region; /** @@ -22,20 +29,52 @@ * * All lines are read; there is no provision for blank lines. *

    - * The result is a {@link MatrixMap2} of coefficients (one-based), indexed first by BEC Zone and then Region. + * The result is a {@link MatrixMap2} of ComponentSizeLimits, indexed first by Species and then Region. *

    * FIP Control index: 061 *

    * Example file: coe/COMPLIM.COE * * @author Kevin Smith, Vivid Solutions - * @see SimpleCoefficientParser2 + * @see BaseCoefficientParser */ -public class ComponentSizeParser extends SimpleCoefficientParser2 { +public class ComponentSizeParser extends + BaseCoefficientParser> { public ComponentSizeParser() { - super(1, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT); + super(2, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT); this.speciesKey().space(1).regionKey().coefficients(4, 6); } + @SuppressWarnings("unchecked") + @Override + protected MatrixMap2 createMap(List> keyRanges) { + return new MatrixMap2Impl<>( + (Collection) keyRanges.get(0), (Collection) keyRanges.get(1), + (k1, k2) -> wrapCoefficients(getCoefficients()) + ); + } + + @Override + protected Coefficients getCoefficients(List coefficients) { + return new Coefficients(coefficients, 1); + } + + @Override + protected ComponentSizeLimits wrapCoefficients(Coefficients coefficients) { + return new ComponentSizeLimits( + coefficients.getCoe(1), coefficients.getCoe(2), coefficients.getCoe(3), coefficients.getCoe(4) + ); + } + + @Override + protected void + validate(MatrixMap2 result, int parsed, List> keyRanges) + throws ResourceParseValidException { + var expected = keyRanges.stream().mapToInt(Collection::size).reduce(1, (x, y) -> x * y); + if (expected != parsed) { + throw new ResourceParseValidException("Expected " + expected + " records but there were " + parsed); + } + } + } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java index 17c6d4278..f5ef6e8aa 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStream; +import java.text.MessageFormat; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -24,8 +25,8 @@ * This file contains a (possibly incomplete) mapping of species aliases x species aliases x regions to a * (one-based) list of two coefficients. Each row contains: *

      - *
    1. (cols 0-1) species alias #1
    2. - *
    3. (cols 3-4) species alias #2
    4. + *
    5. (cols 0-1) non-primary species alias
    6. + *
    7. (cols 3-4) primary species alias
    8. *
    9. (col 6) region character ('I' or 'C')
    10. *
    11. (col 8) an equation number
    12. *
    13. (cols 9-18, 19-28) two coefficients
    14. @@ -47,8 +48,8 @@ public class HLNonprimaryCoefficientParser public static final int NUM_COEFFICIENTS = 2; - public static final String SPECIES_1_KEY = "species1"; - public static final String SPECIES_2_KEY = "species2"; + public static final String NON_PRIMARY_SPECIES_KEY = "nonPrimarySpecies"; + public static final String PRIMARY_SPECIES_KEY = "primarySpecies"; public static final String REGION_KEY = "region"; public static final String EQUATION_KEY = "ieqn"; public static final String COEFFICIENT_KEY = "coefficient"; @@ -62,8 +63,10 @@ public boolean isIgnoredLine(String line) { return (line.length() < 6 && line.isBlank()) || line.substring(0, 6).isBlank(); } - }.value(2, SPECIES_1_KEY, ValueParser.STRING).space(1).value(2, SPECIES_2_KEY, ValueParser.STRING).space(1) - .value(1, REGION_KEY, ValueParser.REGION).space(1).integer(1, EQUATION_KEY) + }.value(2, NON_PRIMARY_SPECIES_KEY, ValueParser.STRING).space(1) // + .value(2, PRIMARY_SPECIES_KEY, ValueParser.STRING).space(1) // + .value(1, REGION_KEY, ValueParser.REGION).space(1) // + .integer(1, EQUATION_KEY) // .multiValue(NUM_COEFFICIENTS, 10, COEFFICIENT_KEY, ValueParser.FLOAT); } @@ -80,9 +83,9 @@ public boolean isIgnoredLine(String line) { ); lineParser.parse(is, result, (value, r, line) -> { @SuppressWarnings("java:S117") - var sp0_1 = (String) value.get(SPECIES_1_KEY); + var sp0_1 = (String) value.get(NON_PRIMARY_SPECIES_KEY); @SuppressWarnings("java:S117") - var sp0_2 = (String) value.get(SPECIES_2_KEY); + var sp0_2 = (String) value.get(PRIMARY_SPECIES_KEY); var ieqn = (Integer) value.get(EQUATION_KEY); var region = (Region) value.get(REGION_KEY); @SuppressWarnings("unchecked") @@ -91,8 +94,19 @@ public boolean isIgnoredLine(String line) { GenusDefinitionParser.checkSpecies(speciesIndicies, sp0_2); if (coefficients.size() < NUM_COEFFICIENTS) { - throw new ValueParseException(null, "Expected 2 coefficients"); // TODO handle this better + throw new ValueParseException( + MessageFormat.format("{0}, {1}, {2}", sp0_1, sp0_2, region), + "Expected 2 coefficients but saw " + coefficients.size() + ); } + + if (ieqn != 1 && ieqn != 2) { + throw new ValueParseException( + MessageFormat.format("{0}, {1}, {2}", sp0_1, sp0_2, region), + "Equation number " + ieqn + " is not 1 or 2" + ); + } + r.put(sp0_1, sp0_2, region, Optional.of(new NonprimaryHLCoefficients(coefficients, ieqn))); return r; diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java index 413490907..c0403d0d1 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java @@ -44,7 +44,5 @@ protected void validate(MatrixMap2 result, int parsed, Lis if (expected != parsed) { throw new ResourceParseValidException("Expected " + expected + " records but there were " + parsed); } - } - } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java new file mode 100644 index 000000000..de9900227 --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java @@ -0,0 +1,9 @@ +package ca.bc.gov.nrs.vdyp.model; + +public record ComponentSizeLimits( + float loreyHeightMaximum, // + float quadMeanDiameterMaximum, // + float minQuadMeanDiameterLoreyHeightRatio, // + float maxQuadMeanDiameterLoreyHeightRatio +) { +} diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java index bab758b1b..5978f320b 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java @@ -20,4 +20,9 @@ public int getEquationIndex() { return equationIndex; } + private static final NonprimaryHLCoefficients DEFAULT_VALUE = new NonprimaryHLCoefficients(new float[] { 1.0f, 1.0f }, 2); + + public static final NonprimaryHLCoefficients getDefault() { + return DEFAULT_VALUE; + } } diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java index 5c5894041..c35b05f65 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java @@ -4,6 +4,7 @@ import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.mmHasEntry; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.HashMap; @@ -12,6 +13,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseLineException; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.test.TestUtils; @@ -35,7 +37,7 @@ void testParseSimpleP1() throws Exception { var result = parser.parse(is, controlMap); - assertThat(result, mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "S1", Region.COASTAL)); + assertThat(result, mmHasEntry(is(new ComponentSizeLimits(49.4f, 153.3f, 0.726f, 3.647f)), "S1", Region.COASTAL)); } @Test From 672f0a35001db0feaf513bedd8ce6aab14988493 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 23 Jul 2024 10:53:05 -0700 Subject: [PATCH 18/66] Reimplementation of CompVarAdjustments for usability --- .../nrs/vdyp/model/CompVarAdjustments.java | 148 +++++++++++------- .../parse/CompVarAdjustmentsParserTest.java | 79 +++++----- 2 files changed, 131 insertions(+), 96 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java index 0ee34f9ba..675d8312d 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java @@ -1,93 +1,121 @@ package ca.bc.gov.nrs.vdyp.model; +import java.text.MessageFormat; import java.util.HashMap; import java.util.Map; -import java.util.Set; public class CompVarAdjustments { public static final int MIN_INDEX = 1; public static final int MAX_INDEX = 98; - public static final int SMALL_BA = 1; - public static final int SMALL_DQ = 2; - public static final int SMALL_HL = 3; - public static final int SMALL_VOL = 4; - - public static final int LOREY_HEIGHT_PRIMARY_PARAM = 51; - public static final int LOREY_HEIGHT_OTHER_PARAM = 52; - - private static final Set validNamedParams = Set - .of(SMALL_BA, SMALL_DQ, SMALL_HL, SMALL_VOL, LOREY_HEIGHT_PRIMARY_PARAM, LOREY_HEIGHT_OTHER_PARAM); + private static final int SMALL_VARIABLE_START_INDEX = 1; private static final int BA_ADJ_UC_START_INDEX = 5; - private static final int DQ_ADJ_UC_START_INDEX = 15; - private static final int UC_VOL_START_INDEX = 11; - - private static final int WHOLE_STEM_VOL_OFFSET = 0; - private static final int CLOSE_UTIL_VOL_OFFSET = 1; - private static final int CLOSE_UTIL_VOL_LESS_DECAY_OFFSET = 2; - private static final int CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTE_OFFSET = 3; - - private Map values; - + private static final int LOREY_HEIGHT_PRIMARY_PARAM = 51; + private static final int LOREY_HEIGHT_OTHER_PARAM = 52; + + private final Map smallUtilizationClassVariables = new HashMap<>(); + private final Map utilizationClassBasalAreaVariables = new HashMap<>(); + private final Map utilizationClassQuadMeanDiameterVariables = new HashMap<>(); + private final MatrixMap2 utilizationClassVolumeVariables + = new MatrixMap2Impl<>(VolumeVariable.ALL, UtilizationClass.UTIL_CLASSES, (k1, k2) -> 1.0f); + + private float loreyHeightPrimary; + private float loreyHeightOther; + + static { + assert UtilizationClassVariable.BASAL_AREA.ordinal() == 0; + assert UtilizationClassVariable.QUAD_MEAN_DIAMETER.ordinal() == 1; + assert UtilizationClassVariable.LOREY_HEIGHT.ordinal() == 2; + assert UtilizationClassVariable.WHOLE_STEM_VOLUME.ordinal() == 3; + + assert UtilizationClass.U75TO125.ordinal() == 2; + assert UtilizationClass.U125TO175.ordinal() == 3; + assert UtilizationClass.U175TO225.ordinal() == 4; + assert UtilizationClass.OVER225.ordinal() == 5; + + assert VolumeVariable.WHOLE_STEM_VOL.ordinal() == 0; + assert VolumeVariable.CLOSE_UTIL_VOL.ordinal() == 1; + assert VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY.ordinal() == 2; + assert VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE.ordinal() == 3; + } + + private final static Map ucOffsets = new HashMap<>(); + private final static Map defaultValuesMap = new HashMap<>(); + + static { + ucOffsets.put(UtilizationClass.U75TO125, 11); + ucOffsets.put(UtilizationClass.U125TO175, 21); + ucOffsets.put(UtilizationClass.U175TO225, 31); + ucOffsets.put(UtilizationClass.OVER225, 41); + + for (int i = MIN_INDEX; i <= MAX_INDEX; i++) + defaultValuesMap.put(i, 1.0f); + } + /** * Constructs a default instance, one in which all index values are 1.0f. See rd_e028.for. */ public CompVarAdjustments() { - values = new HashMap<>(); - for (int i = MIN_INDEX; i <= MAX_INDEX; i++) - values.put(i, 1.0f); + this(defaultValuesMap); } /** * Constructs an instance from a data set. */ public CompVarAdjustments(Map values) { - this.values = new HashMap<>(values); - } - - public Float getParam(int paramNumber) { - if (!validNamedParams.contains(paramNumber)) - throw new IllegalArgumentException("paramNumber (" + paramNumber + ") is not a valid named parameter"); - - return values.get(paramNumber); - } - - public Float getBaUcAdjustment(UtilizationClass uc) { - validateUc(uc); - return values.get(BA_ADJ_UC_START_INDEX + uc.index - 1); - } - public Float getDqUcAdjustment(UtilizationClass uc) { - validateUc(uc); - return values.get(DQ_ADJ_UC_START_INDEX + uc.index - 1); + for (UtilizationClassVariable ucv: UtilizationClassVariable.values()) { + smallUtilizationClassVariables.put(ucv, values.get(SMALL_VARIABLE_START_INDEX + ucv.ordinal())); + } + + for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + utilizationClassBasalAreaVariables.put(uc, values.get(BA_ADJ_UC_START_INDEX + uc.ordinal() - 2)); + } + + for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + utilizationClassQuadMeanDiameterVariables.put(uc, values.get(DQ_ADJ_UC_START_INDEX + uc.ordinal() - 2)); + } + + for (VolumeVariable vv: VolumeVariable.ALL) { + for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + utilizationClassVolumeVariables.put(vv, uc, values.get(ucOffsets.get(uc) + vv.ordinal())); + } + } + + loreyHeightPrimary = values.get(LOREY_HEIGHT_PRIMARY_PARAM); + loreyHeightOther = values.get(LOREY_HEIGHT_OTHER_PARAM); } - public Float getWholeStemVolumeAdjustment(UtilizationClass uc) { - validateUc(uc); - return values.get(UC_VOL_START_INDEX + (10 * (uc.index - 1)) + WHOLE_STEM_VOL_OFFSET); + public float getLoreyHeightPrimaryParam() { + return loreyHeightPrimary; } - public Float getCloseUtilVolumeAdjustment(UtilizationClass uc) { - validateUc(uc); - return values.get(UC_VOL_START_INDEX + (10 * (uc.index - 1)) + CLOSE_UTIL_VOL_OFFSET); + public float getLoreyHeightOther() { + return loreyHeightOther; } - - public Float getCloseUtilLessDecayVolumeAdjustment(UtilizationClass uc) { - validateUc(uc); - return values.get(UC_VOL_START_INDEX + (10 * (uc.index - 1)) + CLOSE_UTIL_VOL_LESS_DECAY_OFFSET); + + public float getValue(UtilizationClass uc, UtilizationClassVariable v) { + if (UtilizationClass.SMALL.equals(uc)) { + return smallUtilizationClassVariables.get(v); + } else if (!UtilizationClass.ALL.equals(uc)) { + switch (v) { + case BASAL_AREA: return utilizationClassBasalAreaVariables.get(uc); + case QUAD_MEAN_DIAMETER: return utilizationClassQuadMeanDiameterVariables.get(uc); + default: break; + } + } + + throw new IllegalArgumentException(MessageFormat.format("getValue({}, {}) - combination of UtilizationClass and UtilizationClassVariable is invalid", uc, v)); } + + public float getVolumeValue(UtilizationClass uc, VolumeVariable vv) { + if (uc.ordinal() >= UtilizationClass.U75TO125.ordinal()) { + return utilizationClassVolumeVariables.get(vv, uc); + } - public Float getCloseUtilLessDecayLessWasteVolumeAdjustment(UtilizationClass uc) { - validateUc(uc); - return values.get(UC_VOL_START_INDEX + (10 * (uc.index - 1)) + CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTE_OFFSET); - } - - private void validateUc(UtilizationClass uc) { - if (uc == UtilizationClass.SMALL || uc == UtilizationClass.ALL) - throw new IllegalArgumentException("UC (" + uc + ") is not a specific UC other than SMALL"); - + throw new IllegalArgumentException(MessageFormat.format("getVolumeValue({}, {}) - UtilizationClass is invalid", uc, vv)); } } diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java index 8663be729..598e5a9ec 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java @@ -3,6 +3,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.HashMap; import java.util.Map; @@ -14,6 +15,8 @@ import ca.bc.gov.nrs.vdyp.io.parse.coe.CompVarAdjustmentsParser; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; +import ca.bc.gov.nrs.vdyp.model.VolumeVariable; import ca.bc.gov.nrs.vdyp.test.TestUtils; /** @@ -64,42 +67,46 @@ void testParseSimple() throws Exception { CompVarAdjustments m = (CompVarAdjustments) controlMap.get(ControlKey.PARAM_ADJUSTMENTS.name()); - assertThat(m.getParam(CompVarAdjustments.SMALL_BA), is(0.50f)); - assertThat(m.getParam(CompVarAdjustments.SMALL_DQ), is(0.51f)); - assertThat(m.getParam(CompVarAdjustments.SMALL_HL), is(0.52f)); - assertThat(m.getParam(CompVarAdjustments.SMALL_VOL), is(0.53f)); - assertThat(m.getParam(CompVarAdjustments.LOREY_HEIGHT_PRIMARY_PARAM), is(0.80f)); - assertThat(m.getParam(CompVarAdjustments.LOREY_HEIGHT_OTHER_PARAM), is(0.81f)); - - assertThat(m.getBaUcAdjustment(UtilizationClass.U75TO125), is(0.54f)); - assertThat(m.getBaUcAdjustment(UtilizationClass.U125TO175), is(0.55f)); - assertThat(m.getBaUcAdjustment(UtilizationClass.U175TO225), is(0.56f)); - assertThat(m.getBaUcAdjustment(UtilizationClass.OVER225), is(0.57f)); - - assertThat(m.getDqUcAdjustment(UtilizationClass.U75TO125), is(0.58f)); - assertThat(m.getDqUcAdjustment(UtilizationClass.U125TO175), is(0.59f)); - assertThat(m.getDqUcAdjustment(UtilizationClass.U175TO225), is(0.60f)); - assertThat(m.getDqUcAdjustment(UtilizationClass.OVER225), is(0.61f)); - - assertThat(m.getWholeStemVolumeAdjustment(UtilizationClass.U75TO125), is(0.91f)); - assertThat(m.getWholeStemVolumeAdjustment(UtilizationClass.U125TO175), is(0.92f)); - assertThat(m.getWholeStemVolumeAdjustment(UtilizationClass.U175TO225), is(0.93f)); - assertThat(m.getWholeStemVolumeAdjustment(UtilizationClass.OVER225), is(0.94f)); - - assertThat(m.getCloseUtilVolumeAdjustment(UtilizationClass.U75TO125), is(0.92f)); - assertThat(m.getCloseUtilVolumeAdjustment(UtilizationClass.U125TO175), is(0.93f)); - assertThat(m.getCloseUtilVolumeAdjustment(UtilizationClass.U175TO225), is(0.94f)); - assertThat(m.getCloseUtilVolumeAdjustment(UtilizationClass.OVER225), is(0.95f)); - - assertThat(m.getCloseUtilLessDecayVolumeAdjustment(UtilizationClass.U75TO125), is(0.93f)); - assertThat(m.getCloseUtilLessDecayVolumeAdjustment(UtilizationClass.U125TO175), is(0.94f)); - assertThat(m.getCloseUtilLessDecayVolumeAdjustment(UtilizationClass.U175TO225), is(0.95f)); - assertThat(m.getCloseUtilLessDecayVolumeAdjustment(UtilizationClass.OVER225), is(0.96f)); - - assertThat(m.getCloseUtilLessDecayLessWasteVolumeAdjustment(UtilizationClass.U75TO125), is(0.94f)); - assertThat(m.getCloseUtilLessDecayLessWasteVolumeAdjustment(UtilizationClass.U125TO175), is(0.95f)); - assertThat(m.getCloseUtilLessDecayLessWasteVolumeAdjustment(UtilizationClass.U175TO225), is(0.96f)); - assertThat(m.getCloseUtilLessDecayLessWasteVolumeAdjustment(UtilizationClass.OVER225), is(0.97f)); + assertThat(m.getValue(UtilizationClass.SMALL, UtilizationClassVariable.BASAL_AREA), is(0.50f)); + assertThat(m.getValue(UtilizationClass.SMALL, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.51f)); + assertThat(m.getValue(UtilizationClass.SMALL, UtilizationClassVariable.LOREY_HEIGHT), is(0.52f)); + assertThat(m.getValue(UtilizationClass.SMALL, UtilizationClassVariable.WHOLE_STEM_VOLUME), is(0.53f)); + assertThat(m.getLoreyHeightPrimaryParam(), is(0.80f)); + assertThat(m.getLoreyHeightOther(), is(0.81f)); + + assertThat(m.getValue(UtilizationClass.U75TO125, UtilizationClassVariable.BASAL_AREA), is(0.54f)); + assertThat(m.getValue(UtilizationClass.U125TO175, UtilizationClassVariable.BASAL_AREA), is(0.55f)); + assertThat(m.getValue(UtilizationClass.U175TO225, UtilizationClassVariable.BASAL_AREA), is(0.56f)); + assertThat(m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.BASAL_AREA), is(0.57f)); + + assertThat(m.getValue(UtilizationClass.U75TO125, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.58f)); + assertThat(m.getValue(UtilizationClass.U125TO175, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.59f)); + assertThat(m.getValue(UtilizationClass.U175TO225, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.60f)); + assertThat(m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.61f)); + + assertThrows(IllegalArgumentException.class, () -> m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.LOREY_HEIGHT)); + assertThrows(IllegalArgumentException.class, () -> m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.WHOLE_STEM_VOLUME)); + assertThrows(IllegalArgumentException.class, () -> m.getValue(UtilizationClass.ALL, UtilizationClassVariable.BASAL_AREA)); + + assertThat(m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.WHOLE_STEM_VOL), is(0.91f)); + assertThat(m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.WHOLE_STEM_VOL), is(0.92f)); + assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.WHOLE_STEM_VOL), is(0.93f)); + assertThat(m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.WHOLE_STEM_VOL), is(0.94f)); + + assertThat(m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.CLOSE_UTIL_VOL), is(0.92f)); + assertThat(m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.CLOSE_UTIL_VOL), is(0.93f)); + assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.CLOSE_UTIL_VOL), is(0.94f)); + assertThat(m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.CLOSE_UTIL_VOL), is(0.95f)); + + assertThat(m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY), is(0.93f)); + assertThat(m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY), is(0.94f)); + assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY), is(0.95f)); + assertThat(m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY), is(0.96f)); + + assertThat(m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.94f)); + assertThat(m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.95f)); + assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.96f)); + assertThat(m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.97f)); } @Test From dcd7725dfe9d61503acbef9ac468a9e33d8f9bf1 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 23 Jul 2024 10:53:39 -0700 Subject: [PATCH 19/66] UtilizationClass changes for usability --- .../vdyp/model/SmallUtilizationClassVariable.java | 5 ----- .../ca/bc/gov/nrs/vdyp/model/UtilizationClass.java | 11 +++++------ .../gov/nrs/vdyp/model/UtilizationClassVariable.java | 12 ++++++++++++ 3 files changed, 17 insertions(+), 11 deletions(-) delete mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SmallUtilizationClassVariable.java create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SmallUtilizationClassVariable.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SmallUtilizationClassVariable.java deleted file mode 100644 index 798087f7d..000000000 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SmallUtilizationClassVariable.java +++ /dev/null @@ -1,5 +0,0 @@ -package ca.bc.gov.nrs.vdyp.model; - -public enum SmallUtilizationClassVariable { - BASAL_AREA, QUAD_MEAN_DIAMETER, LOREY_HEIGHT, WHOLE_STEM_VOLUME; -} diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java index de30f1120..cb94e2ee1 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java @@ -1,7 +1,5 @@ package ca.bc.gov.nrs.vdyp.model; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -23,13 +21,14 @@ public enum UtilizationClass { private Optional next = Optional.empty(); private Optional previous = Optional.empty(); - public static final Collection UTIL_CLASSES = List.of(U75TO125, U125TO175, U175TO225, OVER225); + public static final Collection UTIL_CLASSES = Collections + .unmodifiableList(List.of(U75TO125, U125TO175, U175TO225, OVER225)); public static final Collection ALL_BUT_SMALL = Collections - .unmodifiableList(new ArrayList<>(Arrays.asList(ALL, U75TO125, U125TO175, U175TO225, OVER225))); + .unmodifiableList(List.of(ALL, U75TO125, U125TO175, U175TO225, OVER225)); - public static final Collection ALL_BUT_SMALL_ALL = Collections - .unmodifiableList(new ArrayList<>(Arrays.asList(U75TO125, U125TO175, U175TO225, OVER225))); + public static final Collection ALL_CLASSES = Collections + .unmodifiableList(List.of(SMALL, U75TO125, U125TO175, U175TO225, OVER225)); static { for (int i = 1; i < UtilizationClass.values().length; i++) { diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java new file mode 100644 index 000000000..bd359dae9 --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java @@ -0,0 +1,12 @@ +package ca.bc.gov.nrs.vdyp.model; + +import java.util.Collections; +import java.util.List; + +public enum UtilizationClassVariable { + BASAL_AREA, QUAD_MEAN_DIAMETER, LOREY_HEIGHT, WHOLE_STEM_VOLUME; + + public static final List ALL = Collections.unmodifiableList( + List.of(BASAL_AREA, QUAD_MEAN_DIAMETER, LOREY_HEIGHT, WHOLE_STEM_VOLUME) + ); +} From 43ca25cd666b5548a87fa8a8a7c9053dbd952466 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 23 Jul 2024 10:54:58 -0700 Subject: [PATCH 20/66] Next grow steps --- .../vdyp/forward/ForwardProcessingEngine.java | 1120 +++++++++++++++-- .../vdyp/forward/PolygonProcessingState.java | 66 +- .../controlmap/ForwardResolvedControlMap.java | 24 + .../ForwardResolvedControlMapImpl.java | 54 +- .../forward/ForwardControlParserTest.java | 4 +- ...yVariablesForwardProcessingEngineTest.java | 8 +- 6 files changed, 1113 insertions(+), 163 deletions(-) diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 7bdbb7f96..057d2fd97 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -43,19 +43,25 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CommonData; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDistribution; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.MatrixMap3Impl; +import ca.bc.gov.nrs.vdyp.model.ModelCoefficients; +import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; -import ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; +/** + * + */ public class ForwardProcessingEngine { private static final Logger logger = LoggerFactory.getLogger(ForwardProcessor.class); @@ -256,7 +262,6 @@ private void grow( // Call to BANKOUT1 unnecessary; pps.wallet already contains the primary layer - Bank primaryBank = fps.getBank(primaryLayerSourceInstance, LayerType.PRIMARY); Optional veteranBank = Optional.ofNullable(fps.getBank(veteranLayerInstance, LayerType.VETERAN)); // If update-during-growth is set, and this is not the starting year, update the @@ -272,16 +277,16 @@ private void grow( calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); } - float dominantHeight = pps.getPrimarySpeciesDominantHeight(); + float dhStart = pps.getPrimarySpeciesDominantHeight(); int siteCurveNumber = pps.getSiteCurveNumber(pps.getPrimarySpeciesIndex()); float siteIndex = pps.getPrimarySpeciesSiteIndex(); - float yearsToBreastHeight = pps.getPrimarySpeciesAgeToBreastHeight(); - float primarySpeciesYearsAtBreastHeight = pps.getPrimarySpeciesAgeAtBreastHeight(); + float ytbhStart = pps.getPrimarySpeciesAgeToBreastHeight(); + float primarySpeciesYearsAtBreastHeightStart = pps.getPrimarySpeciesAgeAtBreastHeight(); // Calculate change in dominant height - float growthInDominantHeight = growDominantHeight( - dominantHeight, siteCurveNumber, siteIndex, yearsToBreastHeight + float dhDelta = growDominantHeight( + dhStart, siteCurveNumber, siteIndex, ytbhStart ); // Calculate change in basal area @@ -293,19 +298,844 @@ private void grow( veteranLayerBasalArea = Optional.empty(); } - float basalAreaAtStartOfPeriod = primaryBank.basalAreas[0][UC_ALL_INDEX]; - float growthInBasalArea = growBasalArea( - primarySpeciesYearsAtBreastHeight, fps.fcm - .getDebugSettings(), dominantHeight, basalAreaAtStartOfPeriod, veteranLayerBasalArea, growthInDominantHeight + float baStart = pps.wallet.basalAreas[0][UC_ALL_INDEX]; + float baDelta = growBasalArea( + primarySpeciesYearsAtBreastHeightStart, fps.fcm + .getDebugSettings(), dhStart, baStart, veteranLayerBasalArea, dhDelta ); - float qmdAtStartOfGrowthPeriod = primaryBank.quadMeanDiameters[0][UC_ALL_INDEX]; - float primaryLayerBasalArea = primaryBank.basalAreas[0][UC_ALL_INDEX]; - Reference dqGrowthLimitApplied = new Reference<>(); - float growthInQuadMeanDiameter = growQuadMeanDiameter( - yearsToBreastHeight, primaryLayerBasalArea, dominantHeight, qmdAtStartOfGrowthPeriod, veteranLayerBasalArea, - veteranLayerBasalArea, growthInDominantHeight, dqGrowthLimitApplied + float dqStart = pps.wallet.quadMeanDiameters[0][UC_ALL_INDEX]; + Reference wasDqGrowthLimitApplied = new Reference<>(); + float dqDelta = growQuadMeanDiameter( + ytbhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied ); + + if (wasDqGrowthLimitApplied.get() /* is true */) { + // Limit BA growth if DQ hit limit. + float qmdEndOfGrowthPeriod = dqStart + dqDelta; + float baMax = baStart * (qmdEndOfGrowthPeriod * qmdEndOfGrowthPeriod + / dqStart * dqStart); + baDelta = Math.min(baDelta, baMax - baStart); + } + + // Cache some values for calculations below. + + float baGrowthRate = baDelta / baStart; + float dhMultiplier = dhStart + dhDelta / dhStart; + + float primarySpeciesLhStart = pps.wallet.loreyHeights[pps.getPrimarySpeciesGroupNumber()][UC_ALL_INDEX]; + float primarySpeciesTphStart = pps.wallet.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float tphStart = pps.wallet.treesPerHectare[0][UC_ALL_INDEX]; + + float dhEnd = dhStart + dhDelta; + float dqEnd = dqStart + dqDelta; + float baEnd = baStart + baDelta; + float tphEnd = calculateTreesPerHectare(baEnd, dqEnd); + float tphMultiplier = tphEnd / tphStart; + + // Begin storing computed results + pps.wallet.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; + pps.wallet.basalAreas[0][UC_ALL_INDEX] = baEnd; + pps.wallet.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; + + // Now do DQ growth by species, using one of several options: "full species", "dynamic", "partial dynamics" + // or "no dynamics." + int debugSetting1Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1); + + boolean wasSolutionFound = false; + if (debugSetting1Value == 2) { + // This is the partial species dynamics section. + + // Begin by updating HL for all species (save the ungrown HLs). + float[] currentLoreyHeights = new float[pps.wallet.getNSpecies() + 1]; + for (int i = 1; i < pps.wallet.getNSpecies(); i++) { + currentLoreyHeights[i] = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + } + + float primarySpeciesTphEndEstimate = primarySpeciesTphStart * (tphEnd / tphStart); + + growLoreyHeights( + dhStart, dhEnd, primarySpeciesTphStart, primarySpeciesTphEndEstimate, primarySpeciesLhStart + ); + + float sum1 = 0.0f; + float sum2 = 0.0f; + + for (int i = 1; i <= pps.getNSpecies(); i++) { + sum1 += pps.wallet.basalAreas[i][UC_ALL_INDEX] * pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + sum2 += pps.wallet.basalAreas[i][UC_ALL_INDEX]; + } + + pps.wallet.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; + + // Now do the actual updates of DQ by species + wasSolutionFound = growUsingPartialSpeciesDynamics(); + + // Restore the Lorey Heights back to the values at the beginning of the period. + // They will be updated below using the new estimate of TPH-primary species. + for (int i = 1; i < pps.wallet.getNSpecies(); i++) { + pps.wallet.loreyHeights[i][UC_ALL_INDEX] = currentLoreyHeights[i]; + } + } else { + if (debugSetting1Value == 1 || pps.wallet.getNSpecies() == 1 || !wasSolutionFound) { + // No species dynamics section + growUsingNoSpeciesDynamics(baGrowthRate, tphMultiplier); + } else { + // Full species dynamics section + growUsingFullSpeciesDynamics(dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); + } + } + + // Calculate trees-per-hectare over all species + float totalTreesPerHectare = 0.0f; + for (int i = 1; i < pps.wallet.getNSpecies(); i++) { + if (pps.wallet.basalAreas[i][UC_ALL_INDEX] > 0.0f) { + totalTreesPerHectare += pps.wallet.treesPerHectare[i][UC_ALL_INDEX]; + } + } + pps.wallet.treesPerHectare[0][0] = totalTreesPerHectare; + + // Calculate quad-mean-diameter for all species. + pps.wallet.quadMeanDiameters[0][0] = calculateQuadMeanDiameter( + pps.wallet.basalAreas[0][0], pps.wallet.treesPerHectare[0][0] + ); + + growLoreyHeightsForAllSpecies(); + + // We now have predications for basal area, quad-mean-diameter, trees-per-hectare and Lorey height. + + // Calculate basal area percentages per species + for (int i = 1; i < pps.wallet.getNSpecies(); i++) { + pps.wallet.percentagesOfForestedLand[i] = 100.0f * pps.wallet.basalAreas[i][UC_ALL_INDEX] + / pps.wallet.basalAreas[0][UC_ALL_INDEX]; + } + + // Update the running values. TODO: why isn't siteIndex being updated? + pps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); + + for (int i = 1; i < pps.wallet.getNSpecies(); i++) { + if (i == pps.getPrimarySpeciesIndex()) { + pps.wallet.ageTotals[i] = pps.getPrimarySpeciesTotalAge(); + pps.wallet.dominantHeights[i] = dhEnd; + pps.wallet.siteIndices[i] = pps.getPrimarySpeciesSiteIndex(); + pps.wallet.yearsAtBreastHeight[i] = pps.getPrimarySpeciesAgeAtBreastHeight(); + } else { + float speciesSiStart = pps.wallet.siteIndices[i]; + float speciesDhStart = pps.wallet.dominantHeights[i]; + float speciesYtbhStart = pps.wallet.yearsToBreastHeight[i]; + float speciesYabhStart = pps.wallet.yearsAtBreastHeight[i]; + + if (!Float.isNaN(speciesSiStart) && !Float.isNaN(speciesDhStart) + && !Float.isNaN(speciesYtbhStart) && !Float.isNaN(speciesYabhStart)) { + + float dhGrowth = growDominantHeight( + speciesDhStart, siteCurveNumber, pps.wallet.siteCurveNumbers[i], speciesYtbhStart + ); + pps.wallet.dominantHeights[i] += dhGrowth; + } else { + pps.wallet.dominantHeights[i] = Float.NaN; + } + } + } + + pps.updateCompatibilityVariableAfterGrowth(); + + computeUtilizationComponentsPrimary(); + + calculateSmallComponentYields(); + } + + private void growUsingNoSpeciesDynamics(float baGrowthRate, float tphMultiplier) { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + for (int i : pps.getIndices()) { + + float spBaAllStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + if (spBaAllStart > 0.0f) { + float spBaAllEnd = spBaAllStart * (1.0f * baGrowthRate); + + float spTphAllStart = pps.wallet.treesPerHectare[i][UC_ALL_INDEX]; + float spTphAllEnd = spTphAllStart * tphMultiplier; + float spDqAllEnd = calculateQuadMeanDiameter(spBaAllEnd, spTphAllEnd); + if (spDqAllEnd < 7.51f) { + spDqAllEnd = 7.51f; + spTphAllEnd = calculateTreesPerHectare(spBaAllEnd, spDqAllEnd); + } + + pps.wallet.basalAreas[i][UC_ALL_INDEX] = spBaAllEnd; + pps.wallet.treesPerHectare[i][UC_ALL_INDEX] = spTphAllEnd; + pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX] = spDqAllEnd; + } + } + } + + private boolean growUsingPartialSpeciesDynamics() { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + boolean wasSuccessful = true; + + return wasSuccessful; + } + + private void growUsingFullSpeciesDynamics( + float dqDelta, float baDelta, float baStart, float dqStart, + float tphStart, float lhStart + ) throws ProcessingException { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + float spBaEnd[] = new float[pps.getNSpecies() + 1]; + float spTphNew[] = new float[pps.getNSpecies() + 1]; + float spDqNew[] = new float[pps.getNSpecies() + 1]; + boolean doSkip[] = new boolean[pps.getNSpecies() + 1]; + + for (int i : pps.getIndices()) { + spBaEnd[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + spTphNew[i] = pps.wallet.treesPerHectare[i][UC_ALL_INDEX]; + spDqNew[i] = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; + + doSkip[i] = false; + } + + float sumSpBaDelta = 0.0f; + float spBaDelta[] = new float[pps.getNSpecies()]; + + for (int i : pps.getIndices()) { + float pspLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + if (i == pps.getPrimarySpeciesIndex()) { + float pspBaStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + float pspYabhStart = pps.getPrimarySpeciesAgeAtBreastHeight(); + + // Note: the FORTRAN passes Lorey height into parameter "HD" ("Dominant Height") - are these + // equivalent? + spBaDelta[i] = growBasalAreaForPrimarySpecies( + baStart, baDelta, pspBaStart, lhStart, pspYabhStart, pspLhStart + ); + } else { + float spBaStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + float spDqStart = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; + float spLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + spBaDelta[i] = growBasalAreaForNonPrimarySpecies( + i, baStart, baDelta, pspLhStart, spBaStart, spDqStart, spLhStart + ); + } + + sumSpBaDelta += spBaDelta[i]; + } + + { + // Estimates of basal area growth by species + + // Iteratively attempt to find a value f such that: + // + // if revised spBaDelta = spBaStart * (f + spBaDelta / spBaStart) + // then sum(revised spBaDelta) = baDelta + // + // for all species whose basal area after growth is non-negative. + + var baBase = baStart; + var passNumber = 0; + + while (true) { + + var f = (baDelta - sumSpBaDelta) / baBase; + + int nSkipped = 0; + sumSpBaDelta = 0.0f; + + for (int i : pps.getIndices()) { + if (!doSkip[i]) { + var spBaStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + spBaEnd[i] = spBaStart + spBaDelta[i] + f * spBaStart; + if (spBaEnd[i] < 0.0f) { + spBaEnd[i] = 0.0f; + doSkip[i] = true; + nSkipped += 1; + sumSpBaDelta -= spBaStart; + baBase -= spBaStart; + } else { + sumSpBaDelta += spBaEnd[i] - spBaStart; + } + } + } + + if (nSkipped == 0) { + break; + } + + passNumber += 1; + if (passNumber > 5 || baBase <= 0.0f) { + throw new ProcessingException( + MessageFormat.format( + "Unable to converge on a value for \"f\" in" + + " growUsingFullSpeciesDynamics({0}, {1}, {2}, {3}, {4}, {5})", dqDelta, baDelta, baStart, dqStart, tphStart, lhStart + ) + ); + } + } + } + + { + while (true) { + // Base estimates of DQ growth by species + var f = 0.0f; + var passNumber = 0; + var nSkipped = 0; + var totalBasalAreaSkipped = 0.0f; + var bestScore = 1000.0; + var bestF = Float.NaN; + + for (int i : pps.getIndices()) { + float spDqStart = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; + float spLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + + float spDqDelta; + if (i == pps.getPrimarySpeciesIndex()) { + + spDqDelta = growQuadMeanDiameterForPrimarySpecies( + dqStart, dqDelta, spDqStart, lhStart, spLhStart + ); + } else { + spDqDelta = growQuadMeanDiameterForNonPrimarySpecies( + i, dqStart, dqDelta, spDqStart, lhStart, spLhStart + ); + } + + spDqDelta += f; + + ComponentSizeLimits csl = getComponentSizeLimits(pps.wallet.speciesNames[i], pps.getBecZone().getRegion()); + + var spLhAllStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + + float spDqMaximum = Math.min(csl.quadMeanDiameterMaximum(), csl.maxQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); + + if (spDqStart + spDqDelta > spDqMaximum) { + spDqDelta = Math.min(0.0f, spDqMaximum - spDqStart); + nSkipped += 1; + totalBasalAreaSkipped += pps.wallet.basalAreas[i][UC_ALL_INDEX]; + } + + float spDqMinimum = Math.max(7.6f, csl.minQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); + + if (spDqStart + spDqDelta < spDqMinimum) { + spDqDelta = spDqMinimum - spDqStart; + nSkipped += 1; + totalBasalAreaSkipped += pps.wallet.basalAreas[i][UC_ALL_INDEX]; + } + + spDqNew[i] = spDqStart + spDqDelta; + } + + float tph = 0.0f; + for (int i: pps.wallet.speciesIndices) { + if (spBaEnd[i] > 0.0f) { + spTphNew[i] = calculateTreesPerHectare(spBaEnd[i], spDqNew[i]); + } else { + spTphNew[i] = 0.0f; + } + tph += spTphNew[i]; + } + + if (passNumber == 15 || (nSkipped == pps.wallet.getNSpecies() && passNumber > 2)) { + break; + } + + float dqNewBar = calculateQuadMeanDiameter(baStart + baDelta, tph); + float dqStartEstimate = calculateQuadMeanDiameter(baStart, tphStart); + float dqWant = dqStartEstimate + dqDelta; + + var score = FloatMath.abs(dqWant - dqNewBar); + if (score < bestScore) { + bestScore = score; + bestF = f; + } + + if (FloatMath.abs(score) < 0.001) { + break; + } + + if (totalBasalAreaSkipped > 0.7f) { + totalBasalAreaSkipped = 0.7f * baStart; + } + + score = score * baStart / (baStart - totalBasalAreaSkipped); + f += score; + + passNumber += 1; + if (passNumber == 15) { + f = bestF; + } + } + + for (int i : pps.wallet.speciesIndices) { + pps.wallet.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; + pps.wallet.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; + if (spBaEnd[i] > 0.0f) { + pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX] = calculateQuadMeanDiameter(spBaEnd[i], spTphNew[i]); + } + } + } + } + + /** + * EMP061 - get the component size limits for the given genus and alias. + * + * @param genusAlias the alias of the genus in question + * @param region the region in question + * + * @return as described + */ + private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region region) { + + MatrixMap2 limits = fps.fcm.getComponentSizeCoefficients(); + Coefficients coe = limits.get(genusAlias, region); + + return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); + } + + /** + * EMP150 - return the quad-mean-diameter growth for the primary species of the + * Primary layer. Based on IPSJF150.doc (July, 1999). + * + * @param dqStart primary layer quad-mean-diameter at start of growth period + * @param dqDelta change in quad-mean-diameter of primary layer during growth period + * @param pspDqStart primary species quad-mean-diameter at start of growth period + * @param lhStart primary layer Lorey height at start of growth period + * @param pspLhStart primary species Lorey height at start of growth period + + * @return as described + * @throws ProcessingException in the event of an error + */ + private float growQuadMeanDiameterForPrimarySpecies( + float dqStart, float dqDelta, float pspDqStart, float lhStart, float pspLhStart + ) throws ProcessingException { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); + + ModelCoefficients mc = fps.fcm.getPrimarySpeciesQuadMeanDiameterGrowthCoefficients().get(pspStratumNumber); + + if (mc == null) { + throw new ProcessingException( + MessageFormat.format( + "primaryQuadMeanDiameterGrowthCoefficients do not exist" + + " for stratum number {0}, call growQuadMeanDiameterForPrimarySpecies(" + + "{1}, {2}, {3}, {4}, {5})", dqStart, dqDelta, pspDqStart, lhStart, pspLhStart + ) + ); + } + + return growQuadMeanDiameter(mc.getCoefficients(), dqStart, dqDelta, pspDqStart, lhStart, pspLhStart); + } + + private float growQuadMeanDiameterForNonPrimarySpecies( + int speciesIndex, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart + ) throws ProcessingException { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + String speciesName = pps.wallet.speciesNames[speciesIndex]; + int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); + + var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() + .get(speciesName, pspStratumNumber); + + if (modelCoefficientsOpt.isEmpty()) { + modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients().get(speciesName, 0); + } + + if (modelCoefficientsOpt.isEmpty()) { + throw new ProcessingException( + MessageFormat.format( + "No nonPrimarySpeciesQuadMeanDiameterGrowthCoefficients exist for stratum {0}" + + "; call growQuadMeanDiameterForNonPrimarySpecies({1}, {2}, {3}, {4}, {5}, {6})", pspStratumNumber, speciesIndex, dqStart, dqDelta, lhStart, spDqStart, spLhStart + ) + ); + } + + return growQuadMeanDiameter(modelCoefficientsOpt.get(), dqStart, dqDelta, spDqStart, lhStart, spLhStart); + } + + private float growQuadMeanDiameter( + Coefficients mc, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart + ) { + + float a0 = mc.getCoe(1); + float a1 = mc.getCoe(2); + float a2 = mc.getCoe(3); + + final float dqBase = 7.45f; + + float dqRateStart = (spDqStart - dqBase) / (dqStart - dqBase); + float logDqRateStart = FloatMath.log(dqRateStart); + float logDqRateDelta = a0 + a1 * FloatMath.log(spDqStart) + a2 * spLhStart / lhStart; + float dqRateEnd = FloatMath.exp(logDqRateStart + logDqRateDelta); + + float spDqEnd = dqRateEnd * (dqStart + dqDelta - dqBase) + dqBase; + if (spDqEnd < 7.51f) { + spDqEnd = 7.51f; + } + + float spDqDelta = spDqEnd - spDqStart; + + return spDqDelta; + } + + /** + * EMP149 - return the basal area growth for non-Primary species of Primary layer. Based on + * IPSJF149.doc (July, 1999). + * + * @param speciesIndex + * @param baStart layer basal area at start of growth period + * @param baDelta layer basal area growth during period + * @param lhStart layer Lorey height at start of growth period + * @param spBaStart this species basal area at start of growth period + * @param spDqStart this species quad-mean-diameter at start of growth period + * @param spLhStart this species Lorey height at start of growth period\ + * + * @return as described + * @throws ProcessingException + */ + private float growBasalAreaForNonPrimarySpecies( + int speciesIndex, float baStart, float baDelta, float lhStart, float spBaStart, float spDqStart, + float spLhStart + ) throws ProcessingException { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + if (spBaStart <= 0.0f || spBaStart >= baStart) { + throw new ProcessingException( + MessageFormat.format( + "Species basal area {} is out of range; it must be" + + " positive and less that overall basal area", spBaStart, baStart + ) + ); + } + + String speciesName = pps.wallet.speciesNames[speciesIndex]; + int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); + + var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients() + .get(speciesName, pspStratumNumber); + + if (modelCoefficientsOpt.isEmpty()) { + modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients().get(speciesName, 0); + } + + if (modelCoefficientsOpt.isEmpty()) { + throw new ProcessingException( + MessageFormat.format( + "No nonPrimarySpeciesBasalAreaGrowthCoefficients exist for stratum {0}" + + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", pspStratumNumber, speciesIndex, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart + ) + ); + } + + Coefficients mc = modelCoefficientsOpt.get(); + + float a0 = mc.getCoe(1); + float a1 = mc.getCoe(2); + float a2 = mc.getCoe(3); + + var baProportionStart = spBaStart / baStart; + var logBaProportionStart = FloatMath.log(baProportionStart / 1.0f - baProportionStart); + + var logBaDeltaProportion = a0 + a1 * FloatMath.log(spDqStart) + a2 * spLhStart / lhStart; + var logBaProportionEnd = logBaProportionStart + logBaDeltaProportion; + var baProportionEnd = FloatMath.exp(logBaProportionEnd) / (1.0f + FloatMath.exp(logBaProportionEnd)); + + var spDeltaBa = baProportionEnd * (baStart + baDelta) - spBaStart; + + return spDeltaBa; + } + + /** + * EMP148 - return the basal area growth for Primary species of Primary layer. Based on + * IPSJF148.doc (July, 1999). + * + * @param baStart layer basal area at start of growth period + * @param baDelta layer basal area growth during period + * @param pspBaStart primary species basal area at start of growth period + * @param dhStart dominant height of primary species at start of growth period + * @param pspYabhStart primary species years at breast height at start of growth period + * @param pspLhStart primary species Lorey height at start of growth period + * + * @return as described + * @throws ProcessingException + */ + private float growBasalAreaForPrimarySpecies( + float baStart, float baDelta, float pspBaStart, float dhStart, float pspYabhStart, + float pspLhStart + ) throws ProcessingException { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + float spToAllProportionStart = pspBaStart / baStart; + if (spToAllProportionStart <= 0.999f) { + var psStratumNumber = pps.getPrimarySpeciesStratumNumber(); + + ModelCoefficients mc = fps.fcm.getPrimarySpeciesBasalAreaGrowthCoefficients().get(psStratumNumber); + int model = mc.getModel(); + var a0 = mc.getCoefficients().getCoe(1); + var a1 = mc.getCoefficients().getCoe(2); + var a2 = mc.getCoefficients().getCoe(3); + + var logBaProportionStart = FloatMath.log(spToAllProportionStart / (1.0f - spToAllProportionStart)); + + float logBaDeltaProportion; + if (model == 3) { + logBaDeltaProportion = a0 + a1 * dhStart; + } else if (model == 8) { + logBaDeltaProportion = a0 + a1 * pspYabhStart + a2 * pspLhStart / dhStart; + } else if (model == 9) { + logBaDeltaProportion = a0 + a1 * logBaProportionStart + a2 * baStart; + } else { + throw new ProcessingException( + MessageFormat + .format("Model value {} for polygon stratum {} is out of range", model, psStratumNumber) + ); + } + + var x = FloatMath.exp(logBaProportionStart + logBaDeltaProportion); + var spToAllProportionEnd = FloatMath.exp(x) / (1 + FloatMath.exp(x)); + baDelta = spToAllProportionEnd * (baStart + baDelta) - pspBaStart; + } + + return baDelta; + } + + private void growLoreyHeightsForAllSpecies() { + // TODO Auto-generated method stub + } + + private void computeUtilizationComponentsPrimary() { + // TODO Auto-generated method stub + } + + /** + * Record small component utilization values for primary layer. + * + * @throws ProcessingException + */ + private void calculateSmallComponentYields() throws ProcessingException { + + PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank wallet = pps.wallet; + + float lhSum = 0.0f; + float baSum = 0.0f; + float tphSum = 0.0f; + float wsVolumeSum = 0.0f; + + for (int speciesIndex : pps.getIndices()) { + + float spLhAll = wallet.loreyHeights[speciesIndex][UC_ALL_INDEX]; + float spBaAll = wallet.basalAreas[speciesIndex][UC_ALL_INDEX]; + float spDqAll = wallet.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; + + Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); + String speciesName = wallet.speciesNames[speciesIndex]; + + // EMP080 + float smallProbability = smallComponentProbability(speciesName, spLhAll, region); + + // This whole operation is on Actual BA's, not 100% occupancy. + float fractionAvailable = pps.getPolygon().getPercentForestLand() / 100.0f; + + if (fractionAvailable > 0.0f) { + spBaAll *= fractionAvailable; + } + + // EMP081 + float conditionalExpectedBasalArea = conditionalExpectedBaseArea(speciesName, spBaAll, spLhAll, region); + + if (fractionAvailable > 0.0f) { + conditionalExpectedBasalArea /= fractionAvailable; + } + + float spBaSmall = smallProbability * conditionalExpectedBasalArea; + + // EMP082 + float spDqSmall = smallComponentQuadMeanDiameter(speciesName, spLhAll); // DQSMsp + + // EMP085 + float spLhSmall = smallComponentLoreyHeight(speciesName, spLhAll, spDqSmall, spDqAll); // HLSMsp + + // EMP086 + float meanVolumeSmall = meanVolumeSmall(speciesName, spLhSmall, spDqSmall); // VMEANSMs + + int controlVar3Value = fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); + + if (controlVar3Value >= 1 /* apply compatibility variables */) { + spBaSmall += pps.getCVSmall(speciesIndex, UtilizationClassVariable.BASAL_AREA); + if (spBaSmall < 0.0f) { + spBaSmall = 0.0f; + } + spDqSmall += pps.getCVSmall(speciesIndex, UtilizationClassVariable.QUAD_MEAN_DIAMETER); + if (spDqSmall < 4.01f) { + spDqSmall = 4.01f; + } else if (spDqSmall > 7.49) { + spDqSmall = 7.49f; + } + spLhSmall = 1.3f * (spLhSmall - 1.3f) + * FloatMath.exp(pps.getCVSmall(speciesIndex, UtilizationClassVariable.LOREY_HEIGHT)); + + if (controlVar3Value >= 2 && meanVolumeSmall > 0.0f) { + meanVolumeSmall *= FloatMath + .exp(pps.getCVSmall(speciesIndex, UtilizationClassVariable.WHOLE_STEM_VOLUME)); + } + } + + float spTphSmall = calculateTreesPerHectare(spBaSmall, spDqSmall); + float spWsVolumeSmall = spTphSmall * meanVolumeSmall; + + pps.wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX] = spLhSmall; + pps.wallet.basalAreas[speciesIndex][UC_SMALL_INDEX] = spBaSmall; + pps.wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX] = spTphSmall; + pps.wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX] = spDqSmall; + pps.wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX] = spWsVolumeSmall; + pps.wallet.closeUtilizationVolumes[speciesIndex][UC_SMALL_INDEX] = 0.0f; + pps.wallet.cuVolumesMinusDecay[speciesIndex][UC_SMALL_INDEX] = 0.0f; + pps.wallet.cuVolumesMinusDecayAndWastage[speciesIndex][UC_SMALL_INDEX] = 0.0f; + + lhSum += spBaSmall * spDqSmall; + baSum += spBaSmall; + tphSum += spTphSmall; + wsVolumeSum += spWsVolumeSmall; + } + + if (baSum > 0.0) { + pps.wallet.loreyHeights[0][UC_SMALL_INDEX] = lhSum / baSum; + } else { + pps.wallet.loreyHeights[0][UC_SMALL_INDEX] = 0.0f; + } + pps.wallet.basalAreas[0][UC_SMALL_INDEX] = baSum; + pps.wallet.treesPerHectare[0][UC_SMALL_INDEX] = tphSum; + pps.wallet.quadMeanDiameters[0][UC_SMALL_INDEX] = calculateQuadMeanDiameter(baSum, tphSum); + pps.wallet.wholeStemVolumes[0][UC_SMALL_INDEX] = wsVolumeSum; + pps.wallet.closeUtilizationVolumes[0][UC_SMALL_INDEX] = 0.0f; + pps.wallet.cuVolumesMinusDecay[0][UC_SMALL_INDEX] = 0.0f; + pps.wallet.cuVolumesMinusDecayAndWastage[0][UC_SMALL_INDEX] = 0.0f; + } + + /** + * GRSPHL - estimate the Lorey Heights of all species at end of growth period. The results of + * the calculations are persisted in {@code pps.wallet}. + * + * @param primarySpeciesDhStart primary species dominant height at start + * @param primarySpeciesDhEnd primary species dominant height at end + * @param primarySpeciesTphStart primary species trees-per-hectare at start + * @param primarySpeciesTphEnd primary species trees-per-hectare at end + * @param primarySpeciesLhStart primary species Lorey height at end + */ + private void growLoreyHeights( + float primarySpeciesDhStart, float primarySpeciesDhEnd, float primarySpeciesTphStart, + float primarySpeciesTphEnd, float primarySpeciesLhStart + ) { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank wallet = pps.wallet; + + float lhStartEstimate = estimatePrimarySpeciesLoreyHeight(primarySpeciesDhStart, primarySpeciesTphStart); + float lhEndEstimate = estimatePrimarySpeciesLoreyHeight(primarySpeciesDhEnd, primarySpeciesTphEnd); + + float primaryF = (primarySpeciesLhStart - 1.3f) / (lhStartEstimate - 1.3f); + float primaryLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightPrimaryParam(); + primaryF = 1.0f + (primaryF - 1.0f) * primaryLhAdjustment; + + float primarySpeciesLhEnd = 1.3f + (lhEndEstimate - 1.3f) * primaryF; + + int debugSetting8Value = fps.fcm.getDebugSettings() + .getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8); + + int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + if (debugSetting8Value != 2 || primarySpeciesDhStart != primarySpeciesDhEnd) { + wallet.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX] = primarySpeciesLhEnd; + } else if (debugSetting8Value == 2) { + primarySpeciesLhEnd = wallet.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; + } + + float otherLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightOther(); + + for (int i = 1; i < fps.getPolygonProcessingState().getNSpecies(); i++) { + if (wallet.basalAreas[i][UC_ALL_INDEX] > 0.0f && i != primarySpeciesIndex) { + if (! (primarySpeciesDhEnd == primarySpeciesDhStart && debugSetting8Value >= 1)) { + float lhEstimate1 = estimateNonPrimarySpeciesLoreyHeight( + i, primarySpeciesDhStart, primarySpeciesLhStart + ); + float lhEstimate2 = estimateNonPrimarySpeciesLoreyHeight( + i, primarySpeciesDhEnd, primarySpeciesLhEnd + ); + + float otherF = (wallet.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (lhEstimate1 - 1.3f); + otherF = 1.0f - (otherF - 1.0f) * otherLhAdjustment; + wallet.loreyHeights[i][UC_ALL_INDEX] = 1.3f + (lhEstimate2 - 1.3f) * otherF; + } + } + } + } + + /** + * EMP050, method 1. Estimate the Lorey height of the primary species at the end of the growth period. + * + * @param primarySpeciesDominantHeight the dominantHeight of the primary species + * @param primarySpeciesTph trees-per-hectare of the primary species + * + * @return as described + */ + private float estimatePrimarySpeciesLoreyHeight(float primarySpeciesDominantHeight, float primarySpeciesTph) { + + String primarySpeciesAlias = fps.getPolygonProcessingState().getPrimarySpeciesAlias(); + Region polygonRegion = fps.getPolygonProcessingState().getBecZone().getRegion(); + var coefficients = fps.fcm.getLoreyHeightPrimarySpeciesEquationP1Coefficients(); + + float a0 = coefficients.get(primarySpeciesAlias, polygonRegion).getCoe(1); + float a1 = coefficients.get(primarySpeciesAlias, polygonRegion).getCoe(2); + float a2 = coefficients.get(primarySpeciesAlias, polygonRegion).getCoe(3); + + float hMult = a0 - a1 + a1 * FloatMath.exp(a2 * (primarySpeciesTph - 100.0f)); + + return 1.3f + (primarySpeciesDominantHeight - 1.3f) * hMult; + } + + /** + * EMP053 - estimate the Lorey height of a non-primary species of the polygon. + * + * @param speciesIndex (non-primary) species index + * @param primarySpeciesDominantHeight primary species dominant height + * + * @return as described + */ + private float estimateNonPrimarySpeciesLoreyHeight( + int speciesIndex, float primarySpeciesDominantHeight, + float primarySpeciesLoreyHeight + ) { + float lh; + + var coefficients = fps.fcm.getLoreyHeightNonPrimaryCoefficients(); + int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + String primarySpeciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex]; + String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; + Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); + + var configuredLhCoefficients = coefficients.get(speciesAlias, primarySpeciesAlias, region); + var lhCoefficients = configuredLhCoefficients.orElseGet(() -> NonprimaryHLCoefficients.getDefault()); + + float a0 = lhCoefficients.getCoe(1); + float a1 = lhCoefficients.getCoe(2); + int equationIndex = lhCoefficients.getEquationIndex(); + + if (equationIndex == 1) { + lh = 1.3f + a0 * (FloatMath.pow(primarySpeciesDominantHeight - 1.3f, a1)); + } else if (equationIndex == 2) { + lh = 1.3f + a0 * (FloatMath.pow(primarySpeciesLoreyHeight - 1.3f, a1)); + } else { + throw new IllegalStateException( + MessageFormat.format("Expecting equation index 1 or 2 but saw {0}", equationIndex) + ); + } + + return lh; } /** @@ -313,16 +1143,17 @@ private void grow( * * @param yearsAtBreastHeight * @param dominantHeight - * @param dqAtStart + * @param dqStart * @param veteranBasalAreaStart * @param veteranBasalAreaEnd * @param hdGrowth + * * @return * * @throws StandProcessingException */ float growQuadMeanDiameter( - float yearsAtBreastHeight, float primaryLayerBasalArea, float dominantHeight, float dqAtStart, + float yearsAtBreastHeight, float primaryLayerBasalArea, float dominantHeight, float dqStart, Optional veteranBasalAreaStart, Optional veteranBasalAreaEnd, float hdGrowth, Reference dqGrowthLimitApplied ) @@ -344,22 +1175,22 @@ float growQuadMeanDiameter( coefficientsWeightedBySpeciesAndDecayBec.setCoe(i, sum); } - float dqYieldAtStart = fps.estimators.estimateQuadMeanDiameterYield( + float dqYieldStart = fps.estimators.estimateQuadMeanDiameterYield( coefficientsWeightedBySpeciesAndDecayBec, dominantHeight, yearsAtBreastHeight, veteranBasalAreaStart, fps .getPolygonProcessingState() .getBecZone(), fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber() ); - float dominantHeightAtEnd = dominantHeight + hdGrowth; - float yearsAtBreastHeightAtEnd = yearsAtBreastHeight + 1.0f; + float dominantHeightEnd = dominantHeight + hdGrowth; + float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; - float dqYieldAtEnd = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, dominantHeightAtEnd, yearsAtBreastHeightAtEnd, veteranBasalAreaEnd, fps + float dqYieldEnd = fps.estimators.estimateQuadMeanDiameterYield( + coefficientsWeightedBySpeciesAndDecayBec, dominantHeightEnd, yearsAtBreastHeightEnd, veteranBasalAreaEnd, fps .getPolygonProcessingState() .getBecZone(), fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber() ); - float dqYieldGrowth = dqYieldAtEnd - dqYieldAtStart; + float dqYieldGrowth = dqYieldEnd - dqYieldStart; int debugSetting6Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6); @@ -370,7 +1201,7 @@ float growQuadMeanDiameter( if (debugSetting6Value != 1) { var convergenceCoefficient = growthFaitDetails.calculateCoefficient(yearsAtBreastHeight); - float adjust = -convergenceCoefficient * (dqAtStart - dqYieldAtStart); + float adjust = -convergenceCoefficient * (dqStart - dqYieldStart); dqGrowthFiat = Optional.of(dqYieldGrowth + adjust); } @@ -378,56 +1209,54 @@ float growQuadMeanDiameter( if (debugSetting6Value != 0) { dqGrowthEmpirical = Optional.of( calculateQuadMeanDiameterGrowthEmpirical( - yearsAtBreastHeight, dominantHeight, primaryLayerBasalArea, dqAtStart, hdGrowth, dqYieldAtStart, dqYieldAtEnd + yearsAtBreastHeight, dominantHeight, primaryLayerBasalArea, dqStart, hdGrowth, dqYieldStart, dqYieldEnd ) ); } - + float dqGrowth; - + switch (debugSetting6Value) { - case 0: - dqGrowth = dqGrowthFiat.orElseThrow(); - break; - - case 1: - dqGrowth = dqGrowthEmpirical.orElseThrow(); - break; - - case 2: { - float c = 1.0f; - if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { - c = 0.0f; - } else if (yearsAtBreastHeight > growthFaitDetails.getMixedCoefficient(0)) { - float t1 = yearsAtBreastHeight - growthFaitDetails.getMixedCoefficient(0); - float t2 = growthFaitDetails.getMixedCoefficient(1) - growthFaitDetails.getMixedCoefficient(0); - float t3 = growthFaitDetails.getMixedCoefficient(2); - c = 1.0f - FloatMath.pow(t1 / t2, t3); - } - dqGrowth = c * dqGrowthEmpirical.orElseThrow() + (1.0f - c) * dqGrowthFiat.orElseThrow(); - break; + case 0: + dqGrowth = dqGrowthFiat.orElseThrow(); + break; + + case 1: + dqGrowth = dqGrowthEmpirical.orElseThrow(); + break; + + case 2: { + float c = 1.0f; + if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { + c = 0.0f; + } else if (yearsAtBreastHeight > growthFaitDetails.getMixedCoefficient(0)) { + float t1 = yearsAtBreastHeight - growthFaitDetails.getMixedCoefficient(0); + float t2 = growthFaitDetails.getMixedCoefficient(1) - growthFaitDetails.getMixedCoefficient(0); + float t3 = growthFaitDetails.getMixedCoefficient(2); + c = 1.0f - FloatMath.pow(t1 / t2, t3); } - - default: - throw new IllegalStateException("debugSetting6Value of " + debugSetting6Value + " is not supported"); + dqGrowth = c * dqGrowthEmpirical.orElseThrow() + (1.0f - c) * dqGrowthFiat.orElseThrow(); + break; } - + + default: + throw new IllegalStateException("debugSetting6Value of " + debugSetting6Value + " is not supported"); + } + float dqUpperBound = growQuadraticMeanDiameterUpperBound(); - float dqLimit = Math.max(dqUpperBound, dqAtStart); + float dqLimit = Math.max(dqUpperBound, dqStart); - if (dqAtStart + dqGrowth < 7.6f) { - dqGrowth = 7.6f - dqAtStart; + if (dqStart + dqGrowth < 7.6f) { + dqGrowth = 7.6f - dqStart; } - - if (dqAtStart + dqGrowth > dqLimit - 0.001f) { + + if (dqStart + dqGrowth > dqLimit - 0.001f) { dqGrowthLimitApplied.set(true); - dqGrowth = Math.max(dqLimit - dqAtStart, 0.0f); + dqGrowth = Math.max(dqLimit - dqStart, 0.0f); } else { dqGrowthLimitApplied.set(false); } - - // TODO: Must note if limited by maximum!!! - + return dqGrowth; } @@ -437,17 +1266,17 @@ float growQuadMeanDiameter( * @param yearsAtBreastHeight primary species years at breast height or more * @param dominantHeight primary species dominant height * @param primaryLayerBasalArea basal area of primary layer - * @param dqAtStart quad mean diameter at start of growth period + * @param dqStart quad mean diameter at start of growth period * @param hdGrowth growth in dominant height - * @param dqYieldAtStart quad mean diameter yield at start of growth period - * @param dqYieldAtEnd quad mean diameter yield at end of growth period + * @param dqYieldStart quad mean diameter yield at start of growth period + * @param dqYieldEnd quad mean diameter yield at end of growth period * * @return the change in primary layer basal area from start to start + 1 year */ private float calculateQuadMeanDiameterGrowthEmpirical( float yearsAtBreastHeight, float dominantHeight, - float primaryLayerBasalArea, float dqAtStart, float hdGrowth, float dqYieldAtStart, - float dqYieldAtEnd + float primaryLayerBasalArea, float dqStart, float hdGrowth, float dqYieldStart, + float dqYieldEnd ) { // Compute the growth in quadratic mean diameter @@ -465,11 +1294,12 @@ private float calculateQuadMeanDiameterGrowthEmpirical( float a6 = firstSpeciesDqGrowthCoe.get(6); yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); - float dqYieldGrowth = dqYieldAtEnd - dqYieldAtStart; + float dqYieldGrowth = dqYieldEnd - dqYieldStart; float dqDelta = FloatMath.exp( - a0 + a2 * FloatMath.log(yearsAtBreastHeight) + a3 * dqAtStart - + a4 * dominantHeight + a5 * primaryLayerBasalArea + a6 * hdGrowth) + a0 + a2 * FloatMath.log(yearsAtBreastHeight) + a3 * dqStart + + a4 * dominantHeight + a5 * primaryLayerBasalArea + a6 * hdGrowth + ) + a1 * dqYieldGrowth; dqDelta = Math.max(dqDelta, 0.0f); @@ -483,7 +1313,7 @@ private float calculateQuadMeanDiameterGrowthEmpirical( l[i] = quadMeanDiameterGrowthEmpiricalLimits.get(stratumNumber).getCoe(i); } - float x = dqAtStart - 7.5f; + float x = dqStart - 7.5f; float xsq = x * x; var dqGrowthMin = Math.max(l[0] + l[1] * x + l[2] * xsq / 100.0f, l[6]); @@ -554,7 +1384,7 @@ float growBasalArea( int primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); - float basalAreaYieldAtStart = fps.estimators.estimateBaseAreaYield( + float basalAreaYieldStart = fps.estimators.estimateBaseAreaYield( estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, isFullOccupancy, fps .getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber ); @@ -562,7 +1392,7 @@ float growBasalArea( float dominantHeightEnd = dominantHeight + growthInDominantHeight; float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; - float basalAreaYieldAtEnd = fps.estimators.estimateBaseAreaYield( + float basalAreaYieldEnd = fps.estimators.estimateBaseAreaYield( estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, isFullOccupancy, fps .getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber ); @@ -572,15 +1402,15 @@ float growBasalArea( var convergenceCoefficient = growthFaitDetails.calculateCoefficient(yearsAtBreastHeight); - float baGrowth = basalAreaYieldAtEnd - basalAreaYieldAtStart; - var adjust = -convergenceCoefficient * (primaryLayerBasalArea - basalAreaYieldAtStart); + float baGrowth = basalAreaYieldEnd - basalAreaYieldStart; + var adjust = -convergenceCoefficient * (primaryLayerBasalArea - basalAreaYieldStart); baGrowth += adjust; // Special check at young ages. - if (yearsAtBreastHeight < 40.0f && primaryLayerBasalArea > 5.0f * basalAreaYieldAtStart) { + if (yearsAtBreastHeight < 40.0f && primaryLayerBasalArea > 5.0f * basalAreaYieldStart) { // This stand started MUCH faster than base yield model. We'll let it keep going like // this for a while. - baGrowth = Math.min(basalAreaYieldAtStart / yearsAtBreastHeight, Math.min(0.5f, baGrowth)); + baGrowth = Math.min(basalAreaYieldStart / yearsAtBreastHeight, Math.min(0.5f, baGrowth)); } int debugSetting3Value = debugSettings.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3); @@ -589,7 +1419,7 @@ float growBasalArea( float baGrowthFiatModel = baGrowth; float baGrowthEmpiricalModel = calculateBasalAreaGrowthEmpirical( - speciesProportionsByBasalArea, primaryLayerBasalArea, yearsAtBreastHeight, dominantHeight, basalAreaYieldAtStart, basalAreaYieldAtEnd + speciesProportionsByBasalArea, primaryLayerBasalArea, yearsAtBreastHeight, dominantHeight, basalAreaYieldStart, basalAreaYieldEnd ); baGrowth = baGrowthEmpiricalModel; @@ -635,14 +1465,14 @@ float growBasalArea( * @param primaryLayerBasalArea basal area of primary layer * @param yearsAtBreastHeight primary species years at breast height or more * @param dominantHeight primary species dominant height - * @param basalAreaYieldAtStart basal area yield at start of period - * @param basalAreaYieldAtEnd basal area yield at end of period + * @param basalAreaYieldStart basal area yield at start of period + * @param basalAreaYieldEnd basal area yield at end of period * * @return the change in primary layer basal area from start to start + 1 year */ private float calculateBasalAreaGrowthEmpirical( float[] speciesProportionsByBasalArea, float primaryLayerBasalArea, float yearsAtBreastHeight, - float dominantHeight, float basalAreaYieldAtStart, float basalAreaYieldAtEnd + float dominantHeight, float basalAreaYieldStart, float basalAreaYieldEnd ) { yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); @@ -688,7 +1518,7 @@ private float calculateBasalAreaGrowthEmpirical( float term3 = b4 * FloatMath.exp(b5 * yearsAtBreastHeight); float term4; - float basalAreaYieldDelta = basalAreaYieldAtEnd - basalAreaYieldAtStart; + float basalAreaYieldDelta = basalAreaYieldEnd - basalAreaYieldStart; if (basalAreaYieldDelta > 0.0) { term4 = b6 * FloatMath.pow(basalAreaYieldDelta, b7); } else { @@ -744,8 +1574,20 @@ private float growQuadraticMeanDiameterUpperBound() { } } + /** + * HDGROW - calculate growth in dominant height from the current dominant height and the parameters + * needed to do the computation + * + * @param dhStart dominant height at the start of the growth period + * @param siteCurveNumber site curve number, used to find the site index equation + * @param siStart + * @param yearsToBreastHeight for the given species + * + * @return the difference in dominant height from the beginning to the end of the growth period + * @throws ProcessingException + */ float growDominantHeight( - float dominantHeight, int siteCurveNumber, float siteIndex, + float dhStart, int siteCurveNumber, float siStart, float yearsToBreastHeight ) throws ProcessingException { @@ -758,44 +1600,44 @@ float growDominantHeight( var siteIndexEquation = SiteIndexEquation.getByIndex(siteCurveNumber); - if (dominantHeight <= 1.3) { + if (dhStart <= 1.3) { throw new ProcessingException( MessageFormat.format( - "(current) DominantHeight {0} is out of range (must be above 1.3)", dominantHeight + "(current) DominantHeight {0} is out of range (must be above 1.3)", dhStart ) ); } final SiteIndexAgeType ageType = SiteIndexAgeType.SI_AT_BREAST; - double siteIndex_d = siteIndex; - double dominantHeight_d = dominantHeight; + double siStart_d = siStart; + double dhStart_d = dhStart; double yearsToBreastHeight_d = yearsToBreastHeight; - double currentAge; + double ageStart; try { - currentAge = SiteTool.heightAndSiteIndexToAge( - siteIndexEquation, dominantHeight_d, ageType, siteIndex_d, yearsToBreastHeight_d + ageStart = SiteTool.heightAndSiteIndexToAge( + siteIndexEquation, dhStart_d, ageType, siStart_d, yearsToBreastHeight_d ); } catch (CommonCalculatorException e) { throw new ProcessingException( MessageFormat.format( - "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3}, {4})", siteIndexEquation, dominantHeight_d, ageType, siteIndex_d, yearsToBreastHeight_d + "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3}, {4})", siteIndexEquation, dhStart_d, ageType, siStart_d, yearsToBreastHeight_d ), e ); } - if (currentAge <= 0.0d) { - if (dominantHeight_d > siteIndex_d) { + if (ageStart <= 0.0d) { + if (dhStart_d > siStart_d) { return 0.0f /* no growth */; } else { throw new ProcessingException( - MessageFormat.format("currentBreastHeightAge value {0} must be positive", currentAge) + MessageFormat.format("currentBreastHeightAge value {0} must be positive", ageStart) ); } } - double nextAge = currentAge + 1.0f; + double ageEnd = ageStart + 1.0f; // If we are past the total age limit for site curve, assign no growth. If we are almost there, go // slightly past the limit (by .01 yr). Once there, we should stop growing. The TOTAL age limit was @@ -808,19 +1650,19 @@ float growDominantHeight( breastHeightAgeLimitInYears = ageLimitInYears - yearsToBreastHeight; } - if (currentAge <= breastHeightAgeLimitInYears || scAgeMaximums.getT1() <= 0.0f) { + if (ageStart <= breastHeightAgeLimitInYears || scAgeMaximums.getT1() <= 0.0f) { float yearPart = 1.0f; if (scAgeMaximums.getT1() <= 0.0f) { - if (breastHeightAgeLimitInYears > 0.0f && nextAge > breastHeightAgeLimitInYears) { - if (currentAge > breastHeightAgeLimitInYears) { + if (breastHeightAgeLimitInYears > 0.0f && ageEnd > breastHeightAgeLimitInYears) { + if (ageStart > breastHeightAgeLimitInYears) { return 0.0f /* no growth */; } - yearPart = (float) (breastHeightAgeLimitInYears - currentAge + 0.01); - nextAge = currentAge + yearPart; + yearPart = (float) (breastHeightAgeLimitInYears - ageStart + 0.01); + ageEnd = ageStart + yearPart; } } @@ -829,11 +1671,11 @@ float growDominantHeight( // correspond to HDD1. Find a new HDD1 to at least get the increment correct. double currentDominantHeight = ageAndSiteIndexToHeight( - siteIndexEquation, currentAge, ageType, siteIndex_d, yearsToBreastHeight_d + siteIndexEquation, ageStart, ageType, siStart_d, yearsToBreastHeight_d ); double nextDominantHeight = ageAndSiteIndexToHeight( - siteIndexEquation, nextAge, ageType, siteIndex_d, yearsToBreastHeight_d, r -> r >= 0.0 + siteIndexEquation, ageEnd, ageType, siStart_d, yearsToBreastHeight_d, r -> r >= 0.0 ); if (nextDominantHeight < currentDominantHeight && yearPart == 1.0) { @@ -858,13 +1700,13 @@ float growDominantHeight( double breastHeightAgeLimitInYears_d = breastHeightAgeLimitInYears; double currentDominantHeight = ageAndSiteIndexToHeight( - siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siStart_d, yearsToBreastHeight_d ); breastHeightAgeLimitInYears_d += 1.0; double nextDominantHeight = ageAndSiteIndexToHeight( - siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siteIndex_d, yearsToBreastHeight_d + siteIndexEquation, breastHeightAgeLimitInYears_d, ageType, siStart_d, yearsToBreastHeight_d ); float rate = (float) (nextDominantHeight - currentDominantHeight); @@ -883,8 +1725,8 @@ float growDominantHeight( // a * t = ln(1 + (dominantHeight - y) * a/rate) // t = ln(1 + (dominantHeight - y) * a/rate) / a float t; - if (dominantHeight > y) { - float term = 1.0f + (dominantHeight - y) * a / rate; + if (dhStart > y) { + float term = 1.0f + (dhStart - y) * a / rate; if (term <= 1.0e-7) { return 0.0f; } @@ -979,13 +1821,13 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce Coefficients treesPerHectare = Utils.utilizationVector(); cvVolume[s] = new MatrixMap3Impl( - UtilizationClass.ALL_BUT_SMALL_ALL, VolumeVariable.ALL, LayerType.ALL_USED, (k1, k2, k3) -> 0f + UtilizationClass.UTIL_CLASSES, VolumeVariable.ALL, LayerType.ALL_USED, (k1, k2, k3) -> 0f ); cvBasalArea[s] = new MatrixMap2Impl( - UtilizationClass.ALL_BUT_SMALL_ALL, LayerType.ALL_USED, (k1, k2) -> 0f + UtilizationClass.UTIL_CLASSES, LayerType.ALL_USED, (k1, k2) -> 0f ); cvQuadraticMeanDiameter[s] = new MatrixMap2Impl( - UtilizationClass.ALL_BUT_SMALL_ALL, LayerType.ALL_USED, (k1, k2) -> 0f + UtilizationClass.UTIL_CLASSES, LayerType.ALL_USED, (k1, k2) -> 0f ); for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL) { @@ -1003,7 +1845,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce } } - for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL_ALL) { + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { float adjustment; float baseVolume; @@ -1081,7 +1923,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, quadMeanDiameters, basalAreas, wholeStemVolumes ); - for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL_ALL) { + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { float adjustment = 0.0f; float basalArea = basalAreas.getCoe(uc.index); if (growthDetails.allowCalculation(basalArea, B_BASE_MIN, (l, r) -> l > r)) { @@ -1134,20 +1976,22 @@ uc.index, calculateTreesPerHectare( // Small components - cvSmall[s] = estimateSmallComponents(s, growthDetails); + cvSmall[s] = calculateSmallCompatibilityVariables(s, growthDetails); } pps.setCompatibilityVariableDetails(cvVolume, cvBasalArea, cvQuadraticMeanDiameter, cvSmall); } /** - * Estimate small component utilization values for primary layer - * @param allowCompatibilitySetting + * Calculate the small component compatibility variables. + * + * @param speciesIndex the index of the species for which this operation is to be performed + * @param forwardControlVariables the control variables for this run * * @throws ProcessingException */ - private HashMap - estimateSmallComponents(int speciesIndex, ForwardControlVariables growthDetails) + private HashMap + calculateSmallCompatibilityVariables(int speciesIndex, ForwardControlVariables forwardControlVariables) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); @@ -1164,7 +2008,7 @@ uc.index, calculateTreesPerHectare( float spBaseArea_All = wallet.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp // EMP080 - float cvSmallComponentProbability = smallComponentProbability(speciesName, spLoreyHeight_All, region); // PROBsp + float smallProbability = smallComponentProbability(speciesName, spLoreyHeight_All, region); // PROBsp // EMP081 float conditionalExpectedBaseArea = conditionalExpectedBaseArea( @@ -1173,54 +2017,54 @@ uc.index, calculateTreesPerHectare( // TODO (see previous TODO): conditionalExpectedBaseArea /= fractionAvailable; - float cvBasalArea_Small = cvSmallComponentProbability * conditionalExpectedBaseArea; + float baSmall = smallProbability * conditionalExpectedBaseArea; // EMP082 - float cvQuadMeanDiameter_Small = smallComponentQuadMeanDiameter(speciesName, spLoreyHeight_All); // DQSMsp + float qmdSmall = smallComponentQuadMeanDiameter(speciesName, spLoreyHeight_All); // DQSMsp // EMP085 - float cvLoreyHeight_Small = smallComponentLoreyHeight( - speciesName, spLoreyHeight_All, cvQuadMeanDiameter_Small, spQuadMeanDiameter_All + float lhSmall = smallComponentLoreyHeight( + speciesName, spLoreyHeight_All, qmdSmall, spQuadMeanDiameter_All ); // HLSMsp // EMP086 - float cvMeanVolume_Small = meanVolumeSmall(speciesName, cvQuadMeanDiameter_Small, cvLoreyHeight_Small); // VMEANSMs + float meanVolumeSmall = meanVolumeSmall(speciesName, qmdSmall, lhSmall); // VMEANSMs - var cvSmall = new HashMap(); + var cvSmall = new HashMap(); float spInputBasalArea_Small = wallet.basalAreas[speciesIndex][UC_SMALL_INDEX]; - cvSmall.put(SmallUtilizationClassVariable.BASAL_AREA, spInputBasalArea_Small - cvBasalArea_Small); + cvSmall.put(UtilizationClassVariable.BASAL_AREA, spInputBasalArea_Small - baSmall); - if (growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { + if (forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { float spInputQuadMeanDiameter_Small = wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; cvSmall.put( - SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - - cvQuadMeanDiameter_Small + UtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small + - qmdSmall ); } else { - cvSmall.put(SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); + cvSmall.put(UtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); } float spInputLoreyHeight_Small = wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX]; - if (spInputLoreyHeight_Small > 1.3f && cvLoreyHeight_Small > 1.3f && spInputBasalArea_Small > 0.0f) { - float cvLoreyHeight = FloatMath.log( (spInputLoreyHeight_Small - 1.3f) / (cvLoreyHeight_Small - 1.3f)); - cvSmall.put(SmallUtilizationClassVariable.LOREY_HEIGHT, cvLoreyHeight); + if (spInputLoreyHeight_Small > 1.3f && lhSmall > 1.3f && spInputBasalArea_Small > 0.0f) { + float cvLoreyHeight = FloatMath.log( (spInputLoreyHeight_Small - 1.3f) / (lhSmall - 1.3f)); + cvSmall.put(UtilizationClassVariable.LOREY_HEIGHT, cvLoreyHeight); } else { - cvSmall.put(SmallUtilizationClassVariable.LOREY_HEIGHT, 0.0f); + cvSmall.put(UtilizationClassVariable.LOREY_HEIGHT, 0.0f); } float spInputWholeStemVolume_Small = wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; - if (spInputWholeStemVolume_Small > 0.0f && cvMeanVolume_Small > 0.0f - && growthDetails.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l >= r)) { + if (spInputWholeStemVolume_Small > 0.0f && meanVolumeSmall > 0.0f + && forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l >= r)) { float spInputTreePerHectare_Small = wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; - var cvWholeStemVolume = FloatMath - .log(spInputWholeStemVolume_Small / spInputTreePerHectare_Small / cvMeanVolume_Small); - cvSmall.put(SmallUtilizationClassVariable.WHOLE_STEM_VOLUME, cvWholeStemVolume); + var wsVolumeSmall = FloatMath + .log(spInputWholeStemVolume_Small / spInputTreePerHectare_Small / meanVolumeSmall); + cvSmall.put(UtilizationClassVariable.WHOLE_STEM_VOLUME, wsVolumeSmall); } else { - cvSmall.put(SmallUtilizationClassVariable.WHOLE_STEM_VOLUME, 0.0f); + cvSmall.put(UtilizationClassVariable.WHOLE_STEM_VOLUME, 0.0f); } return cvSmall; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 13867b0f7..bb42d5b4b 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -16,8 +16,8 @@ import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -import ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; class PolygonProcessingState { @@ -36,7 +36,6 @@ class PolygonProcessingState { private static final String UNSET_SITE_CURVE_NUMBERS = "unset siteCurveNumbers"; private static final String UNSET_INVENTORY_TYPE_GROUP = "unset inventoryTypeGroup"; - @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(PolygonProcessingState.class); /** The containing ForwardProcessingState */ @@ -100,7 +99,7 @@ class PolygonProcessingState { private MatrixMap3[] cvVolume; private MatrixMap2[] cvBasalArea; private MatrixMap2[] cvQuadraticMeanDiameter; - private Map[] cvPrimaryLayerSmall; + private Map[] cvPrimaryLayerSmall; // FRBASP0 - FR // TODO @@ -175,6 +174,13 @@ public int getPrimarySpeciesIndex() { } return primarySpeciesIndex; } + + public String getPrimarySpeciesAlias() { + if (!areRankingDetailsSet) { + throw new IllegalStateException("unset primarySpeciesIndex"); + } + return wallet.speciesNames[primarySpeciesIndex]; + } public boolean hasSecondarySpeciesIndex() { return secondarySpeciesIndex.isPresent(); @@ -275,22 +281,9 @@ public int getPrimarySpeciesStratumNumber() { return primarySpeciesStratumNumber; } - public boolean isAreSiteCurveNumbersSet() { - return areSiteCurveNumbersSet; - } - public int[] getSiteCurveNumbers() { return siteCurveNumbers; } - - public boolean isArePrimarySpeciesDetailsSet() { - return arePrimarySpeciesDetailsSet; - } - - public boolean isAreCompatibilityVariablesSet() { - return areCompatibilityVariablesSet; - } - public MatrixMap3[] getCvVolume() { return cvVolume; } @@ -303,7 +296,7 @@ public MatrixMap2[] getCvQuadraticMeanDiamet return cvQuadraticMeanDiameter; } - public Map[] getCvPrimaryLayerSmall() { + public Map[] getCvPrimaryLayerSmall() { return cvPrimaryLayerSmall; } @@ -417,12 +410,22 @@ public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { this.arePrimarySpeciesDetailsSet = true; } + + public void updatePrimarySpeciesDetailsAfterGrowth(float newPrimarySpeciesDominantHeight) { + + this.primarySpeciesDominantHeight = newPrimarySpeciesDominantHeight; + this.primarySpeciesTotalAge += 1; + this.primarySpeciesAgeAtBreastHeight += 1; + + // primarySpeciesSiteIndex - does this change? + // primarySpeciesAgeToBreastHeight of course doesn't change. + } public void setCompatibilityVariableDetails( MatrixMap3[] cvVolume, MatrixMap2[] cvBasalArea, MatrixMap2[] cvQuadraticMeanDiameter, - Map[] cvPrimaryLayerSmall + Map[] cvPrimaryLayerSmall ) { if (this.areCompatibilityVariablesSet) { throw new IllegalStateException(COMPATIBILITY_VARIABLES_SET_CAN_BE_SET_ONCE_ONLY); @@ -436,6 +439,31 @@ public void setCompatibilityVariableDetails( this.areCompatibilityVariablesSet = true; } + /** + * CVADJ1 - adjust the values of the compatibility variables after one year of growth. + */ + public void updateCompatibilityVariableAfterGrowth() { + + var compVarAdjustments = fps.fcm.getCompVarAdjustments(); + + for (int i: getIndices()) { + for (UtilizationClassVariable sucv: UtilizationClassVariable.values()) { + cvPrimaryLayerSmall[i].put(sucv, cvPrimaryLayerSmall[i].get(sucv) * compVarAdjustments.getValue(UtilizationClass.SMALL, sucv)); + } + for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + cvBasalArea[i].put(uc, LayerType.PRIMARY, cvBasalArea[i].get(uc, LayerType.PRIMARY) + * compVarAdjustments.getValue(uc, UtilizationClassVariable.BASAL_AREA)); + cvQuadraticMeanDiameter[i].put(uc, LayerType.PRIMARY, cvQuadraticMeanDiameter[i].get(uc, LayerType.PRIMARY) + * compVarAdjustments.getValue(uc, UtilizationClassVariable.QUAD_MEAN_DIAMETER)); + + for (VolumeVariable vv: VolumeVariable.ALL) { + cvVolume[i].put(uc, vv, LayerType.PRIMARY, cvVolume[i].get(uc, vv, LayerType.PRIMARY) + * compVarAdjustments.getVolumeValue(uc, vv)); + } + } + } + } + public float getCVVolume(int speciesIndex, UtilizationClass uc, VolumeVariable volumeVariable, LayerType layerType) { if (!this.areCompatibilityVariablesSet) { @@ -461,7 +489,7 @@ public float getCVQuadraticMeanDiameter(int speciesIndex, UtilizationClass uc, L return cvQuadraticMeanDiameter[speciesIndex].get(uc, layerType); } - public float getCVSmall(int speciesIndex, SmallUtilizationClassVariable variable) { + public float getCVSmall(int speciesIndex, UtilizationClassVariable variable) { if (!this.areCompatibilityVariablesSet) { throw new IllegalStateException(UNSET_CV_BASAL_AREAS); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index 06c3d1a57..3b59e0611 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.forward.controlmap; import java.util.Map; +import java.util.Optional; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; @@ -11,6 +12,8 @@ import ca.bc.gov.nrs.vdyp.model.GrowthFiatDetails; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.ModelCoefficients; +import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; public interface ForwardResolvedControlMap extends ResolvedControlMap { @@ -24,6 +27,15 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 43 - UPPER_BA_BY_CI_S0_P */ MatrixMap3 getUpperBoundsCoefficients(); + /** 50 - HL_PRIMARY_SP_EQN_P1 */ + MatrixMap2 getLoreyHeightPrimarySpeciesEquationP1Coefficients(); + + /** 53 - HL_NONPRIMARY */ + MatrixMap3> getLoreyHeightNonPrimaryCoefficients(); + + /** 61 - SPECIES_COMPONENT_SIZE_LIMIT */ + MatrixMap2 getComponentSizeCoefficients(); + /** 101 - VTROL */ ForwardControlVariables getForwardControlVariables(); @@ -48,6 +60,18 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 123 - DQ_GROWTH_EMPIRICAL_LIMITS */ Map getQuadMeanDiameterGrowthEmpiricalLimits(); + /** 148 - PRIMARY_SP_BA_GROWTH */ + Map getPrimarySpeciesBasalAreaGrowthCoefficients(); + + /** 149 - NON_PRIMARY_SP_BA_GROWTH */ + MatrixMap2> getNonPrimarySpeciesBasalAreaGrowthCoefficients(); + + /** 150 - PRIMARY_SP_DQ_GROWTH */ + Map getPrimarySpeciesQuadMeanDiameterGrowthCoefficients(); + + /** 151 - NON_PRIMARY_SP_DQ_GROWTH */ + MatrixMap2> getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients(); + /** 199 - DEBUG_SWITCHES */ ForwardDebugSettings getDebugSettings(); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index 0979971d2..5af3ea2a8 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.forward.controlmap; import java.util.Map; +import java.util.Optional; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Utils; @@ -14,6 +15,8 @@ import ca.bc.gov.nrs.vdyp.model.GrowthFiatDetails; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.ModelCoefficients; +import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl implements ForwardResolvedControlMap { @@ -30,7 +33,14 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl final Map quadMeanDiameterGrowthFiatDetails; final Map quadMeanDiameterGrowthEmpiricalCoefficients; final Map quadMeanDiameterGrowthEmpiricalLimits; - + final MatrixMap2 loreyHeightPrimarySpeciesEquationP1Coefficients; + final MatrixMap3> loreyHeightNonPrimaryCoefficients; + final Map primarySpeciesBasalAreaGrowthCoefficients; + final MatrixMap2> nonPrimarySpeciesBasalAreaGrowthCoefficients; + final Map primaryQuadMeanDiameterGrowthCoefficients; + final MatrixMap2> nonPrimaryQuadMeanDiameterGrowthCoefficients; + final MatrixMap2 componentSizeCoefficients; + public ForwardResolvedControlMapImpl(Map controlMap) { super(controlMap); @@ -47,6 +57,13 @@ public ForwardResolvedControlMapImpl(Map controlMap) { this.quadMeanDiameterGrowthFiatDetails = this.get(ControlKey.DQ_GROWTH_FIAT, Map.class); this.quadMeanDiameterGrowthEmpiricalCoefficients = this.get(ControlKey.DQ_GROWTH_EMPIRICAL, Map.class); this.quadMeanDiameterGrowthEmpiricalLimits = this.get(ControlKey.DQ_GROWTH_EMPIRICAL_LIMITS, Map.class); + this.loreyHeightPrimarySpeciesEquationP1Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); + this.loreyHeightNonPrimaryCoefficients = this.get(ControlKey.HL_NONPRIMARY, MatrixMap3.class); + this.primarySpeciesBasalAreaGrowthCoefficients = this.get(ControlKey.PRIMARY_SP_BA_GROWTH, Map.class); + this.nonPrimarySpeciesBasalAreaGrowthCoefficients = this.get(ControlKey.NON_PRIMARY_SP_BA_GROWTH, MatrixMap2.class); + this.primaryQuadMeanDiameterGrowthCoefficients = this.get(ControlKey.PRIMARY_SP_DQ_GROWTH, Map.class); + this.nonPrimaryQuadMeanDiameterGrowthCoefficients = this.get(ControlKey.NON_PRIMARY_SP_DQ_GROWTH, MatrixMap2.class); + this.componentSizeCoefficients = this.get(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); } @Override @@ -108,4 +125,39 @@ public Map getQuadMeanDiameterGrowthEmpiricalCoefficients public Map getQuadMeanDiameterGrowthEmpiricalLimits() { return quadMeanDiameterGrowthEmpiricalLimits; } + + @Override + public MatrixMap2 getLoreyHeightPrimarySpeciesEquationP1Coefficients() { + return loreyHeightPrimarySpeciesEquationP1Coefficients; + } + + @Override + public MatrixMap3> getLoreyHeightNonPrimaryCoefficients() { + return loreyHeightNonPrimaryCoefficients; + } + + @Override + public Map getPrimarySpeciesBasalAreaGrowthCoefficients() { + return primarySpeciesBasalAreaGrowthCoefficients; + } + + @Override + public MatrixMap2> getNonPrimarySpeciesBasalAreaGrowthCoefficients() { + return nonPrimarySpeciesBasalAreaGrowthCoefficients; + } + + @Override + public Map getPrimarySpeciesQuadMeanDiameterGrowthCoefficients() { + return primaryQuadMeanDiameterGrowthCoefficients; + } + + @Override + public MatrixMap2> getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() { + return nonPrimaryQuadMeanDiameterGrowthCoefficients; + } + + @Override + public MatrixMap2 getComponentSizeCoefficients() { + return this.componentSizeCoefficients; + } } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java index 80643e24d..71b255c53 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java @@ -43,6 +43,8 @@ import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; import ca.bc.gov.nrs.vdyp.test.TestUtils; @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -201,7 +203,7 @@ void testParseE028Empty() throws Exception { CompVarAdjustments m = (CompVarAdjustments) result.get(ControlKey.PARAM_ADJUSTMENTS.name()); - assertThat(m.getParam(CompVarAdjustments.SMALL_BA), is(1.0f)); + assertThat(m.getValue(UtilizationClass.SMALL, UtilizationClassVariable.BASAL_AREA), is(1.0f)); } @Test diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java index c3c4263e7..a1b3efa8d 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java @@ -1,13 +1,13 @@ package ca.bc.gov.nrs.vdyp.forward; -import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.BASAL_AREA; -import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.LOREY_HEIGHT; -import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.QUAD_MEAN_DIAMETER; -import static ca.bc.gov.nrs.vdyp.model.SmallUtilizationClassVariable.WHOLE_STEM_VOLUME; import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.OVER225; import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.U125TO175; import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.U175TO225; import static ca.bc.gov.nrs.vdyp.model.UtilizationClass.U75TO125; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable.BASAL_AREA; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable.LOREY_HEIGHT; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable.QUAD_MEAN_DIAMETER; +import static ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable.WHOLE_STEM_VOLUME; import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.CLOSE_UTIL_VOL; import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY; import static ca.bc.gov.nrs.vdyp.model.VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE; From 94ed1a88a5dd0c1dca12a9775971bcc80fe21b85 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 23 Jul 2024 14:43:44 -0700 Subject: [PATCH 21/66] Housekeeping --- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 8 +- .../vdyp/forward/ForwardProcessingEngine.java | 190 +++++++++--------- .../vdyp/forward/PolygonProcessingState.java | 2 +- .../forward/model/ForwardDebugSettings.java | 32 +++ 4 files changed, 131 insertions(+), 101 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index c841b0232..0805f3d21 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -813,14 +813,14 @@ private static void estimateUtilization( } /** - * EMP106 + * EMP106 - estimate primary layer basal area yield * * @param estimateBaseAreaYieldCoefficients * @param debugSetting2Value * @param dominantHeight * @param breastHeightAge * @param baseAreaOverstory - * @param fullOccupancy + * @param isFullOccupancy * @param bec * @param baseAreaGroup * @return @@ -828,7 +828,7 @@ private static void estimateUtilization( */ public float estimateBaseAreaYield( Coefficients estimateBaseAreaYieldCoefficients, int debugSetting2Value, float dominantHeight, - float breastHeightAge, Optional baseAreaOverstory, boolean fullOccupancy, BecDefinition bec, + float breastHeightAge, Optional baseAreaOverstory, boolean isFullOccupancy, BecDefinition bec, int baseAreaGroup ) throws StandProcessingException { float upperBoundBasalArea = upperBoundsBaseArea(baseAreaGroup); @@ -880,7 +880,7 @@ public float estimateBaseAreaYield( bap = Math.min(bap, upperBoundBasalArea); } - if (fullOccupancy) + if (isFullOccupancy) bap /= EMPIRICAL_OCCUPANCY; return bap; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 057d2fd97..0e84bcaf1 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -277,17 +277,15 @@ private void grow( calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); } - float dhStart = pps.getPrimarySpeciesDominantHeight(); - int siteCurveNumber = pps.getSiteCurveNumber(pps.getPrimarySpeciesIndex()); - float siteIndex = pps.getPrimarySpeciesSiteIndex(); - float ytbhStart = pps.getPrimarySpeciesAgeToBreastHeight(); - float primarySpeciesYearsAtBreastHeightStart = pps.getPrimarySpeciesAgeAtBreastHeight(); + float pspDhStart = pps.getPrimarySpeciesDominantHeight(); + int pspSiteCurveNumber = pps.getSiteCurveNumber(pps.getPrimarySpeciesIndex()); + float pspSiteIndex = pps.getPrimarySpeciesSiteIndex(); + float pspYtbhStart = pps.getPrimarySpeciesAgeToBreastHeight(); + float pspYabhStart = pps.getPrimarySpeciesAgeAtBreastHeight(); // Calculate change in dominant height - float dhDelta = growDominantHeight( - dhStart, siteCurveNumber, siteIndex, ytbhStart - ); + float dhDelta = growDominantHeight(pspDhStart, pspSiteCurveNumber, pspSiteIndex, pspYtbhStart); // Calculate change in basal area @@ -299,15 +297,14 @@ private void grow( } float baStart = pps.wallet.basalAreas[0][UC_ALL_INDEX]; - float baDelta = growBasalArea( - primarySpeciesYearsAtBreastHeightStart, fps.fcm - .getDebugSettings(), dhStart, baStart, veteranLayerBasalArea, dhDelta + float baDelta = growBasalArea(pspYabhStart, fps.fcm.getDebugSettings(), pspDhStart, + baStart, veteranLayerBasalArea, dhDelta ); float dqStart = pps.wallet.quadMeanDiameters[0][UC_ALL_INDEX]; Reference wasDqGrowthLimitApplied = new Reference<>(); float dqDelta = growQuadMeanDiameter( - ytbhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied + pspYtbhStart, baStart, pspDhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied ); if (wasDqGrowthLimitApplied.get() /* is true */) { @@ -321,13 +318,13 @@ private void grow( // Cache some values for calculations below. float baGrowthRate = baDelta / baStart; - float dhMultiplier = dhStart + dhDelta / dhStart; + float dhMultiplier = pspDhStart + dhDelta / pspDhStart; float primarySpeciesLhStart = pps.wallet.loreyHeights[pps.getPrimarySpeciesGroupNumber()][UC_ALL_INDEX]; float primarySpeciesTphStart = pps.wallet.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; float tphStart = pps.wallet.treesPerHectare[0][UC_ALL_INDEX]; - float dhEnd = dhStart + dhDelta; + float dhEnd = pspDhStart + dhDelta; float dqEnd = dqStart + dqDelta; float baEnd = baStart + baDelta; float tphEnd = calculateTreesPerHectare(baEnd, dqEnd); @@ -355,7 +352,7 @@ private void grow( float primarySpeciesTphEndEstimate = primarySpeciesTphStart * (tphEnd / tphStart); growLoreyHeights( - dhStart, dhEnd, primarySpeciesTphStart, primarySpeciesTphEndEstimate, primarySpeciesLhStart + pspDhStart, dhEnd, primarySpeciesTphStart, primarySpeciesTphEndEstimate, primarySpeciesLhStart ); float sum1 = 0.0f; @@ -402,7 +399,8 @@ private void grow( growLoreyHeightsForAllSpecies(); - // We now have predications for basal area, quad-mean-diameter, trees-per-hectare and Lorey height. + // We now have site level predications for basal area, quad-mean-diameter, trees-per-hectare + // and Lorey height. Proceed to per-species estimates. // Calculate basal area percentages per species for (int i = 1; i < pps.wallet.getNSpecies(); i++) { @@ -420,16 +418,16 @@ private void grow( pps.wallet.siteIndices[i] = pps.getPrimarySpeciesSiteIndex(); pps.wallet.yearsAtBreastHeight[i] = pps.getPrimarySpeciesAgeAtBreastHeight(); } else { - float speciesSiStart = pps.wallet.siteIndices[i]; - float speciesDhStart = pps.wallet.dominantHeights[i]; - float speciesYtbhStart = pps.wallet.yearsToBreastHeight[i]; - float speciesYabhStart = pps.wallet.yearsAtBreastHeight[i]; + float spSiStart = pps.wallet.siteIndices[i]; + float spDhStart = pps.wallet.dominantHeights[i]; + float spYtbhStart = pps.wallet.yearsToBreastHeight[i]; + float spYabhStart = pps.wallet.yearsAtBreastHeight[i]; - if (!Float.isNaN(speciesSiStart) && !Float.isNaN(speciesDhStart) - && !Float.isNaN(speciesYtbhStart) && !Float.isNaN(speciesYabhStart)) { + if (!Float.isNaN(spSiStart) && !Float.isNaN(spDhStart) + && !Float.isNaN(spYtbhStart) && !Float.isNaN(spYabhStart)) { float dhGrowth = growDominantHeight( - speciesDhStart, siteCurveNumber, pps.wallet.siteCurveNumbers[i], speciesYtbhStart + spDhStart, pspSiteCurveNumber, spSiStart, spYtbhStart ); pps.wallet.dominantHeights[i] += dhGrowth; } else { @@ -438,7 +436,7 @@ private void grow( } } - pps.updateCompatibilityVariableAfterGrowth(); + pps.updateCompatibilityVariablesAfterGrowth(); computeUtilizationComponentsPrimary(); @@ -525,7 +523,7 @@ private void growUsingFullSpeciesDynamics( } { - // Estimates of basal area growth by species + // Estimate of basal area growth by species // Iteratively attempt to find a value f such that: // @@ -577,22 +575,25 @@ private void growUsingFullSpeciesDynamics( } { + // Estimate of quad-mean-diameter growth by species + while (true) { - // Base estimates of DQ growth by species + + var bestScore = 1000.0; + var bestF = Float.NaN; + var f = 0.0f; var passNumber = 0; var nSkipped = 0; var totalBasalAreaSkipped = 0.0f; - var bestScore = 1000.0; - var bestF = Float.NaN; - + for (int i : pps.getIndices()) { float spDqStart = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; float spLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; - + float spDqDelta; if (i == pps.getPrimarySpeciesIndex()) { - + spDqDelta = growQuadMeanDiameterForPrimarySpecies( dqStart, dqDelta, spDqStart, lhStart, spLhStart ); @@ -607,9 +608,9 @@ private void growUsingFullSpeciesDynamics( ComponentSizeLimits csl = getComponentSizeLimits(pps.wallet.speciesNames[i], pps.getBecZone().getRegion()); var spLhAllStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; - + float spDqMaximum = Math.min(csl.quadMeanDiameterMaximum(), csl.maxQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); - + if (spDqStart + spDqDelta > spDqMaximum) { spDqDelta = Math.min(0.0f, spDqMaximum - spDqStart); nSkipped += 1; @@ -617,7 +618,7 @@ private void growUsingFullSpeciesDynamics( } float spDqMinimum = Math.max(7.6f, csl.minQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); - + if (spDqStart + spDqDelta < spDqMinimum) { spDqDelta = spDqMinimum - spDqStart; nSkipped += 1; @@ -1346,19 +1347,18 @@ private float[] getSpeciesProportionsByBasalArea() { /** * EMP111A - Basal area growth for the primary layer. * - * @param speciesProportionsByBasalArea the proportion by basal area of each of the polygon's species - * @param yearsAtBreastHeight at the start of the year - * @param dominantHeight primary species dominant height at start of year - * @param primaryLayerBasalArea at the start of the year - * @param veteranLayerBasalArea at the start of the year - * @param growthInDominantHeight during the year + * @param pspYabhStart at the start of the year + * @param pspDhStart primary species dominant height at start of year + * @param baStart at the start of the year + * @param veteranLayerBa at the start of the year + * @param dhDelta during the year * * @return the growth in the basal area for the year * @throws StandProcessingException in the event of an error */ float growBasalArea( - float yearsAtBreastHeight, ForwardDebugSettings debugSettings, float dominantHeight, - float primaryLayerBasalArea, Optional veteranLayerBasalArea, float growthInDominantHeight + float pspYabhStart, ForwardDebugSettings debugSettings, float pspDhStart, + float baStart, Optional veteranLayerBa, float dhDelta ) throws StandProcessingException { float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); @@ -1368,8 +1368,7 @@ float growBasalArea( Coefficients estimateBasalAreaYieldCoefficients = Coefficients.empty(7, 0); for (int i = 0; i < 7; i++) { float sum = 0.0f; - for (int speciesIndex = 1; speciesIndex <= fps.getPolygonProcessingState().wallet - .getNSpecies(); speciesIndex++) { + for (int speciesIndex : fps.getPolygonProcessingState().wallet.getIndices()) { String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; @@ -1381,36 +1380,36 @@ float growBasalArea( } boolean isFullOccupancy = true; - int primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + int pspGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); - float basalAreaYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeight, yearsAtBreastHeight, veteranLayerBasalArea, isFullOccupancy, fps - .getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber + float baYieldStart = fps.estimators.estimateBaseAreaYield( + estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhStart, pspYabhStart, veteranLayerBa, + isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), pspGroupNumber ); - float dominantHeightEnd = dominantHeight + growthInDominantHeight; - float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; + float pspDhEnd = pspDhStart + dhDelta; + float pspYabhEnd = pspYabhStart + 1.0f; - float basalAreaYieldEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, dominantHeightEnd, yearsAtBreastHeightEnd, veteranLayerBasalArea, isFullOccupancy, fps - .getPolygonProcessingState().getBecZone(), primarySpeciesGroupNumber + float baYieldEnd = fps.estimators.estimateBaseAreaYield( + estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, + isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), pspGroupNumber ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() .get(fps.getPolygonProcessingState().getBecZone().getRegion()); - var convergenceCoefficient = growthFaitDetails.calculateCoefficient(yearsAtBreastHeight); + var convergenceCoefficient = growthFaitDetails.calculateCoefficient(pspYabhStart); - float baGrowth = basalAreaYieldEnd - basalAreaYieldStart; - var adjust = -convergenceCoefficient * (primaryLayerBasalArea - basalAreaYieldStart); + float baGrowth = baYieldEnd - baYieldStart; + var adjust = -convergenceCoefficient * (baStart - baYieldStart); baGrowth += adjust; // Special check at young ages. - if (yearsAtBreastHeight < 40.0f && primaryLayerBasalArea > 5.0f * basalAreaYieldStart) { + if (pspYabhStart < 40.0f && baStart > 5.0f * baYieldStart) { // This stand started MUCH faster than base yield model. We'll let it keep going like // this for a while. - baGrowth = Math.min(basalAreaYieldStart / yearsAtBreastHeight, Math.min(0.5f, baGrowth)); + baGrowth = Math.min(baYieldStart / pspYabhStart, Math.min(0.5f, baGrowth)); } int debugSetting3Value = debugSettings.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3); @@ -1419,17 +1418,17 @@ float growBasalArea( float baGrowthFiatModel = baGrowth; float baGrowthEmpiricalModel = calculateBasalAreaGrowthEmpirical( - speciesProportionsByBasalArea, primaryLayerBasalArea, yearsAtBreastHeight, dominantHeight, basalAreaYieldStart, basalAreaYieldEnd + speciesProportionsByBasalArea, baStart, pspYabhStart, pspDhStart, baYieldStart, baYieldEnd ); baGrowth = baGrowthEmpiricalModel; if (debugSetting3Value == 2) { float c = 1.0f; - if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { + if (pspYabhStart >= growthFaitDetails.getMixedCoefficient(1)) { c = 0.0f; - } else if (yearsAtBreastHeight > growthFaitDetails.getMixedCoefficient(0)) { - float t1 = yearsAtBreastHeight - growthFaitDetails.getMixedCoefficient(0); + } else if (pspYabhStart > growthFaitDetails.getMixedCoefficient(0)) { + float t1 = pspYabhStart - growthFaitDetails.getMixedCoefficient(0); float t2 = growthFaitDetails.getMixedCoefficient(1) - growthFaitDetails.getMixedCoefficient(0); float t3 = growthFaitDetails.getMixedCoefficient(2); c = 1.0f - FloatMath.pow(t1 / t2, t3); @@ -1442,17 +1441,17 @@ float growBasalArea( var baUpperBound = growBasalAreaUpperBound(); baUpperBound = baUpperBound / Estimators.EMPIRICAL_OCCUPANCY; - var baLimit = Math.max(baUpperBound, primaryLayerBasalArea); + var baLimit = Math.max(baUpperBound, baStart); // Enforce upper limit on growth - if (primaryLayerBasalArea + baGrowth > baLimit) { - baGrowth = Math.max(baLimit - primaryLayerBasalArea, 0.0f); + if (baStart + baGrowth > baLimit) { + baGrowth = Math.max(baLimit - baStart, 0.0f); } // Undocumented check to prevent negative growth that causes BA to go to less than // 1.0. It is doubtful that this condition will ever occur... - if (baGrowth < 0.0f && primaryLayerBasalArea + baGrowth < 1.0f) { - baGrowth = -primaryLayerBasalArea + 1.0f; + if (baGrowth < 0.0f && baStart + baGrowth < 1.0f) { + baGrowth = -baStart + 1.0f; } return baGrowth; @@ -1461,23 +1460,23 @@ float growBasalArea( /** * EMP121. Calculate basal area growth using the empirical model. * - * @param speciesProportionsByBasalArea the proportion by basal area of each of the polygon's species - * @param primaryLayerBasalArea basal area of primary layer - * @param yearsAtBreastHeight primary species years at breast height or more - * @param dominantHeight primary species dominant height - * @param basalAreaYieldStart basal area yield at start of period - * @param basalAreaYieldEnd basal area yield at end of period + * @param speciesBasalAreaProportions the proportion by basal area of each of the polygon's species + * @param ba basal area of primary layer + * @param pspYabhStart primary species years at breast height or more + * @param pspDhStart primary species dominant height + * @param baYieldStart basal area yield at start of period + * @param baYieldEnd basal area yield at end of period * * @return the change in primary layer basal area from start to start + 1 year */ private float calculateBasalAreaGrowthEmpirical( - float[] speciesProportionsByBasalArea, float primaryLayerBasalArea, float yearsAtBreastHeight, - float dominantHeight, float basalAreaYieldStart, float basalAreaYieldEnd + float[] speciesBasalAreaProportions, float ba, float pspYabhStart, + float pspDhStart, float baYieldStart, float baYieldEnd ) { - yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); - if (yearsAtBreastHeight > 999.0f) { - yearsAtBreastHeight = 999.0f; + pspYabhStart = Math.max(pspYabhStart, 1.0f); + if (pspYabhStart > 999.0f) { + pspYabhStart = 999.0f; } var basalAreaGrowthEmpiricalCoefficients = fps.fcm.getBasalAreaGrowthEmpiricalCoefficients(); @@ -1498,27 +1497,27 @@ private float calculateBasalAreaGrowthEmpirical( for (int i = 1; i <= fps.getPolygonProcessingState().wallet.getNSpecies(); i++) { String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[i]; var baGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, speciesAlias); - b4 += speciesProportionsByBasalArea[i] * baGrowthCoe.getCoe(4); - b5 += speciesProportionsByBasalArea[i] * baGrowthCoe.getCoe(5); + b4 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(4); + b5 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(5); } b4 = Math.max(b4, 0.0f); b5 = Math.min(b5, 0.0f); float term1; - if (dominantHeight > b0) { - term1 = 1.0f - FloatMath.exp(b1 * (dominantHeight - b0)); + if (pspDhStart > b0) { + term1 = 1.0f - FloatMath.exp(b1 * (pspDhStart - b0)); } else { term1 = 0.0f; } - float fLogIt = -0.05f * (yearsAtBreastHeight - 350.0f); + float fLogIt = -0.05f * (pspYabhStart - 350.0f); float term2a = FloatMath.exp(fLogIt) / (1.0f + FloatMath.exp(fLogIt)); - float term2 = b2 * FloatMath.pow(dominantHeight / 20.0f, b3) * term2a; - float term3 = b4 * FloatMath.exp(b5 * yearsAtBreastHeight); + float term2 = b2 * FloatMath.pow(pspDhStart / 20.0f, b3) * term2a; + float term3 = b4 * FloatMath.exp(b5 * pspYabhStart); float term4; - float basalAreaYieldDelta = basalAreaYieldEnd - basalAreaYieldStart; + float basalAreaYieldDelta = baYieldEnd - baYieldStart; if (basalAreaYieldDelta > 0.0) { term4 = b6 * FloatMath.pow(basalAreaYieldDelta, b7); } else { @@ -1529,8 +1528,8 @@ private float calculateBasalAreaGrowthEmpirical( // An undocumented check to prevent negative growth that causes BA to go to // less than 1.0. It is doubtful that this condition will ever occur. - if (basalAreaDelta < 0.0 && primaryLayerBasalArea + basalAreaDelta < 1.0f) { - basalAreaDelta = -primaryLayerBasalArea + 1.0f; + if (basalAreaDelta < 0.0 && ba + basalAreaDelta < 1.0f) { + basalAreaDelta = -ba + 1.0f; } return basalAreaDelta; @@ -1578,7 +1577,7 @@ private float growQuadraticMeanDiameterUpperBound() { * HDGROW - calculate growth in dominant height from the current dominant height and the parameters * needed to do the computation * - * @param dhStart dominant height at the start of the growth period + * @param spDhStart dominant height at the start of the growth period * @param siteCurveNumber site curve number, used to find the site index equation * @param siStart * @param yearsToBreastHeight for the given species @@ -1587,8 +1586,7 @@ private float growQuadraticMeanDiameterUpperBound() { * @throws ProcessingException */ float growDominantHeight( - float dhStart, int siteCurveNumber, float siStart, - float yearsToBreastHeight + float spDhStart, int siteCurveNumber, float siStart, float yearsToBreastHeight ) throws ProcessingException { SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); @@ -1600,10 +1598,10 @@ float growDominantHeight( var siteIndexEquation = SiteIndexEquation.getByIndex(siteCurveNumber); - if (dhStart <= 1.3) { + if (spDhStart <= 1.3) { throw new ProcessingException( MessageFormat.format( - "(current) DominantHeight {0} is out of range (must be above 1.3)", dhStart + "(current) DominantHeight {0} is out of range (must be above 1.3)", spDhStart ) ); } @@ -1611,7 +1609,7 @@ float growDominantHeight( final SiteIndexAgeType ageType = SiteIndexAgeType.SI_AT_BREAST; double siStart_d = siStart; - double dhStart_d = dhStart; + double dhStart_d = spDhStart; double yearsToBreastHeight_d = yearsToBreastHeight; double ageStart; @@ -1725,8 +1723,8 @@ float growDominantHeight( // a * t = ln(1 + (dominantHeight - y) * a/rate) // t = ln(1 + (dominantHeight - y) * a/rate) / a float t; - if (dhStart > y) { - float term = 1.0f + (dhStart - y) * a / rate; + if (spDhStart > y) { + float term = 1.0f + (spDhStart - y) * a / rate; if (term <= 1.0e-7) { return 0.0f; } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index bb42d5b4b..30c1e3df1 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -442,7 +442,7 @@ public void setCompatibilityVariableDetails( /** * CVADJ1 - adjust the values of the compatibility variables after one year of growth. */ - public void updateCompatibilityVariableAfterGrowth() { + public void updateCompatibilityVariablesAfterGrowth() { var compVarAdjustments = fps.fcm.getCompVarAdjustments(); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java index aec3173d9..b42baf000 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java @@ -96,13 +96,45 @@ public class ForwardDebugSettings { public static final int MAX_FILL_INDEX_SETTINGS_INDEX = DebugSettings.MAX_DEBUG_SETTINGS; public enum Vars { + /** + *
    15. Value 0: Full species dynamics. Not recommended. + *
    16. Value 1: No species dynamics. Species percents in TPH and BA are constant. + *
    17. Value 2: Limited dynamics. Percents by BA are constant, but TPH %’s vary. + */ SPECIES_DYNAMICS_1(1), + /** + *
    18. Value 0: No upper age for application of BA and DQ yield equations. + *
    19. Value n: Maximum BH age for application of BA and DQ yields is 100 * n (years). + */ MAX_BREAST_HEIGHT_AGE_2(2), + /** + *
    20. Value 0: BA growth comes from fiat model (approach to yield eqn’s). + *
    21. Value 1: BA growth from empirical model (older ages suspect). + *
    22. Value 2: Mixed fiat & empirical model. (See SEQ111 and IPSJF162). + */ BASAL_AREA_GROWTH_MODEL_3(3), + /** + *
    23. Value 0: Will default to (2). Controls upper bounds in some models. + *
    24. Value 1: Limits from SEQ108 on control file, categorized by GRPBA1. + *
    25. Value 2: Limits from SEQ043 on control file, Coast Interior & Leading species. + */ PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4(4), + /** Messaging Level */ MESSAGING_LEVEL_5(5), + /** + *
    26. Value 0: DQ growth comes from fiat model (approach to yield eqn’s). + *
    27. Value 1: DQ growth from empirical model (older ages suspect). + *
    28. Value 2: Mixed fiat & empirical model. (See SEQ117 and IPSJF178). + */ DQ_GROWTH_MODEL_6(6), + /** + *
    29. Value 0: Normal changes in Lorey height (HL), all species. + *
    30. Value 1: Force change to zero for nonprimary species if change in HD is zero. + *
    31. Value 2: Force change to zero for all species if change in HD is zero. + * (option 2 precludes changes in primary sp HL due solely to change in TPH). + */ LOREY_HEIGHT_CHANGE_STRATEGY_8(8), + /** Limit BA if DQ has been limited */ DO_LIMIT_BA_WHEN_DQ_LIMITED_9(9); public final int settingNumber; From 55e505a90e8a12c85a7f3d3adcd8f27bf46f4599 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 24 Jul 2024 18:15:05 -0700 Subject: [PATCH 22/66] Code changes resulting from merge out from main after VDYP-305 merged to main --- .../application/VdypStartApplication.java | 2 +- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 19 ++--- .../BecZoneBySpeciesCoefficientParser.java | 15 ++-- .../vdyp/common/EstimationMethodsTest.java | 73 ++++++++++--------- .../control/NonFipControlParserTest.java | 17 +++-- .../vdyp/model/GrowthFiatDetailsTests.java | 5 -- .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 8 +- .../nrs/vdyp/fip/FipControlParserTest.java | 15 +++- .../forward/ForwardControlParserTest.java | 13 +++- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 30 ++++---- .../nrs/vdyp/vri/VriControlParserTest.java | 15 +++- 11 files changed, 116 insertions(+), 96 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 99183d753..4d51e6ea6 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -1142,7 +1142,7 @@ public void computeUtilizationComponentsPrimary( log.atDebug().log("Estimating tree volume"); var volumeGroup = spec.getVolumeGroup(); - var meanVolume = this.estimationMethods + var meanVolume = this.estimators .estimateWholeStemVolumePerTree(volumeGroup, loreyHeightSpec, quadMeanDiameterSpec); var specWholeStemVolume = treesPerHectareSpec * meanVolume; diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index f16513e43..6f01153f8 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -27,6 +27,7 @@ import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; @@ -268,7 +269,7 @@ public float estimateQuadMeanDiameterForSpecies( } float estimateQuadMeanDiameterClampResult( - Limits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, + ComponentSizeLimits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, float baseArea1, float baseArea2, float quadMeanDiameter1, float treesPerHectare2, float quadMeanDiameter2 ) { float treesPerHectare1; @@ -280,9 +281,9 @@ float estimateQuadMeanDiameterClampResult( quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); } - final float dqMinSp = max(minQuadMeanDiameter, limits.minDiameterHeight() * loreyHeightSpec); + final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); final float dqMaxSp = max( - 7.6f, min(limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() * loreyHeightSpec) + 7.6f, min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) ); if (quadMeanDiameter1 < dqMinSp) { quadMeanDiameter1 = dqMinSp; @@ -315,19 +316,13 @@ float estimateQuadMeanDiameterClampResult( return quadMeanDiameter1; } - public static record Limits( - float maxLoreyHeight, float maxQuadMeanDiameter, float minDiameterHeight, float maxDiameterHeight - ) { - }; - // EMP061 - public Limits getLimitsForHeightAndDiameter(String genus, Region region) { - var coeMap = controlMap.>get( + public ComponentSizeLimits getLimitsForHeightAndDiameter(String genus, Region region) { + var cslMap = controlMap.>get( ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class ); - var coe = coeMap.get(genus, region); - return new Limits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); + return cslMap.get(genus, region); } /** diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java index 713b69748..01726f201 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java @@ -87,18 +87,17 @@ public MatrixMap2 parse(InputStream is, Map 0) { - coefficients.setCoe(index, coe + first); - } else { - coefficients.setCoe(index, coe); - } - if (coefficientIndex == 0) { first = coe; } + Coefficients coefficients = r.get(becZoneId, spec); + if (indicator == 0 || coefficientIndex == 0) { + coefficients.setCoe(index, first); + } else { + coefficients.setCoe(index, first + coe); + } + coefficientIndex += 1; } diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java index d92290908..d8dce7075 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java @@ -18,8 +18,10 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; @@ -30,16 +32,17 @@ import ca.bc.gov.nrs.vdyp.test.TestUtils; import ca.bc.gov.nrs.vdyp.test.VdypMatchers; -class EstimationMethodsTest { +class EstimatorsTest { Map controlMap; BecLookup becLookup; - EstimationMethods emp; + Estimators emp; @BeforeEach void setup() { controlMap = TestUtils.loadControlMap(); - emp = new EstimationMethods(controlMap); + var resolvedControlMap = new ResolvedControlMapImpl(controlMap); + emp = new Estimators(resolvedControlMap); becLookup = (BecLookup) controlMap.get(ControlKey.BEC_DEF.name()); } @@ -56,8 +59,8 @@ void testWhenBasalAreaAllIsZero() throws ProcessingException { Coefficients quadMeanDiameterByUtilization = Utils.utilizationVector(0.0f); Coefficients basalAreaByUtilization = Utils.utilizationVector(0.0f); - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() + emp.estimateBaseAreaByUtilization( + becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() ); for (var c : basalAreaByUtilization) { @@ -76,8 +79,8 @@ void testWhenBasalAreaAllIsTenAndQuadMeanDiametersAreAllZero() throws Processing Coefficients quadMeanDiameterByUtilization = Utils.utilizationVector(0.0f); Coefficients basalAreaByUtilization = Utils.utilizationVector(10.0f); - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() + emp.estimateBaseAreaByUtilization( + becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() ); assertThat(basalAreaByUtilization.getCoe(UtilizationClass.SMALL.index), is(0.0f)); @@ -100,8 +103,8 @@ void testTypical() throws ProcessingException { Coefficients quadMeanDiameterByUtilization = Utils.utilizationVector(31.5006275f); Coefficients basalAreaByUtilization = Utils.utilizationVector(0.406989872f); - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() + emp.estimateBaseAreaByUtilization( + becDefinition, quadMeanDiameterByUtilization, basalAreaByUtilization, genus.getAlias() ); // Result of run in FORTRAN VDYP7 with the above parameters. @@ -160,8 +163,8 @@ void testWhenWholeStemVolumeIsZero() throws ProcessingException { Coefficients closeUtilizationVolume = Utils.utilizationVector(0.0f); float loreyHeight = 30.0f; - EstimationMethods.estimateCloseUtilizationVolume( - controlMap, UtilizationClass.U75TO125, aAdjust, volumeGroup, loreyHeight, + emp.estimateCloseUtilizationVolume( + UtilizationClass.U75TO125, aAdjust, volumeGroup, loreyHeight, quadMeanDiameterByUtilization, wholeStemVolumeByUtilization, closeUtilizationVolume ); @@ -190,8 +193,8 @@ void testTypical() throws ProcessingException { Coefficients closeUtilizationVolume = Utils.utilizationVector(0.0f); float loreyHeight = 36.7552986f; - EstimationMethods.estimateCloseUtilizationVolume( - controlMap, UtilizationClass.U175TO225, aAdjust, volumeGroup, loreyHeight, + emp.estimateCloseUtilizationVolume( + UtilizationClass.U175TO225, aAdjust, volumeGroup, loreyHeight, quadMeanDiameterByUtilization, wholeStemVolumeByUtilization, closeUtilizationVolume ); @@ -243,8 +246,8 @@ void testWhenCloseUtilizationIsZero() throws ProcessingException { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayVolume( - controlMap, genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, + emp.estimateNetDecayVolume( + genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, volumeGroup, 0.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay ); @@ -272,8 +275,8 @@ void testTypical() throws ProcessingException { ); int decayGroup = decayEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayVolume( - controlMap, genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, + emp.estimateNetDecayVolume( + genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, decayGroup, 54.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay ); @@ -299,8 +302,8 @@ void testWhenCloseUtilizationLessDecayIsZero() throws ProcessingException { Coefficients closeUtilizationNetOfDecay = Utils.utilizationVector(0.0f); Coefficients closeUtilizationNetOfDecayAndWastage = Utils.utilizationVector(0.0f); - EstimationMethods.estimateNetDecayAndWasteVolume( - controlMap, becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 0.0f, + emp.estimateNetDecayAndWasteVolume( + becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 0.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay, closeUtilizationNetOfDecayAndWastage ); @@ -326,8 +329,8 @@ void testTypical() throws ProcessingException { .utilizationVector(0.0f, 5.90565634f, 0.000909090857f, 0.0502020158f, 0.152929291f, 5.70161581f); Coefficients closeUtilizationNetOfDecayAndWastage = Utils.utilizationVector(0.0f); - EstimationMethods.estimateNetDecayAndWasteVolume( - controlMap, becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), + emp.estimateNetDecayAndWasteVolume( + becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 36.7552986f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay, closeUtilizationNetOfDecayAndWastage ); @@ -359,8 +362,8 @@ void testWhenCloseUtilizationLessDecayAndWastageIsZero() throws ProcessingExcept ); int breakageGroup = breakageEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, + emp.estimateNetDecayWasteAndBreakageVolume( + UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage ); @@ -389,8 +392,8 @@ void testTypical() throws ProcessingException { ); int breakageGroup = breakageEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, + emp.estimateNetDecayWasteAndBreakageVolume( + UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage ); @@ -520,7 +523,7 @@ void testSimple() throws Exception { @Test void testClampSimple() throws Exception { - var limits = new EstimationMethods.Limits(48.3f, 68.7f, 0.729f, 1.718f); + var limits = new ComponentSizeLimits(48.3f, 68.7f, 0.729f, 1.718f); float standTreesPerHectare = 620.5049f; float minQuadMeanDiameter = 7.6f; float loreyHeightSpec = 38.74565f; @@ -541,7 +544,7 @@ void testClampSimple() throws Exception { @Test void testClampToLow2() throws Exception { - var limits = new EstimationMethods.Limits(48.3f, 68.7f, 0.729f, 1.718f); + var limits = new ComponentSizeLimits(48.3f, 68.7f, 0.729f, 1.718f); float standTreesPerHectare = 620.5049f; float minQuadMeanDiameter = 7.6f; float loreyHeightSpec = 38.74565f; @@ -567,7 +570,7 @@ void testClampToLow2() throws Exception { @Test void testClampToLow1() throws Exception { - var limits = new EstimationMethods.Limits(48.3f, 68.7f, 0.729f, 1.718f); + var limits = new ComponentSizeLimits(48.3f, 68.7f, 0.729f, 1.718f); float standTreesPerHectare = 620.5049f; float minQuadMeanDiameter = 7.6f; float loreyHeightSpec = 38.74565f; @@ -593,7 +596,7 @@ void testClampToLow1() throws Exception { @Test void testClampToHigh1() throws Exception { - var limits = new EstimationMethods.Limits(48.3f, 68.7f, 0.729f, 1.718f); + var limits = new ComponentSizeLimits(48.3f, 68.7f, 0.729f, 1.718f); float standTreesPerHectare = 620.5049f; float minQuadMeanDiameter = 7.6f; float loreyHeightSpec = 38.74565f; @@ -643,8 +646,8 @@ void testPrimary() throws ProcessingException { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - EstimationMethods.estimateWholeStemVolume( - controlMap, UtilizationClass.ALL, 0.0f, volumeGroup, 36.7552986f, quadMeanDiameterByUtilization, + emp.estimateWholeStemVolume( + UtilizationClass.ALL, 0.0f, volumeGroup, 36.7552986f, quadMeanDiameterByUtilization, basalAreaByUtilization, wholeStemVolumeByUtilization ); @@ -690,8 +693,8 @@ void testWholeStemVolumePerTreeEstimation() { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - float result = EstimationMethods - .estimateWholeStemVolumePerTree(controlMap, volumeGroup, 36.7552986f, 31.5006275f); + float result = emp + .estimateWholeStemVolumePerTree(volumeGroup, 36.7552986f, 31.5006275f); // Result of run in FORTRAN VDYP7 with the above parameters. assertThat(result, is(1.2011181f)); @@ -724,7 +727,7 @@ void testEqn1() throws Exception { builder.breakageGroup(-1); }); - var result = emp.estimateNonPrimaryLoreyHeight(spec, specPrime, bec, 24.2999992f, 20.5984688f); + var result = emp.estimateNonPrimaryLoreyHeight(spec.getGenus(), specPrime.getGenus(), bec, 24.2999992f, 20.5984688f); assertThat(result, closeTo(21.5356998f)); @@ -754,7 +757,7 @@ void testEqn2() throws Exception { builder.breakageGroup(-1); }); - var result = emp.estimateNonPrimaryLoreyHeight(spec, specPrime, bec, 35.2999992f, 33.6889763f); + var result = emp.estimateNonPrimaryLoreyHeight(spec.getGenus(), specPrime.getGenus(), bec, 35.2999992f, 33.6889763f); assertThat(result, closeTo(38.7456512f)); diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java index 076da5e66..493d687d9 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java @@ -20,7 +20,6 @@ import java.io.InputStream; import java.io.SequenceInputStream; import java.nio.charset.StandardCharsets; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,14 +29,15 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -325,9 +325,14 @@ void testParseE061() throws Exception { result, (Matcher) controlMapHasEntry( ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - allOf(mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL)) - ) - ); + mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL)) + ); + var cslMap = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + var csl = cslMap.get("AC", Region.COASTAL); + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); } @Test @@ -623,7 +628,7 @@ static InputStream addToEnd(InputStream is, String... lines) { } } - Map parse(BaseControlParser parser, Class klazz, String resourceName) + Map parse(BaseControlParser parser, Class klazz, String resourceName) throws IOException, ResourceParseException { try (var is = klazz.getResourceAsStream(resourceName)) { diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java index 0e85e1316..716d59f98 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java @@ -86,11 +86,6 @@ void testAgesNotMonatonicallyIncreasing() { assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 2.5f, 4.0f, 0.1f, 0.2f, 0.3f))); } - @Test - void testCoefficientsNotMonatonicallyIncreasing() { - assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(2, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 1.5f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); - } - @Test void testRegionValueNot1Or2() { assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(0, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 1.5f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index 647f984b4..bef9af1cf 100644 --- a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -415,7 +415,7 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, final float maxHeightMultiplier = fipLayer.getPrimaryGenus() .orElseThrow(() -> new IllegalStateException("primaryGenus has not been set")) .equals(spec.getGenus()) ? 1.5f : 1.0f; - final float heightMax = limits.maxLoreyHeight() * maxHeightMultiplier; + final float heightMax = limits.loreyHeightMaximum() * maxHeightMultiplier; spec.getLoreyHeightByUtilization().scalarInPlace(UTIL_ALL, x -> min(x, heightMax)); } @@ -462,10 +462,10 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, // EMP061 var limits = estimators.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - var dqMin = limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); + var dqMin = limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); var dqMax = max( - limits.maxQuadMeanDiameter(), - limits.maxDiameterHeight() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) + limits.quadMeanDiameterMaximum(), + limits.maxQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) ); // EMP060 diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java b/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java index 89412e5e1..404000b5e 100644 --- a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java +++ b/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -36,6 +37,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -330,9 +332,14 @@ void testParseE061() throws Exception { result, (Matcher) controlMapHasEntry( ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - allOf(mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL)) - ) - ); + mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL)) + ); + var cslMap = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + var csl = cslMap.get("AC", Region.COASTAL); + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); } @Test @@ -612,7 +619,7 @@ static InputStream addToEnd(InputStream is, String... lines) { } } - Map parse(BaseControlParser parser, Class klazz, String resourceName) + Map parse(BaseControlParser parser, Class klazz, String resourceName) throws IOException, ResourceParseException { try (var is = klazz.getResourceAsStream(resourceName)) { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java index 71b255c53..6ea3ea52f 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java @@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; @@ -39,6 +40,7 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -294,9 +296,14 @@ void testParseE061() throws Exception { result, (Matcher) controlMapHasEntry( ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - allOf(mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL)) - ) - ); + mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL)) + ); + var cslMap = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + var csl = cslMap.get("AC", Region.COASTAL); + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); } @Test diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index c9169c770..6d35a4cc3 100644 --- a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.vri; -import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.*; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.quadMeanDiameter; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.treesPerHectare; import java.io.Closeable; import java.io.IOException; @@ -23,6 +24,7 @@ import org.apache.commons.math3.exception.TooManyEvaluationsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.RuntimeProcessingException; import ca.bc.gov.nrs.vdyp.application.RuntimeStandProcessingException; @@ -30,7 +32,6 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods.Limits; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.SiteIndex2Height; @@ -41,8 +42,6 @@ import ca.bc.gov.nrs.vdyp.io.parse.control.BaseControlParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; -import ca.bc.gov.nrs.vdyp.model.PolygonMode; -import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.BaseVdypSite; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies.Builder; @@ -50,11 +49,14 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.ModelClassBuilder; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; +import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.VdypLayer; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; @@ -440,8 +442,8 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws var leadHeight = requirePositive(primarySiteIn.getHeight(), "Primary layer lead species height"); // HLPL1 + var primaryHeight = estimators.primaryHeightFromLeadHeight( // EMP050 Method 1 - var primaryHeight = estimationMethods.primaryHeightFromLeadHeight( leadHeight, primarySiteIn.getSiteGenus(), bec.getRegion(), primarySpeciesDensity ); @@ -463,14 +465,14 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws float speciesQuadMeanDiameter = Math.max(7.5f, height / leadHeight * layerQuadMeanDiameter); float speciesDensity = treesPerHectare(primaryBaseArea, speciesQuadMeanDiameter); // EMP050 Method 1 - float speciesLoreyHeight = estimationMethods.primaryHeightFromLeadHeight( + float speciesLoreyHeight = estimators.primaryHeightFromLeadHeight( vriSite.getHeight().get(), vriSite.getSiteGenus(), bec.getRegion(), speciesDensity ); return speciesLoreyHeight; }).orElseGet(() -> { try { // EMP053 - float speciesLoreyHeight = estimationMethods.estimateNonPrimaryLoreyHeight( + float speciesLoreyHeight = estimators.estimateNonPrimaryLoreyHeight( vriSite.getSiteGenus(), primarySiteIn.getSiteGenus(), bec, leadHeight, primaryHeight ); return speciesLoreyHeight; @@ -479,8 +481,8 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws } }); - float maxHeight = estimationMethods.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) - .maxLoreyHeight(); + float maxHeight = estimators.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) + .loreyHeightMaximum(); loreyHeight = Math.min(loreyHeight, maxHeight); sBuilder.loreyHeight(loreyHeight); } @@ -589,7 +591,7 @@ void getDqBySpeciesInitial( ) throws ProcessingException { for (var spec : layer.getSpecies().values()) { // EMP060 - float specDq = estimationMethods.estimateQuadMeanDiameterForSpecies( + float specDq = estimators.estimateQuadMeanDiameterForSpecies( spec, layer.getSpecies(), region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, loreyHeightTotal ); @@ -597,9 +599,9 @@ void getDqBySpeciesInitial( var limits = getLimitsForSpecies(spec, region); float min = Math - .max(7.6f, limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL)); + .max(7.6f, limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL)); float loreyHeightToUse = Math.max(spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL), 7.0f); - float max = Math.min(limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() * loreyHeightToUse); + float max = Math.min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightToUse); max = Math.max(7.75f, max); minPerSpecies.put(spec.getGenus(), min); @@ -613,11 +615,11 @@ void getDqBySpeciesInitial( } } - protected Limits getLimitsForSpecies(VdypSpecies spec, Region region) { + protected ComponentSizeLimits getLimitsForSpecies(VdypSpecies spec, Region region) { // TODO for JPROGRAM = 7 implement this differently, see ROOTV01 L91-L99 // EMP061 - return estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), region); + return estimators.getLimitsForHeightAndDiameter(spec.getGenus(), region); } float quadMeanDiameterFractionalError( diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java b/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java index 5f6e302f9..c44f4ee5e 100644 --- a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java +++ b/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java @@ -30,6 +30,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -37,6 +38,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -321,9 +323,14 @@ void testParseE061() throws Exception { result, (Matcher) controlMapHasEntry( ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - allOf(mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL)) - ) - ); + mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL)) + ); + var cslMap = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + var csl = cslMap.get("AC", Region.COASTAL); + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); } @Test @@ -619,7 +626,7 @@ static InputStream addToEnd(InputStream is, String... lines) { } } - Map parse(BaseControlParser parser, Class klazz, String resourceName) + Map parse(BaseControlParser parser, Class klazz, String resourceName) throws IOException, ResourceParseException { try (var is = klazz.getResourceAsStream(resourceName)) { From 374732e558c3365f940905e5766320904fcb2f3e Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 29 Jul 2024 09:52:29 -0700 Subject: [PATCH 23/66] Begin refactoring to common data structures --- .../ca/bc/gov/nrs/vdyp/common/UtilsTest.java | 1 - .../io/parse/coe/ComponentSizeParserTest.java | 2 - .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 123 +- .../vdyp/forward/ForwardProcessingEngine.java | 951 +++--- .../vdyp/forward/ForwardProcessingState.java | 4 +- .../vdyp/forward/PolygonProcessingState.java | 57 +- .../vdyp/forward/VdypForwardApplication.java | 2979 ----------------- .../nrs/vdyp/forward/model/VdypPolygon.java | 13 +- .../vdyp/forward/model/VdypPolygonLayer.java | 2 +- .../forward/parsers/VdypPolygonParser.java | 10 +- .../GeneralForwardProcessingEngineTest.java | 8 +- .../forward/PolygonProcessingStateTest.java | 3 +- 12 files changed, 653 insertions(+), 3500 deletions(-) diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java index 10cc67a22..85dd869b9 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java @@ -2,7 +2,6 @@ import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.arrayContaining; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasProperty; diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java index c35b05f65..6dc067692 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java @@ -1,9 +1,7 @@ package ca.bc.gov.nrs.vdyp.io.parse.coe; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe; import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.mmHasEntry; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 2af0508ec..825e8c0b2 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -62,41 +62,45 @@ public Bank(VdypPolygonLayer layer, BecDefinition becZone, Predicate speciesToRetain = new ArrayList<>(); + for (VdypLayerSpecies s : layer.getGenera().values()) { if (retainCriteria.test(s)) { speciesToRetain.add(s); } } + speciesToRetain.sort((o1, o2) -> o1.getGenusIndex().compareTo(o2.getGenusIndex())); - nSpecies = speciesToRetain.size(); - indices = IntStream.range(1, nSpecies + 1).toArray(); + this.nSpecies = speciesToRetain.size(); + this.indices = IntStream.range(1, nSpecies + 1).toArray(); // In the following, index 0 is unused - speciesNames = new String[getNSpecies() + 1]; - sp64Distributions = new GenusDistributionSet[getNSpecies() + 1]; - siteIndices = new float[getNSpecies() + 1]; - dominantHeights = new float[getNSpecies() + 1]; - ageTotals = new float[getNSpecies() + 1]; - yearsAtBreastHeight = new float[getNSpecies() + 1]; - yearsToBreastHeight = new float[getNSpecies() + 1]; - siteCurveNumbers = new int[getNSpecies() + 1]; - speciesIndices = new int[getNSpecies() + 1]; - percentagesOfForestedLand = new float[getNSpecies() + 1]; + speciesNames = new String[nSpecies + 1]; + sp64Distributions = new GenusDistributionSet[nSpecies + 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]; int nUtilizationClasses = UtilizationClass.values().length; // In the following, index 0 is used for the default species utilization - basalAreas = new float[getNSpecies() + 1][nUtilizationClasses]; - closeUtilizationVolumes = new float[getNSpecies() + 1][nUtilizationClasses]; - cuVolumesMinusDecay = new float[getNSpecies() + 1][nUtilizationClasses]; - cuVolumesMinusDecayAndWastage = new float[getNSpecies() + 1][nUtilizationClasses]; - loreyHeights = new float[getNSpecies() + 1][2]; - quadMeanDiameters = new float[getNSpecies() + 1][nUtilizationClasses]; - treesPerHectare = new float[getNSpecies() + 1][nUtilizationClasses]; - wholeStemVolumes = new float[getNSpecies() + 1][nUtilizationClasses]; + basalAreas = new float[nSpecies + 1][nUtilizationClasses]; + closeUtilizationVolumes = new float[nSpecies + 1][nUtilizationClasses]; + cuVolumesMinusDecay = new float[nSpecies + 1][nUtilizationClasses]; + cuVolumesMinusDecayAndWastage = new float[nSpecies + 1][nUtilizationClasses]; + loreyHeights = new float[nSpecies + 1][2]; + quadMeanDiameters = new float[nSpecies + 1][nUtilizationClasses]; + treesPerHectare = new float[nSpecies + 1][nUtilizationClasses]; + wholeStemVolumes = new float[nSpecies + 1][nUtilizationClasses]; if (layer.getDefaultUtilizationMap().isPresent()) { recordUtilizations(0, layer.getDefaultUtilizationMap().get()); @@ -108,32 +112,75 @@ public Bank(VdypPolygonLayer layer, BecDefinition becZone, PredicateprocessPolygon for each polygon to be processed. All calls + * to processPolygon are entirely independent of one another, allowing (different) + * polygons to the processed in parallel. */ public class ForwardProcessingEngine { @@ -115,12 +119,27 @@ public ExecutionStep successor() { } } + /** + * Run all steps of the engine on the given polygon. + * + * @param polygon the polygon on which to operate + * + * @throws ProcessingException should an error with the data occur during processing + */ public void processPolygon(VdypPolygon polygon) throws ProcessingException { processPolygon(polygon, ExecutionStep.ALL); } - public void processPolygon(VdypPolygon polygon, ExecutionStep lastStep) throws ProcessingException { + /** + * Run all steps of the engine on the given polygon up to and including the given lastStep. + * + * @param polygon the polygon on which to operate + * @param lastStepInclusive execute up to and including this step + * + * @throws ProcessingException should an error with the data occur during processing + */ + public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) throws ProcessingException { logger.info("Starting processing of polygon {}", polygon.getDescription()); @@ -139,8 +158,7 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStep) throws P throw new ProcessingException( "Control Variable 1 has the value -1, indicating that the grow-to years are" + " to be read from a grow-to-year file (at " + ControlKey.FORWARD_INPUT_GROWTO.name() - + " in the" - + " control file), but no such file was specified." + + " in the control file), but no such file was specified." ); } targetYear = polygon.getTargetYear().get(); @@ -154,10 +172,10 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStep) throws P // Run the forward algorithm for this polygon - executeForwardAlgorithm(lastStep, targetYear); + executeForwardAlgorithm(lastStepInclusive, targetYear); } - private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) throws ProcessingException { + private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilYear) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank bank = fps.getBank(0, LayerType.PRIMARY); @@ -165,53 +183,54 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro logger.info("Beginning processing of polygon {} layer {}", pps.getLayer().getParent(), pps.getLayer()); // BANKCHK1, simplified for the parameters METH_CHK = 4, LayerI = 1, and INSTANCE = 1 - if (lastStep.ordinal() >= ExecutionStep.CHECK_FOR_WORK.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.CHECK_FOR_WORK.ordinal()) { stopIfNoWork(pps); } // SCINXSET - note these are calculated directly from the Primary bank of instance 1 - if (lastStep.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { calculateMissingSiteCurves(bank, fps.fcm.getSiteCurveMap(), fps.getPolygonProcessingState()); } // VPRIME1, method == 1 - if (lastStep.ordinal() >= ExecutionStep.CALCULATE_COVERAGES.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_COVERAGES.ordinal()) { calculateCoverages(); } - if (lastStep.ordinal() >= ExecutionStep.DETERMINE_POLYGON_RANKINGS.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.DETERMINE_POLYGON_RANKINGS.ordinal()) { determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); } // SITEADD (TODO: SITEADDU when NDEBUG 11 > 0) - if (lastStep.ordinal() >= ExecutionStep.ESTIMATE_MISSING_SITE_INDICES.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.ESTIMATE_MISSING_SITE_INDICES.ordinal()) { estimateMissingSiteIndices(pps); } - if (lastStep.ordinal() >= ExecutionStep.ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES.ordinal()) { estimateMissingYearsToBreastHeightValues(pps); } // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 - if (lastStep.ordinal() >= ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX.ordinal()) { calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); } // CVSET1 - if (lastStep.ordinal() >= ExecutionStep.SET_COMPATIBILITY_VARIABLES.ordinal()) { - setCompatibilityVariables(pps); + if (lastStepInclusive.ordinal() >= ExecutionStep.SET_COMPATIBILITY_VARIABLES.ordinal()) { + setCompatibilityVariables(); } // VGROW1 - if (lastStep.ordinal() >= ExecutionStep.GROW.ordinal()) { + if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { int veteranLayerInstance = 0; - int primaryLayerSourceInstance = 2; - fps.storeActive(primaryLayerSourceInstance, LayerType.PRIMARY); - int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); + Bank startBank = pps.getStartBank(); + + int primaryLayerSourceInstance = 2; + fps.storeActive(pps.getStartBank(), primaryLayerSourceInstance, LayerType.PRIMARY); - writeLayers(primaryLayerSourceInstance, veteranLayerInstance, false); + writeLayers(startBank, veteranLayerInstance, false); boolean createNewGroups = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 @@ -221,16 +240,18 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro int currentYear = startingYear; while (currentYear <= untilYear) { - grow(primaryLayerSourceInstance, currentYear, primaryLayerTargetInstance, veteranLayerInstance); + Bank endBank = grow(startBank, currentYear, veteranLayerInstance); // Store polygon (both primary and veteran layers) to output - writeLayers(primaryLayerTargetInstance, veteranLayerInstance, createNewGroups); + writeLayers(endBank, veteranLayerInstance, createNewGroups); currentYear += 1; int newPrimaryLayerSourceInstance = primaryLayerTargetInstance; primaryLayerTargetInstance = primaryLayerSourceInstance; primaryLayerSourceInstance = newPrimaryLayerSourceInstance; + + startBank = endBank; } } } @@ -244,29 +265,24 @@ private void executeForwardAlgorithm(ExecutionStep lastStep, int untilYear) thro * @param currentYear * @param primaryLayerTargetInstance * @param veteranLayerInstance + * @return * * @throws ProcessingException */ - private void grow( - int primaryLayerSourceInstance, int currentYear, int primaryLayerTargetInstance, int veteranLayerInstance - ) + private Bank grow(Bank start, int currentYear, int veteranLayerInstance) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); VdypPolygon polygon = pps.getPolygon(); - logger.info( - "Performing grow of {} for year {} from instance {} to instance {}", polygon.getDescription() - .getName(), currentYear, primaryLayerSourceInstance, primaryLayerTargetInstance - ); + logger.info("Performing grow of {} for year {}", polygon.getDescription().getName(), currentYear); - // Call to BANKOUT1 unnecessary; pps.wallet already contains the primary layer + Bank end = new Bank(start, CopyMode.CopyStructure); Optional veteranBank = Optional.ofNullable(fps.getBank(veteranLayerInstance, LayerType.VETERAN)); - // If update-during-growth is set, and this is not the starting year, update the - // context - int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); + // If update-during-growth is set, and this is not the starting year, update the context + int startingYear = polygon.getDescription().getYear(); if (currentYear > startingYear && fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { @@ -277,7 +293,7 @@ private void grow( calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); } - float pspDhStart = pps.getPrimarySpeciesDominantHeight(); + float dhStart = pps.getPrimarySpeciesDominantHeight(); int pspSiteCurveNumber = pps.getSiteCurveNumber(pps.getPrimarySpeciesIndex()); float pspSiteIndex = pps.getPrimarySpeciesSiteIndex(); float pspYtbhStart = pps.getPrimarySpeciesAgeToBreastHeight(); @@ -285,7 +301,7 @@ private void grow( // Calculate change in dominant height - float dhDelta = growDominantHeight(pspDhStart, pspSiteCurveNumber, pspSiteIndex, pspYtbhStart); + float dhDelta = growDominantHeight(dhStart, pspSiteCurveNumber, pspSiteIndex, pspYtbhStart); // Calculate change in basal area @@ -296,44 +312,45 @@ private void grow( veteranLayerBasalArea = Optional.empty(); } - float baStart = pps.wallet.basalAreas[0][UC_ALL_INDEX]; - float baDelta = growBasalArea(pspYabhStart, fps.fcm.getDebugSettings(), pspDhStart, - baStart, veteranLayerBasalArea, dhDelta + float dqStart = start.quadMeanDiameters[0][UC_ALL_INDEX]; + float baStart = start.basalAreas[0][UC_ALL_INDEX]; + float tphStart = start.treesPerHectare[0][UC_ALL_INDEX]; + float lhStart = start.loreyHeights[0][UC_ALL_INDEX]; + + float baDelta = growBasalArea( + pspYabhStart, fps.fcm.getDebugSettings(), dhStart, baStart, veteranLayerBasalArea, dhDelta ); - float dqStart = pps.wallet.quadMeanDiameters[0][UC_ALL_INDEX]; Reference wasDqGrowthLimitApplied = new Reference<>(); float dqDelta = growQuadMeanDiameter( - pspYtbhStart, baStart, pspDhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied + pspYtbhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied ); if (wasDqGrowthLimitApplied.get() /* is true */) { // Limit BA growth if DQ hit limit. - float qmdEndOfGrowthPeriod = dqStart + dqDelta; - float baMax = baStart * (qmdEndOfGrowthPeriod * qmdEndOfGrowthPeriod - / dqStart * dqStart); - baDelta = Math.min(baDelta, baMax - baStart); + float dqEnd = dqStart + dqDelta; + float baEndMax = baStart * (dqEnd * dqEnd) / (dqStart * dqStart); + baDelta = Math.min(baDelta, baEndMax - baStart); } // Cache some values for calculations below. - float baGrowthRate = baDelta / baStart; - float dhMultiplier = pspDhStart + dhDelta / pspDhStart; + float baChangeRate = baDelta / baStart; - float primarySpeciesLhStart = pps.wallet.loreyHeights[pps.getPrimarySpeciesGroupNumber()][UC_ALL_INDEX]; - float primarySpeciesTphStart = pps.wallet.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; - float tphStart = pps.wallet.treesPerHectare[0][UC_ALL_INDEX]; + float pspLhStart = start.loreyHeights[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspTphStart = start.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; - float dhEnd = pspDhStart + dhDelta; + float dhEnd = dhStart + dhDelta; float dqEnd = dqStart + dqDelta; float baEnd = baStart + baDelta; float tphEnd = calculateTreesPerHectare(baEnd, dqEnd); float tphMultiplier = tphEnd / tphStart; - // Begin storing computed results - pps.wallet.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; - pps.wallet.basalAreas[0][UC_ALL_INDEX] = baEnd; - pps.wallet.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; + // Begin storing computed results - dq, ba and tph for the layer + + end.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; + end.basalAreas[0][UC_ALL_INDEX] = baEnd; + end.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; // Now do DQ growth by species, using one of several options: "full species", "dynamic", "partial dynamics" // or "no dynamics." @@ -341,87 +358,97 @@ private void grow( boolean wasSolutionFound = false; if (debugSetting1Value == 2) { - // This is the partial species dynamics section. + // This is the PARTIAL SPECIES DYNAMICS section. // Begin by updating HL for all species (save the ungrown HLs). - float[] currentLoreyHeights = new float[pps.wallet.getNSpecies() + 1]; - for (int i = 1; i < pps.wallet.getNSpecies(); i++) { - currentLoreyHeights[i] = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + float[] currentLoreyHeights = new float[start.getNSpecies() + 1]; + currentLoreyHeights[0] = start.loreyHeights[0][UC_ALL_INDEX]; + for (int i : start.getIndices()) { + currentLoreyHeights[i] = start.loreyHeights[i][UC_ALL_INDEX]; } - float primarySpeciesTphEndEstimate = primarySpeciesTphStart * (tphEnd / tphStart); + float pspTphEndEstimate = pspTphStart * (tphEnd / tphStart); - growLoreyHeights( - pspDhStart, dhEnd, primarySpeciesTphStart, primarySpeciesTphEndEstimate, primarySpeciesLhStart - ); + growLoreyHeights(end, dhStart, dhEnd, pspTphStart, pspTphEndEstimate, pspLhStart); float sum1 = 0.0f; float sum2 = 0.0f; - for (int i = 1; i <= pps.getNSpecies(); i++) { - sum1 += pps.wallet.basalAreas[i][UC_ALL_INDEX] * pps.wallet.loreyHeights[i][UC_ALL_INDEX]; - sum2 += pps.wallet.basalAreas[i][UC_ALL_INDEX]; + for (int i : start.getIndices()) { + sum1 += start.basalAreas[i][UC_ALL_INDEX] * start.loreyHeights[i][UC_ALL_INDEX]; + sum2 += start.basalAreas[i][UC_ALL_INDEX]; } - pps.wallet.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; + start.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; // Now do the actual updates of DQ by species - wasSolutionFound = growUsingPartialSpeciesDynamics(); + wasSolutionFound = growUsingPartialSpeciesDynamics(end, dqDelta, baDelta, baStart, dqStart, tphStart, currentLoreyHeights); // Restore the Lorey Heights back to the values at the beginning of the period. // They will be updated below using the new estimate of TPH-primary species. - for (int i = 1; i < pps.wallet.getNSpecies(); i++) { - pps.wallet.loreyHeights[i][UC_ALL_INDEX] = currentLoreyHeights[i]; + for (int i = 1; i < start.getNSpecies(); i++) { + start.loreyHeights[i][UC_ALL_INDEX] = currentLoreyHeights[i]; } - } else { - if (debugSetting1Value == 1 || pps.wallet.getNSpecies() == 1 || !wasSolutionFound) { - // No species dynamics section - growUsingNoSpeciesDynamics(baGrowthRate, tphMultiplier); + } + + if (!wasSolutionFound) { + + if (debugSetting1Value == 1 || start.getNSpecies() == 1) { + + // This is the NO SPECIES DYNAMICS section + growUsingNoSpeciesDynamics(end, baChangeRate, tphMultiplier); } else { - // Full species dynamics section + + // This is the FULL SPECIES DYNAMICS section growUsingFullSpeciesDynamics(dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); } } - // Calculate trees-per-hectare over all species - float totalTreesPerHectare = 0.0f; - for (int i = 1; i < pps.wallet.getNSpecies(); i++) { - if (pps.wallet.basalAreas[i][UC_ALL_INDEX] > 0.0f) { - totalTreesPerHectare += pps.wallet.treesPerHectare[i][UC_ALL_INDEX]; + // Calculate trees-per-hectare over all species, all ucs + + float totalTphEnd = 0.0f; + for (int i = 1; i < end.getNSpecies(); i++) { + if (end.basalAreas[i][UC_ALL_INDEX] > 0.0f) { + totalTphEnd += end.treesPerHectare[i][UC_ALL_INDEX]; } } - pps.wallet.treesPerHectare[0][0] = totalTreesPerHectare; + end.treesPerHectare[0][UC_ALL_INDEX] = totalTphEnd; + + // Calculate quad-mean-diameter over all species, uc UC_ALL_INDEX - // Calculate quad-mean-diameter for all species. - pps.wallet.quadMeanDiameters[0][0] = calculateQuadMeanDiameter( - pps.wallet.basalAreas[0][0], pps.wallet.treesPerHectare[0][0] + end.quadMeanDiameters[0][UC_ALL_INDEX] = calculateQuadMeanDiameter( + end.basalAreas[0][UC_ALL_INDEX], end.treesPerHectare[0][UC_ALL_INDEX] ); - growLoreyHeightsForAllSpecies(); + // Calculate Lorey heights over all species, uc UC_ALL_INDEX + + float pspTphEnd = end.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + growLoreyHeights(end, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); // We now have site level predications for basal area, quad-mean-diameter, trees-per-hectare // and Lorey height. Proceed to per-species estimates. - // Calculate basal area percentages per species - for (int i = 1; i < pps.wallet.getNSpecies(); i++) { - pps.wallet.percentagesOfForestedLand[i] = 100.0f * pps.wallet.basalAreas[i][UC_ALL_INDEX] - / pps.wallet.basalAreas[0][UC_ALL_INDEX]; + // Calculate basal area percentages per species, uc UC_ALL_INDEX + + for (int i : start.getIndices()) { + end.percentagesOfForestedLand[i] = 100.0f * end.basalAreas[i][UC_ALL_INDEX] + / end.basalAreas[0][UC_ALL_INDEX]; } // Update the running values. TODO: why isn't siteIndex being updated? pps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); - for (int i = 1; i < pps.wallet.getNSpecies(); i++) { + for (int i = 1; i < start.getNSpecies(); i++) { if (i == pps.getPrimarySpeciesIndex()) { - pps.wallet.ageTotals[i] = pps.getPrimarySpeciesTotalAge(); - pps.wallet.dominantHeights[i] = dhEnd; - pps.wallet.siteIndices[i] = pps.getPrimarySpeciesSiteIndex(); - pps.wallet.yearsAtBreastHeight[i] = pps.getPrimarySpeciesAgeAtBreastHeight(); + end.ageTotals[i] = pps.getPrimarySpeciesTotalAge(); + end.dominantHeights[i] = dhEnd; + end.siteIndices[i] = pps.getPrimarySpeciesSiteIndex(); + end.yearsAtBreastHeight[i] = pps.getPrimarySpeciesAgeAtBreastHeight(); } else { - float spSiStart = pps.wallet.siteIndices[i]; - float spDhStart = pps.wallet.dominantHeights[i]; - float spYtbhStart = pps.wallet.yearsToBreastHeight[i]; - float spYabhStart = pps.wallet.yearsAtBreastHeight[i]; + float spSiStart = start.siteIndices[i]; + float spDhStart = start.dominantHeights[i]; + float spYtbhStart = start.yearsToBreastHeight[i]; + float spYabhStart = start.yearsAtBreastHeight[i]; if (!Float.isNaN(spSiStart) && !Float.isNaN(spDhStart) && !Float.isNaN(spYtbhStart) && !Float.isNaN(spYabhStart)) { @@ -429,9 +456,9 @@ private void grow( float dhGrowth = growDominantHeight( spDhStart, pspSiteCurveNumber, spSiStart, spYtbhStart ); - pps.wallet.dominantHeights[i] += dhGrowth; + end.dominantHeights[i] += dhGrowth; } else { - pps.wallet.dominantHeights[i] = Float.NaN; + end.dominantHeights[i] = Float.NaN; } } } @@ -440,39 +467,71 @@ private void grow( computeUtilizationComponentsPrimary(); - calculateSmallComponentYields(); + calculateSmallComponentYields(end); + + return end; } - private void growUsingNoSpeciesDynamics(float baGrowthRate, float tphMultiplier) { + /** + * Calculate basal area, trees-per-hectare and quad-mean-diameter for all species + * in the polygon, given the per-layer basal area growth rate and tree-per-hectare + * muliplier + * + * @param baChangeRate + * @param tphChangeRate + */ + private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphChangeRate) { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); for (int i : pps.getIndices()) { - float spBaAllStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; - if (spBaAllStart > 0.0f) { - float spBaAllEnd = spBaAllStart * (1.0f * baGrowthRate); - - float spTphAllStart = pps.wallet.treesPerHectare[i][UC_ALL_INDEX]; - float spTphAllEnd = spTphAllStart * tphMultiplier; - float spDqAllEnd = calculateQuadMeanDiameter(spBaAllEnd, spTphAllEnd); - if (spDqAllEnd < 7.51f) { - spDqAllEnd = 7.51f; - spTphAllEnd = calculateTreesPerHectare(spBaAllEnd, spDqAllEnd); + float spBaStart = start.basalAreas[i][UC_ALL_INDEX]; + if (spBaStart > 0.0f) { + float spBaEnd = spBaStart * (1.0f + baChangeRate); + float spTphStart = start.treesPerHectare[i][UC_ALL_INDEX]; + float spTphEnd = spTphStart * tphChangeRate; + float spDqEnd = calculateQuadMeanDiameter(spBaEnd, spTphEnd); + if (spDqEnd < 7.51f) { + spDqEnd = 7.51f; + spTphEnd = calculateTreesPerHectare(spBaEnd, spDqEnd); } - pps.wallet.basalAreas[i][UC_ALL_INDEX] = spBaAllEnd; - pps.wallet.treesPerHectare[i][UC_ALL_INDEX] = spTphAllEnd; - pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX] = spDqAllEnd; + end.basalAreas[i][UC_ALL_INDEX] = spBaEnd; + end.treesPerHectare[i][UC_ALL_INDEX] = spTphEnd; + end.quadMeanDiameters[i][UC_ALL_INDEX] = spDqEnd; } } } - private boolean growUsingPartialSpeciesDynamics() { - - PolygonProcessingState pps = fps.getPolygonProcessingState(); + /** + * GRSPpart - update quad-mean-diameter (dq) by species. + * + * @param end the target of the computation + * @param dqDelta change in overall quad-mean-diameter during the growth period + * @param baDelta change in overall basal area during the growth period + * @param baStart overall basal area at start of growth period + * @param dqStart overall quad-mean-diameter at start of growth period + * @param tphStart overall trees-per-hectare value at the start of growth period + * @param currentLoreyHeights the current Lorey heights of each of the species + * (indices 1 - # species) | overall (index 0) the start of the growth period + * + * @return true if and only if a solution was found. + */ + private boolean growUsingPartialSpeciesDynamics(Bank end, float dqDelta, float baDelta, float baStart, + float dqStart, float tphStart, float[] currentLoreyHeights) { boolean wasSuccessful = true; + PolygonProcessingState pps = fps.getPolygonProcessingState(); + + if (dqDelta == 0 || baDelta == 0 || pps.getNSpecies() == 1) { + return false /* no solution available */; + } + + + return wasSuccessful; } @@ -482,6 +541,8 @@ private void growUsingFullSpeciesDynamics( ) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); + Bank end = new Bank(start, CopyMode.CopyStructure); float spBaEnd[] = new float[pps.getNSpecies() + 1]; float spTphNew[] = new float[pps.getNSpecies() + 1]; @@ -489,9 +550,9 @@ private void growUsingFullSpeciesDynamics( boolean doSkip[] = new boolean[pps.getNSpecies() + 1]; for (int i : pps.getIndices()) { - spBaEnd[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX]; - spTphNew[i] = pps.wallet.treesPerHectare[i][UC_ALL_INDEX]; - spDqNew[i] = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; + spBaEnd[i] = start.basalAreas[i][UC_ALL_INDEX]; + spTphNew[i] = start.treesPerHectare[i][UC_ALL_INDEX]; + spDqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; doSkip[i] = false; } @@ -500,9 +561,9 @@ private void growUsingFullSpeciesDynamics( float spBaDelta[] = new float[pps.getNSpecies()]; for (int i : pps.getIndices()) { - float pspLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + float pspLhStart = start.loreyHeights[i][UC_ALL_INDEX]; if (i == pps.getPrimarySpeciesIndex()) { - float pspBaStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + float pspBaStart = start.basalAreas[i][UC_ALL_INDEX]; float pspYabhStart = pps.getPrimarySpeciesAgeAtBreastHeight(); // Note: the FORTRAN passes Lorey height into parameter "HD" ("Dominant Height") - are these @@ -511,11 +572,11 @@ private void growUsingFullSpeciesDynamics( baStart, baDelta, pspBaStart, lhStart, pspYabhStart, pspLhStart ); } else { - float spBaStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; - float spDqStart = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; - float spLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; + float spBaStart = start.basalAreas[i][UC_ALL_INDEX]; + float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; + float spLhStart = start.loreyHeights[i][UC_ALL_INDEX]; spBaDelta[i] = growBasalAreaForNonPrimarySpecies( - i, baStart, baDelta, pspLhStart, spBaStart, spDqStart, spLhStart + start.speciesNames[i], baStart, baDelta, pspLhStart, spBaStart, spDqStart, spLhStart ); } @@ -544,7 +605,7 @@ private void growUsingFullSpeciesDynamics( for (int i : pps.getIndices()) { if (!doSkip[i]) { - var spBaStart = pps.wallet.basalAreas[i][UC_ALL_INDEX]; + var spBaStart = pps.getStartBank().basalAreas[i][UC_ALL_INDEX]; spBaEnd[i] = spBaStart + spBaDelta[i] + f * spBaStart; if (spBaEnd[i] < 0.0f) { spBaEnd[i] = 0.0f; @@ -578,7 +639,7 @@ private void growUsingFullSpeciesDynamics( // Estimate of quad-mean-diameter growth by species while (true) { - + var bestScore = 1000.0; var bestF = Float.NaN; @@ -586,14 +647,14 @@ private void growUsingFullSpeciesDynamics( var passNumber = 0; var nSkipped = 0; var totalBasalAreaSkipped = 0.0f; - + for (int i : pps.getIndices()) { - float spDqStart = pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX]; - float spLhStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; - + float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; + float spLhStart = start.loreyHeights[i][UC_ALL_INDEX]; + float spDqDelta; if (i == pps.getPrimarySpeciesIndex()) { - + spDqDelta = growQuadMeanDiameterForPrimarySpecies( dqStart, dqDelta, spDqStart, lhStart, spLhStart ); @@ -602,34 +663,38 @@ private void growUsingFullSpeciesDynamics( i, dqStart, dqDelta, spDqStart, lhStart, spLhStart ); } - + spDqDelta += f; - - ComponentSizeLimits csl = getComponentSizeLimits(pps.wallet.speciesNames[i], pps.getBecZone().getRegion()); - - var spLhAllStart = pps.wallet.loreyHeights[i][UC_ALL_INDEX]; - - float spDqMaximum = Math.min(csl.quadMeanDiameterMaximum(), csl.maxQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); - + + ComponentSizeLimits csl = getComponentSizeLimits( + start.speciesNames[i], pps.getBecZone().getRegion() + ); + + var spLhAllStart = start.loreyHeights[i][UC_ALL_INDEX]; + + float spDqMaximum = Math.min( + csl.quadMeanDiameterMaximum(), csl.maxQuadMeanDiameterLoreyHeightRatio() * spLhAllStart + ); + if (spDqStart + spDqDelta > spDqMaximum) { spDqDelta = Math.min(0.0f, spDqMaximum - spDqStart); nSkipped += 1; - totalBasalAreaSkipped += pps.wallet.basalAreas[i][UC_ALL_INDEX]; + totalBasalAreaSkipped += start.basalAreas[i][UC_ALL_INDEX]; } - + float spDqMinimum = Math.max(7.6f, csl.minQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); - + if (spDqStart + spDqDelta < spDqMinimum) { spDqDelta = spDqMinimum - spDqStart; nSkipped += 1; - totalBasalAreaSkipped += pps.wallet.basalAreas[i][UC_ALL_INDEX]; + totalBasalAreaSkipped += start.basalAreas[i][UC_ALL_INDEX]; } - + spDqNew[i] = spDqStart + spDqDelta; } - + float tph = 0.0f; - for (int i: pps.wallet.speciesIndices) { + for (int i : start.speciesIndices) { if (spBaEnd[i] > 0.0f) { spTphNew[i] = calculateTreesPerHectare(spBaEnd[i], spDqNew[i]); } else { @@ -637,43 +702,43 @@ private void growUsingFullSpeciesDynamics( } tph += spTphNew[i]; } - - if (passNumber == 15 || (nSkipped == pps.wallet.getNSpecies() && passNumber > 2)) { + + if (passNumber == 15 || (nSkipped == pps.getNSpecies() && passNumber > 2)) { break; } - + float dqNewBar = calculateQuadMeanDiameter(baStart + baDelta, tph); float dqStartEstimate = calculateQuadMeanDiameter(baStart, tphStart); float dqWant = dqStartEstimate + dqDelta; - + var score = FloatMath.abs(dqWant - dqNewBar); if (score < bestScore) { bestScore = score; bestF = f; } - + if (FloatMath.abs(score) < 0.001) { break; } - + if (totalBasalAreaSkipped > 0.7f) { totalBasalAreaSkipped = 0.7f * baStart; - } - + } + score = score * baStart / (baStart - totalBasalAreaSkipped); f += score; - + passNumber += 1; if (passNumber == 15) { f = bestF; } } - - for (int i : pps.wallet.speciesIndices) { - pps.wallet.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; - pps.wallet.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; + + for (int i : start.speciesIndices) { + end.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; + end.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; if (spBaEnd[i] > 0.0f) { - pps.wallet.quadMeanDiameters[i][UC_ALL_INDEX] = calculateQuadMeanDiameter(spBaEnd[i], spTphNew[i]); + end.quadMeanDiameters[i][UC_ALL_INDEX] = calculateQuadMeanDiameter(spBaEnd[i], spTphNew[i]); } } } @@ -688,10 +753,10 @@ private void growUsingFullSpeciesDynamics( * @return as described */ private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region region) { - + MatrixMap2 limits = fps.fcm.getComponentSizeCoefficients(); Coefficients coe = limits.get(genusAlias, region); - + return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); } @@ -733,9 +798,10 @@ private float growQuadMeanDiameterForPrimarySpecies( private float growQuadMeanDiameterForNonPrimarySpecies( int speciesIndex, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart ) throws ProcessingException { + PolygonProcessingState pps = fps.getPolygonProcessingState(); - String speciesName = pps.wallet.speciesNames[speciesIndex]; + String speciesName = pps.getStartBank().speciesNames[speciesIndex]; int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() @@ -757,10 +823,9 @@ private float growQuadMeanDiameterForNonPrimarySpecies( return growQuadMeanDiameter(modelCoefficientsOpt.get(), dqStart, dqDelta, spDqStart, lhStart, spLhStart); } - private float growQuadMeanDiameter( + private static float growQuadMeanDiameter( Coefficients mc, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart ) { - float a0 = mc.getCoe(1); float a1 = mc.getCoe(2); float a2 = mc.getCoe(3); @@ -786,7 +851,7 @@ private float growQuadMeanDiameter( * EMP149 - return the basal area growth for non-Primary species of Primary layer. Based on * IPSJF149.doc (July, 1999). * - * @param speciesIndex + * @param speciesName * @param baStart layer basal area at start of growth period * @param baDelta layer basal area growth during period * @param lhStart layer Lorey height at start of growth period @@ -798,7 +863,7 @@ private float growQuadMeanDiameter( * @throws ProcessingException */ private float growBasalAreaForNonPrimarySpecies( - int speciesIndex, float baStart, float baDelta, float lhStart, float spBaStart, float spDqStart, + String speciesName, float baStart, float baDelta, float lhStart, float spBaStart, float spDqStart, float spLhStart ) throws ProcessingException { @@ -813,7 +878,6 @@ private float growBasalAreaForNonPrimarySpecies( ); } - String speciesName = pps.wallet.speciesNames[speciesIndex]; int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients() @@ -827,7 +891,8 @@ private float growBasalAreaForNonPrimarySpecies( throw new ProcessingException( MessageFormat.format( "No nonPrimarySpeciesBasalAreaGrowthCoefficients exist for stratum {0}" - + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", pspStratumNumber, speciesIndex, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart + + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", + pspStratumNumber, speciesName, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart ) ); } @@ -905,10 +970,9 @@ private float growBasalAreaForPrimarySpecies( return baDelta; } - private void growLoreyHeightsForAllSpecies() { - // TODO Auto-generated method stub - } - + /** + * YUC1 + */ private void computeUtilizationComponentsPrimary() { // TODO Auto-generated method stub } @@ -918,10 +982,10 @@ private void computeUtilizationComponentsPrimary() { * * @throws ProcessingException */ - private void calculateSmallComponentYields() throws ProcessingException { + private void calculateSmallComponentYields(Bank end) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); - Bank wallet = pps.wallet; + Bank start = pps.getStartBank(); float lhSum = 0.0f; float baSum = 0.0f; @@ -930,12 +994,12 @@ private void calculateSmallComponentYields() throws ProcessingException { for (int speciesIndex : pps.getIndices()) { - float spLhAll = wallet.loreyHeights[speciesIndex][UC_ALL_INDEX]; - float spBaAll = wallet.basalAreas[speciesIndex][UC_ALL_INDEX]; - float spDqAll = wallet.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; + float spLhAll = end.loreyHeights[speciesIndex][UC_ALL_INDEX]; + float spBaAll = end.basalAreas[speciesIndex][UC_ALL_INDEX]; + float spDqAll = end.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); - String speciesName = wallet.speciesNames[speciesIndex]; + String speciesName = start.speciesNames[speciesIndex]; // EMP080 float smallProbability = smallComponentProbability(speciesName, spLhAll, region); @@ -991,14 +1055,14 @@ private void calculateSmallComponentYields() throws ProcessingException { float spTphSmall = calculateTreesPerHectare(spBaSmall, spDqSmall); float spWsVolumeSmall = spTphSmall * meanVolumeSmall; - pps.wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX] = spLhSmall; - pps.wallet.basalAreas[speciesIndex][UC_SMALL_INDEX] = spBaSmall; - pps.wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX] = spTphSmall; - pps.wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX] = spDqSmall; - pps.wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX] = spWsVolumeSmall; - pps.wallet.closeUtilizationVolumes[speciesIndex][UC_SMALL_INDEX] = 0.0f; - pps.wallet.cuVolumesMinusDecay[speciesIndex][UC_SMALL_INDEX] = 0.0f; - pps.wallet.cuVolumesMinusDecayAndWastage[speciesIndex][UC_SMALL_INDEX] = 0.0f; + end.loreyHeights[speciesIndex][UC_SMALL_INDEX] = spLhSmall; + end.basalAreas[speciesIndex][UC_SMALL_INDEX] = spBaSmall; + end.treesPerHectare[speciesIndex][UC_SMALL_INDEX] = spTphSmall; + end.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX] = spDqSmall; + end.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX] = spWsVolumeSmall; + end.closeUtilizationVolumes[speciesIndex][UC_SMALL_INDEX] = 0.0f; + end.cuVolumesMinusDecay[speciesIndex][UC_SMALL_INDEX] = 0.0f; + end.cuVolumesMinusDecayAndWastage[speciesIndex][UC_SMALL_INDEX] = 0.0f; lhSum += spBaSmall * spDqSmall; baSum += spBaSmall; @@ -1007,84 +1071,83 @@ private void calculateSmallComponentYields() throws ProcessingException { } if (baSum > 0.0) { - pps.wallet.loreyHeights[0][UC_SMALL_INDEX] = lhSum / baSum; + end.loreyHeights[0][UC_SMALL_INDEX] = lhSum / baSum; } else { - pps.wallet.loreyHeights[0][UC_SMALL_INDEX] = 0.0f; - } - pps.wallet.basalAreas[0][UC_SMALL_INDEX] = baSum; - pps.wallet.treesPerHectare[0][UC_SMALL_INDEX] = tphSum; - pps.wallet.quadMeanDiameters[0][UC_SMALL_INDEX] = calculateQuadMeanDiameter(baSum, tphSum); - pps.wallet.wholeStemVolumes[0][UC_SMALL_INDEX] = wsVolumeSum; - pps.wallet.closeUtilizationVolumes[0][UC_SMALL_INDEX] = 0.0f; - pps.wallet.cuVolumesMinusDecay[0][UC_SMALL_INDEX] = 0.0f; - pps.wallet.cuVolumesMinusDecayAndWastage[0][UC_SMALL_INDEX] = 0.0f; + end.loreyHeights[0][UC_SMALL_INDEX] = 0.0f; + } + end.basalAreas[0][UC_SMALL_INDEX] = baSum; + end.treesPerHectare[0][UC_SMALL_INDEX] = tphSum; + end.quadMeanDiameters[0][UC_SMALL_INDEX] = calculateQuadMeanDiameter(baSum, tphSum); + end.wholeStemVolumes[0][UC_SMALL_INDEX] = wsVolumeSum; + end.closeUtilizationVolumes[0][UC_SMALL_INDEX] = 0.0f; + end.cuVolumesMinusDecay[0][UC_SMALL_INDEX] = 0.0f; + end.cuVolumesMinusDecayAndWastage[0][UC_SMALL_INDEX] = 0.0f; } /** * GRSPHL - estimate the Lorey Heights of all species at end of growth period. The results of - * the calculations are persisted in {@code pps.wallet}. + * the calculations are persisted in {@code start}. * - * @param primarySpeciesDhStart primary species dominant height at start - * @param primarySpeciesDhEnd primary species dominant height at end - * @param primarySpeciesTphStart primary species trees-per-hectare at start - * @param primarySpeciesTphEnd primary species trees-per-hectare at end - * @param primarySpeciesLhStart primary species Lorey height at end + * @param dhStart (primary species) dominant height at start + * @param dhEnd (primary species) dominant height at end + * @param pspTphStart primary species trees-per-hectare at start + * @param pspTphEnd primary species trees-per-hectare at end + * @param pspLhStart primary species Lorey height at end */ - private void growLoreyHeights( - float primarySpeciesDhStart, float primarySpeciesDhEnd, float primarySpeciesTphStart, - float primarySpeciesTphEnd, float primarySpeciesLhStart - ) { + private void growLoreyHeights(Bank end, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart) { + PolygonProcessingState pps = fps.getPolygonProcessingState(); - Bank wallet = pps.wallet; + Bank start = pps.getStartBank(); - float lhStartEstimate = estimatePrimarySpeciesLoreyHeight(primarySpeciesDhStart, primarySpeciesTphStart); - float lhEndEstimate = estimatePrimarySpeciesLoreyHeight(primarySpeciesDhEnd, primarySpeciesTphEnd); + float pspLhStartEstimate = estimatePrimarySpeciesLoreyHeight(dhStart, pspTphStart); + float pspLhEndEstimate = estimatePrimarySpeciesLoreyHeight(dhEnd, pspTphEnd); - float primaryF = (primarySpeciesLhStart - 1.3f) / (lhStartEstimate - 1.3f); + float primaryF = (pspLhStart - 1.3f) / (pspLhStartEstimate - 1.3f); float primaryLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightPrimaryParam(); primaryF = 1.0f + (primaryF - 1.0f) * primaryLhAdjustment; - float primarySpeciesLhEnd = 1.3f + (lhEndEstimate - 1.3f) * primaryF; + float pspLhEnd = 1.3f + (pspLhEndEstimate - 1.3f) * primaryF; int debugSetting8Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8); int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); - if (debugSetting8Value != 2 || primarySpeciesDhStart != primarySpeciesDhEnd) { - wallet.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX] = primarySpeciesLhEnd; + if (debugSetting8Value != 2 || dhStart != dhEnd) { + end.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX] = pspLhEnd; } else if (debugSetting8Value == 2) { - primarySpeciesLhEnd = wallet.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; + pspLhEnd = start.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; } - float otherLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightOther(); + float nonPrimaryLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightOther(); - for (int i = 1; i < fps.getPolygonProcessingState().getNSpecies(); i++) { - if (wallet.basalAreas[i][UC_ALL_INDEX] > 0.0f && i != primarySpeciesIndex) { - if (! (primarySpeciesDhEnd == primarySpeciesDhStart && debugSetting8Value >= 1)) { - float lhEstimate1 = estimateNonPrimarySpeciesLoreyHeight( - i, primarySpeciesDhStart, primarySpeciesLhStart + for (int i : pps.getIndices()) { + if (start.basalAreas[i][UC_ALL_INDEX] > 0.0f && i != primarySpeciesIndex) { + if (! (dhEnd == dhStart && debugSetting8Value >= 1)) { + float spLhEstimate1 = estimateNonPrimarySpeciesLoreyHeight( + i, dhStart, pspLhStart ); - float lhEstimate2 = estimateNonPrimarySpeciesLoreyHeight( - i, primarySpeciesDhEnd, primarySpeciesLhEnd + float spLhEstimate2 = estimateNonPrimarySpeciesLoreyHeight( + i, dhEnd, pspLhEnd ); - float otherF = (wallet.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (lhEstimate1 - 1.3f); - otherF = 1.0f - (otherF - 1.0f) * otherLhAdjustment; - wallet.loreyHeights[i][UC_ALL_INDEX] = 1.3f + (lhEstimate2 - 1.3f) * otherF; + float otherF = (start.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (spLhEstimate1 - 1.3f); + otherF = 1.0f - (otherF - 1.0f) * nonPrimaryLhAdjustment; + end.loreyHeights[i][UC_ALL_INDEX] = 1.3f + (spLhEstimate2 - 1.3f) * otherF; } } } } /** - * EMP050, method 1. Estimate the Lorey height of the primary species at the end of the growth period. + * EMP050, method 1. Estimate the Lorey height of the primary species from the + * its dominant height and trees-per-hectare. * - * @param primarySpeciesDominantHeight the dominantHeight of the primary species - * @param primarySpeciesTph trees-per-hectare of the primary species + * @param dh the dominantHeight (of the primary species) + * @param pspTph trees-per-hectare of the primary species * * @return as described */ - private float estimatePrimarySpeciesLoreyHeight(float primarySpeciesDominantHeight, float primarySpeciesTph) { + private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { String primarySpeciesAlias = fps.getPolygonProcessingState().getPrimarySpeciesAlias(); Region polygonRegion = fps.getPolygonProcessingState().getBecZone().getRegion(); @@ -1094,30 +1157,34 @@ private float estimatePrimarySpeciesLoreyHeight(float primarySpeciesDominantHeig float a1 = coefficients.get(primarySpeciesAlias, polygonRegion).getCoe(2); float a2 = coefficients.get(primarySpeciesAlias, polygonRegion).getCoe(3); - float hMult = a0 - a1 + a1 * FloatMath.exp(a2 * (primarySpeciesTph - 100.0f)); + float hMult = a0 - a1 + a1 * FloatMath.exp(a2 * (pspTph - 100.0f)); - return 1.3f + (primarySpeciesDominantHeight - 1.3f) * hMult; + return 1.3f + (dh - 1.3f) * hMult; } /** * EMP053 - estimate the Lorey height of a non-primary species of the polygon. * * @param speciesIndex (non-primary) species index - * @param primarySpeciesDominantHeight primary species dominant height + * @param dh (primary species) dominant height + * @param pspLoreyHeight primary species Lorey height * * @return as described */ private float estimateNonPrimarySpeciesLoreyHeight( - int speciesIndex, float primarySpeciesDominantHeight, - float primarySpeciesLoreyHeight + int speciesIndex, float dh, float pspLoreyHeight ) { - float lh; + PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); + + float spLh; + + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + String primarySpeciesAlias = start.speciesNames[primarySpeciesIndex]; + String speciesAlias = start.speciesNames[speciesIndex]; + Region region = pps.getBecZone().getRegion(); var coefficients = fps.fcm.getLoreyHeightNonPrimaryCoefficients(); - int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); - String primarySpeciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex]; - String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; - Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); var configuredLhCoefficients = coefficients.get(speciesAlias, primarySpeciesAlias, region); var lhCoefficients = configuredLhCoefficients.orElseGet(() -> NonprimaryHLCoefficients.getDefault()); @@ -1127,49 +1194,51 @@ private float estimateNonPrimarySpeciesLoreyHeight( int equationIndex = lhCoefficients.getEquationIndex(); if (equationIndex == 1) { - lh = 1.3f + a0 * (FloatMath.pow(primarySpeciesDominantHeight - 1.3f, a1)); + spLh = 1.3f + a0 * (FloatMath.pow(dh - 1.3f, a1)); } else if (equationIndex == 2) { - lh = 1.3f + a0 * (FloatMath.pow(primarySpeciesLoreyHeight - 1.3f, a1)); + spLh = 1.3f + a0 * (FloatMath.pow(pspLoreyHeight - 1.3f, a1)); } else { throw new IllegalStateException( MessageFormat.format("Expecting equation index 1 or 2 but saw {0}", equationIndex) ); } - return lh; + return spLh; } /** * EMP117 - Quad Mean Diameter growth for the primary layer. * - * @param yearsAtBreastHeight - * @param dominantHeight - * @param dqStart - * @param veteranBasalAreaStart - * @param veteranBasalAreaEnd - * @param hdGrowth + * @param pspYabhStart primary species years at breast height (age) at start of growth period + * @param dhStart layer dominant height (i.e., the height of the primary species) at start of growth period + * @param dqStart layer quad-mean-diameter at start of growth period + * @param veteranBaStart veteran layer basal area at start of growth period + * @param veteranBaEnd veteran layer basal area at end of growth period + * @param dhDelta growth in dominant height during growth period * - * @return + * @return growth in quad-mean-diameter for the year. This may be negative. * * @throws StandProcessingException */ float growQuadMeanDiameter( - float yearsAtBreastHeight, float primaryLayerBasalArea, float dominantHeight, float dqStart, - Optional veteranBasalAreaStart, Optional veteranBasalAreaEnd, float hdGrowth, + float pspYabhStart, float baStart, float dhStart, float dqStart, + Optional veteranBaStart, Optional veteranBaEnd, float dhDelta, Reference dqGrowthLimitApplied ) throws StandProcessingException { + var pps = fps.getPolygonProcessingState(); + var becZone = pps.getBecZone(); + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); var dqYieldCoefficients = fps.fcm.getQuadMeanDiameterYieldCoefficients(); - var decayBecZoneAlias = fps.getPolygonProcessingState().getBecZone().getDecayBec().getAlias(); + var decayBecZoneAlias = becZone.getDecayBec().getAlias(); Coefficients coefficientsWeightedBySpeciesAndDecayBec = Coefficients.empty(6, 0); for (int i = 0; i < 6; i++) { float sum = 0.0f; - for (int speciesIndex = 1; speciesIndex <= fps.getPolygonProcessingState().wallet - .getNSpecies(); speciesIndex++) { - String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; + for (int speciesIndex : pps.getIndices()) { + String speciesAlias = pps.getStartBank().speciesNames[speciesIndex]; sum += dqYieldCoefficients.get(decayBecZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; } @@ -1177,30 +1246,27 @@ float growQuadMeanDiameter( } float dqYieldStart = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, dominantHeight, yearsAtBreastHeight, veteranBasalAreaStart, fps - .getPolygonProcessingState() - .getBecZone(), fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber() + coefficientsWeightedBySpeciesAndDecayBec, dhStart, pspYabhStart, veteranBaStart, becZone, pps + .getPrimarySpeciesGroupNumber() ); - float dominantHeightEnd = dominantHeight + hdGrowth; - float yearsAtBreastHeightEnd = yearsAtBreastHeight + 1.0f; + float dhEnd = dhStart + dhDelta; + float pspYabhEnd = pspYabhStart + 1.0f; float dqYieldEnd = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, dominantHeightEnd, yearsAtBreastHeightEnd, veteranBasalAreaEnd, fps - .getPolygonProcessingState() - .getBecZone(), fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber() + coefficientsWeightedBySpeciesAndDecayBec, dhEnd, pspYabhEnd, veteranBaEnd, becZone, pps + .getPrimarySpeciesGroupNumber() ); float dqYieldGrowth = dqYieldEnd - dqYieldStart; int debugSetting6Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6); - var growthFaitDetails = fps.fcm.getQuadMeanDiameterGrowthFiatDetails() - .get(fps.getPolygonProcessingState().getBecZone().getRegion()); + var growthFaitDetails = fps.fcm.getQuadMeanDiameterGrowthFiatDetails().get(becZone.getRegion()); Optional dqGrowthFiat = Optional.empty(); if (debugSetting6Value != 1) { - var convergenceCoefficient = growthFaitDetails.calculateCoefficient(yearsAtBreastHeight); + var convergenceCoefficient = growthFaitDetails.calculateCoefficient(pspYabhStart); float adjust = -convergenceCoefficient * (dqStart - dqYieldStart); dqGrowthFiat = Optional.of(dqYieldGrowth + adjust); @@ -1210,7 +1276,7 @@ float growQuadMeanDiameter( if (debugSetting6Value != 0) { dqGrowthEmpirical = Optional.of( calculateQuadMeanDiameterGrowthEmpirical( - yearsAtBreastHeight, dominantHeight, primaryLayerBasalArea, dqStart, hdGrowth, dqYieldStart, dqYieldEnd + pspYabhStart, dhStart, baStart, dqStart, dhDelta, dqYieldStart, dqYieldEnd ) ); } @@ -1227,16 +1293,17 @@ float growQuadMeanDiameter( break; case 2: { - float c = 1.0f; - if (yearsAtBreastHeight >= growthFaitDetails.getMixedCoefficient(1)) { - c = 0.0f; - } else if (yearsAtBreastHeight > growthFaitDetails.getMixedCoefficient(0)) { - float t1 = yearsAtBreastHeight - growthFaitDetails.getMixedCoefficient(0); + float empiricalProportion = 1.0f; + if (pspYabhStart >= growthFaitDetails.getMixedCoefficient(1)) { + empiricalProportion = 0.0f; + } else if (pspYabhStart > growthFaitDetails.getMixedCoefficient(0)) { + float t1 = pspYabhStart - growthFaitDetails.getMixedCoefficient(0); float t2 = growthFaitDetails.getMixedCoefficient(1) - growthFaitDetails.getMixedCoefficient(0); float t3 = growthFaitDetails.getMixedCoefficient(2); - c = 1.0f - FloatMath.pow(t1 / t2, t3); + empiricalProportion = 1.0f - FloatMath.pow(t1 / t2, t3); } - dqGrowth = c * dqGrowthEmpirical.orElseThrow() + (1.0f - c) * dqGrowthFiat.orElseThrow(); + dqGrowth = empiricalProportion * dqGrowthEmpirical.orElseThrow() + + (1.0f - empiricalProportion) * dqGrowthFiat.orElseThrow(); break; } @@ -1264,9 +1331,9 @@ float growQuadMeanDiameter( /** * EMP122. Calculate quad mean diameter growth using the empirical model. * - * @param yearsAtBreastHeight primary species years at breast height or more - * @param dominantHeight primary species dominant height - * @param primaryLayerBasalArea basal area of primary layer + * @param pspYabhStart primary species years at breast height at start of growth period + * @param dhStart primary species dominant height at start of growth period + * @param baStart basal area of primary layer at start of growth period * @param dqStart quad mean diameter at start of growth period * @param hdGrowth growth in dominant height * @param dqYieldStart quad mean diameter yield at start of growth period @@ -1274,10 +1341,8 @@ float growQuadMeanDiameter( * * @return the change in primary layer basal area from start to start + 1 year */ - private float calculateQuadMeanDiameterGrowthEmpirical( - float yearsAtBreastHeight, float dominantHeight, - float primaryLayerBasalArea, float dqStart, float hdGrowth, float dqYieldStart, - float dqYieldEnd + private float calculateQuadMeanDiameterGrowthEmpirical(float pspYabhStart, float dhStart, + float baStart, float dqStart, float hdGrowth, float dqYieldStart, float dqYieldEnd ) { // Compute the growth in quadratic mean diameter @@ -1294,12 +1359,12 @@ private float calculateQuadMeanDiameterGrowthEmpirical( float a5 = firstSpeciesDqGrowthCoe.get(5); float a6 = firstSpeciesDqGrowthCoe.get(6); - yearsAtBreastHeight = Math.max(yearsAtBreastHeight, 1.0f); + pspYabhStart = Math.max(pspYabhStart, 1.0f); float dqYieldGrowth = dqYieldEnd - dqYieldStart; float dqDelta = FloatMath.exp( - a0 + a2 * FloatMath.log(yearsAtBreastHeight) + a3 * dqStart - + a4 * dominantHeight + a5 * primaryLayerBasalArea + a6 * hdGrowth + a0 + a2 * FloatMath.log(pspYabhStart) + a3 * dqStart + + a4 * dhStart + a5 * baStart + a6 * hdGrowth ) + a1 * dqYieldGrowth; @@ -1309,36 +1374,34 @@ private float calculateQuadMeanDiameterGrowthEmpirical( Map quadMeanDiameterGrowthEmpiricalLimits = fps.fcm .getQuadMeanDiameterGrowthEmpiricalLimits(); - float[] l = new float[8]; + float[] dqDeltaLimits = new float[8]; for (int i = 0; i < 8; i++) { - l[i] = quadMeanDiameterGrowthEmpiricalLimits.get(stratumNumber).getCoe(i); + dqDeltaLimits[i] = quadMeanDiameterGrowthEmpiricalLimits.get(stratumNumber).getCoe(i); } float x = dqStart - 7.5f; float xsq = x * x; - var dqGrowthMin = Math.max(l[0] + l[1] * x + l[2] * xsq / 100.0f, l[6]); - var dqGrowthMax = Math.min(l[3] + l[4] * x + l[5] * xsq / 100.0f, l[7]); + var dqGrowthMin = Math.max(dqDeltaLimits[0] + dqDeltaLimits[1] * x + dqDeltaLimits[2] * xsq / 100.0f, dqDeltaLimits[6]); + var dqGrowthMax = Math.min(dqDeltaLimits[3] + dqDeltaLimits[4] * x + dqDeltaLimits[5] * xsq / 100.0f, dqDeltaLimits[7]); dqGrowthMax = Math.max(dqGrowthMax, dqGrowthMin); // Apply the just-computed limits to the previously computed value. - dqDelta = Math.max(dqDelta, dqGrowthMin); - dqDelta = Math.min(dqDelta, dqGrowthMax); - - return dqDelta; + return FloatMath.clamp(dqDelta, dqGrowthMin, dqGrowthMax); } private float[] getSpeciesProportionsByBasalArea() { PolygonProcessingState pps = fps.getPolygonProcessingState(); - + Bank start = pps.getStartBank(); + float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; for (int i = 1; i <= pps.getNSpecies(); i++) { - speciesProportionsByBasalArea[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] - / pps.wallet.basalAreas[0][UC_ALL_INDEX]; + speciesProportionsByBasalArea[i] = start.basalAreas[i][UC_ALL_INDEX] + / start.basalAreas[0][UC_ALL_INDEX]; } return speciesProportionsByBasalArea; @@ -1361,6 +1424,9 @@ float growBasalArea( float baStart, Optional veteranLayerBa, float dhDelta ) throws StandProcessingException { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); @@ -1368,8 +1434,8 @@ float growBasalArea( Coefficients estimateBasalAreaYieldCoefficients = Coefficients.empty(7, 0); for (int i = 0; i < 7; i++) { float sum = 0.0f; - for (int speciesIndex : fps.getPolygonProcessingState().wallet.getIndices()) { - String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[speciesIndex]; + for (int speciesIndex : pps.getIndices()) { + String speciesAlias = start.speciesNames[speciesIndex]; sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; } @@ -1384,16 +1450,16 @@ float growBasalArea( int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhStart, pspYabhStart, veteranLayerBa, - isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), pspGroupNumber + estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, fps + .getPolygonProcessingState().getBecZone(), pspGroupNumber ); float pspDhEnd = pspDhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float baYieldEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, - isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), pspGroupNumber + estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, isFullOccupancy, fps + .getPolygonProcessingState().getBecZone(), pspGroupNumber ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() @@ -1461,7 +1527,7 @@ float growBasalArea( * EMP121. Calculate basal area growth using the empirical model. * * @param speciesBasalAreaProportions the proportion by basal area of each of the polygon's species - * @param ba basal area of primary layer + * @param baStart basal area of primary layer * @param pspYabhStart primary species years at breast height or more * @param pspDhStart primary species dominant height * @param baYieldStart basal area yield at start of period @@ -1470,7 +1536,7 @@ float growBasalArea( * @return the change in primary layer basal area from start to start + 1 year */ private float calculateBasalAreaGrowthEmpirical( - float[] speciesBasalAreaProportions, float ba, float pspYabhStart, + float[] speciesBasalAreaProportions, float baStart, float pspYabhStart, float pspDhStart, float baYieldStart, float baYieldEnd ) { @@ -1494,8 +1560,8 @@ private float calculateBasalAreaGrowthEmpirical( float b6 = firstSpeciesBaGrowthCoe.get(6); float b7 = firstSpeciesBaGrowthCoe.get(7); - for (int i = 1; i <= fps.getPolygonProcessingState().wallet.getNSpecies(); i++) { - String speciesAlias = fps.getPolygonProcessingState().wallet.speciesNames[i]; + for (int i = 1; i <= fps.getPolygonProcessingState().getNSpecies(); i++) { + String speciesAlias = fps.getPolygonProcessingState().getStartBank().speciesNames[i]; var baGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, speciesAlias); b4 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(4); b5 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(5); @@ -1528,8 +1594,8 @@ private float calculateBasalAreaGrowthEmpirical( // An undocumented check to prevent negative growth that causes BA to go to // less than 1.0. It is doubtful that this condition will ever occur. - if (basalAreaDelta < 0.0 && ba + basalAreaDelta < 1.0f) { - basalAreaDelta = -ba + 1.0f; + if (basalAreaDelta < 0.0 && baStart + basalAreaDelta < 1.0f) { + basalAreaDelta = -baStart + 1.0f; } return basalAreaDelta; @@ -1540,16 +1606,18 @@ private float calculateBasalAreaGrowthEmpirical( */ private float growBasalAreaUpperBound() { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); - Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); - int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + Region region = pps.getBecZone().getRegion(); + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); return upperBoundsCoefficients - .get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 1); + .get(region, pps.getStartBank().speciesNames[primarySpeciesIndex], 1); } else { - var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + var primarySpeciesGroupNumber = pps.getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); } } @@ -1559,14 +1627,17 @@ private float growBasalAreaUpperBound() { */ private float growQuadraticMeanDiameterUpperBound() { + PolygonProcessingState pps = fps.getPolygonProcessingState(); + int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { + var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); - Region region = fps.getPolygonProcessingState().getBecZone().getRegion(); - int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + Region region = pps.getBecZone().getRegion(); + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); return upperBoundsCoefficients - .get(region, fps.getPolygonProcessingState().wallet.speciesNames[primarySpeciesIndex], 2); + .get(region, pps.getStartBank().speciesNames[primarySpeciesIndex], 2); } else { var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); @@ -1590,7 +1661,7 @@ float growDominantHeight( ) throws ProcessingException { SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); - Region region = fps.getPolygonProcessingState().wallet.getBecZone().getRegion(); + Region region = fps.getPolygonProcessingState().getStartBank().getBecZone().getRegion(); if (siteCurveNumber == VdypEntity.MISSING_INTEGER_VALUE) { throw new ProcessingException("No SiteCurveNumber supplied"); @@ -1773,10 +1844,10 @@ private static double ageAndSiteIndexToHeight( } } - private void writeLayers(int primaryLayerInstance, int veteranLayerInstance, boolean b) { + private void writeLayers(Bank endBank, int veteranLayerInstance, boolean b) { logger.info( - "Writing primary layer from instance {} and veteran layer from instance {}", primaryLayerInstance, veteranLayerInstance + "Writing primary layer, and veteran layer from instance {}", endBank, veteranLayerInstance ); } @@ -1785,11 +1856,14 @@ private void writeLayers(int primaryLayerInstance, int veteranLayerInstance, boo private static final float B_BASE_MIN = 0.01f; @SuppressWarnings("unchecked") - void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingException { + void setCompatibilityVariables() throws ProcessingException { + Coefficients aAdjust = new Coefficients(new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, 1); - var growthDetails = pps.getFps().fcm.getForwardControlVariables(); - + var growthDetails = fps.fcm.getForwardControlVariables(); + var pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); + // Note: L1COM2 (INL1VGRP, INL1DGRP, INL1BGRP) is initialized when // PolygonProcessingState (volumeEquationGroups, decayEquationGroups // breakageEquationGroups, respectively) is constructed. Copying @@ -1806,9 +1880,9 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce for (int s = 1; s <= pps.getNSpecies(); s++) { - String genusName = pps.wallet.speciesNames[s]; + String genusName = start.speciesNames[s]; - float spLoreyHeight_All = pps.wallet.loreyHeights[s][UtilizationClass.ALL.ordinal()]; + float spLoreyHeight_All = start.loreyHeights[s][UtilizationClass.ALL.ordinal()]; Coefficients basalAreas = Utils.utilizationVector(); Coefficients wholeStemVolumes = Utils.utilizationVector(); @@ -1830,14 +1904,14 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL) { - basalAreas.setCoe(uc.index, pps.wallet.basalAreas[s][uc.ordinal()]); - wholeStemVolumes.setCoe(uc.index, pps.wallet.wholeStemVolumes[s][uc.ordinal()]); - closeUtilizationVolumes.setCoe(uc.index, pps.wallet.closeUtilizationVolumes[s][uc.ordinal()]); - closeUtilizationVolumesNetOfDecay.setCoe(uc.index, pps.wallet.cuVolumesMinusDecay[s][uc.ordinal()]); + basalAreas.setCoe(uc.index, start.basalAreas[s][uc.ordinal()]); + wholeStemVolumes.setCoe(uc.index, start.wholeStemVolumes[s][uc.ordinal()]); + closeUtilizationVolumes.setCoe(uc.index, start.closeUtilizationVolumes[s][uc.ordinal()]); + closeUtilizationVolumesNetOfDecay.setCoe(uc.index, start.cuVolumesMinusDecay[s][uc.ordinal()]); closeUtilizationVolumesNetOfDecayAndWaste - .setCoe(uc.index, pps.wallet.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]); + .setCoe(uc.index, start.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]); - quadMeanDiameters.setCoe(uc.index, pps.wallet.quadMeanDiameters[s][uc.ordinal()]); + quadMeanDiameters.setCoe(uc.index, start.quadMeanDiameters[s][uc.ordinal()]); if (uc != UtilizationClass.ALL && quadMeanDiameters.getCoe(uc.index) <= 0.0f) { quadMeanDiameters.setCoe(uc.index, DEFAULT_QUAD_MEAN_DIAMETERS[uc.ordinal()]); } @@ -1850,17 +1924,17 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce // Volume less decay and waste adjustment = 0.0f; - baseVolume = pps.wallet.cuVolumesMinusDecay[s][uc.ordinal()]; + baseVolume = start.cuVolumesMinusDecay[s][uc.ordinal()]; if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP094 fps.estimators.estimateNetDecayAndWasteVolume( pps.getBecZone() - .getRegion(), uc, aAdjust, pps.wallet.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste + .getRegion(), uc, aAdjust, start.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste ); - float actualVolume = pps.wallet.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; + float actualVolume = start.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; float staticVolume = closeUtilizationVolumesNetOfDecayAndWaste.getCoe(uc.index); adjustment = calculateCompatibilityVariable(actualVolume, baseVolume, staticVolume); } @@ -1870,18 +1944,18 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce // Volume less decay adjustment = 0.0f; - baseVolume = pps.wallet.closeUtilizationVolumes[s][uc.ordinal()]; + baseVolume = start.closeUtilizationVolumes[s][uc.ordinal()]; if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP093 int decayGroup = pps.decayEquationGroups[s]; fps.estimators.estimateNetDecayVolume( - pps.wallet.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, pps + start.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, pps .getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay ); - float actualVolume = pps.wallet.cuVolumesMinusDecay[s][uc.ordinal()]; + float actualVolume = start.cuVolumesMinusDecay[s][uc.ordinal()]; float staticVolume = closeUtilizationVolumesNetOfDecay.getCoe(uc.index); adjustment = calculateCompatibilityVariable(actualVolume, baseVolume, staticVolume); } @@ -1890,7 +1964,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce // Volume adjustment = 0.0f; - baseVolume = pps.wallet.wholeStemVolumes[s][uc.ordinal()]; + baseVolume = start.wholeStemVolumes[s][uc.ordinal()]; if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { @@ -1900,7 +1974,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes ); - float actualVolume = pps.wallet.closeUtilizationVolumes[s][uc.ordinal()]; + float actualVolume = start.closeUtilizationVolumes[s][uc.ordinal()]; float staticVolume = closeUtilizationVolumes.getCoe(uc.index); adjustment = calculateCompatibilityVariable(actualVolume, baseVolume, staticVolume); } @@ -1909,8 +1983,8 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce } int primarySpeciesVolumeGroup = pps.volumeEquationGroups[s]; - float primarySpeciesQMDAll = pps.wallet.quadMeanDiameters[s][UC_ALL_INDEX]; - var wholeStemVolume = pps.wallet.treesPerHectare[s][UC_ALL_INDEX] + float primarySpeciesQMDAll = start.quadMeanDiameters[s][UC_ALL_INDEX]; + var wholeStemVolume = start.treesPerHectare[s][UC_ALL_INDEX] * fps.estimators.estimateWholeStemVolumePerTree( primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll ); @@ -1926,7 +2000,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce float basalArea = basalAreas.getCoe(uc.index); if (growthDetails.allowCalculation(basalArea, B_BASE_MIN, (l, r) -> l > r)) { adjustment = calculateWholeStemVolume( - pps.wallet.wholeStemVolumes[s][uc.ordinal()], basalArea, wholeStemVolumes.getCoe(uc.index) + start.wholeStemVolumes[s][uc.ordinal()], basalArea, wholeStemVolumes.getCoe(uc.index) ); } @@ -1942,7 +2016,7 @@ void setCompatibilityVariables(PolygonProcessingState pps) throws ProcessingExce ); // Calculate trees-per-hectare per utilization - treesPerHectare.setCoe(UtilizationClass.ALL.index, pps.wallet.treesPerHectare[s][UC_ALL_INDEX]); + treesPerHectare.setCoe(UtilizationClass.ALL.index, start.treesPerHectare[s][UC_ALL_INDEX]); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { treesPerHectare.setCoe( uc.index, calculateTreesPerHectare( @@ -1954,10 +2028,10 @@ uc.index, calculateTreesPerHectare( ReconcilationMethods.reconcileComponents(basalAreas, treesPerHectare, quadMeanDiameters); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { - float baCvValue = pps.wallet.basalAreas[s][uc.ordinal()] - basalAreas.getCoe(uc.index); + float baCvValue = start.basalAreas[s][uc.ordinal()] - basalAreas.getCoe(uc.index); cvBasalArea[s].put(uc, LayerType.PRIMARY, baCvValue); - float originalQmd = pps.wallet.quadMeanDiameters[s][uc.ordinal()]; + float originalQmd = start.quadMeanDiameters[s][uc.ordinal()]; float adjustedQmd = quadMeanDiameters.getCoe(uc.index); float qmdCvValue; @@ -1992,18 +2066,18 @@ uc.index, calculateTreesPerHectare( calculateSmallCompatibilityVariables(int speciesIndex, ForwardControlVariables forwardControlVariables) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); - Bank wallet = pps.wallet; + var pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); - String speciesName = wallet.speciesNames[speciesIndex]; + String speciesName = start.speciesNames[speciesIndex]; - float spLoreyHeight_All = wallet.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp - float spQuadMeanDiameter_All = wallet.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp + float spLoreyHeight_All = start.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp + float spQuadMeanDiameter_All = start.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp // this WHOLE operation on Actual BA's, not 100% occupancy. // TODO: verify this: float fractionAvailable = polygon.getPercentForestLand(); - float spBaseArea_All = wallet.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp + float spBaseArea_All = start.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp // EMP080 float smallProbability = smallComponentProbability(speciesName, spLoreyHeight_All, region); // PROBsp @@ -2030,11 +2104,11 @@ uc.index, calculateTreesPerHectare( var cvSmall = new HashMap(); - float spInputBasalArea_Small = wallet.basalAreas[speciesIndex][UC_SMALL_INDEX]; + float spInputBasalArea_Small = start.basalAreas[speciesIndex][UC_SMALL_INDEX]; cvSmall.put(UtilizationClassVariable.BASAL_AREA, spInputBasalArea_Small - baSmall); if (forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { - float spInputQuadMeanDiameter_Small = wallet.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; + float spInputQuadMeanDiameter_Small = start.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; cvSmall.put( UtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - qmdSmall @@ -2043,7 +2117,7 @@ uc.index, calculateTreesPerHectare( cvSmall.put(UtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); } - float spInputLoreyHeight_Small = wallet.loreyHeights[speciesIndex][UC_SMALL_INDEX]; + float spInputLoreyHeight_Small = start.loreyHeights[speciesIndex][UC_SMALL_INDEX]; if (spInputLoreyHeight_Small > 1.3f && lhSmall > 1.3f && spInputBasalArea_Small > 0.0f) { float cvLoreyHeight = FloatMath.log( (spInputLoreyHeight_Small - 1.3f) / (lhSmall - 1.3f)); cvSmall.put(UtilizationClassVariable.LOREY_HEIGHT, cvLoreyHeight); @@ -2051,11 +2125,11 @@ uc.index, calculateTreesPerHectare( cvSmall.put(UtilizationClassVariable.LOREY_HEIGHT, 0.0f); } - float spInputWholeStemVolume_Small = wallet.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; + float spInputWholeStemVolume_Small = start.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; if (spInputWholeStemVolume_Small > 0.0f && meanVolumeSmall > 0.0f && forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l >= r)) { - float spInputTreePerHectare_Small = wallet.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; + float spInputTreePerHectare_Small = start.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; var wsVolumeSmall = FloatMath .log(spInputWholeStemVolume_Small / spInputTreePerHectare_Small / meanVolumeSmall); @@ -2087,7 +2161,7 @@ private float smallComponentProbability( float logit = a0 + // a1 + // - a2 * pps.wallet.yearsAtBreastHeight[pps.getPrimarySpeciesIndex()] + // + a2 * pps.getStartBank().yearsAtBreastHeight[pps.getPrimarySpeciesIndex()] + // a3 * loreyHeight; return exp(logit) / (1.0f + exp(logit)); @@ -2253,59 +2327,61 @@ private static float calculateWholeStemVolume(float actualVolume, float basalAre /** * VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 * - * @param state + * @param pps * @param hl1Coefficients * @throws ProcessingException */ static void calculateDominantHeightAgeSiteIndex( - PolygonProcessingState state, MatrixMap2 hl1Coefficients + PolygonProcessingState pps, MatrixMap2 hl1Coefficients ) throws ProcessingException { + Bank startBank = pps.getStartBank(); + // Calculate primary species values - int primarySpeciesIndex = state.getPrimarySpeciesIndex(); + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); // (1) Dominant Height - float primarySpeciesDominantHeight = state.wallet.dominantHeights[primarySpeciesIndex]; + float primarySpeciesDominantHeight = startBank.dominantHeights[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesDominantHeight)) { - float loreyHeight = state.wallet.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; + float loreyHeight = startBank.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; if (Float.isNaN(loreyHeight)) { throw new ProcessingException( MessageFormat.format( - "Neither dominant nor lorey height[All] is available for primary species {}", state.wallet.speciesNames[primarySpeciesIndex] + "Neither dominant nor lorey height[All] is available for primary species {}", startBank.speciesNames[primarySpeciesIndex] ), 2 ); } // Estimate dominant height from the lorey height - String primarySpeciesAlias = state.wallet.speciesNames[primarySpeciesIndex]; - Region primarySpeciesRegion = state.getBecZone().getRegion(); + String primarySpeciesAlias = startBank.speciesNames[primarySpeciesIndex]; + Region primarySpeciesRegion = pps.getBecZone().getRegion(); var coefficients = hl1Coefficients.get(primarySpeciesAlias, primarySpeciesRegion); float a0 = coefficients.getCoe(1); float a1 = coefficients.getCoe(2); float a2 = coefficients.getCoe(3); - float treesPerHectare = state.wallet.treesPerHectare[primarySpeciesIndex][UC_ALL_INDEX]; + float treesPerHectare = startBank.treesPerHectare[primarySpeciesIndex][UC_ALL_INDEX]; float hMult = a0 - a1 + a1 * FloatMath.exp(a2 * (treesPerHectare - 100.0f)); primarySpeciesDominantHeight = 1.3f + (loreyHeight - 1.3f) / hMult; } // (2) Age (total, years at breast height, years to breast height - float primarySpeciesTotalAge = state.wallet.ageTotals[primarySpeciesIndex]; - float primarySpeciesYearsAtBreastHeight = state.wallet.yearsAtBreastHeight[primarySpeciesIndex]; - float primarySpeciesYearsToBreastHeight = state.wallet.yearsToBreastHeight[primarySpeciesIndex]; + float primarySpeciesTotalAge = startBank.ageTotals[primarySpeciesIndex]; + float primarySpeciesYearsAtBreastHeight = startBank.yearsAtBreastHeight[primarySpeciesIndex]; + float primarySpeciesYearsToBreastHeight = startBank.yearsToBreastHeight[primarySpeciesIndex]; Optional activeIndex = Optional.empty(); if (Float.isNaN(primarySpeciesTotalAge)) { - if (state.hasSecondarySpeciesIndex() - && !Float.isNaN(state.wallet.ageTotals[state.getSecondarySpeciesIndex()])) { - activeIndex = Optional.of(state.getSecondarySpeciesIndex()); + if (pps.hasSecondarySpeciesIndex() + && !Float.isNaN(startBank.ageTotals[pps.getSecondarySpeciesIndex()])) { + activeIndex = Optional.of(pps.getSecondarySpeciesIndex()); } else { - for (int i = 1; i <= state.getNSpecies(); i++) { - if (!Float.isNaN(state.wallet.ageTotals[i])) { + for (int i = 1; i <= pps.getNSpecies(); i++) { + if (!Float.isNaN(startBank.ageTotals[i])) { activeIndex = Optional.of(i); break; } @@ -2314,42 +2390,42 @@ static void calculateDominantHeightAgeSiteIndex( activeIndex.orElseThrow(() -> new ProcessingException("Age data unavailable for ALL species", 5)); - primarySpeciesTotalAge = state.wallet.ageTotals[activeIndex.get()]; + primarySpeciesTotalAge = startBank.ageTotals[activeIndex.get()]; if (!Float.isNaN(primarySpeciesYearsToBreastHeight)) { primarySpeciesYearsAtBreastHeight = primarySpeciesTotalAge - primarySpeciesYearsToBreastHeight; } else if (!Float.isNaN(primarySpeciesYearsAtBreastHeight)) { primarySpeciesYearsToBreastHeight = primarySpeciesTotalAge - primarySpeciesYearsAtBreastHeight; } else { - primarySpeciesYearsAtBreastHeight = state.wallet.yearsAtBreastHeight[activeIndex.get()]; - primarySpeciesYearsToBreastHeight = state.wallet.yearsToBreastHeight[activeIndex.get()]; + primarySpeciesYearsAtBreastHeight = startBank.yearsAtBreastHeight[activeIndex.get()]; + primarySpeciesYearsToBreastHeight = startBank.yearsToBreastHeight[activeIndex.get()]; } } // (3) Site Index - float primarySpeciesSiteIndex = state.wallet.siteIndices[primarySpeciesIndex]; + float primarySpeciesSiteIndex = startBank.siteIndices[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesSiteIndex)) { - if (state.hasSecondarySpeciesIndex() - && !Float.isNaN(state.wallet.siteIndices[state.getSecondarySpeciesIndex()])) { - activeIndex = Optional.of(state.getSecondarySpeciesIndex()); + if (pps.hasSecondarySpeciesIndex() + && !Float.isNaN(startBank.siteIndices[pps.getSecondarySpeciesIndex()])) { + activeIndex = Optional.of(pps.getSecondarySpeciesIndex()); } else { - if (activeIndex.isEmpty() || Float.isNaN(state.wallet.siteIndices[activeIndex.get()])) { - for (int i = 1; i <= state.getNSpecies(); i++) { - if (!Float.isNaN(state.wallet.siteIndices[i])) { + if (activeIndex.isEmpty() || Float.isNaN(startBank.siteIndices[activeIndex.get()])) { + for (int i = 1; i <= pps.getNSpecies(); i++) { + if (!Float.isNaN(startBank.siteIndices[i])) { activeIndex = Optional.of(i); break; } } } } - primarySpeciesSiteIndex = state.wallet.siteIndices[activeIndex + primarySpeciesSiteIndex = startBank.siteIndices[activeIndex .orElseThrow(() -> new ProcessingException("Site Index data unavailable for ALL species", 7))]; } else { activeIndex = Optional.of(primarySpeciesIndex); } - SiteIndexEquation siteCurve1 = SiteIndexEquation.getByIndex(state.getSiteCurveNumber(activeIndex.get())); - SiteIndexEquation siteCurve2 = SiteIndexEquation.getByIndex(state.getSiteCurveNumber(0)); + SiteIndexEquation siteCurve1 = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(activeIndex.get())); + SiteIndexEquation siteCurve2 = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(0)); try { double newSI = SiteTool.convertSiteIndexBetweenCurves(siteCurve1, primarySpeciesSiteIndex, siteCurve2); @@ -2360,7 +2436,7 @@ static void calculateDominantHeightAgeSiteIndex( // do nothing. primarySpeciesSiteIndex will not be modified. } - state.setPrimarySpeciesDetails( + pps.setPrimarySpeciesDetails( new PrimarySpeciesDetails( primarySpeciesDominantHeight, primarySpeciesSiteIndex, primarySpeciesTotalAge, primarySpeciesYearsAtBreastHeight, primarySpeciesYearsToBreastHeight @@ -2373,12 +2449,14 @@ static void calculateDominantHeightAgeSiteIndex( * years-at-breast-height and age-total values if given or otherwise estimate it from the site curve and site index * values for the species. * - * @param state the bank in which calculations are performed + * @param pps the current state of the processing of the polygon */ - static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState state) { + static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState pps) { - int primarySpeciesIndex = state.getPrimarySpeciesIndex(); - float primarySpeciesSiteIndex = state.wallet.siteIndices[primarySpeciesIndex]; + Bank start = pps.getStartBank(); + + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; // Determine the default site index by using the site index of the primary species unless // it hasn't been set in which case pick any. Note that there may still not be a @@ -2388,16 +2466,16 @@ static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState stat float defaultSiteIndex = primarySpeciesSiteIndex; if (Float.isNaN(defaultSiteIndex)) { - for (int i : state.getIndices()) { - if (!Float.isNaN(state.wallet.siteIndices[i])) { - defaultSiteIndex = state.wallet.siteIndices[i]; + for (int i : pps.getIndices()) { + if (!Float.isNaN(start.siteIndices[i])) { + defaultSiteIndex = start.siteIndices[i]; break; } } } - for (int i : state.getIndices()) { - if (!Float.isNaN(state.wallet.yearsToBreastHeight[i])) { + for (int i : pps.getIndices()) { + if (!Float.isNaN(start.yearsToBreastHeight[i])) { // was supplied continue; } @@ -2405,18 +2483,18 @@ static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState stat // Note: this block will normally never be executed because of the logic in // the constructor of VdypLayerSpecies that computes missing values when the // other two measurement values are present. - if (!Float.isNaN(state.wallet.yearsAtBreastHeight[i]) - && state.wallet.ageTotals[i] > state.wallet.yearsAtBreastHeight[i]) { - state.wallet.yearsToBreastHeight[i] = state.wallet.ageTotals[i] - state.wallet.yearsAtBreastHeight[i]; + if (!Float.isNaN(start.yearsAtBreastHeight[i]) + && start.ageTotals[i] > start.yearsAtBreastHeight[i]) { + start.yearsToBreastHeight[i] = start.ageTotals[i] - start.yearsAtBreastHeight[i]; continue; } - float siteIndex = !Float.isNaN(state.wallet.siteIndices[i]) ? state.wallet.siteIndices[i] + float siteIndex = !Float.isNaN(start.siteIndices[i]) ? start.siteIndices[i] : defaultSiteIndex; try { - SiteIndexEquation curve = SiteIndexEquation.getByIndex(state.getSiteCurveNumber(i)); + SiteIndexEquation curve = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(i)); double yearsToBreastHeight = SiteTool.yearsToBreastHeight(curve, siteIndex); - state.wallet.yearsToBreastHeight[i] = (float) yearsToBreastHeight; + start.yearsToBreastHeight[i] = (float) yearsToBreastHeight; } catch (CommonCalculatorException e) { logger.warn(MessageFormat.format("Unable to determine yearsToBreastHeight of species {0}", i), e); } @@ -2432,32 +2510,33 @@ static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState stat * index has not been set from the primary site index after converting it between the site curve of the other * species and that of the primary species. * - * @param state the bank in which the calculations are done. + * @param pps the bank in which the calculations are done. * @throws ProcessingException */ - static void estimateMissingSiteIndices(PolygonProcessingState state) throws ProcessingException { + static void estimateMissingSiteIndices(PolygonProcessingState pps) throws ProcessingException { - int primarySpeciesIndex = state.getPrimarySpeciesIndex(); - SiteIndexEquation primarySiteCurve = SiteIndexEquation - .getByIndex(state.getSiteCurveNumber(primarySpeciesIndex)); + Bank start = pps.getStartBank(); + + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + SiteIndexEquation primarySiteCurve = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(primarySpeciesIndex)); // (1) - if (Float.isNaN(state.wallet.siteIndices[primarySpeciesIndex])) { + if (Float.isNaN(start.siteIndices[primarySpeciesIndex])) { double otherSiteIndicesSum = 0.0f; int nOtherSiteIndices = 0; - for (int i : state.getIndices()) { + for (int i : pps.getIndices()) { if (i == primarySpeciesIndex) { continue; } - float siteIndexI = state.wallet.siteIndices[i]; + float siteIndexI = start.siteIndices[i]; if (!Float.isNaN(siteIndexI)) { - SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(state.getSiteCurveNumber(i)); + SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(i)); try { double mappedSiteIndex = SiteTool @@ -2483,29 +2562,29 @@ static void estimateMissingSiteIndices(PolygonProcessingState state) throws Proc } if (nOtherSiteIndices > 0) { - state.wallet.siteIndices[primarySpeciesIndex] = (float) (otherSiteIndicesSum / nOtherSiteIndices); + start.siteIndices[primarySpeciesIndex] = (float) (otherSiteIndicesSum / nOtherSiteIndices); } } // (2) - float primarySpeciesSiteIndex = state.wallet.siteIndices[primarySpeciesIndex]; + float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; if (!Float.isNaN(primarySpeciesSiteIndex)) { - for (int i : state.getIndices()) { + for (int i : pps.getIndices()) { if (i == primarySpeciesIndex) { continue; } - float siteIndexI = state.wallet.siteIndices[i]; + float siteIndexI = start.siteIndices[i]; if (Float.isNaN(siteIndexI)) { - SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(state.getSiteCurveNumber(i)); + SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(i)); try { double mappedSiteIndex = SiteTool .convertSiteIndexBetweenCurves(primarySiteCurve, primarySpeciesSiteIndex, siteCurveI); - state.wallet.siteIndices[i] = (float) mappedSiteIndex; + start.siteIndices[i] = (float) mappedSiteIndex; } catch (NoAnswerException e) { logger.warn( MessageFormat.format( @@ -2524,7 +2603,7 @@ static void estimateMissingSiteIndices(PolygonProcessingState state) throws Proc } // Finally, set bank.siteIndices[0] to that of the primary species. - state.wallet.siteIndices[0] = primarySpeciesSiteIndex; + start.siteIndices[0] = primarySpeciesSiteIndex; } /** @@ -2536,18 +2615,19 @@ static void estimateMissingSiteIndices(PolygonProcessingState state) throws Proc void calculateCoverages() { PolygonProcessingState pps = this.fps.getPolygonProcessingState(); - - logger.atDebug().addArgument(pps.getNSpecies()).addArgument(pps.wallet.basalAreas[0][0]).log( + Bank start = pps.getStartBank(); + + logger.atDebug().addArgument(pps.getNSpecies()).addArgument(start.basalAreas[0][0]).log( "Calculating coverages as a ratio of Species BA over Total BA. # species: {}; Layer total 7.5cm+ basal area: {}" ); for (int i : pps.getIndices()) { - pps.wallet.percentagesOfForestedLand[i] = pps.wallet.basalAreas[i][UC_ALL_INDEX] - / pps.wallet.basalAreas[0][UC_ALL_INDEX] * 100.0f; + start.percentagesOfForestedLand[i] = start.basalAreas[i][UC_ALL_INDEX] + / start.basalAreas[0][UC_ALL_INDEX] * 100.0f; - logger.atDebug().addArgument(i).addArgument(pps.wallet.speciesIndices[i]) - .addArgument(pps.wallet.speciesNames[i]).addArgument(pps.wallet.basalAreas[i][0]) - .addArgument(pps.wallet.percentagesOfForestedLand[i]) + logger.atDebug().addArgument(i).addArgument(start.speciesIndices[i]) + .addArgument(start.speciesNames[i]).addArgument(start.basalAreas[i][0]) + .addArgument(start.percentagesOfForestedLand[i]) .log("Species {}: SP0 {}, Name {}, Species 7.5cm+ BA {}, Calculated Percent {}"); } } @@ -2665,16 +2745,17 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing void determinePolygonRankings(Collection> speciesToCombine) { PolygonProcessingState pps = fps.getPolygonProcessingState(); - + Bank start = pps.getStartBank(); + if (pps.getNSpecies() == 0) { throw new IllegalArgumentException("Can not find primary species as there are no species"); } float[] percentages = Arrays - .copyOf(pps.wallet.percentagesOfForestedLand, pps.wallet.percentagesOfForestedLand.length); + .copyOf(start.percentagesOfForestedLand, start.percentagesOfForestedLand.length); for (var speciesPair : speciesToCombine) { - combinePercentages(pps.wallet.speciesNames, speciesPair, percentages); + combinePercentages(start.speciesNames, speciesPair, percentages); } float highestPercentage = 0.0f; @@ -2703,9 +2784,9 @@ void determinePolygonRankings(Collection> speciesToCombine) { throw new IllegalStateException("There are no species with covering percentage > 0"); } - String primaryGenusName = pps.wallet.speciesNames[highestPercentageIndex]; + String primaryGenusName = start.speciesNames[highestPercentageIndex]; Optional secondaryGenusName = secondHighestPercentageIndex != -1 - ? Optional.of(pps.wallet.speciesNames[secondHighestPercentageIndex]) + ? Optional.of(start.speciesNames[secondHighestPercentageIndex]) : Optional.empty(); try { @@ -2713,8 +2794,8 @@ void determinePolygonRankings(Collection> speciesToCombine) { int basalAreaGroup1 = 0; - String primarySpeciesName = pps.wallet.speciesNames[highestPercentageIndex]; - String becZoneAlias = pps.wallet.getBecZone().getAlias(); + String primarySpeciesName = start.speciesNames[highestPercentageIndex]; + String becZoneAlias = start.getBecZone().getAlias(); int defaultEquationGroup = fps.fcm.getDefaultEquationGroup().get(primarySpeciesName, becZoneAlias); Optional equationModifierGroup = fps.fcm.getEquationModifierGroup() @@ -2725,9 +2806,9 @@ void determinePolygonRankings(Collection> speciesToCombine) { basalAreaGroup1 = defaultEquationGroup; } - int primarySpeciesIndex = pps.wallet.speciesIndices[highestPercentageIndex]; + int primarySpeciesIndex = start.speciesIndices[highestPercentageIndex]; int basalAreaGroup3 = defaultEquationGroups[primarySpeciesIndex]; - if (Region.INTERIOR.equals(pps.wallet.getBecZone().getRegion()) + if (Region.INTERIOR.equals(start.getBecZone().getRegion()) && exceptedSpeciesIndicies.contains(primarySpeciesIndex)) { basalAreaGroup3 += 20; } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index d660ad37c..ec6df5a8f 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -64,8 +64,8 @@ public PolygonProcessingState getPolygonProcessingState() { return pps; } - public void storeActive(int instanceNumber, LayerType layerType) { - banks[instanceNumber][layerType.getIndex()] = pps.wallet.copy(); + public void storeActive(Bank end, int instanceNumber, LayerType layerType) { + banks[instanceNumber][layerType.getIndex()] = end.copy(); } public void transfer(int fromInstanceNumber, int toInstanceNumber, LayerType layerType) { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 30c1e3df1..d261eccae 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -46,8 +46,13 @@ class PolygonProcessingState { // L1COM1, L1COM4 and L1COM5 - these common blocks mirror BANK1, BANK2 and BANK3 and are initialized // when copied to "active" in ForwardProcessingEngine. - Bank wallet; - + + /** + * State of the polygon at the start of processing; read-write during preparation for grow + * and read-only after that. + */ + private Bank start; + // L1COM2 - equation groups. From the configuration, narrowed to the // polygon's BEC zone. @@ -114,7 +119,7 @@ public PolygonProcessingState( this.fps = fps; this.polygon = polygon; - this.wallet = bank.copy(); + this.start = bank.copy(); var volumeEquationGroupMatrix = this.fps.fcm.>get( ControlKey.VOLUME_EQN_GROUPS, MatrixMap2.class @@ -126,17 +131,17 @@ public PolygonProcessingState( ControlKey.BREAKAGE_GROUPS, MatrixMap2.class ); - this.volumeEquationGroups = new int[this.wallet.getNSpecies() + 1]; - this.decayEquationGroups = new int[this.wallet.getNSpecies() + 1]; - this.breakageEquationGroups = new int[this.wallet.getNSpecies() + 1]; + this.volumeEquationGroups = new int[this.start.getNSpecies() + 1]; + this.decayEquationGroups = new int[this.start.getNSpecies() + 1]; + this.breakageEquationGroups = new int[this.start.getNSpecies() + 1]; this.volumeEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; this.decayEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; this.breakageEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; String becZoneAlias = this.getBecZone().getAlias(); - for (int i = 1; i < this.wallet.getNSpecies() + 1; i++) { - String speciesName = this.wallet.speciesNames[i]; + for (int i = 1; i < this.start.getNSpecies() + 1; i++) { + String speciesName = this.start.speciesNames[i]; this.volumeEquationGroups[i] = volumeEquationGroupMatrix.get(speciesName, becZoneAlias); // From VGRPFIND, volumeEquationGroup 10 is mapped to 11. if (this.volumeEquationGroups[i] == 10) { @@ -152,19 +157,19 @@ public VdypPolygon getPolygon() { } public int getNSpecies() { - return wallet.getNSpecies(); + return start.getNSpecies(); } public int[] getIndices() { - return wallet.getIndices(); + return start.getIndices(); } public BecDefinition getBecZone() { - return wallet.getBecZone(); + return start.getBecZone(); } public VdypPolygonLayer getLayer() { - return wallet.getLayer(); + return start.getLayer(); } @@ -179,7 +184,7 @@ public String getPrimarySpeciesAlias() { if (!areRankingDetailsSet) { throw new IllegalStateException("unset primarySpeciesIndex"); } - return wallet.speciesNames[primarySpeciesIndex]; + return start.speciesNames[primarySpeciesIndex]; } public boolean hasSecondarySpeciesIndex() { @@ -253,8 +258,8 @@ public ForwardProcessingState getFps() { return fps; } - public Bank getWallet() { - return wallet; + public Bank getStartBank() { + return start; } public int[] getVolumeEquationGroups() { @@ -391,21 +396,21 @@ public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { this.primarySpeciesAgeAtBreastHeight = details.primarySpeciesAgeAtBreastHeight(); this.primarySpeciesAgeToBreastHeight = details.primarySpeciesAgeToBreastHeight(); - // Store these values into the wallet - VHDOM1 lines 182 - 186 - if (wallet.dominantHeights[primarySpeciesIndex] <= 0.0) { - wallet.dominantHeights[primarySpeciesIndex] = this.primarySpeciesDominantHeight; + // Store these values into start - VHDOM1 lines 182 - 186 + if (start.dominantHeights[primarySpeciesIndex] <= 0.0) { + start.dominantHeights[primarySpeciesIndex] = this.primarySpeciesDominantHeight; } - if (wallet.siteIndices[primarySpeciesIndex] <= 0.0) { - wallet.siteIndices[primarySpeciesIndex] = this.primarySpeciesSiteIndex; + if (start.siteIndices[primarySpeciesIndex] <= 0.0) { + start.siteIndices[primarySpeciesIndex] = this.primarySpeciesSiteIndex; } - if (wallet.ageTotals[primarySpeciesIndex] <= 0.0) { - wallet.ageTotals[primarySpeciesIndex] = this.primarySpeciesTotalAge; + if (start.ageTotals[primarySpeciesIndex] <= 0.0) { + start.ageTotals[primarySpeciesIndex] = this.primarySpeciesTotalAge; } - if (wallet.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { - wallet.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeAtBreastHeight; + if (start.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { + start.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeAtBreastHeight; } - if (wallet.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { - wallet.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeToBreastHeight; + if (start.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { + start.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeToBreastHeight; } this.arePrimarySpeciesDetailsSet = true; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java index 1cc7f0bdf..5f79d2e59 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java @@ -98,2983 +98,4 @@ private void logVersionInformation() { public VdypApplicationIdentifier getId() { return VdypApplicationIdentifier.VDYP_FORWARD; } - - // @formatter:off - - // public static final float PI_40K = 0.78539816E-04f; - // - // static final Set HARDWOODS = Set.of("AC", "AT", "D", "E", "MB"); - // - // static final Collection UTIL_CLASSES = List.of( - // UtilizationClass.U75TO125, UtilizationClass.U125TO175, UtilizationClass.U175TO225, UtilizationClass.OVER225 - // ); - // - // static final Map ITG_PURE = Utils.constMap(map -> { - // map.put("AC", 36); - // map.put("AT", 42); - // map.put("B", 18); - // map.put("C", 9); - // map.put("D", 38); - // map.put("E", 40); - // map.put("F", 1); - // map.put("H", 12); - // map.put("L", 34); - // map.put("MB", 39); - // map.put("PA", 28); - // map.put("PL", 28); - // map.put("PW", 27); - // map.put("PY", 32); - // map.put("S", 21); - // map.put("Y", 9); - // }); - // - // private static final Comparator PERCENT_GENUS_DESCENDING = Utils - // .compareUsing(FipSpecies::getPercentGenus).reversed(); - // public static final int UTIL_ALL = UtilizationClass.ALL.index; - // public static final int UTIL_LARGEST = UtilizationClass.OVER225.index; - // public static final int UTIL_SMALL = UtilizationClass.SMALL.index; - // - // public static final float TOLERANCE = 2.0e-3f; - // - // /** - // * When finding primary species these genera should be combined - // */ - // static final Collection> PRIMARY_SPECIES_TO_COMBINE = Arrays - // .asList(Arrays.asList("PL", "PA"), Arrays.asList("C", "Y")); - // - // @SuppressWarnings("unchecked") - // private StreamingParser getStreamingParser(String key) throws ProcessingException { - // try { - // var factory = (StreamingParserFactory) controlMap.get(key); - // if (factory == null) { - // throw new ProcessingException(String.format("Data file %s not specified in control map.", key)); - // } - // return factory.get(); - // } catch (IOException ex) { - // throw new ProcessingException("Error while opening data file.", ex); - // } - // } - // - // void process() throws ProcessingException { - // try ( - // var polyStream = this.getStreamingParser(FipPolygonParser.CONTROL_KEY); - // var layerStream = this.>getStreamingParser(FipLayerParser.CONTROL_KEY); - // var speciesStream = this.>getStreamingParser(FipSpeciesParser.CONTROL_KEY); - // ) { - // log.atDebug().setMessage("Start Stand processing").log(); - // int polygonsRead = 0; - // int polygonsWritten = 0; - // - // while (polyStream.hasNext()) { - // - // // FIP_GET - // log.atInfo().setMessage("Getting polygon {}").addArgument(polygonsRead + 1).log(); - // var polygon = getPolygon(polyStream, layerStream, speciesStream); - // VdypPolygon resultPoly; - // try { - // - // log.atInfo().setMessage("Read polygon {}, preparing to process") - // .addArgument(polygon.getPolygonIdentifier()).log(); - // - // // if (MODE .eq. -1) go to 100 - // - // final var mode = polygon.getModeFip().orElse(FipMode.DONT_PROCESS); - // - // if (mode == FipMode.DONT_PROCESS) { - // log.atInfo().setMessage("Skipping polygon with mode {}").addArgument(mode).log(); - // continue; - // } - // - // // IP_IN = IP_IN+1 - // // if (IP_IN .gt. MAXPOLY) go to 200 - // - // polygonsRead++; // Don't count polygons we aren't processing due to mode. This was the behavior - // // in VDYP7 - // - // // IPASS = 1 - // // CALL FIP_CHK( IPASS, IER) - // // if (ier .gt. 0) go to 1000 - // // - // // if (IPASS .le. 0) GO TO 120 - // - // log.atInfo().setMessage("Checking validity of polygon {}:{}").addArgument(polygonsRead) - // .addArgument(polygon.getPolygonIdentifier()).log(); - // checkPolygon(polygon); - // - // // CALL FIPCALCV( BAV, IER) - // // CALL FIPCALC1( BAV, BA_TOTL1, IER) - // - // Map processedLayers = new EnumMap<>(Layer.class); - // - // var fipLayers = polygon.getLayers(); - // var fipVetLayer = Optional.ofNullable(fipLayers.get(Layer.VETERAN)); - // Optional resultVetLayer; - // if (fipVetLayer.isPresent()) { - // resultVetLayer = Optional.of(processLayerAsVeteran(polygon, fipVetLayer.get())); - // } else { - // resultVetLayer = Optional.empty(); - // } - // resultVetLayer.ifPresent(layer -> processedLayers.put(Layer.VETERAN, layer)); - // - // FipLayerPrimary fipPrimeLayer = (FipLayerPrimary) fipLayers.get(Layer.PRIMARY); - // assert fipPrimeLayer != null; - // var resultPrimeLayer = processLayerAsPrimary( - // polygon, fipPrimeLayer, - // resultVetLayer.map(VdypLayer::getBaseAreaByUtilization).map(coe -> coe.get(UTIL_ALL)) - // .orElse(0f) - // ); - // processedLayers.put(Layer.PRIMARY, resultPrimeLayer); - // - // resultPoly = createVdypPolygon(polygon, processedLayers); - // - // float baseAreaTotalPrime = resultPrimeLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL); // BA_TOTL1 - // - // // if (FIPPASS(6) .eq. 0 .or. FIPPASS(6) .eq. 2) then - // if (true /* TODO */) { - // @SuppressWarnings("unchecked") - // var minima = (Map) controlMap.get(VDYPForwardControlParser.MINIMA); - // float minimumBaseArea = minima.get(VDYPForwardControlParser.MINIMUM_BASE_AREA); - // float minimumPredictedBaseArea = minima.get(VDYPForwardControlParser.MINIMUM_PREDICTED_BASE_AREA); - // if (baseAreaTotalPrime < minimumBaseArea) { - // throw new LowValueException("Base area", baseAreaTotalPrime, minimumBaseArea); - // } - // float predictedBaseArea = baseAreaTotalPrime * (100f / resultPoly.getPercentAvailable()); - // if (predictedBaseArea < minimumPredictedBaseArea) { - // throw new LowValueException( - // "Predicted base area", predictedBaseArea, minimumPredictedBaseArea - // ); - // } - // } - // BecDefinition bec = BecDefinitionParser.getBecs(controlMap).get(polygon.getBiogeoclimaticZone()) - // .orElseThrow( - // () -> new ProcessingException("Missing Bec " + polygon.getBiogeoclimaticZone()) - // ); - // // FIPSTK - // adjustForStocking(resultPoly.getLayers().get(Layer.PRIMARY), fipPrimeLayer, bec); - // } catch (StandProcessingException ex) { - // // TODO include some sort of hook for different forms of user output - // // TODO Implement single stand mode that propagates the exception - // - // log.atWarn().setMessage("Polygon {} bypassed").addArgument(polygon.getPolygonIdentifier()) - // .setCause(ex); - // } - // - // } - // } catch (IOException | ResourceParseException ex) { - // throw new ProcessingException("Error while reading or writing data.", ex); - // } - // } - // - // // FIPSTK - // void adjustForStocking(VdypLayer vdypLayer, FipLayerPrimary fipLayerPrimary, BecDefinition bec) { - // - // @SuppressWarnings("unchecked") - // var stockingClassMap = (MatrixMap2>) controlMap - // .get(StockingClassFactorParser.CONTROL_KEY); - // - // Region region = bec.getRegion(); - // - // var factorEntry = fipLayerPrimary.getStockingClass() - // .flatMap(stockingClass -> stockingClassMap.get(stockingClass, region)); - // - // if (!factorEntry.isPresent()) { - // return; - // } - // - // float factor = factorEntry.get().getFactor(); - // - // scaleAllSummableUtilization(vdypLayer, factor); - // vdypLayer.getSpecies().values().forEach(spec -> scaleAllSummableUtilization(spec, factor)); - // - // log.atInfo().addArgument(fipLayerPrimary.getStockingClass()).addArgument(factor).setMessage( - // "Foregoing Primary Layer has stocking class {} Yield values will be multiplied by {} before being written to output file." - // ); - // } - // - // VdypPolygon createVdypPolygon(FipPolygon fipPolygon, Map processedLayers) - // throws ProcessingException { - // var fipVetLayer = fipPolygon.getLayers().get(Layer.VETERAN); - // var fipPrimaryLayer = (FipLayerPrimary) fipPolygon.getLayers().get(Layer.PRIMARY); - // - // float percentAvailable = estimatePercentForestLand(fipPolygon, fipVetLayer, fipPrimaryLayer); - // - // var vdypPolygon = new VdypPolygon(fipPolygon.getPolygonIdentifier(), percentAvailable); - // vdypPolygon.setLayers(processedLayers); - // return vdypPolygon; - // } - // - // // FIPLAND - // float estimatePercentForestLand(FipPolygon fipPolygon, FipLayer fipVetLayer, FipLayerPrimary fipPrimaryLayer) - // throws ProcessingException { - // if (fipPolygon.getPercentAvailable().isPresent()) { - // return fipPolygon.getPercentAvailable().get(); - // } else { - // - // boolean veteran = fipVetLayer != null && fipVetLayer.getHeight() > 0f && fipVetLayer.getCrownClosure() > 0f; // LAYERV - // - // if (jprogram == 1 && fipPolygon.getModeFip().map(mode -> mode == FipMode.FIPYOUNG).orElse(false)) { - // return 100f; - // } - // if (jprogram == 3) { - // veteran = fipVetLayer != null; - // } - // - // assert fipPrimaryLayer != null; - // - // float crownClosure = fipPrimaryLayer.getCrownClosure(); - // - // // Assume crown closure linear with age, to 25. - // if (fipPrimaryLayer.getAgeTotal() < 25f) { - // crownClosure *= 25f / fipPrimaryLayer.getAgeTotal(); - // } - // // define crown closure as the SUM of two layers - // if (veteran) { - // crownClosure += fipVetLayer.getCrownClosure(); - // } - // crownClosure = clamp(crownClosure, 0, 100); - // - // /* - // * assume that CC occurs at age 25 and that most land goes to 90% occupancy but - // * that occupancy increases only 1% /yr with no increases after ages 25. }); - // */ - // - // // Obtain the percent yield (in comparison with CC = 90%) - // - // float crownClosureTop = 90f; - // float breastHeightAge = fipPrimaryLayer.getAgeTotal() - fipPrimaryLayer.getYearsToBreastHeight(); - // - // float yieldFactor = fipPolygon.getYieldFactor(); - // - // var bec = BecDefinitionParser.getBecs(controlMap).get(fipPolygon.getBiogeoclimaticZone()).orElseThrow( - // () -> new ProcessingException("Could not find BEC " + fipPolygon.getBiogeoclimaticZone()) - // ); - // - // breastHeightAge = max(5.0f, breastHeightAge); - // // EMP040 - // float baseAreaTop = estimatePrimaryBaseArea( - // fipPrimaryLayer, bec, yieldFactor, breastHeightAge, 0f, crownClosureTop - // ); - // // EMP040 - // float baseAreaHat = estimatePrimaryBaseArea( - // fipPrimaryLayer, bec, yieldFactor, breastHeightAge, 0f, crownClosure - // ); - // - // float percentYield; - // if (baseAreaTop > 0f && baseAreaHat > 0f) { - // percentYield = min(100f, 100f * baseAreaHat / baseAreaTop); - // } else { - // percentYield = 90f; - // } - // - // float gainMax; - // if (fipPrimaryLayer.getAgeTotal() > 125f) { - // gainMax = 0f; - // } else if (fipPrimaryLayer.getAgeTotal() < 25f) { - // gainMax = max(90f - percentYield, 0); - // } else { - // gainMax = max(90f - percentYield, 0); - // gainMax = min(gainMax, 125 - fipPrimaryLayer.getAgeTotal()); - // } - // - // return floor(min(percentYield + gainMax, 100f)); - // - // } - // } - // - // // FIPCALC1 - // VdypLayer processLayerAsPrimary(FipPolygon fipPolygon, FipLayerPrimary fipLayer, float baseAreaOverstory) - // throws ProcessingException { - // - // var lookup = BecDefinitionParser.getBecs(controlMap); - // var primarySpecies = findPrimarySpecies(fipLayer.getSpecies()); - // // VDYP7 stores this in the common FIPL_1C/ITGL1 but only seems to use it - // // locally - // var itg = findItg(primarySpecies); - // - // BecDefinition bec = lookup.get(fipPolygon.getBiogeoclimaticZone()).orElseThrow( - // () -> new IllegalStateException("Could not find BEC " + fipPolygon.getBiogeoclimaticZone()) - // ); - // - // var result = new VdypLayer(fipLayer.getPolygonIdentifier(), fipLayer.getLayer()); - // - // result.setAgeTotal(fipLayer.getAgeTotal()); - // result.setYearsToBreastHeight(fipLayer.getYearsToBreastHeight()); - // result.setBreastHeightAge(fipLayer.getAgeTotal() - fipLayer.getYearsToBreastHeight()); - // result.setHeight(fipLayer.getHeight()); - // - // // EMP040 - // var baseArea = estimatePrimaryBaseArea( - // fipLayer, bec, fipPolygon.getYieldFactor(), result.getBreastHeightAge(), baseAreaOverstory - // ); // BA_TOT - // - // result.getBaseAreaByUtilization().setCoe(UTIL_ALL, baseArea); - // - // var quadMeanDiameter = estimatePrimaryQuadMeanDiameter( - // fipLayer, bec, result.getBreastHeightAge(), baseAreaOverstory - // ); - // - // result.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_ALL, quadMeanDiameter); - // - // var tphTotal = treesPerHectare(baseArea, quadMeanDiameter); - // - // result.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, tphTotal); - // - // // Copy over Species entries. - // // LVCOM/ISPL1=ISPV - // // LVCOM4/SP0L1=FIPSA/SP0V - // // LVCOM4/SP64DISTL1=FIPSA/VDISTRV - // // LVCOM1/PCLT1=FIPS/PCTVOLV - // var vdypSpecies = fipLayer.getSpecies().values().stream() // - // .map(VdypSpecies::new) // - // .collect(Collectors.toMap(VdypSpecies::getGenus, Function.identity())); - // - // var vdypPrimarySpecies = vdypSpecies.get(primarySpecies.get(0).getGenus()); - // - // // Lookup volume group, Decay Group, and Breakage group for each species. - // - // var volumeGroupMap = getGroupMap(VolumeEquationGroupParser.CONTROL_KEY); - // var decayGroupMap = getGroupMap(DecayEquationGroupParser.CONTROL_KEY); - // var breakageGroupMap = getGroupMap(BreakageEquationGroupParser.CONTROL_KEY); - // - // Map targetPercentages = new HashMap<>(vdypSpecies.size()); - // - // for (var vSpec : vdypSpecies.values()) { - // var volumeGroup = getGroup(fipPolygon, volumeGroupMap, vSpec); - // var decayGroup = getGroup(fipPolygon, decayGroupMap, vSpec); - // var breakageGroup = getGroup(fipPolygon, breakageGroupMap, vSpec); - // - // vSpec.setVolumeGroup(volumeGroup); - // vSpec.setDecayGroup(decayGroup); - // vSpec.setBreakageGroup(breakageGroup); - // - // targetPercentages.put(vSpec.getGenus(), vSpec.getPercentGenus()); - // } - // - // var maxPass = fipLayer.getSpecies().size() > 1 ? 2 : 1; - // - // result.setSpecies(vdypSpecies); - // - // float primaryHeight; - // float leadHeight = fipLayer.getHeight(); - // for (var iPass = 1; iPass <= maxPass; iPass++) { - // if (iPass == 2) { - // for (var vSpec : vdypSpecies.values()) { - // vSpec.setPercentGenus(targetPercentages.get(vSpec.getGenus())); - // } - // } - // // Estimate lorey height for primary species - // if (iPass == 1 && vdypSpecies.size() == 1) { - // primaryHeight = primaryHeightFromLeadHeight( - // leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), tphTotal - // ); - // } else if (iPass == 1) { - // primaryHeight = primaryHeightFromLeadHeightInitial( - // leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion() - // ); - // } else { - // primaryHeight = primaryHeightFromLeadHeight( - // leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), - // vdypPrimarySpecies.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - // ); - // } - // vdypPrimarySpecies.getLoreyHeightByUtilization().setCoe(UTIL_ALL, primaryHeight); - // - // // Estimate lorey height for non-primary species - // for (var vspec : vdypSpecies.values()) { - // if (vspec == vdypPrimarySpecies) - // continue; - // - // // EMP053 - // vspec.getLoreyHeightByUtilization().setCoe( - // UTIL_ALL, - // estimateNonPrimaryLoreyHeight(vspec, vdypPrimarySpecies, bec, leadHeight, primaryHeight) - // ); - // } - // - // // ROOTF01 - // findRootsForDiameterAndBaseArea(result, fipLayer, bec, iPass + 1); - // } - // - // estimateSmallComponents(fipPolygon, result); - // - // // YUC1 - // computeUtilizationComponentsPrimary(bec, result, VolumeComputeMode.BY_UTIL, CompatibilityVariableMode.NONE); - // - // return result; - // } - // - // // ROOTF01 - // void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, BecDefinition bec, int source) - // throws ProcessingException { - // - // var quadMeanDiameterTotal = result.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL); // DQ_TOT - // var baseAreaTotal = result.getBaseAreaByUtilization().getCoe(UTIL_ALL); // BA_TOT - // var treesPerHectareTotal = result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL); // TPH_TOT - // Map goal = new LinkedHashMap<>(); // GOAL - // Map xMap = new LinkedHashMap<>(); // X - // - // float treesPerHectareSum; - // - // assert result.getSpecies().size() > 0; - // - // if (result.getSpecies().size() == 1) { - // var spec = result.getSpecies().values().iterator().next(); - // for (var accessors : NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS) { - // - // try { - // Coefficients specVector = (Coefficients) accessors.getReadMethod().invoke(spec); - // Coefficients layerVector = (Coefficients) accessors.getReadMethod().invoke(result); - // specVector.setCoe(UTIL_ALL, layerVector.getCoe(UTIL_ALL)); - // } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - // throw new IllegalStateException(e); - // } - // } - // - // result.getLoreyHeightByUtilization().setCoe(UTIL_ALL, spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL)); - // spec.setPercentGenus(100f); - // treesPerHectareSum = treesPerHectareTotal; - // } else { - // // Multiple Species - // for (var spec : result.getSpecies().values()) { - // - // Coefficients limitCoe = getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - // - // final float maxHeightMultiplier = fipLayer.getPrimaryGenus().equals(spec.getGenus()) ? 1.5f : 1.0f; - // final float heightMax = limitCoe.getCoe(1) * maxHeightMultiplier; - // - // spec.getLoreyHeightByUtilization().scalarInPlace(UTIL_ALL, x -> min(x, heightMax)); - // } - // ToDoubleFunction accessor; - // - // switch (source) { - // case 1: - // accessor = x -> x.getPercentGenus(); - // break; - // case 2: - // accessor = x -> x.getPercentGenus() / x.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - // break; - // case 3: - // accessor = x -> x.getBaseAreaByUtilization().getCoe(UTIL_ALL); - // break; - // default: - // throw new UnsupportedOperationException("Unknown source for root finding " + source); - // } - // - // var sumSourceArea = result.getSpecies().values().stream().mapToDouble(accessor).sum(); - // - // // FRJ - // var fractionMap = result.getSpecies().values().stream().collect( - // Collectors.toMap( - // VdypSpecies::getGenus, spec -> (float) (accessor.applyAsDouble(spec) / sumSourceArea) - // ) - // ); - // - // // HL_TOT - // float loreyHeightTotal = (float) fractionMap.entrySet().stream().mapToDouble( - // e -> e.getValue() * result.getSpecies().get(e.getKey()).getLoreyHeightByUtilization().getCoe(0) - // ).sum(); - // // FRJ(ISP) = FRJ(J) // We aren't using the remapping between global species - // // index and index for the species within the layer, so we can probably assign - // // directly to the fraction attribute on the species object. - // fractionMap.entrySet().forEach(e -> result.getSpecies().get(e.getKey()).setFractionGenus(e.getValue())); - // - // double[] quadMeanDiameterBase = new double[result.getSpecies().size()]; // DQspbase - // - // { - // int i = 0; - // for (var spec : result.getSpecies().values()) { - // - // // EMP061 - // Coefficients limitCoe = getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - // - // var dqMin = limitCoe.getCoe(3) * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - // var dqMax = max( - // limitCoe.getCoe(2), limitCoe.getCoe(4) * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) - // ); - // - // // EMP060 - // float quadMeanDiameter = clamp( - // estimateQuadMeanDiameterForSpecies( - // spec, result.getSpecies(), bec.getRegion(), quadMeanDiameterTotal, baseAreaTotal, - // treesPerHectareTotal, loreyHeightTotal - // ), // - // dqMin, dqMax - // ); - // - // quadMeanDiameterBase[i++] = quadMeanDiameter; - // } - // } - // // VDYP7 checks the number of species here, but this is already inside a branch - // // that must be more than 1 - // // Fill in target and trial values - // - // eachButLast(result.getSpecies().values(), spec -> { - // goal.put(spec.getGenus(), spec.getPercentGenus()); - // xMap.put(spec.getGenus(), spec.getPercentGenus()); - // }, spec -> { - // goal.put(spec.getGenus(), quadMeanDiameterTotal); - // xMap.put(spec.getGenus(), 0f); - // }); - // - // var xVec = xMap.values().stream().mapToDouble(v -> (double) v).toArray(); - // var goalVec = goal.values().stream().mapToDouble(v -> (double) v).toArray(); - // - // // SNQSOL - // var rootVec = this.findRoot(quadMeanDiameterBase, goalVec, xVec, result, TOLERANCE); - // - // var rootMap = new LinkedHashMap(); - // { - // float percentSum = 0; - // var it = result.getSpecies().values().iterator(); - // for (int i = 0; it.hasNext(); i++) { - // var spec = it.next(); - // rootMap.put(spec.getGenus(), (float) rootVec.getEntry(i)); - // if (it.hasNext()) { - // spec.setPercentGenus((float) rootVec.getEntry(i)); - // percentSum += rootVec.getEntry(i); - // } else { - // spec.setPercentGenus(100 - percentSum); - // } - // } - // } - // - // float loreyHeightSum = 0; - // treesPerHectareSum = 0; - // - // { - // int i = 0; - // for (var spec : result.getSpecies().values()) { - // float dqBase = (float) quadMeanDiameterBase[i++]; - // float dq = 7.5f + (dqBase - 7.5f) * exp((float) rootVec.getEntry(rootVec.getDimension() - 1) / 20f); - // assert dq >= 0; - // float ba = baseAreaTotal * spec.getPercentGenus() / 100f; - // assert ba >= 0; - // float tph = treesPerHectare(ba, dq); - // assert tph >= 0; - // spec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_ALL, dq); - // spec.getBaseAreaByUtilization().setCoe(UTIL_ALL, ba); - // spec.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, tph); - // treesPerHectareSum += tph; - // loreyHeightSum += spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) * ba; - // } - // } - // result.getLoreyHeightByUtilization().setCoe(UTIL_ALL, loreyHeightSum / baseAreaTotal); - // - // } // end of Multiple Species branch - // - // var volumeSum = 0f; - // - // for (var spec : result.getSpecies().values()) { - // // EMP090 - // var wholeStemVolume = spec.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - // * estimateWholeStemVolumePerTree( - // spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL), - // spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL) - // ); - // spec.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, wholeStemVolume); - // volumeSum += wholeStemVolume; - // } - // - // result.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, volumeSum); - // var treesPerHectareStart = result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL); - // result.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, treesPerHectareSum); - // result.getQuadraticMeanDiameterByUtilization().setCoe( - // UTIL_ALL, - // quadMeanDiameter( - // result.getBaseAreaByUtilization().getCoe(UTIL_ALL), - // result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - // ) - // ); - // - // if (abs(treesPerHectareStart / result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - 1f) > 0.002) { - // throw new ProcessingException("TODO"); - // } - // - // if (result.getSpecies().size() > 1) { - // for (var spec : result.getSpecies().values()) { - // if (spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL) / volumeSum - // - goal.get(spec.getGenus()) > 0.1) { - // throw new ProcessingException("TODO"); - // } - // } - // } - // } - // - // // EMP060 - // /** - // * Estimate DQ for a species (primary or not). Using eqn in jf125.doc. - // * - // * Enforces mins and maxes from EMP061. - // * - // * @param spec Species of insterest - // * @param allSpecies Collection of all species on the layer - // * @param region BEC Region of the stand - // * @param standQuadMeanDiameter Quadratic mean diameter of the stand - // * @param standBaseArea Base area of the stand - // * @param standTreesPerHectare Density opf the stand - // * @param standLoreyHeight Lorey height of the stand - // * @return Quadratic mean diameter of the species of interest - // * @throws ProcessingException - // */ - // float estimateQuadMeanDiameterForSpecies( - // VdypSpecies spec, // ISP, HLsp, DQsp - // Map allSpecies, // FR - // Region region, // INDEX_IC - // float standQuadMeanDiameter, // DQ_TOT - // float standBaseArea, // BA_TOT - // float standTreesPerHectare, // TPH_TOT - // float standLoreyHeight // HL_TOT - // ) throws ProcessingException { - // String species = spec.getGenus(); - // - // float c = 0.00441786467f; - // - // float minQuadMeanDiameter = min(7.6f, standQuadMeanDiameter); - // - // // Quick solution - // if (spec.getFractionGenus() >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { - // return standQuadMeanDiameter; - // } - // - // var coeMap = Utils.>expectParsedControl( - // controlMap, BySpeciesDqCoefficientParser.CONTROL_KEY, Map.class - // ); - // var specAliases = GenusDefinitionParser.getSpeciesAliases(controlMap); - // - // // TODO we can probably remove these as they seem to only be used for debugging - // // in VDYP7 - // Map adjust = new HashMap<>(coeMap.size()); - // Map mult = new HashMap<>(coeMap.size()); - // - // var specIt = specAliases.iterator(); - // - // var spec1 = specIt.next(); - // - // float a2 = coeMap.get(spec1).getCoe(2); - // - // float fractionOther = 1f - spec.getFractionGenus(); // FR_REST - // - // mult.put(spec1, 1f); - // float a0 = coeMap.get(spec1).getCoe(0); - // float a1 = coeMap.get(spec1).getCoe(1); - // - // while (specIt.hasNext()) { - // var specIAlias = specIt.next(); - // var specI = allSpecies.get(specIAlias); - // if (specIAlias.equals(spec.getGenus())) { - // float multI = 1f; - // mult.put(specIAlias, multI); - // a0 += multI * coeMap.get(specIAlias).getCoe(0); - // a1 += multI * coeMap.get(specIAlias).getCoe(1); - // } else { - // if (specI != null && specI.getFractionGenus() > 0f) { - // float multI = -specI.getFractionGenus() / fractionOther; - // mult.put(specIAlias, multI); - // a0 += multI * coeMap.get(specIAlias).getCoe(0); - // a1 -= multI * coeMap.get(specIAlias).getCoe(1); - // } - // } - // } - // - // float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - // float loreyHeight1 = max(4f, loreyHeightSpec); - // float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spec.getFractionGenus()) / fractionOther; - // float loreyHeightRatio = clamp( (loreyHeight1 - 3f) / (loreyHeight2 - 3f), 0.05f, 20f); - // - // float r = exp( - // a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) + adjust.getOrDefault(species, 0f) - // ); - // - // float baseArea1 = spec.getFractionGenus() * standBaseArea; - // float baseArea2 = standBaseArea - baseArea1; - // - // float treesPerHectare1; - // if (abs(r - 1f) < 0.0005) { - // treesPerHectare1 = spec.getFractionGenus() * standTreesPerHectare; - // } else { - // float aa = (r - 1f) * c; - // float bb = c * (1f - r) * standTreesPerHectare + baseArea1 + baseArea2 * r; - // float cc = -baseArea1 * standTreesPerHectare; - // float term = bb * bb - 4 * aa * cc; - // if (term <= 0f) { - // throw new ProcessingException( - // "Term for trees per hectare calculation when estimating quadratic mean diameter for species " - // + species + " was " + term + " but should be positive." - // ); - // } - // treesPerHectare1 = (-bb + sqrt(term)) / (2f * aa); - // if (treesPerHectare1 <= 0f || treesPerHectare1 > standTreesPerHectare) { - // throw new ProcessingException( - // "Trees per hectare 1 for species " + species + " was " + treesPerHectare1 - // + " but should be positive and less than or equal to stand trees per hectare " - // + standTreesPerHectare - // ); - // } - // } - // - // float quadMeanDiameter1 = quadMeanDiameter(baseArea1, treesPerHectare1); - // float treesPerHectare2 = standTreesPerHectare - treesPerHectare1; - // float quadMeanDiameter2 = quadMeanDiameter(baseArea2, treesPerHectare2); - // - // if (quadMeanDiameter2 < minQuadMeanDiameter) { - // // species 2 is too small. Make target species smaller. - // quadMeanDiameter2 = minQuadMeanDiameter; - // treesPerHectare2 = treesPerHectare(baseArea2, quadMeanDiameter2); - // treesPerHectare1 = standTreesPerHectare - treesPerHectare2; - // quadMeanDiameter1 = quadMeanDiameter(baseArea1, treesPerHectare1); - // } - // var limitCoe = getLimitsForHeightAndDiameter(species, region); - // - // final var dqMinSp = max(minQuadMeanDiameter, limitCoe.getCoe(3) * loreyHeightSpec); - // final var dqMaxSp = max(7.6f, min(limitCoe.getCoe(2), limitCoe.getCoe(4) * loreyHeightSpec)); - // if (quadMeanDiameter1 < dqMinSp) { - // quadMeanDiameter1 = dqMinSp; - // treesPerHectare1 = treesPerHectare(baseArea1, quadMeanDiameter1); - // treesPerHectare2 = standTreesPerHectare - treesPerHectare2; - // quadMeanDiameter2 = quadMeanDiameter(baseArea2, treesPerHectare2); - // } - // if (quadMeanDiameter1 > dqMaxSp) { - // // target species is too big. Make target species smaller, DQ2 bigger. - // - // quadMeanDiameter1 = dqMaxSp; - // treesPerHectare1 = treesPerHectare(baseArea1, quadMeanDiameter1); - // treesPerHectare2 = standTreesPerHectare - treesPerHectare2; - // - // if (treesPerHectare2 > 0f && baseArea2 > 0f) { - // quadMeanDiameter2 = quadMeanDiameter(baseArea2, treesPerHectare2); - // } else { - // quadMeanDiameter2 = 1000f; - // } - // - // // under rare circumstances, let DQ1 exceed DQMAXsp - // if (quadMeanDiameter2 < minQuadMeanDiameter) { - // quadMeanDiameter2 = minQuadMeanDiameter; - // treesPerHectare2 = treesPerHectare(baseArea2, quadMeanDiameter2); - // treesPerHectare1 = standTreesPerHectare - treesPerHectare2; - // quadMeanDiameter1 = quadMeanDiameter(baseArea1, treesPerHectare1); - // } - // - // } - // return quadMeanDiameter1; - // } - // - // // EMP061 - // private Coefficients getLimitsForHeightAndDiameter(String genus, Region region) { - // var coeMap = Utils.>expectParsedControl( - // controlMap, ComponentSizeParser.CONTROL_KEY, MatrixMap2.class - // ); - // - // return coeMap.get(genus, region); - // } - // - // // EMP090 - // private float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - // var coeMap = Utils.>expectParsedControl( - // controlMap, TotalStandWholeStemParser.CONTROL_KEY, Map.class - // ); - // var coe = coeMap.get(volumeGroup).reindex(0); - // - // var logMeanVolume = coe.getCoe(UTIL_ALL) + // - // coe.getCoe(1) * log(quadMeanDiameter) + // - // coe.getCoe(2) * log(loreyHeight) + // - // coe.getCoe(3) * quadMeanDiameter + // - // coe.getCoe(4) / quadMeanDiameter + // - // coe.getCoe(5) * loreyHeight + // - // coe.getCoe(6) * quadMeanDiameter * quadMeanDiameter + // - // coe.getCoe(7) * loreyHeight * quadMeanDiameter // - // + coe.getCoe(8) * loreyHeight / quadMeanDiameter; - // - // return exp(logMeanVolume); - // } - // - // // EMP053 Using eqns N1 and N2 from ipsjf124.doc - // /** - // * Estimate the lorey height of a non-primary species of a primary layer. - // * - // * @param vspec The species. - // * @param vspecPrime The primary species. - // * @param leadHeight lead height of the layer - // * @param primaryHeight height of the primary species - // * @throws ProcessingException - // */ - // float estimateNonPrimaryLoreyHeight( - // VdypSpecies vspec, VdypSpecies vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight - // ) throws ProcessingException { - // var coeMap = Utils.>>expectParsedControl( - // controlMap, HLNonprimaryCoefficientParser.CONTROL_KEY, MatrixMap3.class - // ); - // - // var coe = coeMap.get(vspec.getGenus(), vspecPrime.getGenus(), bec.getRegion()).orElseThrow( - // () -> new ProcessingException( - // String.format( - // "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec.getGenus(), - // vspecPrime.getGenus(), bec.getRegion() - // ) - // ) - // ); - // var heightToUse = coe.getEquationIndex() == 1 ? leadHeight : primaryHeight; - // return 1.3f + coe.getCoe(1) * pow(heightToUse - 1.3f, coe.getCoe(2)); - // } - // - // VdypLayer processLayerAsVeteran(FipPolygon fipPolygon, FipLayer fipLayer) throws ProcessingException { - // - // var polygonIdentifier = fipLayer.getPolygonIdentifier(); - // - // assert fipLayer.getLayer().equals(Layer.VETERAN) : "Layer must be VETERAN"; - // assert fipPolygon.getPolygonIdentifier().equals(fipLayer.getPolygonIdentifier()) : String.format( - // "Polygon polygonIdentifier '%s' doesn't match that of layer '%s'", fipPolygon.getPolygonIdentifier(), - // fipLayer.getPolygonIdentifier() - // ); - // - // var layer = Layer.VETERAN; - // - // // find Primary genus (highest percentage) ISPPVET - // - // var primaryGenus = fipLayer.getSpecies().values().stream() // - // .max(Utils.compareUsing(FipSpecies::getPercentGenus)) // - // .orElseThrow(() -> new IllegalStateException("No primarty genus (SP0) found. This should not happen.")) - // .getGenus(); - // - // // ageTotal copy, LVCOM3/AGETOTLV copied from FIPL_V/AGETOT_LV - // var ageTotal = fipLayer.getAgeTotal(); - // - // // yearsToBreastHeight copy, minimum 6.0, LVCOM3/YTBHLV copied from - // // FIPL_V/YTBH_L - // var yearsToBreastHeight = Math.max(fipLayer.getYearsToBreastHeight(), 6.0f); - // - // // breastHeightAge LVCOM3/AGEBHLV ageTotal-yearsToBreastHeight - // var breastHeightAge = ageTotal - yearsToBreastHeight; - // - // // height? copy LVCOM3/HDLV = FIPL_V/HT_LV - // var height = fipLayer.getHeight(); - // - // var crownClosure = fipLayer.getCrownClosure(); - // - // var becId = fipPolygon.getBiogeoclimaticZone(); - // var bec = BecDefinitionParser.getBecs(controlMap).get(becId) - // .orElseThrow(() -> new ProcessingException("Could not find BEC " + becId)); - // var region = bec.getRegion(); - // - // // Call EMP098 to get Veteran Basal Area, store in LVCOM1/BA array at positions - // // 0,0 and 0,4 - // var estimatedBaseArea = estimateVeteranBaseArea(height, crownClosure, primaryGenus, region); - // var baseAreaByUtilization = new Coefficients( - // new float[] { 0.0f, estimatedBaseArea, 0.0f, 0.0f, 0.0f, estimatedBaseArea }, -1 - // ); - // // Copy over Species entries. - // // LVCOM/ISPLV=ISPV - // // LVCOM4/SP0LV=FIPSA/SP0V - // // LVCOM4/SP64DISTLV=FIPSA/VDISTRV - // // LVCOM1/PCLTV=FIPS/PCTVOLV - // // LVCOM1/HL=FIPL_V/HT_LV - // var vdypSpecies = fipLayer.getSpecies().values().stream() // - // .map(fipSpec -> { - // var vs = new VdypSpecies(fipSpec); - // vs.setLoreyHeightByUtilization(new Coefficients(new float[] { 0f, height }, -1)); - // return vs; - // }) // - // .collect(Collectors.toMap(VdypSpecies::getGenus, Function.identity())); - // - // // Lookup volume group, Decay Group, and Breakage group for each species. - // - // var volumeGroupMap = getGroupMap(VolumeEquationGroupParser.CONTROL_KEY); - // var decayGroupMap = getGroupMap(DecayEquationGroupParser.CONTROL_KEY); - // var breakageGroupMap = getGroupMap(BreakageEquationGroupParser.CONTROL_KEY); - // for (var vSpec : vdypSpecies.values()) { - // var volumeGroup = getGroup(fipPolygon, volumeGroupMap, vSpec); - // var decayGroup = getGroup(fipPolygon, decayGroupMap, vSpec); - // var breakageGroup = getGroup(fipPolygon, breakageGroupMap, vSpec); - // - // vSpec.setVolumeGroup(volumeGroup); - // vSpec.setDecayGroup(decayGroup); - // vSpec.setBreakageGroup(breakageGroup); - // } - // - // /* - // * From VDYP7 - // * - // * At this point we SHOULD invoke a root finding procedure sets species percents - // * and adjusts DQ by species. fills in main components, through whole-stem - // * volume INSTEAD, I will assume %volumes apply to % BA's - // */ - // - // for (var vSpec : vdypSpecies.values()) { - // vSpec.getBaseAreaByUtilization() - // .setCoe(UTIL_LARGEST, baseAreaByUtilization.getCoe(UTIL_LARGEST) * vSpec.getPercentGenus() / 100f); - // } - // - // var vetDqMap = Utils.>expectParsedControl( - // controlMap, VeteranDQParser.CONTROL_KEY, MatrixMap2.class - // ); - // - // for (var vSpec : vdypSpecies.values()) { - // var genus = vSpec.getGenus(); - // var coe = vetDqMap.get(genus, region); - // var a0 = coe.getCoe(1); - // var a1 = coe.getCoe(2); - // var a2 = coe.getCoe(3); - // float hl = vSpec.getLoreyHeightByUtilization().getCoe(0); - // float dq = max(a0 + a1 * pow(hl, a2), 22.5f); - // vSpec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_LARGEST, dq); - // vSpec.getTreesPerHectareByUtilization() - // .setCoe(UTIL_LARGEST, treesPerHectare(vSpec.getBaseAreaByUtilization().getCoe(UTIL_LARGEST), dq)); - // } - // - // var vdypLayer = new VdypLayer(polygonIdentifier, layer); - // vdypLayer.setAgeTotal(ageTotal); - // vdypLayer.setHeight(height); - // vdypLayer.setYearsToBreastHeight(yearsToBreastHeight); - // vdypLayer.setBreastHeightAge(breastHeightAge); - // vdypLayer.setSpecies(vdypSpecies); - // // vdypLayer.setPrimaryGenus(primaryGenus); - // vdypLayer.setBaseAreaByUtilization(baseAreaByUtilization); - // - // computeUtilizationComponentsVeteran(vdypLayer, bec); - // - // return vdypLayer; - // } - // - // static Coefficients utilizationVector() { - // return new Coefficients(new float[] { 0f, 0f, 0f, 0f, 0f, 0f }, -1); - // } - // - // static Coefficients utilizationVector(float small, float all, float u1, float u2, float u3, float u4) { - // return new Coefficients(new float[] { small, all, u1, u2, u3, u4 }, -1); - // } - // - // static Coefficients utilizationVector(float small, float u1, float u2, float u3, float u4) { - // return new Coefficients(new float[] { small, u1 + u2 + u3 + u4, u1, u2, u3, u4 }, -1); - // } - // - // // YUC1 - // void computeUtilizationComponentsPrimary( - // BecDefinition bec, VdypLayer vdypLayer, VolumeComputeMode volumeComputeMode, - // CompatibilityVariableMode compatibilityVariableMode - // ) throws ProcessingException { - // log.atTrace().setMessage("computeUtilizationComponentsPrimary for {}, stand total age is {}") - // .addArgument(vdypLayer.getPolygonIdentifier()).addArgument(vdypLayer.getAgeTotal()).log(); - // log.atDebug().setMessage("Primary layer for {} has {} species/genera: {}") - // .addArgument(vdypLayer::getPolygonIdentifier) // - // .addArgument(() -> vdypLayer.getSpecies().size()) // - // .addArgument(() -> vdypLayer.getSpecies().keySet().stream().collect(Collectors.joining(", "))) // - // .log(); - // - // for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - // float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - // float baseAreaSpec = spec.getBaseAreaByUtilization().getCoe(UTIL_ALL); - // float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL); - // float treesPerHectareSpec = spec.getTreesPerHectareByUtilization().getCoe(UTIL_ALL); - // - // log.atDebug().setMessage("Working with species {} LH: {} DQ: {} BA: {} TPH: {}") - // .addArgument(spec.getClass()).addArgument(loreyHeightSpec).addArgument(quadMeanDiameterSpec) - // .addArgument(baseAreaSpec).addArgument(treesPerHectareSpec); - // - // if (volumeComputeMode == VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC) { - // log.atDebug().log("Estimating tree volume"); - // - // // EMP090 - // throw new UnsupportedOperationException("TODO"); // Not used yet - // - // // log.atDebug().setMessage("Species WS stand volume {}") - // // .addArgument(() -> spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL)); - // - // } - // float wholeStemVolumeSpec = spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL); - // - // var baseAreaUtil = utilizationVector(); - // var quadMeanDiameterUtil = utilizationVector(); - // var treesPerHectareUtil = utilizationVector(); - // var wholeStemVolumeUtil = utilizationVector(); - // var closeVolumeUtil = utilizationVector(); - // var closeVolumeNetDecayUtil = utilizationVector(); - // var closeVolumeNetDecayWasteUtil = utilizationVector(); - // var closeVolumeNetDecayWasteBreakUtil = utilizationVector(); - // - // baseAreaUtil.setCoe(UTIL_ALL, baseAreaSpec); // BAU - // quadMeanDiameterUtil.setCoe(UTIL_ALL, quadMeanDiameterSpec); // DQU - // treesPerHectareUtil.setCoe(UTIL_ALL, treesPerHectareSpec); // TPHU - // wholeStemVolumeUtil.setCoe(UTIL_ALL, wholeStemVolumeSpec); // WSU - // - // var adjustCloseUtil = utilizationVector(); // ADJVCU - // var adjustDecayUtil = utilizationVector(); // ADJVD - // var adjustDecayWasteUtil = utilizationVector(); // ADJVDW - // - // // EMP071 - // estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec); - // - // // EMP070 - // estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec); - // - // // Calculate tree density components - // for (var uc : UTIL_CLASSES) { - // treesPerHectareUtil.setCoe( - // uc.index, treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - // ); - // } - // - // // reconcile components with totals - // - // // YUC1R - // reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - // - // if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { - // throw new UnsupportedOperationException("TODO"); - // } - // - // // Recalculate TPH's - // - // for (var uc : UTIL_CLASSES) { - // treesPerHectareUtil.setCoe( - // uc.index, treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - // ); - // } - // - // // Since DQ's may have changed, MUST RECONCILE AGAIN - // // Seems this might only be needed when compatibilityVariableMode is not NONE? - // - // // YUC1R - // reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - // - // if (volumeComputeMode == VolumeComputeMode.ZERO) { - // throw new UnsupportedOperationException("TODO"); - // } else { - // - // // EMP091 - // estimateWholeStemVolume( - // UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, - // quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - // ); - // - // if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { - // // apply compatibity variables to WS volume - // throw new UnsupportedOperationException("TODO"); - // } - // // TODO Combine this with IF above - // if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { - // // Set the adjustment factors for next three volume types - // throw new UnsupportedOperationException("TODO"); - // } else { - // // Do nothing as the adjustment vectors are already set to 0 - // } - // - // // EMP092 - // estimateCloseUtilizationVolume( - // UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, - // quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil - // ); - // - // // EMP093 - // estimateNetDecayVolume( - // spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), - // loreyHeightSpec, vdypLayer.getBreastHeightAge(), quadMeanDiameterUtil, closeVolumeUtil, - // closeVolumeNetDecayUtil - // ); - // - // // EMP094 - // estimateNetDecayAndWasteVolume( - // bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, - // vdypLayer.getBreastHeightAge(), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, - // closeVolumeNetDecayWasteUtil - // ); - // - // if (jprogram < 6) { - // // EMP095 - // estimateNetDecayWasteAndBreakageVolume( - // UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, - // closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil - // ); - // } - // } - // - // spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, COPY_IF_BAND); - // spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, COPY_IF_BAND); - // spec.getQuadraticMeanDiameterByUtilization().pairwiseInPlace(quadMeanDiameterUtil, COPY_IF_BAND); - // - // spec.getWholeStemVolumeByUtilization().pairwiseInPlace(wholeStemVolumeUtil, COPY_IF_NOT_TOTAL); - // spec.getCloseUtilizationVolumeByUtilization().pairwiseInPlace(closeVolumeUtil, COPY_IF_NOT_TOTAL); - // spec.getCloseUtilizationVolumeNetOfDecayByUtilization() - // .pairwiseInPlace(closeVolumeNetDecayUtil, COPY_IF_NOT_TOTAL); - // spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - // .pairwiseInPlace(closeVolumeNetDecayWasteUtil, COPY_IF_NOT_TOTAL); - // spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() - // .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, COPY_IF_NOT_TOTAL); - // - // } - // computeLayerUtilizationComponentsFromSpecies(vdypLayer); - // - // for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - // if (vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL) > 0f) { - // spec.setFractionGenus( - // spec.getBaseAreaByUtilization().getCoe(UTIL_ALL) - // / vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL) - // ); - // } - // log.atDebug().addArgument(spec.getGenus()).addArgument(spec.getFractionGenus()) - // .setMessage("Species {} base area {}%").log(); - // } - // - // log.atDebug().setMessage("Calculating Stand Lorey Height").log(); - // - // vdypLayer.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, 0f); - // vdypLayer.getLoreyHeightByUtilization().setCoe(UTIL_ALL, 0f); - // - // for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - // log.atDebug() // - // .addArgument(spec.getGenus()) // - // .addArgument(() -> spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL)) - // .addArgument(() -> spec.getBaseAreaByUtilization().getCoe(UTIL_ALL)) - // .addArgument( - // () -> spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) - // * spec.getBaseAreaByUtilization().getCoe(UTIL_ALL) - // ) - // .setMessage( - // "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" - // ).log(); - // vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - // UTIL_SMALL, - // x -> x + spec.getLoreyHeightByUtilization().getCoe(UTIL_SMALL) - // * spec.getBaseAreaByUtilization().getCoe(UTIL_SMALL) - // ); - // vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - // UTIL_ALL, - // x -> x + spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) - // * spec.getBaseAreaByUtilization().getCoe(UTIL_ALL) - // ); - // } - // { - // float baSmall = vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_SMALL); - // float baAll = vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL); - // - // if (baSmall > 0) { - // vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UTIL_SMALL, x -> x / baSmall); - // } - // if (baAll > 0) { - // vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UTIL_ALL, x -> x / baAll); - // } - // - // } - // - // } - // - // private static final IndexedFloatBinaryOperator COPY_IF_BAND = (oldX, newX, i) -> i <= UTIL_ALL ? oldX : newX; - // private static final IndexedFloatBinaryOperator COPY_IF_NOT_TOTAL = (oldX, newX, i) -> i < UTIL_ALL ? oldX : newX; - // - // // YUCV - // private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinition bec) - // throws ProcessingException { - // log.trace( - // "computeUtilizationComponentsVeterany for {}, stand total age is {}", vdypLayer.getPolygonIdentifier(), - // vdypLayer.getAgeTotal() - // ); - // - // var volumeAdjustMap = Utils.>expectParsedControl( - // controlMap, VeteranLayerVolumeAdjustParser.CONTROL_KEY, Map.class - // ); - // try { - // for (var vdypSpecies : vdypLayer.getSpecies().values()) { - // - // var treesPerHectareUtil = utilizationVector(); - // var quadMeanDiameterUtil = utilizationVector(); - // var baseAreaUtil = utilizationVector(); - // var wholeStemVolumeUtil = utilizationVector(); - // - // var closeUtilizationVolumeUtil = utilizationVector(); - // var closeUtilizationNetOfDecayUtil = utilizationVector(); - // var closeUtilizationNetOfDecayAndWasteUtil = utilizationVector(); - // var closeUtilizationNetOfDecayWasteAndBreakageUtil = utilizationVector(); - // - // var hlSp = vdypSpecies.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - // { - // var baSp = vdypSpecies.getBaseAreaByUtilization().getCoe(UTIL_LARGEST); - // var tphSp = vdypSpecies.getTreesPerHectareByUtilization().getCoe(UTIL_LARGEST); - // var dqSp = vdypSpecies.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_LARGEST); - // - // treesPerHectareUtil.setCoe(UTIL_ALL, tphSp); - // quadMeanDiameterUtil.setCoe(UTIL_ALL, dqSp); - // baseAreaUtil.setCoe(UTIL_ALL, baSp); - // wholeStemVolumeUtil.setCoe(UTIL_ALL, 0f); - // - // treesPerHectareUtil.setCoe(UTIL_LARGEST, tphSp); - // quadMeanDiameterUtil.setCoe(UTIL_LARGEST, dqSp); - // baseAreaUtil.setCoe(UTIL_LARGEST, baSp); - // wholeStemVolumeUtil.setCoe(UTIL_LARGEST, 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 - // estimateWholeStemVolume( - // utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, - // quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - // ); - // - // adjust.setCoe(4, volumeAdjustCoe.getCoe(2)); - // // EMP092 - // estimateCloseUtilizationVolume( - // utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, - // wholeStemVolumeUtil, closeUtilizationVolumeUtil - // ); - // - // adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); - // // EMP093 - // estimateNetDecayVolume( - // vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, vdypSpecies.getDecayGroup(), - // hlSp, vdypLayer.getBreastHeightAge(), quadMeanDiameterUtil, closeUtilizationVolumeUtil, - // closeUtilizationNetOfDecayUtil - // ); - // - // adjust.setCoe(4, volumeAdjustCoe.getCoe(4)); - // // EMP094 - // estimateNetDecayAndWasteVolume( - // bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, - // vdypLayer.getBreastHeightAge(), quadMeanDiameterUtil, closeUtilizationVolumeUtil, - // closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil - // ); - // - // if (jprogram < 6) { - // // EMP095 - // estimateNetDecayWasteAndBreakageVolume( - // 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) { - // Coefficients utilVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); - // - // // Set all components other than 4 to 0.0 - // for (var i = -1; i < UTIL_LARGEST; i++) { - // utilVector.setCoe(i, 0f); - // } - // - // // Set component 0 to equal component 4. - // utilVector.setCoe(UTIL_ALL, utilVector.getCoe(UTIL_LARGEST)); - // - // accessors.getWriteMethod().invoke(vdypSpecies, utilVector); - // } - // } - // - // computeLayerUtilizationComponentsFromSpecies(vdypLayer); - // - // } catch (IllegalAccessException | InvocationTargetException ex) { - // throw new IllegalStateException(ex); - // } - // } - // - // /** - // * Sets the Layer's utilization components based on those of its species. - // * - // * @param vdypLayer - // */ - // private void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { - // // Layer utilization vectors other than quadratic mean diameter are the pairwise - // // sums of those of their species - // sumSpeciesUtilizationVectorsToLayer(vdypLayer); - // - // // Quadratic mean diameter for the layer is computed from the BA and TPH after - // // they have been found from the species - // { - // var utilVector = vdypLayer.getBaseAreaByUtilization() - // .pairwise(vdypLayer.getTreesPerHectareByUtilization(), VDYPForwardStart::quadMeanDiameter); - // vdypLayer.setQuadraticMeanDiameterByUtilization(utilVector); - // } - // } - // - // // TODO De-reflectify this when we want to make it work in GralVM - // private void sumSpeciesUtilizationVectorsToLayer(VdypLayer vdypLayer) throws IllegalStateException { - // try { - // for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { - // var utilVector = utilizationVector(); - // for (var vdypSpecies : vdypLayer.getSpecies().values()) { - // var speciesVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); - // utilVector.pairwiseInPlace(speciesVector, (x, y) -> x + y); - // } - // accessors.getWriteMethod().invoke(vdypLayer, utilVector); - // } - // } catch (IllegalAccessException | InvocationTargetException ex) { - // throw new IllegalStateException(ex); - // } - // } - // - // // TODO De-reflectify this when we want to make it work in GralVM - // private void scaleAllSummableUtilization(VdypUtilizationHolder holder, float factor) throws IllegalStateException { - // try { - // for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { - // ((Coefficients) accessors.getReadMethod().invoke(holder)).scalarInPlace(x -> x * factor); - // } - // } catch (IllegalAccessException | InvocationTargetException ex) { - // throw new IllegalStateException(ex); - // } - // } - // - // /** - // * Implements the three reconciliation modes for layer 1 as described in - // * ipsjf120.doc - // * - // * @param baseAreaUtil - // * @param treesPerHectareUtil - // * @param quadMeanDiameterUtil - // * @throws ProcessingException - // */ - // // YUC1R - // void reconcileComponents( - // Coefficients baseAreaUtil, Coefficients treesPerHectareUtil, Coefficients quadMeanDiameterUtil - // ) throws ProcessingException { - // if (baseAreaUtil.getCoe(UTIL_ALL) == 0f) { - // UTIL_CLASSES.forEach(uc -> { - // treesPerHectareUtil.setCoe(uc.index, 0f); - // baseAreaUtil.setCoe(uc.index, 0f); - // }); - // return; - // } - // - // float tphSum = 0f; - // float baSum = 0f; - // for (var uc : UTIL_CLASSES) { - // tphSum += treesPerHectareUtil.getCoe(uc.index); - // baSum += baseAreaUtil.getCoe(uc.index); - // } - // - // if (abs(baSum - baseAreaUtil.getCoe(UTIL_ALL)) / baSum > 0.00003) { - // throw new ProcessingException("Computed base areas for 7.5+ components do not sum to expected total"); - // } - // - // float dq0 = quadMeanDiameter(baseAreaUtil.getCoe(UTIL_ALL), treesPerHectareUtil.getCoe(UTIL_ALL)); - // - // if (dq0 < 7.5f) { - // throw new ProcessingException( - // "Quadratic mean diameter computed from total base area and trees per hectare is less than 7.5 cm" - // ); - // } - // - // float tphSumHigh = (float) UTIL_CLASSES.stream() - // .mapToDouble(uc -> treesPerHectare(baseAreaUtil.getCoe(uc.index), uc.lowBound)).sum(); - // - // if (tphSumHigh < treesPerHectareUtil.getCoe(UTIL_ALL)) { - // reconcileComponentsMode1(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil, tphSumHigh); - // } else { - // reconcileComponentsMode2Check(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - // } - // - // } - // - // private static final List MODE_1_RECONCILE_AVAILABILITY_CLASSES = List - // .of(UtilizationClass.OVER225, UtilizationClass.U175TO225, UtilizationClass.U125TO175); - // - // void reconcileComponentsMode1( - // Coefficients baseAreaUtil, Coefficients treesPerHectareUtil, Coefficients quadMeanDiameterUtil, - // float tphSumHigh - // ) { - // // MODE 1 - // - // // the high sum of TPH's is too low. Need MODE 1 reconciliation MUST set DQU's - // // to lowest allowable values AND must move BA from upper classes to lower - // // classes. - // - // float tphNeed = treesPerHectareUtil.getCoe(UTIL_ALL) - tphSumHigh; - // - // UTIL_CLASSES.forEach(uc -> quadMeanDiameterUtil.setCoe(uc.index, uc.lowBound)); - // - // for (var uc : MODE_1_RECONCILE_AVAILABILITY_CLASSES) { - // float tphAvail = treesPerHectare(baseAreaUtil.getCoe(uc.index), uc.previous().get().lowBound) - // - treesPerHectare(baseAreaUtil.getCoe(uc.index), uc.lowBound); - // - // if (tphAvail < tphNeed) { - // baseAreaUtil.scalarInPlace(uc.previous().get().index, x -> x + baseAreaUtil.getCoe(uc.index)); - // baseAreaUtil.setCoe(uc.index, 0f); - // tphNeed -= tphAvail; - // } else { - // float baseAreaMove = baseAreaUtil.getCoe(uc.index) * tphNeed / tphAvail; - // baseAreaUtil.scalarInPlace(uc.previous().get().index, x -> x + baseAreaMove); - // baseAreaUtil.scalarInPlace(uc.index, x -> x - baseAreaMove); - // break; - // } - // } - // UTIL_CLASSES.forEach( - // uc -> treesPerHectareUtil.setCoe( - // uc.index, treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - // ) - // ); - // } - // - // void reconcileComponentsMode2Check( - // Coefficients baseAreaUtil, Coefficients treesPerHectareUtil, Coefficients quadMeanDiameterUtil - // ) throws ProcessingException { - // // Before entering mode 2, check to see if reconciliation is already adequate - // - // float tphSum = (float) UTIL_CLASSES.stream().mapToDouble(uc -> treesPerHectareUtil.getCoe(uc.index)).sum(); - // - // if (abs(tphSum - treesPerHectareUtil.getCoe(UTIL_ALL)) / tphSum > 0.00001) { - // reconcileComponentsMode2(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - // return; - // } - // for (var uc : UTIL_CLASSES) { - // if (baseAreaUtil.getCoe(uc.index) > 0f) { - // if (treesPerHectareUtil.getCoe(uc.index) <= 0f) { - // reconcileComponentsMode2(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - // return; - // } - // float dWant = quadMeanDiameter(baseAreaUtil.getCoe(uc.index), treesPerHectareUtil.getCoe(uc.index)); - // float dqI = quadMeanDiameterUtil.getCoe(uc.index); - // if (dqI >= uc.lowBound && dqI <= uc.highBound && abs(dWant - dqI) < 0.00001) { - // return; - // } - // } - // } - // - // } - // - // private void reconcileComponentsMode2( - // Coefficients baseAreaUtil, Coefficients treesPerHectareUtil, Coefficients quadMeanDiameterUtil - // ) throws ProcessingException { - // int n = 0; - // float baseAreaFixed = 0f; - // float treesPerHectareFixed = 0f; - // var quadMeanDiameterLimit = new boolean[] { false, false, false, false, false }; - // Coefficients dqTrial = utilizationVector(); - // - // while (true) { - // n++; - // - // if (n > 4) { - // throw new ProcessingException("Mode 2 component reconciliation iterations exceeded 4"); - // } - // - // float sum = (float) UTIL_CLASSES.stream().mapToDouble(uc -> { - // float baI = baseAreaUtil.getCoe(uc.index); - // float dqI = quadMeanDiameterUtil.getCoe(uc.index); - // if (baI != 0 && !quadMeanDiameterLimit[uc.index]) { - // return baI / (dqI * dqI); - // } - // return 0; - // }).sum(); - // - // float baAll = baseAreaUtil.getCoe(UTIL_ALL) - baseAreaFixed; - // float tphAll = treesPerHectareUtil.getCoe(UTIL_ALL) - treesPerHectareFixed; - // - // if (baAll <= 0f || tphAll <= 0f) { - // reconcileComponentsMode3(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - // return; - // } - // - // float dqAll = quadMeanDiameter(baAll, tphAll); - // - // float k = dqAll * dqAll / baAll * sum; - // float sqrtK = sqrt(k); - // - // for (var uc : UTIL_CLASSES) { - // if (!quadMeanDiameterLimit[uc.index] && baseAreaUtil.getCoe(uc.index) > 0f) { - // dqTrial.setCoe(uc.index, quadMeanDiameterUtil.getCoe(uc.index) * sqrtK); - // } - // } - // - // UtilizationClass violateClass = null; - // float violate = 0f; - // boolean violateLow = false; - // - // for (var uc : UTIL_CLASSES) { - // if (baseAreaUtil.getCoe(uc.index) > 0f) { - // if (dqTrial.getCoe(uc.index) < uc.lowBound) { - // float vi = 1f - dqTrial.getCoe(uc.index) / uc.lowBound; - // if (vi > violate) { - // violate = vi; - // violateClass = uc; - // violateLow = true; - // } - // } - // } - // if (dqTrial.getCoe(uc.index) > uc.highBound) { - // float vi = dqTrial.getCoe(uc.index) / uc.highBound - 1f; - // if (vi > violate) { - // violate = vi; - // violateClass = uc; - // violateLow = false; - // } - // } - // } - // if (violateClass == null) - // break; - // // Move the worst offending DQ to its limit - // dqTrial.setCoe(violateClass.index, violateLow ? violateClass.lowBound : violateClass.highBound); - // - // quadMeanDiameterLimit[violateClass.index] = true; - // baseAreaFixed += baseAreaUtil.getCoe(violateClass.index); - // treesPerHectareFixed += treesPerHectare( - // baseAreaUtil.getCoe(violateClass.index), dqTrial.getCoe(violateClass.index) - // ); - // } - // - // // Make BA's agree with DQ's and TPH's - // for (var uc : UTIL_CLASSES) { - // quadMeanDiameterUtil.setCoe(uc.index, dqTrial.getCoe(uc.index)); - // treesPerHectareUtil.setCoe( - // uc.index, treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - // ); - // } - // // RE VERIFY That sums are correct - // float baSum = (float) UTIL_CLASSES.stream().mapToDouble(uc -> baseAreaUtil.getCoe(uc.index)).sum(); - // float tphSum = (float) UTIL_CLASSES.stream().mapToDouble(uc -> treesPerHectareUtil.getCoe(uc.index)).sum(); - // if (abs(baSum - baseAreaUtil.getCoe(UTIL_ALL)) / baSum > 0.0002) { - // throw new ProcessingException("Failed to reconcile Base Area"); - // } - // if (abs(tphSum - treesPerHectareUtil.getCoe(UTIL_ALL)) / tphSum > 0.0002) { - // throw new ProcessingException("Failed to reconcile Trees per Hectare"); - // } - // } - // - // void reconcileComponentsMode3( - // Coefficients baseAreaUtil, Coefficients treesPerHectareUtil, Coefficients quadMeanDiameterUtil - // ) { - // - // /* - // * Reconciliation mode 3 NOT IN THE ORIGINAL DESIGN The primary motivation for - // * this mode is an example where all trees were in a signle utilization class - // * and had a DQ of 12.4 cm. BUT the true DQ for the stand was slightly over - // * 12.5. In this case the best solution is to simply reassign all trees to the - // * single most appropriate class. - // * - // * Note, "original design" means something pre-VDYP 7. This was added to the - // * Fortran some time before the port to Java including the comment above. - // */ - // UTIL_CLASSES.forEach(uc -> { - // baseAreaUtil.setCoe(uc.index, 0f); - // treesPerHectareUtil.setCoe(uc.index, 0f); - // quadMeanDiameterUtil.setCoe(uc.index, uc.lowBound + 2.5f); - // }); - // - // var ucToUpdate = UTIL_CLASSES.stream().filter(uc -> quadMeanDiameterUtil.getCoe(UTIL_ALL) < uc.highBound) - // .findFirst().get(); - // - // baseAreaUtil.setCoe(ucToUpdate.index, baseAreaUtil.getCoe(UTIL_ALL)); - // treesPerHectareUtil.setCoe(ucToUpdate.index, treesPerHectareUtil.getCoe(UTIL_ALL)); - // quadMeanDiameterUtil.setCoe(ucToUpdate.index, quadMeanDiameterUtil.getCoe(UTIL_ALL)); - // } - // - // // EMP070 - // void estimateBaseAreaByUtilization( - // BecDefinition bec, Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, VdypSpecies spec - // ) throws ProcessingException { - // final var coeMap = Utils.>expectParsedControl( - // controlMap, UtilComponentBaseAreaParser.CONTROL_KEY, MatrixMap3.class - // ); - // - // float dq = quadMeanDiameterUtil.getCoe(UTIL_ALL); - // var b = utilizationVector(); - // b.setCoe(0, baseAreaUtil.getCoe(UTIL_ALL)); - // for (int i = 1; i < UTIL_LARGEST; i++) { - // var coe = coeMap.get(i, spec.getGenus(), bec.getGrowthBec().getAlias()); - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // - // float logit; - // if (i == 1) { - // logit = a0 + a1 * pow(dq, 0.25f); - // } else { - // logit = a0 + a1 * dq; - // } - // b.setCoe(i, b.getCoe(i - 1) * exponentRatio(logit)); - // if (i == 1 && quadMeanDiameterUtil.getCoe(UTIL_ALL) < 12.5f) { - // float ba12Max = (1f - pow( - // (quadMeanDiameterUtil.getCoe(1) - 7.4f) / (quadMeanDiameterUtil.getCoe(UTIL_ALL) - 7.4f), 2f - // )) * b.getCoe(0); - // b.scalarInPlace(1, x -> min(x, ba12Max)); - // } - // } - // - // baseAreaUtil.setCoe(1, baseAreaUtil.getCoe(UTIL_ALL) - b.getCoe(1)); - // baseAreaUtil.setCoe(2, b.getCoe(1) - b.getCoe(2)); - // baseAreaUtil.setCoe(3, b.getCoe(2) - b.getCoe(3)); - // baseAreaUtil.setCoe(4, b.getCoe(3)); - // } - // - // /** - // * Estimate DQ by utilization class, see ipsjf120.doc - // * - // * @param bec - // * @param quadMeanDiameterUtil - // * @param spec - // * @throws ProcessingException - // */ - // // EMP071 - // void estimateQuadMeanDiameterByUtilization(BecDefinition bec, Coefficients quadMeanDiameterUtil, VdypSpecies spec) - // throws ProcessingException { - // log.atTrace().setMessage("Estimate DQ by utilization class for {} in BEC {}. DQ for all >7.5 is {}") - // .addArgument(spec.getGenus()).addArgument(bec.getName()) - // .addArgument(quadMeanDiameterUtil.getCoe(UTIL_ALL)); - // - // float quadMeanDiameter07 = quadMeanDiameterUtil.getCoe(UTIL_ALL); - // - // for (var uc : UTIL_CLASSES) { - // log.atDebug().setMessage("For util level {}").addArgument(uc.name); - // final var coeMap = Utils.>expectParsedControl( - // controlMap, UtilComponentDQParser.CONTROL_KEY, MatrixMap3.class - // ); - // var coe = coeMap.get(uc.index, spec.getGenus(), bec.getGrowthBec().getAlias()); - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // float a2 = coe.getCoe(3); - // - // log.atDebug().setMessage("a0={}, a1={}, a3={}").addArgument(a0).addArgument(a1).addArgument(a2); - // - // float logit; - // - // switch (uc) { - // case U75TO125: - // if (quadMeanDiameter07 < 7.5001f) { - // quadMeanDiameterUtil.setCoe(UTIL_ALL, 7.5f); - // } else { - // log.atDebug().setMessage("DQ = 7.5 + a0 * (1 - exp(a1 / a0*(DQ07 - 7.5) ))**a2' )"); - // - // logit = a1 / a0 * (quadMeanDiameter07 - 7.5f); - // - // quadMeanDiameterUtil - // .setCoe(uc.index, min(7.5f + a0 * pow(1 - safeExponent(logit), a2), quadMeanDiameter07)); - // } - // break; - // case U125TO175, U175TO225: - // log.atDebug().setMessage( - // "LOGIT = a0 + a1*(SQ07 / 7.5)**a2, DQ = (12.5 or 17.5) + 5 * exp(LOGIT) / (1 + exp(LOGIT))" - // ); - // logit = a0 + a1 * pow(quadMeanDiameter07 / 7.5f, a2); - // - // quadMeanDiameterUtil.setCoe(uc.index, uc.lowBound + 5f * exponentRatio(logit)); - // break; - // case OVER225: - // float a3 = coe.getCoe(4); - // - // log.atDebug().setMessage( - // "Coeff A3 {}, LOGIT = a2 + a1*DQ07**a3, DQ = DQ07 + a0 * (1 - exp(LOGIT) / (1 + exp(LOGIT)) )" - // ); - // - // logit = a2 + a1 * pow(quadMeanDiameter07, a3); - // - // quadMeanDiameterUtil - // .setCoe(uc.index, max(22.5f, quadMeanDiameter07 + a0 * (1f - exponentRatio(logit)))); - // break; - // case ALL, SMALL: - // throw new IllegalStateException( - // "Should not be attempting to process small component or all large components" - // ); - // } - // - // log.atDebug().setMessage("Util DQ for class {} is {}").addArgument(uc.name) - // .addArgument(quadMeanDiameterUtil.getCoe(uc.index)); - // } - // - // log.atTrace().setMessage("Estimated Diameters {}").addArgument( - // () -> UTIL_CLASSES.stream() - // .map(uc -> String.format("%s: %d", uc.name, quadMeanDiameterUtil.getCoe(uc.index))) - // ); - // - // } - // - // static float exponentRatio(float logit) throws ProcessingException { - // float exp = safeExponent(logit); - // return exp / (1f + exp); - // } - // - // static float safeExponent(float logit) throws ProcessingException { - // if (logit > 88f) { - // throw new ProcessingException("logit " + logit + " exceeds 88"); - // } - // return exp(logit); - // } - // - // /** - // * Returns the primary, and secondary if present species records as a one or two - // * element list. - // */ - // // PRIMFIND - // List findPrimarySpecies(Map allSpecies) { - // if (allSpecies.isEmpty()) { - // throw new IllegalArgumentException("Can not find primary species as there are no species"); - // } - // var result = new ArrayList(2); - // - // // Start with a deep copy of the species map so there are no side effects from - // // the manipulation this method does. - // var combined = new HashMap(allSpecies.size()); - // allSpecies.entrySet().stream().forEach(spec -> { - // combined.put(spec.getKey(), new FipSpecies(spec.getValue())); - // }); - // - // for (var combinationGroup : PRIMARY_SPECIES_TO_COMBINE) { - // var groupSpecies = combinationGroup.stream().map(combined::get).filter(Objects::nonNull).toList(); - // if (groupSpecies.size() < 2) { - // continue; - // } - // var groupPrimary = new FipSpecies(groupSpecies.stream().sorted(PERCENT_GENUS_DESCENDING).findFirst().get()); - // var total = (float) groupSpecies.stream().mapToDouble(FipSpecies::getPercentGenus).sum(); - // combinationGroup.forEach(combined::remove); - // groupPrimary.setPercentGenus(total); - // combined.put(groupPrimary.getGenus(), groupPrimary); - // } - // - // assert !combined.isEmpty(); - // - // if (combined.size() == 1) { - // // There's only one - // result.addAll(combined.values()); - // } else { - // var NDEBUG_22 = false; - // if (NDEBUG_22) { - // // TODO - // throw new UnsupportedOperationException(); - // } else { - // combined.values().stream().sorted(PERCENT_GENUS_DESCENDING).limit(2).forEach(result::add); - // } - // } - // - // assert !result.isEmpty(); - // assert result.size() <= 2; - // return result; - // } - // - // - // // GRPBA1FD - // int findBaseAreaGroup(FipSpecies fipSpecies, BecDefinition bec, int itg) { - // var growthBec = bec.getGrowthBec(); - // final var defaultGroupsMap = Utils.>expectParsedControl( - // controlMap, DefaultEquationNumberParser.CONTROL_KEY, MatrixMap2.class - // ); - // final var modifierMap = Utils.>>expectParsedControl( - // controlMap, EquationModifierParser.CONTROL_KEY, MatrixMap2.class - // ); - // var defaultGroup = defaultGroupsMap.get(fipSpecies.getGenus(), growthBec.getAlias()); - // return modifierMap.getM(defaultGroup, itg).orElse(defaultGroup); - // } - // - // private float heightMultiplier(String genus, Region region, float treesPerHectarePrimary) { - // final var coeMap = Utils.>>expectParsedControl( - // controlMap, HLCoefficientParser.CONTROL_KEY_P1, MatrixMap2.class - // ); - // var coe = coeMap.get(genus, region).orElse(Coefficients.empty(HLCoefficientParser.NUM_COEFFICIENTS_P1, 1)) - // .reindex(0); - // return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); - // } - // - // // EMP050 Meth==1 - // /** - // * Return the lorey height of the primary species based on the dominant height - // * of the lead species. - // * - // * @param leadHeight dominant height of the lead species - // * @param genus Primary species - // * @param region Region of the polygon - // * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary - // * species - // * @return - // */ - // float primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - // return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); - // } - // - // // EMP050 Meth==2 - // /** - // * Return the dominant height of the lead species based on the lorey height of - // * the primary species. - // * - // * @param primaryHeight lorey height of the primary species - // * @param genus Primary species - // * @param region Region of the polygon - // * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary - // * species - // * @return - // */ - // float leadHeightFromPrimaryHeight(float primaryHeight, String genus, Region region, float treesPerHectarePrimary) { - // return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(genus, region, treesPerHectarePrimary); - // } - // - // // EMP051 - // /** - // * Return the lorey height of the primary species based on the dominant height - // * of the lead species. - // * - // * @param leadHeight dominant height of the lead species - // * @param genus Primary species - // * @param region Region of the polygon - // * @return - // */ - // private float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { - // final var coeMap = Utils.>>expectParsedControl( - // controlMap, HLCoefficientParser.CONTROL_KEY_P2, MatrixMap2.class - // ); - // var coe = coeMap.get(genus, region).orElse(Coefficients.empty(HLCoefficientParser.NUM_COEFFICIENTS_P2, 1)); - // return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); - // } - // - // /** - // * Accessor methods for utilization vectors, except for Lorey Height, on Layer - // * and Species objects. - // */ - // static final Collection UTILIZATION_VECTOR_ACCESSORS; - // - // /** - // * Accessor methods for utilization vectors, except for Lorey Height and - // * Quadratic Mean Diameter, on Layer and Species objects. These are properties - // * where the values for the layer are the sum of those for its species. - // */ - // static final Collection SUMMABLE_UTILIZATION_VECTOR_ACCESSORS; - // - // /** - // * Accessor methods for utilization vectors, except for Lorey Height,and Volume - // * on Layer and Species objects. - // */ - // static final Collection NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS; - // - // private static final float LOW_CROWN_CLOSURE = 10f; - // - // static { - // try { - // var bean = Introspector.getBeanInfo(VdypUtilizationHolder.class); - // UTILIZATION_VECTOR_ACCESSORS = Arrays.stream(bean.getPropertyDescriptors()) // - // .filter(p -> p.getName().endsWith("ByUtilization")) // - // .filter(p -> !p.getName().startsWith("loreyHeight")) // - // .filter(p -> p.getPropertyType() == Coefficients.class) // - // .toList(); - // } catch (IntrospectionException e) { - // throw new IllegalStateException(e); - // } - // - // SUMMABLE_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() - // .filter(x -> !x.getName().startsWith("quadraticMeanDiameter")).toList(); - // - // NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() - // .filter(x -> !x.getName().contains("Volume")).toList(); - // } - // - // // EMP091 - // /** - // * Updates wholeStemVolumeUtil with estimated values. - // */ - // void estimateWholeStemVolume( - // UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - // Coefficients quadMeanDiameterUtil, Coefficients baseAreaUtil, Coefficients wholeStemVolumeUtil - // ) throws ProcessingException { - // var dqSp = quadMeanDiameterUtil.getCoe(UTIL_ALL); - // final var wholeStemUtilizationComponentMap = Utils - // .>>expectParsedControl( - // controlMap, UtilComponentWSVolumeParser.CONTROL_KEY, MatrixMap2.class - // ); - // estimateUtilization(baseAreaUtil, wholeStemVolumeUtil, utilizationClass, (uc, ba) -> { - // Coefficients wholeStemCoe = wholeStemUtilizationComponentMap.get(uc.index, volumeGroup).orElseThrow( - // () -> new ProcessingException( - // "Could not find whole stem utilization coefficients for group " + volumeGroup - // ) - // ); - // - // // Fortran code uses 1 index into array when reading it here, but 0 index when - // // writing into it in the parser. I use 0 for both. - // var a0 = wholeStemCoe.getCoe(0); - // var a1 = wholeStemCoe.getCoe(1); - // var a2 = wholeStemCoe.getCoe(2); - // 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); - // - // if (uc == utilizationClass) { - // arg += adjustCloseUtil; - // } - // - // var vbaruc = exp(arg); // volume base area ?? utilization class? - // - // return ba * vbaruc; - // }, x -> x < 0f, 0f); - // - // if (utilizationClass == UtilizationClass.ALL) { - // normalizeUtilizationComponents(wholeStemVolumeUtil); - // } - // - // } - // - // // EMP092 - // /** - // * Updates closeUtilizationVolumeUtil with estimated values. - // * - // * @throws ProcessingException - // */ - // void estimateCloseUtilizationVolume( - // UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, float hlSp, - // Coefficients quadMeanDiameterUtil, Coefficients wholeStemVolumeUtil, Coefficients closeUtilizationVolumeUtil - // ) throws ProcessingException { - // var dqSp = quadMeanDiameterUtil.getCoe(UTIL_ALL); - // final var closeUtilizationCoeMap = Utils - // .>>expectParsedControl( - // controlMap, CloseUtilVolumeParser.CONTROL_KEY, MatrixMap2.class - // ); - // estimateUtilization(wholeStemVolumeUtil, closeUtilizationVolumeUtil, utilizationClass, (uc, ws) -> { - // Coefficients closeUtilCoe = closeUtilizationCoeMap.get(uc.index, volumeGroup).orElseThrow( - // () -> new ProcessingException( - // "Could not find whole stem utilization coefficients for group " + volumeGroup - // ) - // ); - // var a0 = closeUtilCoe.getCoe(1); - // var a1 = closeUtilCoe.getCoe(2); - // var a2 = closeUtilCoe.getCoe(3); - // - // var arg = a0 + a1 * quadMeanDiameterUtil.getCoe(uc.index) + a2 * hlSp + aAdjust.getCoe(uc.index); - // - // float ratio = ratio(arg, 7.0f); - // - // return ws * ratio; - // }); - // - // if (utilizationClass == UtilizationClass.ALL) { - // storeSumUtilizationComponents(closeUtilizationVolumeUtil); - // } - // } - // - // @FunctionalInterface - // static interface UtilizationProcessor { - // float apply(UtilizationClass utilizationClass, float inputValue) throws ProcessingException; - // } - // - // /** - // * Estimate values for one utilization vector from another - // * - // * @param input source utilization - // * @param output result utilization - // * @param utilizationClass the utilization class for which to do the - // * computation, UTIL_ALL for all of them. - // * @param processor Given a utilization class, and the source utilization - // * for that class, return the result utilization - // * @throws ProcessingException - // */ - // static void estimateUtilization( - // Coefficients input, Coefficients output, UtilizationClass utilizationClass, UtilizationProcessor processor - // ) throws ProcessingException { - // estimateUtilization(input, output, utilizationClass, processor, x -> false, 0f); - // } - // - // /** - // * Estimate values for one utilization vector from another - // * - // * @param input source utilization - // * @param output result utilization - // * @param utilizationClass the utilization class for which to do the - // * computation, UTIL_ALL for all of them. - // * @param processor Given a utilization class, and the source utilization - // * for that class, return the result utilization - // * @param skip a utilization class will be skipped and the result - // * set to the default value if this is true for the - // * value of the source utilization - // * @param defaultValue the default value - // * @throws ProcessingException - // */ - // static void estimateUtilization( - // Coefficients input, Coefficients output, UtilizationClass utilizationClass, UtilizationProcessor processor, - // Predicate skip, float defaultValue - // ) throws ProcessingException { - // for (var uc : UTIL_CLASSES) { - // var inputValue = input.getCoe(uc.index); - // - // // it seems like this should be done after checking i against utilizationClass, - // // which could just be done as part of the processor definition, but this is how - // // VDYP7 did it. - // if (skip.test(inputValue)) { - // output.setCoe(uc.index, defaultValue); - // continue; - // } - // - // if (utilizationClass != UtilizationClass.ALL && utilizationClass != uc) { - // continue; - // } - // - // var result = processor.apply(uc, input.getCoe(uc.index)); - // output.setCoe(uc.index, result); - // } - // } - // - // /** - // * Estimate volume NET OF DECAY by (DBH) utilization classes - // * - // * @param utilizationClass - // * @param aAdjust - // * @param decayGroup - // * @param lorieHeight - // * @param ageBreastHeight - // * @param quadMeanDiameterUtil - // * @param closeUtilizationUtil - // * @param closeUtilizationNetOfDecayUtil - // * @throws ProcessingException - // */ - // // EMP093 - // void estimateNetDecayVolume( - // String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - // float lorieHeight, float ageBreastHeight, Coefficients quadMeanDiameterUtil, - // Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayUtil - // ) throws ProcessingException { - // var dqSp = quadMeanDiameterUtil.getCoe(UTIL_ALL); - // final var netDecayCoeMap = Utils.>>expectParsedControl( - // controlMap, VolumeNetDecayParser.CONTROL_KEY, MatrixMap2.class - // ); - // final var decayModifierMap = Utils.>expectParsedControl( - // controlMap, ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class - // ); - // - // final var ageTr = (float) Math.log(Math.max(20.0, ageBreastHeight)); - // - // estimateUtilization(closeUtilizationUtil, closeUtilizationNetOfDecayUtil, utilizationClass, (uc, cu) -> { - // Coefficients netDecayCoe = netDecayCoeMap.get(uc.index, decayGroup).orElseThrow( - // () -> new ProcessingException("Could not find net decay coefficients for group " + decayGroup) - // ); - // var a0 = netDecayCoe.getCoe(1); - // var a1 = netDecayCoe.getCoe(2); - // var a2 = netDecayCoe.getCoe(3); - // - // float arg; - // if (uc != UtilizationClass.OVER225) { - // arg = a0 + a1 * log(dqSp) + a2 * ageTr; - // } else { - // arg = a0 + a1 * log(quadMeanDiameterUtil.getCoe(uc.index)) + a2 * ageTr; - // } - // - // arg += aAdjust.getCoe(uc.index) + decayModifierMap.get(genus, region); - // - // float ratio = ratio(arg, 8.0f); - // - // return cu * ratio; - // }); - // - // if (utilizationClass == UtilizationClass.ALL) { - // storeSumUtilizationComponents(closeUtilizationNetOfDecayUtil); - // } - // } - // - // /** - // * Estimate utilization net of decay and waste - // */ - // // EMP094 - // void estimateNetDecayAndWasteVolume( - // Region region, UtilizationClass utilizationClass, Coefficients aAdjust, String genus, float lorieHeight, - // float ageBreastHeight, Coefficients quadMeanDiameterUtil, Coefficients closeUtilizationUtil, - // Coefficients closeUtilizationNetOfDecayUtil, Coefficients closeUtilizationNetOfDecayAndWasteUtil - // ) throws ProcessingException { - // final var netDecayCoeMap = Utils.>expectParsedControl( - // controlMap, VolumeNetDecayWasteParser.CONTROL_KEY, Map.class - // ); - // final var wasteModifierMap = Utils.>expectParsedControl( - // controlMap, ModifierParser.CONTROL_KEY_MOD301_WASTE, MatrixMap2.class - // ); - // - // estimateUtilization( - // closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, - // (i, netDecay) -> { - // if (Float.isNaN(netDecay) || netDecay <= 0f) { - // return 0f; - // } - // - // Coefficients netWasteCoe = netDecayCoeMap.get(genus); - // if (netWasteCoe == null) { - // throw new ProcessingException("Could not find net waste coefficients for genus " + genus); - // } - // - // var a0 = netWasteCoe.getCoe(0); - // var a1 = netWasteCoe.getCoe(1); - // var a2 = netWasteCoe.getCoe(2); - // var a3 = netWasteCoe.getCoe(3); - // var a4 = netWasteCoe.getCoe(4); - // var a5 = netWasteCoe.getCoe(5); - // - // if (i == UtilizationClass.OVER225) { - // a0 += a5; - // } - // var frd = 1.0f - netDecay / closeUtilizationUtil.getCoe(i.index); - // - // float arg = a0 + a1 * frd + a3 * log(quadMeanDiameterUtil.getCoe(i.index)) + a4 * log(lorieHeight); - // - // arg += wasteModifierMap.get(genus, region); - // - // arg = clamp(arg, -10f, 10f); - // - // var frw = (1.0f - exp(a2 * frd)) * exp(arg) / (1f + exp(arg)) * (1f - frd); - // frw = min(frd, frw); - // - // float result = closeUtilizationUtil.getCoe(i.index) * (1f - frd - frw); - // - // /* - // * Check for an apply adjustments. This is done after computing the result above - // * to allow for clamping frw to frd - // */ - // if (aAdjust.getCoe(i.index) != 0f) { - // var ratio = result / netDecay; - // if (ratio < 1f && ratio > 0f) { - // arg = log(ratio / (1f - ratio)); - // arg += aAdjust.getCoe(i.index); - // arg = clamp(arg, -10f, 10f); - // result = exp(arg) / (1f + exp(arg)) * netDecay; - // } - // } - // - // return result; - // } - // ); - // - // if (utilizationClass == UtilizationClass.ALL) { - // storeSumUtilizationComponents(closeUtilizationNetOfDecayAndWasteUtil); - // } - // } - // - // /** - // * Estimate utilization net of decay, waste, and breakage - // * - // * @throws ProcessingException - // */ - // void estimateNetDecayWasteAndBreakageVolume( - // UtilizationClass utilizationClass, int breakageGroup, Coefficients quadMeanDiameterUtil, - // Coefficients closeUtilizationUtil, Coefficients closeUtilizationNetOfDecayAndWasteUtil, - // Coefficients closeUtilizationNetOfDecayWasteAndBreakageUtil - // ) throws ProcessingException { - // final var netBreakageCoeMap = Utils - // .>expectParsedControl(controlMap, BreakageParser.CONTROL_KEY, Map.class); - // final var coefficients = netBreakageCoeMap.get(breakageGroup); - // if (coefficients == null) { - // throw new ProcessingException("Could not find net breakage coefficients for group " + breakageGroup); - // } - // - // final var a1 = coefficients.getCoe(1); - // final var a2 = coefficients.getCoe(2); - // final var a3 = coefficients.getCoe(3); - // final var a4 = coefficients.getCoe(4); - // - // estimateUtilization( - // closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, - // utilizationClass, (uc, netWaste) -> { - // - // if (netWaste <= 0f) { - // return 0f; - // } - // var percentBroken = a1 + a2 * log(quadMeanDiameterUtil.getCoe(uc.index)); - // percentBroken = clamp(percentBroken, a3, a4); - // var broken = min(percentBroken / 100 * closeUtilizationUtil.getCoe(uc.index), netWaste); - // return netWaste - broken; - // } - // ); - // - // if (utilizationClass == UtilizationClass.ALL) { - // storeSumUtilizationComponents(closeUtilizationNetOfDecayWasteAndBreakageUtil); - // } - // - // } - // - // /** - // * Sums the individual utilization components (1-4) - // */ - // float sumUtilizationComponents(Coefficients components) { - // return (float) UTIL_CLASSES.stream().mapToInt(x -> x.index).mapToDouble(components::getCoe).sum(); - // } - // - // /** - // * Sums the individual utilization components (1-4) and stores the results in - // * coefficient UTIL_ALL - // */ - // float storeSumUtilizationComponents(Coefficients components) { - // var sum = sumUtilizationComponents(components); - // components.setCoe(UTIL_ALL, sum); - // return sum; - // } - // - // /** - // * Normalizes the utilization components 1-4 so they sum to the value of - // * component UTIL_ALL - // * - // * @throws ProcessingException if the sum is not positive - // */ - // float normalizeUtilizationComponents(Coefficients components) throws ProcessingException { - // var sum = sumUtilizationComponents(components); - // var k = components.getCoe(UTIL_ALL) / sum; - // if (sum <= 0f) { - // throw new ProcessingException("Total volume " + sum + " was not positive."); - // } - // UTIL_CLASSES.forEach(uc -> { - // components.setCoe(uc.index, components.getCoe(uc.index) * k); - // }); - // return k; - // } - // - // int getGroup(FipPolygon fipPolygon, MatrixMap2 volumeGroupMap, VdypSpecies vSpec) { - // return volumeGroupMap.get(vSpec.getGenus(), fipPolygon.getBiogeoclimaticZone()); - // } - // - // MatrixMap2 getGroupMap(String key) { - // return Utils.expectParsedControl(controlMap, key, MatrixMap2.class); - // } - // - // // FIP_GET - // private FipPolygon getPolygon( - // StreamingParser polyStream, StreamingParser> layerStream, - // StreamingParser> speciesStream - // ) throws ProcessingException, IOException, ResourceParseException { - // - // log.trace("Getting polygon"); - // var polygon = polyStream.next(); - // - // log.trace("Getting layers for polygon {}", polygon.getPolygonIdentifier()); - // Map layers; - // try { - // layers = layerStream.next(); - // } catch (NoSuchElementException ex) { - // throw validationError("Layers file has fewer records than polygon file.", ex); - // } - // - // log.trace("Getting species for polygon {}", polygon.getPolygonIdentifier()); - // Collection species; - // try { - // species = speciesStream.next(); - // } catch (NoSuchElementException ex) { - // throw validationError("Species file has fewer records than polygon file.", ex); - // } - // - // // Validate that layers belong to the correct polygon - // for (FipLayer layer : layers.values()) { - // if (!layer.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { - // throw validationError( - // "Record in layer file contains layer for polygon %s when expecting one for %s.", - // layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() - // ); - // } - // layer.setSpecies(new HashMap<>()); - // } - // - // for (var spec : species) { - // var layer = layers.get(spec.getLayer()); - // // Validate that species belong to the correct polygon - // if (!spec.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { - // throw validationError( - // "Record in species file contains species for polygon %s when expecting one for %s.", - // layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() - // ); - // } - // if (Objects.isNull(layer)) { - // throw validationError( - // "Species entry references layer %s of polygon %s but it is not present.", layer, - // polygon.getPolygonIdentifier() - // ); - // } - // layer.getSpecies().put(spec.getGenus(), spec); - // } - // - // polygon.setLayers(layers); - // - // return polygon; - // } - // - // private Optional heightMinimum(Layer layer) { - // var minima = Utils.>expectParsedControl(controlMap, VDYPForwardControlParser.MINIMA, Map.class); - // switch (layer) { - // case PRIMARY: - // return Optional.of(minima.get(VDYPForwardControlParser.MINIMUM_HEIGHT)); - // case VETERAN: - // return Optional.of(minima.get(VDYPForwardControlParser.MINIMUM_VETERAN_HEIGHT)); - // default: - // return Optional.empty(); - // } - // } - // - // // FIP_CHK - // void checkPolygon(FipPolygon polygon) throws ProcessingException { - // - // // Fortran did debug logging when a polygon is found to be invalid. Attaching - // // messages to exceptions fills that need. - // - // // TODO finding all the things that are wrong rather than failing on just the - // // first would be a good idea. - // - // if (!polygon.getLayers().containsKey(Layer.PRIMARY)) { - // throw validationError( - // "Polygon %s has no %s layer, or that layer has non-positive height or crown closure.", - // polygon.getPolygonIdentifier(), Layer.PRIMARY - // ); - // } - // - // var primaryLayer = (FipLayerPrimary) polygon.getLayers().get(Layer.PRIMARY); - // - // // FIXME VDYP7 actually tests if total age - YTBH is less than 0.5 but gives an - // // error that total age is "less than" YTBH. Replicating that for now but - // // consider changing it. - // - // if (primaryLayer.getAgeTotal() - primaryLayer.getYearsToBreastHeight() < 0.5f) { - // throw validationError( - // "Polygon %s has %s layer where total age is less than YTBH.", polygon.getPolygonIdentifier(), - // Layer.PRIMARY - // ); - // } - // - // // TODO This is the only validation step done to non-primary layers, VDYP7 had a - // // less well defined idea of a layer being present or not and so it may have - // // skipped validating other layers rather than validating them conditionally on - // // being present. Consider extending validation of other properties to other - // // layers. - // - // for (FipLayer layer : polygon.getLayers().values()) { - // var height = layer.getHeight(); - // - // throwIfPresent( - // heightMinimum(layer.getLayer()).filter(minimum -> height < minimum).map( - // minimum -> validationError( - // "Polygon %s has %s layer where height %.1f is less than minimum %.1f.", - // polygon.getPolygonIdentifier(), layer.getLayer(), layer.getHeight(), minimum - // ) - // ) - // ); - // } - // - // if (polygon.getModeFip().map(x -> x == FipMode.FIPYOUNG).orElse(false)) { - // throw validationError( - // "Polygon %s is using unsupported mode %s.", polygon.getPolygonIdentifier(), FipMode.FIPYOUNG - // ); - // } - // - // if (primaryLayer.getYearsToBreastHeight() < 0.5) { - // throw validationError( - // "Polygon %s has %s layer where years to breast height %.1f is less than minimum %.1f years.", - // polygon.getPolygonIdentifier(), Layer.PRIMARY, primaryLayer.getYearsToBreastHeight(), 0.5f - // ); - // } - // - // if (primaryLayer.getSiteIndex() < 0.5) { - // throw validationError( - // "Polygon %s has %s layer where site index %.1f is less than minimum %.1f years.", - // polygon.getPolygonIdentifier(), Layer.PRIMARY, primaryLayer.getSiteIndex(), 0.5f - // ); - // } - // - // for (FipLayer layer : polygon.getLayers().values()) { - // var percentTotal = layer.getSpecies().values().stream()// - // .map(FipSpecies::getPercentGenus)// - // .reduce(0.0f, (x, y) -> x + y); - // if (Math.abs(percentTotal - 100f) > 0.01f) { - // throw validationError( - // "Polygon %s has %s layer where species entries have a percentage total that does not sum to 100%%.", - // polygon.getPolygonIdentifier(), Layer.PRIMARY - // ); - // } - // // VDYP7 performs this step which should be negligible but might have a small - // // impact due to the 0.01 percent variation and floating point errors. - // if (layer.getLayer() == Layer.PRIMARY) { - // layer.getSpecies().values() - // .forEach(species -> species.setFractionGenus(species.getPercentGenus() / percentTotal)); - // } - // } - // - // } - // - // // EMP040 - // float estimatePrimaryBaseArea( - // FipLayer fipLayer, BecDefinition bec, float yieldFactor, float breastHeightAge, float baseAreaOverstory, - // float crownClosure - // ) throws LowValueException { - // boolean lowCrownClosure = fipLayer.getCrownClosure() < LOW_CROWN_CLOSURE; - // crownClosure = lowCrownClosure ? LOW_CROWN_CLOSURE : crownClosure; - // - // var coeMap = Utils.>expectParsedControl( - // controlMap, CoefficientParser.BA_CONTROL_KEY, MatrixMap2.class - // ); - // var modMap = Utils.>expectParsedControl( - // controlMap, ModifierParser.CONTROL_KEY_MOD200_BA, MatrixMap2.class - // ); - // var upperBoundMap = Utils.>expectParsedControl( - // controlMap, UpperCoefficientParser.CONTROL_KEY, MatrixMap3.class - // ); - // - // var leadGenus = leadGenus(fipLayer); - // - // var decayBecAlias = bec.getDecayBec().getAlias(); - // Coefficients coe = weightedCoefficientSum( - // List.of(0, 1, 2, 3, 4, 5), 9, 0, fipLayer.getSpecies().values(), FipSpecies::getFractionGenus, - // s -> coeMap.get(decayBecAlias, s.getGenus()) - // ); - // - // var ageToUse = clamp(breastHeightAge, 5f, 350f); - // var trAge = log(ageToUse); - // - // var a00 = exp(coe.getCoe(0)) * (1f + coe.getCoe(1) * trAge); - // - // var ap = exp(coe.getCoe(3)) + exp(coe.getCoe(4)) * trAge; - // - // var baseArea = 0f; - // - // float height = fipLayer.getHeight(); - // if (height > coe.getCoe(2) - 3f) { - // var fHeight = height <= coe.getCoe(2) + 3f ? // - // pow(height - (coe.getCoe(2) - 3), 2) / 12f // - // : height - coe.getCoe(2); - // - // baseArea = a00 * pow(crownClosure / 100, coe.getCoe(7) + coe.getCoe(8) * log(height)) * pow(fHeight, ap) - // * exp(coe.getCoe(5) * height + coe.getCoe(6) * baseAreaOverstory); - // - // baseArea *= modMap.get(leadGenus.getGenus(), bec.getRegion()); - // - // // TODO - // var NDEBUG_1 = 0; - // if (NDEBUG_1 <= 0) { - // // See ISPSJF128 - // var upperBound = upperBoundMap.get(bec.getRegion(), leadGenus.getGenus(), UpperCoefficientParser.BA); - // baseArea = min(baseArea, upperBound); - // } - // - // if (lowCrownClosure) { - // baseArea *= fipLayer.getCrownClosure() / LOW_CROWN_CLOSURE; - // } - // - // } - // - // baseArea *= yieldFactor; - // - // // This is to prevent underflow errors in later calculations - // if (baseArea <= 0.05f) { - // throw new LowValueException("Estimated base area", baseArea, 0.05f); - // } - // return baseArea; - // } - // - // // EMP040 - // float estimatePrimaryBaseArea( - // FipLayer fipLayer, BecDefinition bec, float yieldFactor, float breastHeightAge, float baseAreaOverstory - // ) throws LowValueException { - // return estimatePrimaryBaseArea( - // fipLayer, bec, yieldFactor, breastHeightAge, baseAreaOverstory, fipLayer.getCrownClosure() - // ); - // } - // - // /** - // * Create a coefficients object where its values are either a weighted sum of - // * those for each of the given entities, or the value from one arbitrarily chose - // * entity. - // * - // * @param The type of entity - // * @param weighted the indicies of the coefficients that should be - // * weighted sums, those that are not included are assumed - // * to be constant across all entities and one is choses - // * arbitrarily. - // * @param size Size of the resulting coefficients object - // * @param indexFrom index from of the resulting coefficients object - // * @param entities the entities to do weighted sums over - // * @param weight the weight for a given entity - // * @param getCoefficients the coefficients for a given entity - // */ - // Coefficients weightedCoefficientSum( - // Collection weighted, int size, int indexFrom, Collection entities, ToDoubleFunction weight, - // Function getCoefficients - // ) { - // Coefficients coe = Coefficients.empty(size, indexFrom); - // - // // Do the summation in double precision - // var coeWorking = new double[size]; - // Arrays.fill(coeWorking, 0.0); - // - // for (var entity : entities) { - // var entityCoe = getCoefficients.apply(entity); - // double fraction = weight.applyAsDouble(entity); - // for (int i : weighted) { - // coeWorking[i - indexFrom] += (entityCoe.getCoe(i)) * fraction; - // } - // } - // // Reduce back to float once done - // for (int i : weighted) { - // coe.setCoe(i, (float) coeWorking[i - indexFrom]); - // } - // - // // Pick one entity to fill in the fixed coefficients - // // Choice is arbitrary, they should all be the same - // var anyCoe = getCoefficients.apply(entities.iterator().next()); - // - // for (int i = indexFrom; i < size + indexFrom; i++) { - // if (weighted.contains(i)) - // continue; - // coe.setCoe(i, anyCoe.getCoe(i)); - // } - // return coe; - // } - // - // FipSpecies leadGenus(FipLayer fipLayer) { - // return fipLayer.getSpecies().values().stream() - // .sorted(Utils.compareUsing(FipSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); - // } - // - // // EMP098 - // float estimateVeteranBaseArea(float height, float crownClosure, String genus, Region region) { - // @SuppressWarnings("unchecked") - // var coefficients = ((MatrixMap2) controlMap.get(VeteranBQParser.CONTROL_KEY)) - // .getM(genus, region); - // - // // mismatched index is copied from VDYP7 - // float a0 = coefficients.getCoe(1); - // float a1 = coefficients.getCoe(2); - // float a2 = coefficients.getCoe(3); - // - // float baseArea = a0 * pow(max(height - a1, 0.0f), a2); - // - // baseArea *= crownClosure / 4.0f; - // - // baseArea = max(baseArea, 0.01f); - // - // return baseArea; - // } - // - // // EMP041 - // float estimatePrimaryQuadMeanDiameter( - // FipLayerPrimary fipLayer, BecDefinition bec, float breastHeightAge, float baseAreaOverstory - // ) { - // var coeMap = Utils.>expectParsedControl( - // controlMap, CoefficientParser.DQ_CONTROL_KEY, MatrixMap2.class - // ); - // var modMap = Utils.>expectParsedControl( - // controlMap, ModifierParser.CONTROL_KEY_MOD200_DQ, MatrixMap2.class - // ); - // var upperBoundMap = Utils.>expectParsedControl( - // controlMap, UpperCoefficientParser.CONTROL_KEY, MatrixMap3.class - // ); - // - // var leadGenus = leadGenus(fipLayer); - // - // var decayBecAlias = bec.getDecayBec().getAlias(); - // Coefficients coe = weightedCoefficientSum( - // List.of(0, 1, 2, 3, 4), 9, 0, fipLayer.getSpecies().values(), FipSpecies::getFractionGenus, - // s -> coeMap.get(decayBecAlias, s.getGenus()) - // ); - // - // var trAge = log(clamp(breastHeightAge, 5f, 350f)); - // var height = fipLayer.getHeight(); - // - // if (height <= coe.getCoe(5)) { - // return 7.6f; - // } - // - // var c0 = coe.get(0); - // var c1 = exp(coe.getCoe(1)) + exp(coe.getCoe(2)) * trAge; - // var c2 = exp(coe.getCoe(3)) + exp(coe.getCoe(4)) * trAge; - // - // - // var quadMeanDiameter = c0 + pow(c1 * pow(height - coe.getCoe(5), c2), 2) - // * exp(coe.getCoe(7) * baseAreaOverstory) * (1f - coe.getCoe(6) * fipLayer.getCrownClosure() / 100f); - // - // quadMeanDiameter *= modMap.get(leadGenus.getGenus(), bec.getRegion()); - // - // quadMeanDiameter = max(quadMeanDiameter, 7.6f); - // - // // TODO - // var NDEBUG_2 = 0; - // if (NDEBUG_2 <= 0) { - // // See ISPSJF129 - // var upperBound = upperBoundMap.get(bec.getRegion(), leadGenus.getGenus(), UpperCoefficientParser.DQ); - // quadMeanDiameter = min(quadMeanDiameter, upperBound); - // } - // - // return quadMeanDiameter; - // } - // - // // FT_BD - // static float treesPerHectare(float baseArea, float quadraticMeanDiameter) { - // if (baseArea != 0) { - // return baseArea / PI_40K / (quadraticMeanDiameter * quadraticMeanDiameter); - // } - // return 0f; - // } - // - // // FD_BT - // static float quadMeanDiameter(float baseArea, float treesPerHectare) { - // if (baseArea > 1e6f || treesPerHectare > 1e6f || Float.isNaN(baseArea) || Float.isNaN(treesPerHectare)) { - // return 0f; - // } else if (baseArea > 0f && treesPerHectare > 0f) { - // return sqrt(baseArea / treesPerHectare / PI_40K); - // } - // return 0f; - // - // } - // - // private static void throwIfPresent(Optional opt) throws E { - // if (opt.isPresent()) { - // throw opt.get(); - // } - // } - // - // private static StandProcessingException validationError(String template, Object... values) { - // return new StandProcessingException(String.format(template, values)); - // } - // - // /** - // * estimate mean volume per tree For a species, for trees with dbh >= 7.5 CM - // * Using eqn in jf117.doc - // * - // * @param volumeGroup - // * @param loreyHeight - // * @param quadMeanDiameter - // * @return - // */ - // public float estimateMeanVolume(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - // var coeMap = Utils.>expectParsedControl( - // controlMap, TotalStandWholeStemParser.CONTROL_KEY, Map.class - // ); - // - // var coe = coeMap.get(volumeGroup); - // - // if (coe == null) { - // throw new IllegalArgumentException("Coefficients not found for volume group " + volumeGroup); - // } - // - // float lvMean = // - // coe.getCoe(0) + // - // coe.getCoe(1) * log(quadMeanDiameter) + // - // coe.getCoe(2) * log(loreyHeight) + // - // coe.getCoe(3) * quadMeanDiameter + // - // coe.getCoe(4) / quadMeanDiameter + // - // coe.getCoe(5) * loreyHeight + // - // coe.getCoe(6) * quadMeanDiameter * quadMeanDiameter + // - // coe.getCoe(7) * quadMeanDiameter * loreyHeight + // - // coe.getCoe(8) * loreyHeight / quadMeanDiameter; - // - // return exp(lvMean); - // } - // - // double[] rootFinderFunction(double[] point, VdypLayer layer, double[] diameterBase) { - // - // var percentL1 = new double[point.length]; - // double percentSum = 0; - // if (point.length > 1) { - // for (int i = 0; i < point.length - 1; i++) { - // percentL1[i] = point[i]; - // percentSum += point[i]; - // } - // } - // percentL1[point.length - 1] = 100d - percentSum; - // - // double volumeSum = 0d; - // double treesPerHectareSum = 0d; - // - // final var layerBa = layer.getBaseAreaByUtilization().getCoe(UTIL_ALL); - // - // // Iterate over the fixed order list with an index - // { - // var it = layer.getSpecies().entrySet().iterator(); - // for (int j = 0; it.hasNext(); j++) { - // var spec = it.next().getValue(); - // - // // These side effects are evil but that's how VDYP7 works. - // - // final float quadMeanDiameter = (float) (7.5 - // + (diameterBase[j] - 7.5) * FastMath.exp(point[point.length - 1] / 20d)); - // spec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_ALL, quadMeanDiameter); - // - // final float baseArea = (float) (layerBa * percentL1[j] / 100d); - // spec.getBaseAreaByUtilization().setCoe(UTIL_ALL, baseArea); - // - // final float tph = VDYPForwardStart.treesPerHectare(baseArea, quadMeanDiameter); - // spec.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, tph); - // treesPerHectareSum += tph; - // - // final float loreyHeight = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - // - // final float meanVolume = estimateMeanVolume(spec.getVolumeGroup(), loreyHeight, quadMeanDiameter); - // final float wholeStemVolume = tph * meanVolume; - // - // spec.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, wholeStemVolume); - // volumeSum += wholeStemVolume; - // } - // } - // - // double dqFinal = VDYPForwardStart - // .quadMeanDiameter(layer.getBaseAreaByUtilization().getCoe(UTIL_ALL), (float) treesPerHectareSum); - // - // var y = new double[point.length]; - // - // if (layer.getSpecies().size() > 1) { - // var it = layer.getSpecies().values().iterator(); - // for (int i = 0; it.hasNext(); i++) { - // var spec = it.next(); - // - // y[i] = 100d * spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL) / volumeSum; - // } - // } - // y[y.length - 1] = dqFinal; - // return y; - // } - // - // // YSMALL - // // TODO move to shared location as it's used elsewhere and implement - // // compatibility variables - // /** - // * Estimate small components for primary layer - // */ - // public void estimateSmallComponents(FipPolygon fPoly, VdypLayer layer) { - // float loreyHeightSum = 0f; - // float baseAreaSum = 0f; - // float treesPerHectareSum = 0f; - // float volumeSum = 0f; - // - // Region region = BecDefinitionParser.getBecs(controlMap).get(fPoly.getBiogeoclimaticZone()).get().getRegion(); - // - // for (VdypSpecies spec : layer.getSpecies().values()) { - // float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); // HLsp - // float baseAreaSpec = spec.getBaseAreaByUtilization().getCoe(UTIL_ALL); // BAsp - // float quadMeanDiameterSpec = spec.getBaseAreaByUtilization().getCoe(UTIL_ALL); // DQsp - // - // // EMP080 - // float smallComponentProbability = smallComponentProbability(layer, spec, region); // PROBsp - // - // // this WHOLE operation on Actual BA's, not 100% occupancy. - // float fractionAvailable = fPoly.getPercentAvailable().map(p -> p / 100f).orElse(1f); - // baseAreaSpec *= fractionAvailable; - // // EMP081 - // float conditionalExpectedBaseArea = conditionalExpectedBaseArea(spec, baseAreaSpec, region); // BACONDsp - // conditionalExpectedBaseArea /= fractionAvailable; - // - // float baseAreaSpecSmall = smallComponentProbability * conditionalExpectedBaseArea; - // - // // EMP082 - // float quadMeanDiameterSpecSmall = smallComponentQuadMeanDiameter(spec); // DQSMsp - // - // // EMP085 - // float loreyHeightSpecSmall = smallComponentLoreyHeight(spec, quadMeanDiameterSpecSmall); // HLSMsp - // - // // EMP086 - // float meanVolumeSmall = meanVolumeSmall(spec, quadMeanDiameterSpecSmall, loreyHeightSpecSmall); // VMEANSMs - // - // // TODO Apply Compatibility Variables, not needed for FIPSTART - // - // spec.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, loreyHeightSpecSmall); - // float treesPerHectareSpecSmall = treesPerHectare(baseAreaSpecSmall, quadMeanDiameterSpecSmall); // TPHSMsp - // spec.getBaseAreaByUtilization().setCoe(UTIL_SMALL, baseAreaSpecSmall); - // spec.getTreesPerHectareByUtilization().setCoe(UTIL_SMALL, treesPerHectareSpecSmall); - // spec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_SMALL, quadMeanDiameterSpecSmall); - // float wholeStemVolumeSpecSmall = treesPerHectareSpecSmall * meanVolumeSmall; // VOLWS(I,-1) - // spec.getWholeStemVolumeByUtilization().setCoe(UTIL_SMALL, wholeStemVolumeSpecSmall); - // - // loreyHeightSum += baseAreaSpecSmall * loreyHeightSpecSmall; - // baseAreaSum += baseAreaSpecSmall; - // treesPerHectareSum += treesPerHectareSpecSmall; - // volumeSum += wholeStemVolumeSpecSmall; - // } - // - // if (baseAreaSum > 0f) { - // layer.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, loreyHeightSum / baseAreaSum); - // } else { - // layer.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, 0f); - // } - // layer.getBaseAreaByUtilization().setCoe(UTIL_SMALL, baseAreaSum); - // layer.getTreesPerHectareByUtilization().setCoe(UTIL_SMALL, treesPerHectareSum); - // layer.getQuadraticMeanDiameterByUtilization() - // .setCoe(UTIL_SMALL, quadMeanDiameter(baseAreaSum, treesPerHectareSum)); - // layer.getWholeStemVolumeByUtilization().setCoe(UTIL_SMALL, volumeSum); - // } - // - // // EMP086 - // private float meanVolumeSmall(VdypSpecies spec, float quadMeanDiameterSpecSmall, float loreyHeightSpecSmall) { - // Coefficients coe = getCoeForSpec(spec, SmallComponentWSVolumeParser.CONTROL_KEY); - // - // // EQN 1 in IPSJF119.doc - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // float a2 = coe.getCoe(3); - // float a3 = coe.getCoe(4); - // - // return exp( - // a0 + a1 * log(quadMeanDiameterSpecSmall) + a2 * log(loreyHeightSpecSmall) - // + a3 * quadMeanDiameterSpecSmall - // ); - // } - // - // // EMP085 - // private float smallComponentLoreyHeight(VdypSpecies spec, float quadMeanDiameterSpecSmall) { - // Coefficients coe = getCoeForSpec(spec, SmallComponentHLParser.CONTROL_KEY); - // - // // EQN 1 in IPSJF119.doc - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // - // return 1.3f + (spec.getLoreyHeightByUtilization().getCoe(VDYPForwardStart.UTIL_ALL) - 1.3f) * exp( - // a0 * (pow(quadMeanDiameterSpecSmall, a1) - // - pow(spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL), a1)) - // ); - // } - // - // // EMP082 - // private float smallComponentQuadMeanDiameter(VdypSpecies spec) { - // Coefficients coe = getCoeForSpec(spec, SmallComponentDQParser.CONTROL_KEY); - // - // // EQN 5 in IPSJF118.doc - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // - // float logit = // - // a0 + a1 * spec.getLoreyHeightByUtilization().getCoe(VDYPForwardStart.UTIL_ALL); - // - // return 4.0f + 3.5f * exp(logit) / (1.0f + exp(logit)); - // } - // - // // EMP081 - // private float conditionalExpectedBaseArea(VdypSpecies spec, float baseAreaSpec, Region region) { - // Coefficients coe = getCoeForSpec(spec, SmallComponentBaseAreaParser.CONTROL_KEY); - // - // // EQN 3 in IPSJF118.doc - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // float a2 = coe.getCoe(3); - // float a3 = coe.getCoe(4); - // - // float coast = region == Region.COASTAL ? 1.0f : 0.0f; - // - // // FIXME due to a bug in VDYP7 it always treats this as interior. Replicating - // // that for now. - // coast = 0f; - // - // float arg = // - // (a0 + // - // a1 * coast + // - // a2 * spec.getBaseAreaByUtilization().getCoe(VDYPForwardStart.UTIL_ALL)// - // ) * exp(a3 * spec.getLoreyHeightByUtilization().getCoe(VDYPForwardStart.UTIL_ALL)); - // arg = max(arg, 0f); - // - // return arg; - // } - // - // // EMP080 - // private float smallComponentProbability(VdypLayer layer, VdypSpecies spec, Region region) { - // Coefficients coe = getCoeForSpec(spec, SmallComponentProbabilityParser.CONTROL_KEY); - // - // // EQN 1 in IPSJF118.doc - // - // float a0 = coe.getCoe(1); - // float a1 = coe.getCoe(2); - // float a2 = coe.getCoe(3); - // float a3 = coe.getCoe(4); - // - // float coast = region == Region.COASTAL ? 1.0f : 0.0f; - // - // float logit = // - // a0 + // - // a1 * coast + // - // a2 * layer.getBreastHeightAge() + // - // a3 * spec.getLoreyHeightByUtilization().getCoe(VDYPForwardStart.UTIL_ALL); - // - // return exp(logit) / (1.0f + exp(logit)); - // } - // - // Coefficients getCoeForSpec(VdypSpecies spec, String controlKey) { - // var coeMap = Utils.>expectParsedControl(controlMap, controlKey, Map.class); - // return coeMap.get(spec.getGenus()); - // } - // - // /** - // * Estimate the Jacobian Matrix of a function using forward difference - // * - // * @param x - // * @param func - // * @return - // */ - // double[][] estimateJacobian(double[] x, MultivariateVectorFunction func) { - // return estimateJacobian(x, func.value(x), func); - // } - // - // /** - // * Estimate the Jacobian Matrix of a function using forward difference - // * - // * @param x - // * @param y - // * @param func - // * @return - // */ - // double[][] estimateJacobian(double[] x, double[] y, MultivariateVectorFunction func) { - // // TODO - // final double machineEpsilon = 2.22e-16; - // final double functionEpsilon = 1.19e-07; - // - // double epsilon = FastMath.sqrt(FastMath.max(functionEpsilon, machineEpsilon)); - // - // double[] x2 = Arrays.copyOf(x, x.length); - // - // double[][] result = new double[x.length][x.length]; - // - // for (int j = 0; j < x.length; j++) { - // double temp = x[j]; - // double h = epsilon * FastMath.abs(temp); - // if (h == 0) { - // h = epsilon; - // } - // x2[j] = temp + h; - // double[] y2 = func.value(x2); - // x2[j] = temp; - // for (int i = 0; i < x.length; i++) { - // result[i][j] = (y2[i] - y[i]) / h; - // } - // } - // return result; - // } - // - // RealMatrix identityMatrix(int n) { - // var diag = new double[n]; - // Arrays.fill(diag, n); - // return new DiagonalMatrix(diag); - // - // } - // - // RealVector findRoot(double[] diameterBase, double[] goal, double[] x, VdypLayer layer, double tolerance) { - // MultivariateVectorFunction func = point -> rootFinderFunction(point, layer, diameterBase); - // - // MultivariateMatrixFunction jacFunc = point -> estimateJacobian(point, func); - // - // LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer(); - // - // optimizer.withCostRelativeTolerance(tolerance); // Not sure if this is the right tolerance - // - // LeastSquaresProblem leastSquaresProblem = LeastSquaresFactory.create( - // func, // - // jacFunc, // - // goal, // - // x, // - // identityMatrix(x.length), // - // null, // - // 200, // - // 1000 // - // ); - // - // var result = optimizer.optimize(leastSquaresProblem); - // - // return result.getPoint(); - // } - // - // /** - // * Iterates over all but the last entry, passing them to the first consumer then - // * passes the last entry to the second consumer - // */ - // void eachButLast(Collection items, Consumer body, Consumer lastBody) { - // var it = items.iterator(); - // while (it.hasNext()) { - // var value = it.next(); - // if (it.hasNext()) { - // body.accept(value); - // } else { - // lastBody.accept(value); - // } - // } - // } - - // @formatter:off - } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java index 81bda67c9..c887263a6 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java @@ -6,10 +6,11 @@ import java.util.Set; import ca.bc.gov.nrs.vdyp.model.BecDefinition; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; public class VdypPolygon extends VdypEntity { - // See IPSJF155.doc + // See IPSJF155.doc, appendix II private final VdypPolygonDescription description; // POLYDESC private final BecDefinition biogeoclimaticZone; // BEC @@ -17,7 +18,7 @@ public class VdypPolygon extends VdypEntity { private final float percentForestLand; // PCTFLAND private final Optional inventoryTypeGroup; // ITG private final Optional basalAreaGroup; // GRPBA1 - private final Optional fipMode; // MODE + private final Optional polygonMode; // MODE // Set after construction private VdypPolygonLayer primaryLayer; @@ -27,7 +28,7 @@ public class VdypPolygon extends VdypEntity { public VdypPolygon( VdypPolygonDescription vdypPolygonDescription, BecDefinition bec, Character fizId, float percentForestLand, - Optional inventoryTypeGroup, Optional basalAreaGroup, Optional fipMode + Optional inventoryTypeGroup, Optional basalAreaGroup, Optional polygonMode ) { this.description = vdypPolygonDescription; this.biogeoclimaticZone = bec; @@ -41,7 +42,7 @@ public VdypPolygon( this.inventoryTypeGroup = inventoryTypeGroup; this.basalAreaGroup = basalAreaGroup; - this.fipMode = fipMode; + this.polygonMode = polygonMode; } @Override @@ -109,8 +110,8 @@ public Optional getBasalAreaGroup() { return basalAreaGroup; } - public Optional getFipMode() { - return fipMode; + public Optional getFipMode() { + return polygonMode; } public VdypPolygonLayer getPrimaryLayer() { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java index 5d5e976ce..a3375af03 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java @@ -8,7 +8,7 @@ public class VdypPolygonLayer extends VdypEntity { - // See IPSJF155.doc + // See IPSJF155.doc, appendix II private final LayerType layerType; // LAYERG diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java index a70261bfc..d10b071b6 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java @@ -11,7 +11,6 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.ForestInventoryZone; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexForestInventoryZone; -import ca.bc.gov.nrs.vdyp.forward.model.FipMode; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; @@ -23,6 +22,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; public class VdypPolygonParser implements ControlMapValueReplacer { @@ -36,7 +36,7 @@ public class VdypPolygonParser implements ControlMapValueReplacer entry) throws ResourceParseExc var percentForestLand = (Float) entry.get(PERCENT_FOREST_LAND); var inventoryTypeGroup = Utils.optSafe(entry.get(INVENTORY_TYPE_GROUP)); var basalAreaGroup = Utils.optSafe(entry.get(BASAL_AREA_GROUP)); - var fipMode = Utils.optSafe(entry.get(FIP_MODE)); + var fipMode = Utils.optSafe(entry.get(POLYGON_MODE)); BecLookup becLookup = (BecLookup) control.get(ControlKey.BEC_DEF.name()); BecDefinition bec = becLookup.get(becAlias) @@ -100,7 +100,7 @@ protected VdypPolygon convert(Map entry) throws ResourceParseExc return new VdypPolygon( description, bec, fizId, percentForestLand, inventoryTypeGroup, basalAreaGroup, - fipMode.flatMap(FipMode::getByCode) + fipMode.flatMap(PolygonMode::getByCode) ); } }; diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index 90780cc6d..ec0fbbc27 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -86,7 +86,7 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces fpe.fps.setPolygon(polygon); PolygonProcessingState pps = fpe.fps.getPolygonProcessingState(); - var speciesToCombine = Arrays.asList(Arrays.asList(pps.wallet.speciesNames[3], pps.wallet.speciesNames[4])); + var speciesToCombine = Arrays.asList(Arrays.asList(pps.getStartBank().speciesNames[3], pps.getStartBank().speciesNames[4])); fpe.calculateCoverages(); fpe.determinePolygonRankings(speciesToCombine); @@ -381,7 +381,7 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getPolygonProcessingState().wallet.siteIndices[4], is((float) expectedValue)); + assertThat(fpe.fps.getPolygonProcessingState().getStartBank().siteIndices[4], is((float) expectedValue)); } @Test @@ -421,7 +421,7 @@ void testEstimateMissingSiteIndicesStep2() throws ProcessingException, IOExcepti double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getPolygonProcessingState().wallet.siteIndices[2], is((float) expectedValue)); + assertThat(fpe.fps.getPolygonProcessingState().getStartBank().siteIndices[2], is((float) expectedValue)); } @Test @@ -448,7 +448,7 @@ void testEstimateMissingYearsToBreastHeightValues() ); assertThat( - fpe.fps.getPolygonProcessingState().wallet.yearsToBreastHeight, + fpe.fps.getPolygonProcessingState().getStartBank().yearsToBreastHeight, is(new float[] { 0.0f, 4.0f, 4.6f, 1.0f, 5.0f, 5.0f }) ); } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index 21859a0e3..edb472b36 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -18,6 +18,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; @@ -168,7 +169,7 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - Bank ppsCopy = new Bank(pps); + Bank ppsCopy = new Bank(pps, CopyMode.CopyAll); verifyProcessingStateMatchesLayer(ppsCopy, pLayer); } From b2890ea162f5ffa217cdeb1580b7f23133897c9b Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 29 Jul 2024 12:54:12 -0700 Subject: [PATCH 24/66] Switch to PolygonIdentifier from VdypPolygonDescription --- .../gov/nrs/vdyp/model/PolygonIdentifier.java | 35 +++++++++---- .../vdyp/forward/ForwardDataStreamReader.java | 6 +-- .../vdyp/forward/model/VdypLayerSpecies.java | 7 +-- .../nrs/vdyp/forward/model/VdypPolygon.java | 15 +++--- .../forward/model/VdypPolygonDescription.java | 45 ----------------- .../forward/model/VdypSpeciesUtilization.java | 7 +-- .../parsers/VdypPolygonDescriptionParser.java | 14 +++--- .../forward/parsers/VdypPolygonParser.java | 3 +- .../forward/parsers/VdypSpeciesParser.java | 3 +- .../parsers/VdypUtilizationParser.java | 3 +- .../AbstractForwardProcessingEngineTest.java | 8 +-- .../nrs/vdyp/forward/GrowBasalAreaTest.java | 8 +-- .../vdyp/forward/GrowDominantHeightTest.java | 8 +-- .../forward/GrowQuadMeanDiameterTest.java | 8 +-- .../forward/VdypForwardPolygonParserTest.java | 49 ++++++++++--------- .../forward/VdypForwardReadPolygonTest.java | 6 +-- .../forward/VdypForwardSpeciesParserTest.java | 9 ++-- .../VdypForwardUtilizationParserTest.java | 9 ++-- 18 files changed, 112 insertions(+), 131 deletions(-) delete mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java index 41b12aa4f..6da96a5dd 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java @@ -4,6 +4,10 @@ import java.util.function.IntUnaryOperator; public class PolygonIdentifier { + + public static final int ID_LENGTH = 25; + public static final int YEAR_LENGTH = 4; + public static final int BASE_LENGTH = ID_LENGTH - YEAR_LENGTH; private final String base; private final int year; @@ -28,16 +32,25 @@ public static PolygonIdentifier split(String polygonIdentifier) throws IllegalAr return new PolygonIdentifier(base, Integer.parseInt(year)); } - public static final int ID_LENGTH = 25; - public static final int YEAR_LENGTH = 4; - public static final int BASE_LENGTH = ID_LENGTH - YEAR_LENGTH; - - public static final String FORMAT = "%-" + BASE_LENGTH + "s%" + YEAR_LENGTH + "d"; + private static final String FORMAT = "%-" + BASE_LENGTH + "s%" + YEAR_LENGTH + "d"; + private static final String COMPACT_FORMAT = "%s(%" + YEAR_LENGTH + "d)"; + /** + * Return the base (a.k.a. name) of the Polygon. These terms are synonomous. + * @return as described + */ public String getBase() { return base; } + /** + * Return the name (a.k.a. base) of the Polygon. These terms are synonomous. + * @return as described + */ + public String getName() { + return base; + } + public int getYear() { return year; } @@ -49,6 +62,10 @@ public String toString() { return result; } + public String toStringCompact() { + return COMPACT_FORMAT.formatted(base, year); + } + @Override public int hashCode() { return Objects.hash(base, year); @@ -58,12 +75,10 @@ public int hashCode() { public boolean equals(Object obj) { if (this == obj) return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) + if (obj instanceof PolygonIdentifier other) + return Objects.equals(base, other.base) && year == other.year; + else return false; - PolygonIdentifier other = (PolygonIdentifier) obj; - return Objects.equals(base, other.base) && year == other.year; } public PolygonIdentifier forYear(int year) { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 2ed73e710..9afff2f46 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -18,13 +18,13 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; public class ForwardDataStreamReader { @@ -34,7 +34,7 @@ public class ForwardDataStreamReader { private final StreamingParser polygonStream; private final StreamingParser> layerSpeciesStream; private final StreamingParser> speciesUtilizationStream; - Optional> polygonDescriptionStream; + Optional> polygonDescriptionStream; @SuppressWarnings("unchecked") public ForwardDataStreamReader(Map controlMap) throws IOException { @@ -51,7 +51,7 @@ public ForwardDataStreamReader(Map controlMap) throws IOExceptio polygonDescriptionStream = Optional.empty(); if (controlMap.containsKey(ControlKey.FORWARD_INPUT_GROWTO.name())) { - var polygonDescriptionStreamFactory = Utils.> + var polygonDescriptionStreamFactory = Utils.> expectParsedControl(controlMap, ControlKey.FORWARD_INPUT_GROWTO, StreamingParserFactory.class); polygonDescriptionStream = Optional.of(polygonDescriptionStreamFactory.get()); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java index 1bef8334a..df47857fa 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java @@ -5,13 +5,14 @@ import ca.bc.gov.nrs.vdyp.model.GenusDistributionSet; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; public class VdypLayerSpecies { // See IPSJF155.doc - private final VdypPolygonDescription polygonId; // POLYDESC + private final PolygonIdentifier polygonId; // POLYDESC private final LayerType layerType; // LAYERG private final int genusIndex; // ISP private final String genus; // SP0 @@ -29,7 +30,7 @@ public class VdypLayerSpecies { Optional> utilizations; public VdypLayerSpecies( - VdypPolygonDescription polygonId, LayerType layerType, int genusIndex, String genus, + PolygonIdentifier polygonId, LayerType layerType, int genusIndex, String genus, GenusDistributionSet speciesDistributions, float siteIndex, float dominantHeight, float ageTotal, float ageAtBreastHeight, float yearsToBreastHeight, Optional isPrimary, Integer siteCurveNumber ) { @@ -80,7 +81,7 @@ public void setUtilizations(Optional targetYear = Optional.empty(); public VdypPolygon( - VdypPolygonDescription vdypPolygonDescription, BecDefinition bec, Character fizId, float percentForestLand, + PolygonIdentifier vdypPolygonDescription, BecDefinition bec, Character fizId, float percentForestLand, Optional inventoryTypeGroup, Optional basalAreaGroup, Optional polygonMode ) { this.description = vdypPolygonDescription; @@ -47,11 +48,7 @@ public VdypPolygon( @Override public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append(description.getName()).append('(').append(description.getYear()).append(')'); - - return sb.toString(); + return description.toString(); } public void setLayers(VdypPolygonLayer primaryLayer, VdypPolygonLayer veteranLayer) { @@ -78,7 +75,7 @@ public void setTargetYear(int targetYear) { this.targetYear = Optional.of(targetYear); } - public VdypPolygonDescription getDescription() { + public PolygonIdentifier getDescription() { return description; } @@ -110,7 +107,7 @@ public Optional getBasalAreaGroup() { return basalAreaGroup; } - public Optional getFipMode() { + public Optional getPolygonMode() { return polygonMode; } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java deleted file mode 100644 index 02ecc1fd9..000000000 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java +++ /dev/null @@ -1,45 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward.model; - -public class VdypPolygonDescription { - - // See IPSJF155.doc - - private final String description; // POLYDESC - private final String name; // description, with year removed, trimmed - private final Integer year; // derived - last four characters of POLYDESC - - public VdypPolygonDescription(String description, String name, Integer year) { - this.description = description.trim(); - this.year = year; - this.name = name.trim(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(name).append('(').append(year).append(')'); - return sb.toString(); - } - - public String getDescription() { - return description; - } - - public Integer getYear() { - return year; - } - - public String getName() { - return name; - } - - @Override - public boolean equals(Object other) { - return other instanceof VdypPolygonDescription that && this.name.equals(that.name); - } - - @Override - public int hashCode() { - return description.hashCode(); - } -} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java index 519957e19..3e1228881 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java @@ -7,13 +7,14 @@ import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; public class VdypSpeciesUtilization extends VdypEntity { // See IPSJF155.doc - private VdypPolygonDescription polygonId; // POLYDESC + private PolygonIdentifier polygonId; // POLYDESC private final LayerType layerType; // LAYERG private final int genusIndex; // ISP private final Optional genus; // SP0 @@ -36,7 +37,7 @@ public class VdypSpeciesUtilization extends VdypEntity { private VdypLayerSpecies parent; public VdypSpeciesUtilization( - VdypPolygonDescription polygonId, LayerType layerType, Integer genusIndex, Optional genus, + PolygonIdentifier polygonId, LayerType layerType, Integer genusIndex, Optional genus, UtilizationClass ucIndex, float basalArea, float liveTreesPerHectare, float loreyHeight, float wholeStemVolume, float closeUtilizationVolume, float cuVolumeMinusDecay, float cuVolumeMinusDecayWastage, float cuVolumeMinusDecayWastageBreakage, float quadraticMeanDiameterAtBH @@ -71,7 +72,7 @@ public void setParent(VdypLayerSpecies parent) { this.parent = parent; } - public VdypPolygonDescription getPolygonId() { + public PolygonIdentifier getPolygonId() { return polygonId; } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java index 375c4bca0..4fa9c991f 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java @@ -6,7 +6,6 @@ import java.util.regex.Pattern; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -14,6 +13,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.AbstractStreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; public class VdypPolygonDescriptionParser implements ControlMapValueReplacer { @@ -26,7 +26,7 @@ public ControlKey getControlKey() { private static Pattern descriptionPattern = Pattern.compile("(.*)([\\d]{4}$)"); - public static VdypPolygonDescription parse(String description) throws ResourceParseException { + public static PolygonIdentifier parse(String description) throws ResourceParseException { Matcher matcher = descriptionPattern.matcher(description); @@ -35,7 +35,7 @@ public static VdypPolygonDescription parse(String description) throws ResourcePa if (matcher.matches() && matcher.group(2) != null) { year = Integer.parseInt(matcher.group(2)); - name = matcher.group(1); + name = matcher.group(1).trim(); } else { throw new ResourceParseException( "Polygon description " + description + " did not end with a four-digit year value." @@ -44,11 +44,11 @@ public static VdypPolygonDescription parse(String description) throws ResourcePa ); } - return new VdypPolygonDescription(description, name, year); + return new PolygonIdentifier(name, year); } @Override - public StreamingParserFactory + public StreamingParserFactory map(String fileName, FileResolver fileResolver, Map control) throws IOException, ResourceParseException { return () -> { @@ -61,10 +61,10 @@ public boolean isStopLine(String line) { var is = fileResolver.resolveForInput(fileName); - return new AbstractStreamingParser(is, lineParser, control) { + return new AbstractStreamingParser(is, lineParser, control) { @Override - protected VdypPolygonDescription convert(Map entry) throws ResourceParseException { + protected PolygonIdentifier convert(Map entry) throws ResourceParseException { return parse((String) entry.get(DESCRIPTION)); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java index d10b071b6..298873898 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java @@ -22,6 +22,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.PolygonMode; public class VdypPolygonParser implements ControlMapValueReplacer { @@ -85,7 +86,7 @@ protected VdypPolygon convert(Map entry) throws ResourceParseExc ); } - var description = VdypPolygonDescriptionParser.parse(descriptionText); + var description = PolygonIdentifier.split(descriptionText); if (percentForestLand <= 0.0) { // VDYPGETP.for lines 146 - 154 diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index a5608cda6..296851c1a 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -30,6 +30,7 @@ import ca.bc.gov.nrs.vdyp.model.GenusDistribution; import ca.bc.gov.nrs.vdyp.model.GenusDistributionSet; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; public class VdypSpeciesParser implements ControlMapValueReplacer { @@ -108,7 +109,7 @@ public ControlKey getControlKey() { protected ValueOrMarker, EndOfRecord> convert(Map entry) throws ResourceParseException { - var polygonId = VdypPolygonDescriptionParser.parse((String) entry.get(DESCRIPTION)); + var polygonId = PolygonIdentifier.split((String) entry.get(DESCRIPTION)); var layerType = (ValueOrMarker, EndOfRecord>) entry.get(LAYER_TYPE); if (layerType == null) { var builder = new ValueOrMarker.Builder, EndOfRecord>(); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java index 228b0c402..931e6ea02 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java @@ -20,6 +20,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.value.ControlledValueParser; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; public class VdypUtilizationParser implements ControlMapValueReplacer { @@ -82,7 +83,7 @@ public ControlKey getControlKey() { protected ValueOrMarker, EndOfRecord> convert(Map entry) throws ResourceParseException { - var polygonId = VdypPolygonDescriptionParser.parse((String) entry.get(DESCRIPTION)); + var polygonId = PolygonIdentifier.split((String) entry.get(DESCRIPTION)); var layerType = (ValueOrMarker, EndOfRecord>) entry.get(LAYER_TYPE); if (layerType == null) { var builder = new ValueOrMarker.Builder, EndOfRecord>(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java index 05a0edc49..a96b079f4 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypSpeciesParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypUtilizationParser; @@ -16,6 +15,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.test.TestUtils; abstract class AbstractForwardProcessingEngineTest { @@ -26,8 +26,8 @@ abstract class AbstractForwardProcessingEngineTest { protected static ForwardControlParser parser; protected static Map controlMap; - protected static StreamingParserFactory polygonDescriptionStreamFactory; - protected static StreamingParser polygonDescriptionStream; + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; protected static ForwardDataStreamReader forwardDataStreamReader; @@ -37,7 +37,7 @@ void beforeTest() throws IOException, ResourceParseException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap .get(ControlKey.FORWARD_INPUT_GROWTO.name()); polygonDescriptionStream = polygonDescriptionStreamFactory.get(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java index 0dc37652e..2e6559bfc 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java @@ -18,11 +18,11 @@ import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; class GrowBasalAreaTest { @@ -31,8 +31,8 @@ class GrowBasalAreaTest { protected static ForwardControlParser parser; protected static Map controlMap; - protected static StreamingParserFactory polygonDescriptionStreamFactory; - protected static StreamingParser polygonDescriptionStream; + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; protected static ForwardDataStreamReader forwardDataStreamReader; @@ -42,7 +42,7 @@ void beforeTest() throws IOException, ResourceParseException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap .get(ControlKey.FORWARD_INPUT_GROWTO.name()); polygonDescriptionStream = polygonDescriptionStreamFactory.get(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java index 62dfbb2ee..6a7458f15 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -28,11 +28,11 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; class GrowDominantHeightTest { @@ -41,8 +41,8 @@ class GrowDominantHeightTest { protected static ForwardControlParser parser; protected static Map controlMap; - protected static StreamingParserFactory polygonDescriptionStreamFactory; - protected static StreamingParser polygonDescriptionStream; + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; protected static ForwardDataStreamReader forwardDataStreamReader; @@ -52,7 +52,7 @@ void beforeTest() throws IOException, ResourceParseException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap .get(ControlKey.FORWARD_INPUT_GROWTO.name()); polygonDescriptionStream = polygonDescriptionStreamFactory.get(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java index 264d7df02..f01e135ef 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java @@ -20,11 +20,11 @@ import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; class GrowQuadMeanDiameterTest { @@ -33,8 +33,8 @@ class GrowQuadMeanDiameterTest { protected static ForwardControlParser parser; protected static Map controlMap; - protected static StreamingParserFactory polygonDescriptionStreamFactory; - protected static StreamingParser polygonDescriptionStream; + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; protected static ForwardDataStreamReader forwardDataStreamReader; @@ -44,7 +44,7 @@ void beforeTest() throws IOException, ResourceParseException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap .get(ControlKey.FORWARD_INPUT_GROWTO.name()); polygonDescriptionStream = polygonDescriptionStreamFactory.get(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java index e5655cdcf..aca3a2e30 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java @@ -20,6 +20,7 @@ import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; import ca.bc.gov.nrs.vdyp.test.TestUtils; import ca.bc.gov.nrs.vdyp.test.VdypMatchers; @@ -77,14 +78,14 @@ void testParsePolygon() throws Exception { var poly = assertNext(stream); - assertThat(poly, hasProperty("description", hasProperty("description", is("01002 S000001 00 1970")))); + assertThat(poly.toString(), is("01002 S000001 00 1970")); assertThat(poly, hasProperty("year", is(1970))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('A'))); assertThat(poly, hasProperty("percentForestLand", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(37)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(1)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); VdypMatchers.assertEmpty(stream); } @@ -115,14 +116,14 @@ void testParsePolygonWithBlanks() throws Exception { var poly = assertNext(stream); - assertThat(poly, hasProperty("description", hasProperty("description", is("01002 S000001 00 1970")))); + assertThat(poly.toString(), is("01002 S000001 00 1970")); assertThat(poly, hasProperty("year", is(1970))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('A'))); assertThat(poly, hasProperty("percentForestLand", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", notPresent())); assertThat(poly, hasProperty("basalAreaGroup", notPresent())); - assertThat(poly, hasProperty("fipMode", notPresent())); + assertThat(poly, hasProperty("polygonMode", notPresent())); VdypMatchers.assertEmpty(stream); } @@ -165,102 +166,104 @@ void testParseMultiple() throws Exception { var poly = assertNext(stream); // 1 - assertThat(poly, hasProperty("description", hasProperty("description", is("01002 S000001 00 1970")))); + assertThat(poly.toString(), is("01002 S000001 00 1970")); assertThat(poly, hasProperty("year", is(1970))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('A'))); assertThat(poly, hasProperty("percentForestLand", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(37)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(1)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 2 - assertThat(poly, hasProperty("description", hasProperty("description", is("01002 S000002 00 1970")))); + assertThat(poly.toString(), is("01002 S000002 00 1970")); assertThat(poly, hasProperty("year", is(1970))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('A'))); assertThat(poly, hasProperty("percentForestLand", is(98.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(15)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(75)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 3 - assertThat(poly, hasProperty("description", hasProperty("description", is("01002 S000003 00 1970")))); + assertThat(poly.toString(), is("01002 S000003 00 1970")); assertThat(poly, hasProperty("year", is(1970))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('A'))); assertThat(poly, hasProperty("percentForestLand", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(15)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(75)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 4 - assertThat(poly, hasProperty("description", hasProperty("description", is("01002 S000004 00 1970")))); + assertThat(poly.toString(), is("01002 S000004 00 1970")); assertThat(poly, hasProperty("year", is(1970))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("MH")))); assertThat(poly, hasProperty("forestInventoryZone", is('A'))); assertThat(poly, hasProperty("percentForestLand", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(15)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(75)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 5 - assertThat(poly, hasProperty("description", hasProperty("description", is("01003AS000001 00 1953")))); + assertThat(poly.toString(), is("01003AS000001 00 1953")); assertThat(poly, hasProperty("year", is(1953))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('B'))); assertThat(poly, hasProperty("percentForestLand", is(91.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPYOUNG)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.YOUNG)))); poly = assertNext(stream); // 6 - assertThat(poly, hasProperty("description", hasProperty("description", is("01003AS000003 00 1953")))); + assertThat(poly.toString(), is("01003AS000003 00 1953")); assertThat(poly, hasProperty("year", is(1953))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("SBS")))); assertThat(poly, hasProperty("forestInventoryZone", is('B'))); assertThat(poly, hasProperty("percentForestLand", is(92.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 7 - assertThat(poly, hasProperty("description", hasProperty("description", is("01004 S000002 00 1953")))); + assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000002 00")))); assertThat(poly, hasProperty("year", is(1953))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); assertThat(poly, hasProperty("forestInventoryZone", is('B'))); assertThat(poly, hasProperty("percentForestLand", is(96.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("fipMode", present(is(FipMode.FIPSTART)))); + assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 8 - assertThat(poly, hasProperty("description", hasProperty("description", is("01004 S000036 00 1957")))); + assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000036 00")))); + assertThat(poly, hasProperty("description", hasProperty("year", is(1957)))); assertThat(poly, hasProperty("year", is(1957))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("MH")))); assertThat(poly, hasProperty("forestInventoryZone", is('B'))); assertThat(poly, hasProperty("percentForestLand", is(97.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("fipMode", notPresent())); + assertThat(poly, hasProperty("polygonMode", notPresent())); poly = assertNext(stream); // 9 - assertThat(poly, hasProperty("description", hasProperty("description", is("01004 S000037 00 1957")))); + assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000037 00")))); + assertThat(poly, hasProperty("description", hasProperty("year", is(1957)))); assertThat(poly, hasProperty("year", is(1957))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("SBS")))); assertThat(poly, hasProperty("forestInventoryZone", is('B'))); assertThat(poly, hasProperty("percentForestLand", is(94.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); assertThat(poly, hasProperty("basalAreaGroup", notPresent())); - assertThat(poly, hasProperty("fipMode", notPresent())); + assertThat(poly, hasProperty("polygonMode", notPresent())); poly = assertNext(stream); // 10 @@ -272,7 +275,7 @@ void testParseMultiple() throws Exception { assertThat(poly, hasProperty("percentForestLand", is(90.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", notPresent())); assertThat(poly, hasProperty("basalAreaGroup", notPresent())); - assertThat(poly, hasProperty("fipMode", notPresent())); + assertThat(poly, hasProperty("polygonMode", notPresent())); VdypMatchers.assertEmpty(stream); } diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index 98df45875..587676fed 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -22,10 +22,10 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.test.TestUtils; @@ -40,7 +40,7 @@ void testReadPolygons() throws Exception { try { var polygonDescriptionStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_GROWTO.name()); - var polygonDescriptionStream = ((StreamingParserFactory) polygonDescriptionStreamFactory) + var polygonDescriptionStream = ((StreamingParserFactory) polygonDescriptionStreamFactory) .get(); ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); @@ -62,7 +62,7 @@ void testReadPolygons() throws Exception { var polygon = polygons.get(0); - assertThat(polygon.getDescription().toString(), is("01002 S000001 00(1970)")); + assertThat(polygon.getDescription().toStringCompact(), is("01002 S000001 00(1970)")); var primaryLayer = polygon.getPrimaryLayer(); { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java index b99ec9618..d7805c952 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java @@ -91,7 +91,8 @@ void testParseOneGenus() throws Exception { genera, hasItem( allOf( - hasProperty("polygonId", hasProperty("description", is("01002 S000001 00 1970"))), + hasProperty("polygonId", hasProperty("name", is("01002 S000001 00"))), + hasProperty("polygonId", hasProperty("year", is(1970))), hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genusIndex", is(15)), hasProperty("genus", is("S")), hasProperty( @@ -318,7 +319,8 @@ void testParseTwoGenera() throws Exception { genera, hasItems( allOf( - hasProperty("polygonId", hasProperty("description", is("01002 S000002 00 1970"))), + hasProperty("polygonId", hasProperty("name", is("01002 S000002 00"))), + hasProperty("polygonId", hasProperty("year", is(1970))), hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genusIndex", is(15)), hasProperty("genus", is("S")), hasProperty( @@ -342,7 +344,8 @@ void testParseTwoGenera() throws Exception { hasProperty("siteCurveNumber", is(VdypEntity.MISSING_INTEGER_VALUE)) ), allOf( - hasProperty("polygonId", hasProperty("description", is("01002 S000002 00 1970"))), + hasProperty("polygonId", hasProperty("name", is("01002 S000002 00"))), + hasProperty("polygonId", hasProperty("year", is(1970))), hasProperty("layerType", is(LayerType.VETERAN)), hasProperty("genusIndex", is(3)), hasProperty("genus", is("B")), hasProperty( diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java index a9df9efdd..2bd249abe 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java @@ -92,7 +92,8 @@ void testParseOneUtilization() throws Exception { utilizations, hasItem( allOf( - hasProperty("polygonId", hasProperty("description", is("01002 S000001 00 1970"))), + hasProperty("polygonId", hasProperty("name", is("01002 S000001 00"))), + hasProperty("polygonId", hasProperty("year", is(1970))), hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is(Optional.empty())), hasProperty("ucIndex", is(UtilizationClass.SMALL)), @@ -148,7 +149,8 @@ void testParseTwoUtilizations() throws Exception { utilizations, hasItems( allOf( - hasProperty("polygonId", hasProperty("description", is("01002 S000001 00 1970"))), + hasProperty("polygonId", hasProperty("name", is("01002 S000001 00"))), + hasProperty("polygonId", hasProperty("year", is(1970))), hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is(Optional.empty())), hasProperty("ucIndex", is(UtilizationClass.SMALL)), @@ -161,7 +163,8 @@ void testParseTwoUtilizations() throws Exception { hasProperty("genusIndex", is(0)), hasProperty("quadraticMeanDiameterAtBH", is(6.1f)) ), allOf( - hasProperty("polygonId", hasProperty("description", is("01002 S000001 00 1970"))), + hasProperty("polygonId", hasProperty("name", is("01002 S000001 00"))), + hasProperty("polygonId", hasProperty("year", is(1970))), hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is(Optional.empty())), hasProperty("ucIndex", is(UtilizationClass.SMALL)), From 23f7a60d5cba753ff3c55dd930697a00c345e550 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 29 Jul 2024 16:53:42 -0700 Subject: [PATCH 25/66] Initial changes in switch to using common VdypPolygon and children --- .../BaseAreaTreeDensityDiameter.java | 42 ++++-- .../ca/bc/gov/nrs/vdyp/model/VdypEntity.java | 6 + .../gov/nrs/vdyp/model/VdypUtilization.java | 27 ++-- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 24 +-- .../vdyp/forward/ForwardDataStreamReader.java | 56 +++---- .../vdyp/forward/ForwardProcessingEngine.java | 83 +++-------- .../vdyp/forward/ForwardProcessingState.java | 6 +- .../vdyp/forward/PolygonProcessingState.java | 8 +- .../nrs/vdyp/forward/model/VdypEntity.java | 6 - .../vdyp/forward/model/VdypLayerSpecies.java | 139 ------------------ .../nrs/vdyp/forward/model/VdypPolygon.java | 121 --------------- .../vdyp/forward/model/VdypPolygonLayer.java | 49 ------ .../parsers/VdypForwardDefaultingParser.java | 2 +- .../forward/parsers/VdypPolygonParser.java | 2 +- .../forward/parsers/VdypSpeciesParser.java | 24 +-- .../parsers/VdypUtilizationParser.java | 22 +-- .../GeneralForwardProcessingEngineTest.java | 2 +- .../nrs/vdyp/forward/GrowBasalAreaTest.java | 2 +- .../vdyp/forward/GrowDominantHeightTest.java | 6 +- .../forward/GrowQuadMeanDiameterTest.java | 2 +- .../forward/PolygonProcessingStateTest.java | 25 ++-- ...yVariablesForwardProcessingEngineTest.java | 2 +- .../forward/VdypForwardPolygonParserTest.java | 3 +- .../forward/VdypForwardReadPolygonTest.java | 12 +- .../forward/VdypForwardSpeciesParserTest.java | 14 +- .../VdypForwardUtilizationParserTest.java | 8 +- 26 files changed, 182 insertions(+), 511 deletions(-) create mode 100644 vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java rename vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java => vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java (90%) delete mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypEntity.java delete mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java delete mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java delete mode 100644 vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java index 6d765acd9..8a0597d9a 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java @@ -15,37 +15,35 @@ private BaseAreaTreeDensityDiameter() { */ public static final float PI_40K = (float) (Math.PI / 40_000); - // FT_BD /** - * Return an estimate of the number of trees per hectare based on a given base area (a) and quadratic mean diameter + * FT_BD - return an estimate of the number of trees per hectare based on a given base area (a) and quadratic mean diameter * (q) according to the formula *

      - * a / π/4/10⁴ / q^2 + * a / PI_40K / q**2 *

      * - * @param baseArea the base area (m^2 / hectare) + * @param baseArea the base area (m**2 / hectare) * @param quadraticMeanDiameter the quadratic mean diameter (cm / tree) - * @return as described. If baseArea or quadraticMeanDiameter is 0 (or less), 0 is returned. + * @return as described. If baseArea or quadraticMeanDiameter is not positive, 0 is returned. */ public static float treesPerHectare(float baseArea, float quadraticMeanDiameter) { - if (baseArea > 0 && quadraticMeanDiameter > 0.0f) { + if (baseArea > 0 && quadraticMeanDiameter > 0f) { return baseArea / PI_40K / (quadraticMeanDiameter * quadraticMeanDiameter); } return 0f; } - // FD_BT /** - * Return an estimate of the quadratic mean diameter based on a given number of trees per hectare (t) and base area + * FD_BT - return an estimate of the quadratic mean diameter based on a given number of trees per hectare (t) and base area * (a) according to the formula *

      - * (b / t / π/10⁴)^1/2 + * (b / t / PI_40K)**1/2 *

      * * @param baseArea the base area value * @param treesPerHectare the trees per hectare value - * @return as described. If baseArea or treesPerHectare is 0 (or less) or more than 1,000,000, 0.0 is returned. + * @return as described. If baseArea or treesPerHectare is Nan, not positive or more than 1,000,000, 0.0 is returned. */ public static float quadMeanDiameter(float baseArea, float treesPerHectare) { if (baseArea > 1e6f || treesPerHectare > 1e6f || Float.isNaN(baseArea) || Float.isNaN(treesPerHectare)) { @@ -56,4 +54,28 @@ public static float quadMeanDiameter(float baseArea, float treesPerHectare) { return 0f; } + + /** + * FB_DT - return an estimate of the basal area based on a given quad-mean-diameter value (q) and a + * trees-per-hectare value according to the formula + *

      + * q**2 * PI_40K * t + *

      + * @param quadraticMeanDiameter the quadratic mean diameter (cm / tree) + * @param treesPerHectare the trees per hectare value + * @return as described. If either parameter is NaN, 0f is returned. + */ + public static float basalArea(float quadraticMeanDiameter, float treesPerHectare) { + + if (Float.isNaN(quadraticMeanDiameter) || Float.isNaN(treesPerHectare)) { + return 0f; + } else { + // qmd is diameter in cm (per tree); qmd**2 is in cm**2. Multiplying by pi/4 converts + // to area in cm**2. Dividing by 10000 converts into m**2. Finally, multiplying + // by trees-per-hectare takes the per-tree area and converts it into a per-hectare + // area - that is, the basal area per hectare. + + return quadraticMeanDiameter * quadraticMeanDiameter * PI_40K * treesPerHectare; + } + } } diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java new file mode 100644 index 000000000..d71c16d6c --- /dev/null +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java @@ -0,0 +1,6 @@ +package ca.bc.gov.nrs.vdyp.model; + +public interface VdypEntity { + Float MISSING_FLOAT_VALUE = Float.NaN; + Integer MISSING_INTEGER_VALUE = Integer.MIN_VALUE; +} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java similarity index 90% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java rename to vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java index 3e1228881..055b243c4 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java @@ -1,16 +1,13 @@ -package ca.bc.gov.nrs.vdyp.forward.model; +package ca.bc.gov.nrs.vdyp.model; import java.text.MessageFormat; import java.util.Optional; import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine; +import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; import ca.bc.gov.nrs.vdyp.math.FloatMath; -import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; -public class VdypSpeciesUtilization extends VdypEntity { +public class VdypUtilization implements VdypEntity { // See IPSJF155.doc @@ -34,9 +31,9 @@ public class VdypSpeciesUtilization extends VdypEntity { private float quadraticMeanDiameterAtBH; // Set after construction - private VdypLayerSpecies parent; + private VdypSpecies parent; - public VdypSpeciesUtilization( + public VdypUtilization( PolygonIdentifier polygonId, LayerType layerType, Integer genusIndex, Optional genus, UtilizationClass ucIndex, float basalArea, float liveTreesPerHectare, float loreyHeight, float wholeStemVolume, float closeUtilizationVolume, float cuVolumeMinusDecay, @@ -68,7 +65,7 @@ public String toString() { return sb.toString(); } - public void setParent(VdypLayerSpecies parent) { + public void setParent(VdypSpecies parent) { this.parent = parent; } @@ -128,7 +125,7 @@ public float getQuadraticMeanDiameterAtBH() { return quadraticMeanDiameterAtBH; } - public VdypLayerSpecies getParent() { + public VdypSpecies getParent() { return parent; } @@ -211,10 +208,10 @@ private void resetOnMissingValues() { private void adjustBasalAreaToMatchTreesPerHectare() throws ProcessingException { if (this.liveTreesPerHectare > 0.0f) { - float basalAreaLowerBound = ForwardProcessingEngine - .calculateBasalArea(CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()] + DQ_EPS, this.liveTreesPerHectare); - float basalAreaUpperBound = ForwardProcessingEngine - .calculateBasalArea(CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - DQ_EPS, this.liveTreesPerHectare); + float basalAreaLowerBound = BaseAreaTreeDensityDiameter + .basalArea(CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()] + DQ_EPS, this.liveTreesPerHectare); + float basalAreaUpperBound = BaseAreaTreeDensityDiameter + .basalArea(CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - DQ_EPS, this.liveTreesPerHectare); float basalAreaError; float newBasalArea; @@ -257,7 +254,7 @@ private void adjustBasalAreaToMatchTreesPerHectare() throws ProcessingException private void doCalculateQuadMeanDiameter() throws ProcessingException { if (this.basalArea > 0.0f) { - float qmd = ForwardProcessingEngine.calculateQuadMeanDiameter(basalArea, liveTreesPerHectare); + float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, liveTreesPerHectare); if (qmd < CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()]) { qmd = qmd + DQ_EPS; diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 825e8c0b2..8204eac48 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -10,19 +10,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDistributionSet; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypLayer; +import ca.bc.gov.nrs.vdyp.model.VdypSpecies; +import ca.bc.gov.nrs.vdyp.model.VdypUtilization; class Bank { @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(Bank.class); - private final VdypPolygonLayer layer; + private final VdypLayer layer; private final BecDefinition becZone; /** @@ -58,16 +58,16 @@ class Bank { 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(VdypPolygonLayer layer, BecDefinition becZone, Predicate retainCriteria) { + public Bank(VdypLayer layer, BecDefinition becZone, Predicate retainCriteria) { this.layer = layer; this.becZone = becZone; this.indices = IntStream.range(1, nSpecies + 1).toArray(); - List speciesToRetain = new ArrayList<>(); + List speciesToRetain = new ArrayList<>(); - for (VdypLayerSpecies s : layer.getGenera().values()) { + for (VdypSpecies s : layer.getSpecies().values()) { if (retainCriteria.test(s)) { speciesToRetain.add(s); } @@ -107,7 +107,7 @@ public Bank(VdypPolygonLayer layer, BecDefinition becZone, Predicate suMap) { + private void recordUtilizations(int index, Map suMap) { for (var su : suMap.entrySet()) { int ucIndex = su.getKey().ordinal(); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 9afff2f46..338cdf707 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -16,24 +16,24 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; 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.VdypSpecies; +import ca.bc.gov.nrs.vdyp.model.VdypUtilization; public class ForwardDataStreamReader { private static final Logger logger = LoggerFactory.getLogger(ForwardDataStreamReader.class); private final StreamingParser polygonStream; - private final StreamingParser> layerSpeciesStream; - private final StreamingParser> speciesUtilizationStream; + private final StreamingParser> layerSpeciesStream; + private final StreamingParser> speciesUtilizationStream; Optional> polygonDescriptionStream; @SuppressWarnings("unchecked") @@ -43,10 +43,10 @@ public ForwardDataStreamReader(Map controlMap) throws IOExceptio polygonStream = ((StreamingParserFactory) polygonStreamFactory).get(); var layerSpeciesStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SPECIES.name()); - layerSpeciesStream = ((StreamingParserFactory>) layerSpeciesStreamFactory).get(); + layerSpeciesStream = ((StreamingParserFactory>) layerSpeciesStreamFactory).get(); var speciesUtilizationStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()); - speciesUtilizationStream = ((StreamingParserFactory>) speciesUtilizationStreamFactory) + speciesUtilizationStream = ((StreamingParserFactory>) speciesUtilizationStreamFactory) .get(); polygonDescriptionStream = Optional.empty(); @@ -73,7 +73,7 @@ public Optional readNextPolygon() throws ProcessingException { logger.debug("Reading polygon {}", polygon); var utilizationCollection = speciesUtilizationStream.next(); - var utilizationsBySpeciesMap = new HashMap>(); + var utilizationsBySpeciesMap = new HashMap>(); for (var utilization : utilizationCollection) { logger.trace("Saw utilization {}", utilization); @@ -87,13 +87,13 @@ public Optional readNextPolygon() throws ProcessingException { if (!pdStream.hasNext()) { throw new ProcessingException(MessageFormat.format("Grow-to-year file at {0} in the control file does" + " not contain a record for {1} as expected, but instead the end-of-file was reached" - , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getDescription().getName())); + , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getPolygonIdentifier().getName())); } var polygonDescription = pdStream.next(); - if (! polygonDescription.getName().equals(polygon.getDescription().getName())) { + if (! polygonDescription.getName().equals(polygon.getPolygonIdentifier().getName())) { throw new ProcessingException(MessageFormat.format("Grow-to-year file at {0} in the control file does" + " not contain a record for {1} as expected, but instead contains a record for {2}" - , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getDescription().getName() + , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getPolygonIdentifier().getName() , polygonDescription.getName())); } @@ -101,8 +101,8 @@ public Optional readNextPolygon() throws ProcessingException { } var speciesCollection = layerSpeciesStream.next(); - var primarySpecies = new HashMap(); - var veteranSpecies = new HashMap(); + var primarySpecies = new HashMap(); + var veteranSpecies = new HashMap(); for (var species : speciesCollection) { logger.trace("Saw species {}", species); @@ -112,7 +112,7 @@ public Optional readNextPolygon() throws ProcessingException { if (speciesUtilizations != null) { species.setUtilizations(Optional.of(speciesUtilizations)); - for (VdypSpeciesUtilization u : speciesUtilizations.values()) { + for (VdypUtilization u : speciesUtilizations.values()) { u.setParent(species); } } else { @@ -127,40 +127,40 @@ public Optional readNextPolygon() throws ProcessingException { throw new IllegalStateException( MessageFormat.format( "Unrecognized layer type {} for species {} of polygon {}", - species.getLayerType(), species.getGenusIndex(), polygon.getDescription() + species.getLayerType(), species.getGenusIndex(), polygon.getPolygonIdentifier() ) ); } } - VdypPolygonLayer primaryLayer = null; + VdypLayer primaryLayer = null; if (primarySpecies.size() > 0) { var key = new UtilizationBySpeciesKey(LayerType.PRIMARY, 0); - Map defaultSpeciesUtilization = utilizationsBySpeciesMap + Map defaultSpeciesUtilization = utilizationsBySpeciesMap .get(key); - primaryLayer = new VdypPolygonLayer( + primaryLayer = new VdypLayer( LayerType.PRIMARY, polygon, primarySpecies, Optional.ofNullable(defaultSpeciesUtilization) ); - for (VdypLayerSpecies v : primarySpecies.values()) { + for (VdypSpecies v : primarySpecies.values()) { v.setParent(primaryLayer); } } - VdypPolygonLayer veteranLayer = null; + VdypLayer veteranLayer = null; if (veteranSpecies.size() > 0) { var key = new UtilizationBySpeciesKey(LayerType.VETERAN, 0); - Map defaultSpeciesUtilization = utilizationsBySpeciesMap + Map defaultSpeciesUtilization = utilizationsBySpeciesMap .get(key); - veteranLayer = new VdypPolygonLayer( + veteranLayer = new VdypLayer( LayerType.VETERAN, polygon, veteranSpecies, Optional.ofNullable(defaultSpeciesUtilization) ); - for (VdypLayerSpecies v : veteranSpecies.values()) { + for (VdypSpecies v : veteranSpecies.values()) { v.setParent(veteranLayer); } } @@ -187,13 +187,13 @@ public Optional readNextPolygon() throws ProcessingException { */ private void adjustUtilizations(VdypPolygon polygon) throws ProcessingException { - float percentForestedLand = polygon.getPercentForestLand(); + float percentForestedLand = polygon.getPercentAvailable(); assert !Float.isNaN(percentForestedLand); float scalingFactor = 100.0f / percentForestedLand; - List utilizationsToAdjust = new ArrayList<>(); + List utilizationsToAdjust = new ArrayList<>(); - for (VdypPolygonLayer l : polygon.getLayers()) { + for (VdypLayer l : polygon.getLayers().values()) { l.getDefaultUtilizationMap().ifPresent(m -> utilizationsToAdjust.addAll(m.values())); @@ -201,7 +201,7 @@ private void adjustUtilizations(VdypPolygon polygon) throws ProcessingException .forEach(s -> s.getUtilizations().ifPresent(m -> utilizationsToAdjust.addAll(m.values()))); } - for (VdypSpeciesUtilization u : utilizationsToAdjust) { + for (VdypUtilization u : utilizationsToAdjust) { if (percentForestedLand > 0.0f && percentForestedLand < 100.0f) { u.scale(scalingFactor); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index e2287af17..c18389f6c 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -27,6 +27,7 @@ import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CommonCalculatorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.CurveErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.NoAnswerException; @@ -37,8 +38,6 @@ import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperBoundsParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; @@ -57,6 +56,8 @@ import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; @@ -141,7 +142,7 @@ public void processPolygon(VdypPolygon polygon) throws ProcessingException { */ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) throws ProcessingException { - logger.info("Starting processing of polygon {}", polygon.getDescription()); + logger.info("Starting processing of polygon {}", polygon.getPolygonIdentifier()); fps.setPolygon(polygon); @@ -164,7 +165,7 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) targetYear = polygon.getTargetYear().get(); } else { if (growTargetControlVariableValue <= 400) { - targetYear = polygon.getDescription().getYear() + growTargetControlVariableValue; + targetYear = polygon.getPolygonIdentifier().getYear() + growTargetControlVariableValue; } else { targetYear = growTargetControlVariableValue; } @@ -224,7 +225,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { int veteranLayerInstance = 0; - int startingYear = fps.getPolygonProcessingState().getPolygon().getDescription().getYear(); + int startingYear = fps.getPolygonProcessingState().getPolygon().getPolygonIdentifier().getYear(); Bank startBank = pps.getStartBank(); int primaryLayerSourceInstance = 2; @@ -275,14 +276,14 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) PolygonProcessingState pps = fps.getPolygonProcessingState(); VdypPolygon polygon = pps.getPolygon(); - logger.info("Performing grow of {} for year {}", polygon.getDescription().getName(), currentYear); + logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); Bank end = new Bank(start, CopyMode.CopyStructure); Optional veteranBank = Optional.ofNullable(fps.getBank(veteranLayerInstance, LayerType.VETERAN)); // If update-during-growth is set, and this is not the starting year, update the context - int startingYear = polygon.getDescription().getYear(); + int startingYear = polygon.getPolygonIdentifier().getYear(); if (currentYear > startingYear && fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { @@ -343,7 +344,7 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) float dhEnd = dhStart + dhDelta; float dqEnd = dqStart + dqDelta; float baEnd = baStart + baDelta; - float tphEnd = calculateTreesPerHectare(baEnd, dqEnd); + float tphEnd = BaseAreaTreeDensityDiameter.treesPerHectare(baEnd, dqEnd); float tphMultiplier = tphEnd / tphStart; // Begin storing computed results - dq, ba and tph for the layer @@ -416,7 +417,7 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) // Calculate quad-mean-diameter over all species, uc UC_ALL_INDEX - end.quadMeanDiameters[0][UC_ALL_INDEX] = calculateQuadMeanDiameter( + end.quadMeanDiameters[0][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter( end.basalAreas[0][UC_ALL_INDEX], end.treesPerHectare[0][UC_ALL_INDEX] ); @@ -429,7 +430,6 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) // and Lorey height. Proceed to per-species estimates. // Calculate basal area percentages per species, uc UC_ALL_INDEX - for (int i : start.getIndices()) { end.percentagesOfForestedLand[i] = 100.0f * end.basalAreas[i][UC_ALL_INDEX] / end.basalAreas[0][UC_ALL_INDEX]; @@ -492,10 +492,10 @@ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphC float spBaEnd = spBaStart * (1.0f + baChangeRate); float spTphStart = start.treesPerHectare[i][UC_ALL_INDEX]; float spTphEnd = spTphStart * tphChangeRate; - float spDqEnd = calculateQuadMeanDiameter(spBaEnd, spTphEnd); + float spDqEnd = BaseAreaTreeDensityDiameter.quadMeanDiameter(spBaEnd, spTphEnd); if (spDqEnd < 7.51f) { spDqEnd = 7.51f; - spTphEnd = calculateTreesPerHectare(spBaEnd, spDqEnd); + spTphEnd = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd, spDqEnd); } end.basalAreas[i][UC_ALL_INDEX] = spBaEnd; @@ -696,7 +696,7 @@ private void growUsingFullSpeciesDynamics( float tph = 0.0f; for (int i : start.speciesIndices) { if (spBaEnd[i] > 0.0f) { - spTphNew[i] = calculateTreesPerHectare(spBaEnd[i], spDqNew[i]); + spTphNew[i] = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd[i], spDqNew[i]); } else { spTphNew[i] = 0.0f; } @@ -707,8 +707,8 @@ private void growUsingFullSpeciesDynamics( break; } - float dqNewBar = calculateQuadMeanDiameter(baStart + baDelta, tph); - float dqStartEstimate = calculateQuadMeanDiameter(baStart, tphStart); + float dqNewBar = BaseAreaTreeDensityDiameter.quadMeanDiameter(baStart + baDelta, tph); + float dqStartEstimate = BaseAreaTreeDensityDiameter.quadMeanDiameter(baStart, tphStart); float dqWant = dqStartEstimate + dqDelta; var score = FloatMath.abs(dqWant - dqNewBar); @@ -738,7 +738,7 @@ private void growUsingFullSpeciesDynamics( end.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; end.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; if (spBaEnd[i] > 0.0f) { - end.quadMeanDiameters[i][UC_ALL_INDEX] = calculateQuadMeanDiameter(spBaEnd[i], spTphNew[i]); + end.quadMeanDiameters[i][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter(spBaEnd[i], spTphNew[i]); } } } @@ -1005,7 +1005,7 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException float smallProbability = smallComponentProbability(speciesName, spLhAll, region); // This whole operation is on Actual BA's, not 100% occupancy. - float fractionAvailable = pps.getPolygon().getPercentForestLand() / 100.0f; + float fractionAvailable = pps.getPolygon().getPercentAvailable() / 100.0f; if (fractionAvailable > 0.0f) { spBaAll *= fractionAvailable; @@ -1052,7 +1052,7 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException } } - float spTphSmall = calculateTreesPerHectare(spBaSmall, spDqSmall); + float spTphSmall = BaseAreaTreeDensityDiameter.treesPerHectare(spBaSmall, spDqSmall); float spWsVolumeSmall = spTphSmall * meanVolumeSmall; end.loreyHeights[speciesIndex][UC_SMALL_INDEX] = spLhSmall; @@ -1077,7 +1077,7 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException } end.basalAreas[0][UC_SMALL_INDEX] = baSum; end.treesPerHectare[0][UC_SMALL_INDEX] = tphSum; - end.quadMeanDiameters[0][UC_SMALL_INDEX] = calculateQuadMeanDiameter(baSum, tphSum); + end.quadMeanDiameters[0][UC_SMALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter(baSum, tphSum); end.wholeStemVolumes[0][UC_SMALL_INDEX] = wsVolumeSum; end.closeUtilizationVolumes[0][UC_SMALL_INDEX] = 0.0f; end.cuVolumesMinusDecay[0][UC_SMALL_INDEX] = 0.0f; @@ -2019,7 +2019,7 @@ void setCompatibilityVariables() throws ProcessingException { treesPerHectare.setCoe(UtilizationClass.ALL.index, start.treesPerHectare[s][UC_ALL_INDEX]); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { treesPerHectare.setCoe( - uc.index, calculateTreesPerHectare( + uc.index, BaseAreaTreeDensityDiameter.treesPerHectare( basalAreas.getCoe(uc.index), quadMeanDiameters.getCoe(uc.index) ) ); @@ -2241,43 +2241,6 @@ private float meanVolumeSmall( ); } - public static float calculateTreesPerHectare(float basalArea, float qmd) { - if (qmd == 0.0f || Float.isNaN(qmd) || Float.isNaN(basalArea)) { - return 0.0f; - } else { - // basalArea is in m**2/hectare. qmd is diameter in cm. pi/4 converts between - // diameter in cm and area in cm**2 since a = pi * r**2 = pi * (d/2)**2 - // = pi/4 * d**2. Finally, dividing by 10000 converts from cm**2 to m**2. - - return basalArea / PI_40K / (qmd * qmd); - } - } - - public static float calculateBasalArea(float qmd, float treesPerHectare) { - - if (Float.isNaN(qmd) || Float.isNaN(treesPerHectare)) { - return 0.0f; - } else { - // qmd is diameter in cm (per tree); qmd**2 is in cm**2. Multiplying by pi/4 converts - // to area in cm**2. Dividing by 10000 converts into m**2. Finally, multiplying - // by trees-per-hectare takes the per-tree area and converts it into a per-hectare - // area - that is, the basal area per hectare. - - return qmd * qmd * PI_40K * treesPerHectare; - } - } - - public static float calculateQuadMeanDiameter(float basalArea, float treesPerHectare) { - - if (basalArea > 1.0e6 || basalArea == 0.0 || Float.isNaN(basalArea) || treesPerHectare > 1.0e6 - || treesPerHectare == 0.0 || Float.isNaN(treesPerHectare)) { - return 0.0f; - } else { - // See comments above explaining this calculation - return FloatMath.sqrt(basalArea / treesPerHectare / PI_40K); - } - } - private static float calculateCompatibilityVariable(float actualVolume, float baseVolume, float staticVolume) { float staticRatio = staticVolume / baseVolume; @@ -2695,12 +2658,12 @@ static void calculateMissingSiteCurves( */ private static void validatePolygon(VdypPolygon polygon) throws ProcessingException { - if (polygon.getDescription().getYear() < 1900) { + if (polygon.getPolygonIdentifier().getYear() < 1900) { throw new ProcessingException( MessageFormat.format( - "Polygon {0}''s year value {1} is < 1900", polygon.getDescription().getName(), polygon - .getDescription().getYear() + "Polygon {0}''s year value {1} is < 1900", polygon.getPolygonIdentifier().getName(), polygon + .getPolygonIdentifier().getYear() ) ); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index ec6df5a8f..7e4d213e0 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -5,9 +5,9 @@ import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; class ForwardProcessingState { @@ -44,13 +44,13 @@ public void setPolygon(VdypPolygon polygon) { // Move the primary layer of the given polygon to bank zero. Bank primaryBank = banks[0][LayerType.PRIMARY.getIndex()] = new Bank( - polygon.getPrimaryLayer(), polygon.getBiogeoclimaticZone(), + polygon.getLayers().get(LayerType.PRIMARY), polygon.getBiogeoclimaticZone(), s -> s.getUtilizations().isPresent() ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA : true ); - polygon.getVeteranLayer().ifPresent(l -> + polygon.getLayers().get(LayerType.VETERAN).ifPresent(l -> banks[0][LayerType.VETERAN.getIndex()] = new Bank( l, polygon.getBiogeoclimaticZone(), s -> s.getUtilizations().isPresent() diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index d261eccae..4c4003cab 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -9,15 +9,15 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; +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.VolumeVariable; class PolygonProcessingState { @@ -168,7 +168,7 @@ public BecDefinition getBecZone() { return start.getBecZone(); } - public VdypPolygonLayer getLayer() { + public VdypLayer getLayer() { return start.getLayer(); } diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypEntity.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypEntity.java deleted file mode 100644 index 80bfec887..000000000 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypEntity.java +++ /dev/null @@ -1,6 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward.model; - -public abstract class VdypEntity { - public static final Float MISSING_FLOAT_VALUE = Float.NaN; - public static final Integer MISSING_INTEGER_VALUE = Integer.MIN_VALUE; -} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java deleted file mode 100644 index df47857fa..000000000 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypLayerSpecies.java +++ /dev/null @@ -1,139 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward.model; - -import java.util.Map; -import java.util.Optional; - -import ca.bc.gov.nrs.vdyp.model.GenusDistributionSet; -import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; - -public class VdypLayerSpecies { - - // See IPSJF155.doc - - private final PolygonIdentifier polygonId; // POLYDESC - private final LayerType layerType; // LAYERG - private final int genusIndex; // ISP - private final String genus; // SP0 - private final GenusDistributionSet speciesDistributions; // SP64DISTL1 - private final float siteIndex; // SI - private final float dominantHeight; // HD - private final float ageTotal; // AGETOT - private final float ageAtBreastHeight; // AGEBH - private final float yearsToBreastHeight; // YTBH - private final Optional isPrimary; // ISITESP - private final Integer siteCurveNumber; // SCN - - // Set after construction - private VdypPolygonLayer parent; - Optional> utilizations; - - public VdypLayerSpecies( - PolygonIdentifier polygonId, LayerType layerType, int genusIndex, String genus, - GenusDistributionSet speciesDistributions, float siteIndex, float dominantHeight, float ageTotal, - float ageAtBreastHeight, float yearsToBreastHeight, Optional isPrimary, Integer siteCurveNumber - ) { - this.polygonId = polygonId; - this.layerType = layerType; - this.genusIndex = genusIndex; - this.genus = genus; - this.speciesDistributions = speciesDistributions; - this.siteIndex = siteIndex; - this.dominantHeight = dominantHeight; - - // From VDYPGETS.FOR, lines 235 onwards - if (Float.isNaN(ageAtBreastHeight)) { - if (ageTotal > 0.0 && yearsToBreastHeight > 0.0) { - ageAtBreastHeight = ageTotal - yearsToBreastHeight; - if (ageAtBreastHeight < 0.0) - ageAtBreastHeight = Float.NaN; - } - } else if (Float.isNaN(ageTotal)) { - if (ageAtBreastHeight > 0.0 && yearsToBreastHeight > 0.0) - ageTotal = ageAtBreastHeight + yearsToBreastHeight; - } else if (Float.isNaN(yearsToBreastHeight) && ageAtBreastHeight > 0.0 && ageTotal > ageAtBreastHeight) { - yearsToBreastHeight = ageTotal - ageAtBreastHeight; - } - - this.ageTotal = ageTotal; - this.ageAtBreastHeight = ageAtBreastHeight; - this.yearsToBreastHeight = yearsToBreastHeight; - - this.isPrimary = isPrimary; - this.siteCurveNumber = siteCurveNumber; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append(polygonId).append(' ').append(layerType).append(' ').append(genusIndex); - - return sb.toString(); - } - - public void setParent(VdypPolygonLayer parent) { - this.parent = parent; - } - - public void setUtilizations(Optional> utilizations) { - this.utilizations = utilizations; - } - - public PolygonIdentifier getPolygonId() { - return polygonId; - } - - public LayerType getLayerType() { - return layerType; - } - - public Integer getGenusIndex() { - return genusIndex; - } - - public String getGenus() { - return genus; - } - - public GenusDistributionSet getSpeciesDistributions() { - return speciesDistributions; - } - - public float getSiteIndex() { - return siteIndex; - } - - public float getDominantHeight() { - return dominantHeight; - } - - public float getAgeTotal() { - return ageTotal; - } - - public float getAgeAtBreastHeight() { - return ageAtBreastHeight; - } - - public float getYearsToBreastHeight() { - return yearsToBreastHeight; - } - - public Optional getIsPrimary() { - return isPrimary; - } - - public Integer getSiteCurveNumber() { - return siteCurveNumber; - } - - public VdypPolygonLayer getParent() { - return parent; - } - - public Optional> getUtilizations() { - return utilizations; - } -} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java deleted file mode 100644 index f671e3a31..000000000 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygon.java +++ /dev/null @@ -1,121 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward.model; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; -import ca.bc.gov.nrs.vdyp.model.PolygonMode; - -public class VdypPolygon extends VdypEntity { - - // See IPSJF155.doc, appendix II - - private final PolygonIdentifier description; // POLYDESC - private final BecDefinition biogeoclimaticZone; // BEC - private final Character forestInventoryZone; // FIZ - private final float percentForestLand; // PCTFLAND - private final Optional inventoryTypeGroup; // ITG - private final Optional basalAreaGroup; // GRPBA1 - private final Optional polygonMode; // MODE - - // Set after construction - private VdypPolygonLayer primaryLayer; - private Optional veteranLayer = Optional.empty(); - private Set layers = new HashSet<>(); - private Optional targetYear = Optional.empty(); - - public VdypPolygon( - PolygonIdentifier vdypPolygonDescription, BecDefinition bec, Character fizId, float percentForestLand, - Optional inventoryTypeGroup, Optional basalAreaGroup, Optional polygonMode - ) { - this.description = vdypPolygonDescription; - this.biogeoclimaticZone = bec; - this.forestInventoryZone = fizId; - - // VDYPGETP lines 146-154 - if (percentForestLand <= 0.0) - this.percentForestLand = 90.0f; - else - this.percentForestLand = percentForestLand; - - this.inventoryTypeGroup = inventoryTypeGroup; - this.basalAreaGroup = basalAreaGroup; - this.polygonMode = polygonMode; - } - - @Override - public String toString() { - return description.toString(); - } - - public void setLayers(VdypPolygonLayer primaryLayer, VdypPolygonLayer veteranLayer) { - if (primaryLayer != null) { - this.primaryLayer = primaryLayer; - this.layers.add(primaryLayer); - } - - if (veteranLayer != null) { - this.veteranLayer = Optional.of(veteranLayer); - this.layers.add(veteranLayer); - } - } - - public Set getLayers() { - return Collections.unmodifiableSet(layers); - } - - public Optional getTargetYear() { - return targetYear; - } - - public void setTargetYear(int targetYear) { - this.targetYear = Optional.of(targetYear); - } - - public PolygonIdentifier getDescription() { - return description; - } - - public String getName() { - return description.getName(); - } - - public Integer getYear() { - return description.getYear(); - } - - public BecDefinition getBiogeoclimaticZone() { - return biogeoclimaticZone; - } - - public Character getForestInventoryZone() { - return forestInventoryZone; - } - - public float getPercentForestLand() { - return percentForestLand; - } - - public Optional getInventoryTypeGroup() { - return inventoryTypeGroup; - } - - public Optional getBasalAreaGroup() { - return basalAreaGroup; - } - - public Optional getPolygonMode() { - return polygonMode; - } - - public VdypPolygonLayer getPrimaryLayer() { - return primaryLayer; - } - - public Optional getVeteranLayer() { - return veteranLayer; - } -} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java deleted file mode 100644 index a3375af03..000000000 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonLayer.java +++ /dev/null @@ -1,49 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward.model; - -import java.util.Map; -import java.util.Optional; - -import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; - -public class VdypPolygonLayer extends VdypEntity { - - // See IPSJF155.doc, appendix II - - private final LayerType layerType; // LAYERG - - private final VdypPolygon parent; - private final Map genera; - private final Optional> defaultUtilizationMap; - - public VdypPolygonLayer( - LayerType layerType, VdypPolygon parent, Map genera, - Optional> defaultUtilizationMap - ) { - this.layerType = layerType; - this.parent = parent; - this.genera = genera; - this.defaultUtilizationMap = defaultUtilizationMap; - } - - public LayerType getLayerType() { - return layerType; - } - - public VdypPolygon getParent() { - return parent; - } - - public Map getGenera() { - return genera; - } - - public Optional> getDefaultUtilizationMap() { - return defaultUtilizationMap; - } - - @Override - public String toString() { - return layerType.toString(); - } -} diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java index 2598c239a..3742d5417 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java @@ -4,8 +4,8 @@ import org.apache.commons.lang3.StringUtils; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; public interface VdypForwardDefaultingParser extends ValueParser { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java index 298873898..c7012d0db 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java @@ -11,7 +11,6 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.ForestInventoryZone; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexForestInventoryZone; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -24,6 +23,7 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.PolygonMode; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; public class VdypPolygonParser implements ControlMapValueReplacer { diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 296851c1a..ee8dc00a9 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -13,8 +13,6 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.io.EndOfRecord; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.InvalidGenusDistributionSet; @@ -31,6 +29,8 @@ import ca.bc.gov.nrs.vdyp.model.GenusDistributionSet; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; +import ca.bc.gov.nrs.vdyp.model.VdypSpecies; public class VdypSpeciesParser implements ControlMapValueReplacer { @@ -62,7 +62,7 @@ public ControlKey getControlKey() { } @Override - public StreamingParserFactory> + public StreamingParserFactory> map(String fileName, FileResolver fileResolver, Map control) throws IOException, ResourceParseException { return () -> { @@ -101,12 +101,12 @@ public ControlKey getControlKey() { (List) control.get(ControlKey.SP0_DEF.name()) ); - var delegateStream = new AbstractStreamingParser, EndOfRecord>>( + var delegateStream = new AbstractStreamingParser, EndOfRecord>>( is, lineParser, control ) { @SuppressWarnings("unchecked") @Override - protected ValueOrMarker, EndOfRecord> convert(Map entry) + protected ValueOrMarker, EndOfRecord> convert(Map entry) throws ResourceParseException { var polygonId = PolygonIdentifier.split((String) entry.get(DESCRIPTION)); @@ -179,12 +179,12 @@ protected ValueOrMarker, EndOfRecord> convert(Map, EndOfRecord>(); + var builder = new ValueOrMarker.Builder, EndOfRecord>(); return layerType.handle(l -> builder.value(l.map(lt -> { var genus = optionalGenus.orElse(genusDefinitionMap.getByIndex(genusIndex).getAlias()); - return new VdypLayerSpecies( + return new VdypSpecies( polygonId, lt, genusIndex, genus, speciesDistributionSet, siteIndex, dominantHeight, totalAge, ageAtBreastHeight, yearsToBreastHeight, isPrimarySpecies, siteCurveNumber ); @@ -192,22 +192,22 @@ protected ValueOrMarker, EndOfRecord> convert(Map, ValueOrMarker, EndOfRecord>>( + return new GroupingStreamingParser, ValueOrMarker, EndOfRecord>>( delegateStream ) { @Override - protected boolean skip(ValueOrMarker, EndOfRecord> nextChild) { + protected boolean skip(ValueOrMarker, EndOfRecord> nextChild) { return nextChild.getValue().map(Optional::isEmpty).orElse(false); } @Override - protected boolean stop(ValueOrMarker, EndOfRecord> nextChild) { + protected boolean stop(ValueOrMarker, EndOfRecord> nextChild) { return nextChild.isMarker(); } @Override - protected Collection - convert(List, EndOfRecord>> children) { + protected Collection + convert(List, EndOfRecord>> children) { // Skip if empty (and unknown layer type) return children.stream().map(ValueOrMarker::getValue).map(Optional::get).flatMap(Optional::stream) .toList(); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java index 931e6ea02..8ec76395e 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java @@ -8,7 +8,6 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.io.EndOfRecord; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; @@ -22,6 +21,7 @@ import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypUtilization; public class VdypUtilizationParser implements ControlMapValueReplacer { @@ -46,7 +46,7 @@ public ControlKey getControlKey() { } @Override - public StreamingParserFactory> + public StreamingParserFactory> map(String fileName, FileResolver fileResolver, Map control) throws IOException, ResourceParseException { return () -> { @@ -75,12 +75,12 @@ public ControlKey getControlKey() { var is = fileResolver.resolveForInput(fileName); - var delegateStream = new AbstractStreamingParser, EndOfRecord>>( + var delegateStream = new AbstractStreamingParser, EndOfRecord>>( is, lineParser, control ) { @SuppressWarnings("unchecked") @Override - protected ValueOrMarker, EndOfRecord> + protected ValueOrMarker, EndOfRecord> convert(Map entry) throws ResourceParseException { var polygonId = PolygonIdentifier.split((String) entry.get(DESCRIPTION)); @@ -102,10 +102,10 @@ public ControlKey getControlKey() { var cuVolumeLessDecayWastageBreakage = (Float) (entry.get(CU_VOLUME_LESS_DECAY_WASTAGE_BREAKAGE)); var quadraticMeanDBH = (Float) (entry.get(QUADRATIC_MEAN_DIAMETER_BREAST_HEIGHT)); - var builder = new ValueOrMarker.Builder, EndOfRecord>(); + var builder = new ValueOrMarker.Builder, EndOfRecord>(); return layerType.handle(l -> { return builder.value(l.map(lt -> { - return new VdypSpeciesUtilization( + return new VdypUtilization( polygonId, lt, genusIndex, genus, utilizationClass, basalArea, liveTreesPerHectare, loreyHeight, wholeStemVolume, closeUtilVolume, cuVolumeLessDecay, cuVolumeLessDecayWastage, cuVolumeLessDecayWastageBreakage, quadraticMeanDBH @@ -115,23 +115,23 @@ public ControlKey getControlKey() { } }; - return new GroupingStreamingParser, ValueOrMarker, EndOfRecord>>( + return new GroupingStreamingParser, ValueOrMarker, EndOfRecord>>( delegateStream ) { @Override - protected boolean skip(ValueOrMarker, EndOfRecord> nextChild) { + protected boolean skip(ValueOrMarker, EndOfRecord> nextChild) { return nextChild.getValue().map(Optional::isEmpty).orElse(false); } @Override - protected boolean stop(ValueOrMarker, EndOfRecord> nextChild) { + protected boolean stop(ValueOrMarker, EndOfRecord> nextChild) { return nextChild.isMarker(); } @Override - protected Collection - convert(List, EndOfRecord>> children) { + protected Collection + convert(List, EndOfRecord>> children) { // Skip if empty (and unknown layer type) return children.stream().map(ValueOrMarker::getValue).map(Optional::get).flatMap(Optional::stream) .toList(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index ec0fbbc27..73d235ba8 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -25,11 +25,11 @@ import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.NoAnswerException; import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.SpeciesErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.CommonData; import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; import ca.bc.gov.nrs.vdyp.model.Region; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; class GeneralForwardProcessingEngineTest extends AbstractForwardProcessingEngineTest { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java index 2e6559bfc..119480746 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java @@ -17,12 +17,12 @@ import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; class GrowBasalAreaTest { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java index 6a7458f15..63ae4e771 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -27,12 +27,12 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; class GrowDominantHeightTest { @@ -86,7 +86,7 @@ void testCurveExtension1() throws ProcessingException { VdypPolygon polygon; do { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - } while (! polygon.getDescription().getName().equals("01003AS000001 00")); + } while (! polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); fpe.fps.setPolygon(polygon); @@ -109,7 +109,7 @@ void testCurveExtension2() throws ProcessingException { VdypPolygon polygon; do { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - } while (! polygon.getDescription().getName().equals("01003AS000001 00")); + } while (! polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); fpe.fps.setPolygon(polygon); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java index f01e135ef..f9f4cc5a2 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java @@ -19,12 +19,12 @@ import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; class GrowQuadMeanDiameterTest { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index edb472b36..51e502797 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -19,13 +19,14 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypLayer; +import ca.bc.gov.nrs.vdyp.model.VdypSpecies; +import ca.bc.gov.nrs.vdyp.model.VdypUtilization; class PolygonProcessingStateTest { @@ -53,7 +54,7 @@ void testConstruction() throws IOException, ResourceParseException, ProcessingEx var polygon = reader.readNextPolygon().orElseThrow(); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); @@ -114,7 +115,7 @@ void testSetCopy() throws IOException, ResourceParseException, ProcessingExcepti var polygon = reader.readNextPolygon().orElseThrow(); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); @@ -133,7 +134,7 @@ void testRemoveSmallLayers() throws IOException, ResourceParseException, Process var polygon = reader.readNextPolygon().orElseThrow(); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank bank1 = new Bank( @@ -164,7 +165,7 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin var polygon = reader.readNextPolygon().orElseThrow(); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); @@ -174,7 +175,7 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin verifyProcessingStateMatchesLayer(ppsCopy, pLayer); } - private void verifyProcessingStateMatchesLayer(Bank pps, VdypPolygonLayer layer) { + private void verifyProcessingStateMatchesLayer(Bank pps, VdypLayer layer) { List sortedSpIndices = layer.getGenera().keySet().stream().sorted().toList(); @@ -182,7 +183,7 @@ private void verifyProcessingStateMatchesLayer(Bank pps, VdypPolygonLayer layer) int arrayIndex = i + 1; - VdypLayerSpecies genus = layer.getGenera().get(sortedSpIndices.get(i)); + VdypSpecies genus = layer.getGenera().get(sortedSpIndices.get(i)); verifyProcessingStateSpeciesMatchesSpecies(pps, arrayIndex, genus); if (genus.getUtilizations().isPresent()) { @@ -198,11 +199,11 @@ private void verifyProcessingStateMatchesLayer(Bank pps, VdypPolygonLayer layer) } private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - Bank pps, int spIndex, Map map + Bank pps, int spIndex, Map map ) { for (UtilizationClass uc : UtilizationClass.values()) { - VdypSpeciesUtilization u = map.get(uc); + VdypUtilization u = map.get(uc); assertThat(pps.basalAreas[spIndex][uc.index + 1], is(u.getBasalArea())); assertThat(pps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolume())); @@ -217,7 +218,7 @@ private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( } } - private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, VdypLayerSpecies species) { + private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, VdypSpecies species) { assertThat(pps.yearsAtBreastHeight[index], is(species.getAgeAtBreastHeight())); assertThat(pps.ageTotals[index], is(species.getAgeTotal())); assertThat(pps.dominantHeights[index], is(species.getDominantHeight())); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java index a1b3efa8d..75b11ae95 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java @@ -21,9 +21,9 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; class SetCompatibilityVariablesForwardProcessingEngineTest extends AbstractForwardProcessingEngineTest { diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java index aca3a2e30..a03bbabea 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java @@ -15,12 +15,11 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.FipMode; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.PolygonMode; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.test.TestUtils; import ca.bc.gov.nrs.vdyp.test.VdypMatchers; diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index 587676fed..81525f463 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -21,12 +21,12 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.test.TestUtils; @SuppressWarnings({ "unchecked" }) @@ -62,9 +62,9 @@ void testReadPolygons() throws Exception { var polygon = polygons.get(0); - assertThat(polygon.getDescription().toStringCompact(), is("01002 S000001 00(1970)")); + assertThat(polygon.getPolygonIdentifier().toStringCompact(), is("01002 S000001 00(1970)")); - var primaryLayer = polygon.getPrimaryLayer(); + var primaryLayer = polygon.getLayers().get(LayerType.PRIMARY); { assertThat(primaryLayer, hasProperty("layerType", is(LayerType.PRIMARY))); assertThat(primaryLayer, hasProperty("defaultUtilizationMap")); @@ -98,10 +98,8 @@ void testReadPolygons() throws Exception { } } - var optionalVeteranLayer = polygon.getVeteranLayer(); - if (optionalVeteranLayer.isPresent()) { - - var veteranLayer = optionalVeteranLayer.get(); + var veteranLayer = polygon.getLayers().get(LayerType.VETERAN); + if (veteranLayer != null) { if (veteranLayer.getDefaultUtilizationMap().isPresent()) { var utilizationMap = veteranLayer.getDefaultUtilizationMap().get(); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java index d7805c952..f386a4e5b 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java @@ -20,12 +20,12 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypSpeciesParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; +import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.test.TestUtils; class VdypForwardSpeciesParserTest { @@ -49,7 +49,7 @@ void testParseEmpty() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory) parserFactory).get(); + var stream = ((StreamingParserFactory) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); @@ -81,7 +81,7 @@ void testParseOneGenus() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory>) parserFactory).get(); + var stream = ((StreamingParserFactory>) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); @@ -150,7 +150,7 @@ void testParseTwoPairsOfGenera() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory>) parserFactory).get(); + var stream = ((StreamingParserFactory>) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); @@ -190,7 +190,7 @@ void testParseComputesAgesWhenMissing() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory>) parserFactory).get(); + var stream = ((StreamingParserFactory>) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); @@ -309,7 +309,7 @@ void testParseTwoGenera() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory>) parserFactory).get(); + var stream = ((StreamingParserFactory>) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java index 2bd249abe..1a85c3002 100644 --- a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java +++ b/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java @@ -19,12 +19,12 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypUtilizationParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypUtilization; import ca.bc.gov.nrs.vdyp.test.TestUtils; public class VdypForwardUtilizationParserTest { @@ -48,7 +48,7 @@ void testParseEmpty() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory) parserFactory).get(); + var stream = ((StreamingParserFactory) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); @@ -80,7 +80,7 @@ void testParseOneUtilization() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory>) parserFactory).get(); + var stream = ((StreamingParserFactory>) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); @@ -137,7 +137,7 @@ void testParseTwoUtilizations() throws Exception { assertThat(parserFactory, instanceOf(StreamingParserFactory.class)); @SuppressWarnings("unchecked") - var stream = ((StreamingParserFactory>) parserFactory).get(); + var stream = ((StreamingParserFactory>) parserFactory).get(); assertThat(stream, instanceOf(StreamingParser.class)); From b93bfaa2491626febe552138cacd94b4424bdb2f Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 29 Jul 2024 17:59:25 -0700 Subject: [PATCH 26/66] Merging UtilizationClassVector changes --- .../application/VdypStartApplication.java | 10 +- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 356 ++++-------------- .../gov/nrs/vdyp/model/UtilizationClass.java | 2 + .../vdyp/common/EstimationMethodsTest.java | 1 - .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 46 +-- .../vdyp/forward/ForwardProcessingEngine.java | 15 +- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 30 +- 7 files changed, 117 insertions(+), 343 deletions(-) diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 993845839..efaa29a7b 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -1258,15 +1258,15 @@ public void computeUtilizationComponentsPrimary( .pairwiseInPlace(quadMeanDiameterUtil, Estimators.COPY_IF_BAND); spec.getWholeStemVolumeByUtilization() - .pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); + .pairwiseInPlace(wholeStemVolumeUtil, Estimators.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeByUtilization() - .pairwiseInPlace(closeVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeUtil, Estimators.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayByUtilization() - .pairwiseInPlace(closeVolumeNetDecayUtil, EstimationMethods.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeNetDecayUtil, Estimators.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeNetDecayWasteUtil, Estimators.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, Estimators.COPY_IF_NOT_SMALL); } computeLayerUtilizationComponentsFromSpecies(vdypLayer); diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java index d48910294..dc16c7810 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java @@ -20,11 +20,12 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.io.parse.coe.GenusDefinitionParser; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; @@ -34,9 +35,9 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationVector.BinaryOperatorWithClass; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; -public class EstimationMethods { +public class Estimators { - public static final Logger log = LoggerFactory.getLogger(EstimationMethods.class); + public static final Logger log = LoggerFactory.getLogger(Estimators.class); /** * Returns the new value if the index is that of a utilization class that represents a size band, otherwise the old @@ -53,18 +54,17 @@ public class EstimationMethods { oldX, newX, uc ) -> UtilizationClass.ALL_BUT_SMALL.contains(uc) ? newX : oldX; - Map controlMap; + ResolvedControlMap controlMap; - public EstimationMethods(Map controlMap) { - this.controlMap = controlMap; + public Estimators(ResolvedControlMap resolvedControlMap) { + this.controlMap = resolvedControlMap; } - private static float heightMultiplier( - Map controlMap, String genus, Region region, float treesPerHectarePrimary + private float heightMultiplier( + String genus, Region region, float treesPerHectarePrimary ) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class - ); + final var coeMap = controlMap + .>get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); var coe = coeMap.get(genus, region).reindex(0); return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); } @@ -80,23 +80,8 @@ private static float heightMultiplier( */ public float primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - return primaryHeightFromLeadHeight(controlMap, leadHeight, genus, region, treesPerHectarePrimary); - } - /** - * EMP050 Method 1: Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param controlMap Control map containing coefficients - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return - */ - public static float primaryHeightFromLeadHeight( - Map controlMap, float leadHeight, String genus, Region region, float treesPerHectarePrimary - ) { - return 1.3f + (leadHeight - 1.3f) * heightMultiplier(controlMap, genus, region, treesPerHectarePrimary); + return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); } /** @@ -110,34 +95,7 @@ public static float primaryHeightFromLeadHeight( public float leadHeightFromPrimaryHeight( float primaryHeight, String genus, Region region, float treesPerHectarePrimary ) { - return leadHeightFromPrimaryHeight(controlMap, primaryHeight, genus, region, treesPerHectarePrimary); - } - - /** - * EMP050 Method 2: Return the dominant height of the lead species based on the lorey height of the primary species. - * - * @param controlMap Control map containing coefficients - * @param primaryHeight lorey height of the primary species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - */ - public static float leadHeightFromPrimaryHeight( - Map controlMap, float primaryHeight, String genus, Region region, - float treesPerHectarePrimary - ) { - return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(controlMap, genus, region, treesPerHectarePrimary); - } - - /** - * EMP051 Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - */ - public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { - return primaryHeightFromLeadHeightInitial(controlMap, leadHeight, genus, region); + return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(genus, region, treesPerHectarePrimary); } /** @@ -149,11 +107,10 @@ public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, * @param region Region of the polygon */ public float primaryHeightFromLeadHeightInitial( - Map controlMap, float leadHeight, String genus, Region region + float leadHeight, String genus, Region region ) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class - ); + final var coeMap = controlMap + .>get(ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class); var coe = coeMap.get(genus, region); return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); } @@ -190,15 +147,15 @@ public float estimateNonPrimaryLoreyHeight( public float estimateNonPrimaryLoreyHeight( String vspec, String vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight ) throws ProcessingException { - var coeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.HL_NONPRIMARY, MatrixMap3.class + var coeMap = controlMap.>>get( + ControlKey.HL_NONPRIMARY, MatrixMap3.class ); var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( () -> new ProcessingException( String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, - bec.getRegion() + "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, bec + .getRegion() ) ) ); @@ -242,9 +199,8 @@ public float estimateQuadMeanDiameterForSpecies( return standQuadMeanDiameter; } - var coeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BY_SPECIES_DQ, Map.class); - var specAliases = GenusDefinitionParser.getSpeciesAliases(controlMap); + var coeMap = controlMap.>get(ControlKey.BY_SPECIES_DQ, Map.class); + var specAliases = controlMap.getGenusDefinitionMap().getAliases(); // TODO we can probably remove these as they seem to only be used for debugging // in VDYP7 @@ -323,14 +279,13 @@ public float estimateQuadMeanDiameterForSpecies( var limits = getLimitsForHeightAndDiameter(species, region); quadMeanDiameter1 = estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, - quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); return quadMeanDiameter1; } float estimateQuadMeanDiameterClampResult( - Limits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, + ComponentSizeLimits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, float baseArea1, float baseArea2, float quadMeanDiameter1, float treesPerHectare2, float quadMeanDiameter2 ) { float treesPerHectare1; @@ -342,9 +297,9 @@ float estimateQuadMeanDiameterClampResult( quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); } - final float dqMinSp = max(minQuadMeanDiameter, limits.minDiameterHeight() * loreyHeightSpec); + final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); final float dqMaxSp = max( - 7.6f, min(limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() * loreyHeightSpec) + 7.6f, min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) ); if (quadMeanDiameter1 < dqMinSp) { quadMeanDiameter1 = dqMinSp; @@ -377,19 +332,14 @@ float estimateQuadMeanDiameterClampResult( return quadMeanDiameter1; } - public static record Limits( - float maxLoreyHeight, float maxQuadMeanDiameter, float minDiameterHeight, float maxDiameterHeight - ) { - }; - // EMP061 - public Limits getLimitsForHeightAndDiameter(String genus, Region region) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class + public ComponentSizeLimits getLimitsForHeightAndDiameter(String genus, Region region) { + var coeMap = controlMap.>get( + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class ); var coe = coeMap.get(genus, region); - return new Limits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); + return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); } /** @@ -406,26 +356,8 @@ public void estimateBaseAreaByUtilization( BecDefinition bec, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus ) throws ProcessingException { - estimateBaseAreaByUtilization(controlMap, bec, quadMeanDiameterUtil, baseAreaUtil, genus); - } - - /** - * EMP070. Estimate basal area by utilization class from the given parameters, after getting the estimation - * coefficients map from the control map. - * - * @param controlMap - * @param bec - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateBaseAreaByUtilization( - Map controlMap, BecDefinition bec, UtilizationVector quadMeanDiameterUtil, - UtilizationVector baseAreaUtil, String genus - ) throws ProcessingException { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_BA, MatrixMap3.class + final var coeMap = controlMap.>get( + ControlKey.UTIL_COMP_BA, MatrixMap3.class ); estimateBaseAreaByUtilization(bec, coeMap, quadMeanDiameterUtil, baseAreaUtil, genus); @@ -489,24 +421,8 @@ public void estimateQuadMeanDiameterByUtilization( BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus ) throws ProcessingException { - estimateQuadMeanDiameterByUtilization(controlMap, bec, quadMeanDiameterUtil, genus); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param controlMap - * @param bec - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateQuadMeanDiameterByUtilization( - Map controlMap, BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus - ) throws ProcessingException { - - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_DQ, MatrixMap3.class + final var coeMap = controlMap.>get( + ControlKey.UTIL_COMP_DQ, MatrixMap3.class ); estimateQuadMeanDiameterByUtilization(bec, coeMap, quadMeanDiameterUtil, genus); @@ -605,25 +521,8 @@ public static void estimateQuadMeanDiameterByUtilization( */ public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - return estimateWholeStemVolumePerTree(controlMap, volumeGroup, loreyHeight, quadMeanDiameter); - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param controlMap the control map from which the total stand whole stem volume equation coefficients are - * retrieved - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public static float estimateWholeStemVolumePerTree( - Map controlMap, int volumeGroup, float loreyHeight, float quadMeanDiameter - ) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class + var coeMap = controlMap.>get( + ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class ); return estimateWholeStemVolumePerTree(volumeGroup, loreyHeight, quadMeanDiameter, coeMap); @@ -679,39 +578,13 @@ public void estimateWholeStemVolume( UtilizationVector wholeStemVolumeUtil ) throws ProcessingException { - estimateWholeStemVolume( - controlMap, utilizationClass, adjustCloseUtil, volumeGroup, hlSp, quadMeanDiameterUtil, baseAreaUtil, - wholeStemVolumeUtil - ); - } - - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values, getting wholeStemUtilizationComponentMap from the - * given controlMap. - * - * @param controlMap - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public static void estimateWholeStemVolume( - Map controlMap, UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, - Float hlSp, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, - UtilizationVector wholeStemVolumeUtil - ) throws ProcessingException { - final var wholeStemUtilizationComponentMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class + final var wholeStemUtilizationComponentMap = controlMap + .>>get( + ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class ); estimateWholeStemVolume( - utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, - quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil ); } @@ -784,37 +657,13 @@ public void estimateCloseUtilizationVolume( UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, UtilizationVector closeUtilizationVolumeUtil ) throws ProcessingException { - estimateCloseUtilizationVolume( - controlMap, utilizationClass, aAdjust, volumeGroup, hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, - closeUtilizationVolumeUtil - ); - } - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param controlMap - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public static void estimateCloseUtilizationVolume( - Map controlMap, UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, - float hlSp, UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, - UtilizationVector closeUtilizationVolumeUtil - ) throws ProcessingException { - final var closeUtilizationCoeMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class + final var closeUtilizationCoeMap = controlMap + .>>get( + ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class ); estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, - wholeStemVolumeUtil, closeUtilizationVolumeUtil + utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil ); } @@ -879,41 +728,14 @@ public void estimateNetDecayVolume( UtilizationVector closeUtilizationNetOfDecayUtil ) throws ProcessingException { - estimateNetDecayVolume( - controlMap, genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, quadMeanDiameterUtil, - closeUtilizationUtil, closeUtilizationNetOfDecayUtil + final var netDecayCoeMap = controlMap.>>get( + ControlKey.VOLUME_NET_DECAY, MatrixMap2.class ); - } - - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param controlMap - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @throws ProcessingException - */ - public static void estimateNetDecayVolume( - Map controlMap, String genus, Region region, UtilizationClass utilizationClass, - Coefficients aAdjust, int decayGroup, float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil - ) throws ProcessingException { - final var netDecayCoeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY, MatrixMap2.class - ); - final var decayModifierMap = Utils.>expectParsedControl( - controlMap, ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class + final var decayModifierMap = controlMap.>get( + ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class ); estimateNetDecayVolume( - genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, - quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil + genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil ); } @@ -991,44 +813,15 @@ public void estimateNetDecayAndWasteVolume( UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { - estimateNetDecayAndWasteVolume( - controlMap, region, utilizationClass, aAdjust, genus, loreyHeight, quadMeanDiameterUtil, - closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil + final var netDecayWasteCoeMap = controlMap.>get( + ControlKey.VOLUME_NET_DECAY_WASTE, Map.class ); - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param controlMap - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public static void estimateNetDecayAndWasteVolume( - Map controlMap, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, - String genus, float loreyHeight, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil, - UtilizationVector closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { - final var netDecayWasteCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class + final var wasteModifierMap = controlMap.>get( + ControlKey.WASTE_MODIFIERS, MatrixMap2.class ); estimateNetDecayAndWasteVolume( - region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, - quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, - closeUtilizationNetOfDecayAndWasteUtil + region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil ); } @@ -1055,8 +848,9 @@ public static void estimateNetDecayAndWasteVolume( UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { estimateUtilization( - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, - (i, netDecay) -> { + closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( + i, netDecay + ) -> { if (Float.isNaN(netDecay) || netDecay <= 0f) { return 0f; } @@ -1130,36 +924,11 @@ public void estimateNetDecayWasteAndBreakageVolume( UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil ) throws ProcessingException { - estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, breakageGroup, quadMeanDiameterUtil, closeUtilizationUtil, - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil - ); - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public static void estimateNetDecayWasteAndBreakageVolume( - Map controlMap, UtilizationClass utilizationClass, int breakageGroup, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, - UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { - final var netBreakageCoeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BREAKAGE, Map.class); + final var netBreakageCoeMap = controlMap + .>get(ControlKey.BREAKAGE, Map.class); estimateNetDecayWasteAndBreakageVolume( - utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil + utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); } @@ -1192,8 +961,9 @@ public static void estimateNetDecayWasteAndBreakageVolume( final var a4 = coefficients.getCoe(4); estimateUtilization( - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, - utilizationClass, (uc, netWaste) -> { + closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, utilizationClass, ( + uc, netWaste + ) -> { if (netWaste <= 0f) { return 0f; diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java index cfe040b1f..b4cb23e31 100644 --- a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java +++ b/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java @@ -1,5 +1,7 @@ package ca.bc.gov.nrs.vdyp.model; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java index c23594caa..740194241 100644 --- a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java +++ b/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java @@ -16,7 +16,6 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.model.BecLookup; diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index c57687d75..416e63b90 100644 --- a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -46,7 +46,7 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods; +import ca.bc.gov.nrs.vdyp.common.Estimators; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; @@ -334,14 +334,14 @@ VdypLayer processLayerAsPrimary(FipPolygon fipPolygon, FipLayerPrimary fipLayer, } // Estimate lorey height for primary species if (iPass == 1 && vdypSpecies.size() == 1) { - primaryHeight = estimationMethods.primaryHeightFromLeadHeight( + primaryHeight = estimators.primaryHeightFromLeadHeight( leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), tphTotal ); } else if (iPass == 1) { - primaryHeight = estimationMethods + primaryHeight = estimators .primaryHeightFromLeadHeightInitial(leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion()); } else { - primaryHeight = estimationMethods.primaryHeightFromLeadHeight( + primaryHeight = estimators.primaryHeightFromLeadHeight( leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), vdypPrimarySpecies.getTreesPerHectareByUtilization().getAll() ); @@ -355,7 +355,7 @@ VdypLayer processLayerAsPrimary(FipPolygon fipPolygon, FipLayerPrimary fipLayer, // EMP053 vspec.getLoreyHeightByUtilization().setAll( - estimationMethods.estimateNonPrimaryLoreyHeight( + estimators.estimateNonPrimaryLoreyHeight( vspec, vdypPrimarySpecies, bec, leadHeight, primaryHeight ) ); @@ -411,12 +411,12 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, // Multiple Species for (var spec : result.getSpecies().values()) { - var limits = estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); + var limits = estimators.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); final float maxHeightMultiplier = fipLayer.getPrimaryGenus() .orElseThrow(() -> new IllegalStateException("primaryGenus has not been set")) .equals(spec.getGenus()) ? 1.5f : 1.0f; - final float heightMax = limits.maxLoreyHeight() * maxHeightMultiplier; + final float heightMax = limits.loreyHeightMaximum() * maxHeightMultiplier; spec.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.ALL, x -> min(x, heightMax)); } @@ -461,17 +461,17 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, for (var spec : result.getSpecies().values()) { // EMP061 - var limits = estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); + var limits = estimators.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - var dqMin = limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getAll(); + var dqMin = limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll(); var dqMax = max( - limits.maxQuadMeanDiameter(), - limits.maxDiameterHeight() * spec.getLoreyHeightByUtilization().getAll() + limits.quadMeanDiameterMaximum(), + limits.maxQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll() ); // EMP060 float quadMeanDiameter = clamp( - estimationMethods.estimateQuadMeanDiameterForSpecies( + estimators.estimateQuadMeanDiameterForSpecies( spec, result.getSpecies(), bec.getRegion(), quadMeanDiameterTotal, baseAreaTotal, treesPerHectareTotal, loreyHeightTotal ), // @@ -544,8 +544,8 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, for (var spec : result.getSpecies().values()) { // EMP090 var wholeStemVolume = spec.getTreesPerHectareByUtilization().getAll() - * EstimationMethods.estimateWholeStemVolumePerTree( - controlMap, spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getAll(), + * estimators.estimateWholeStemVolumePerTree( + spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getAll(), spec.getQuadraticMeanDiameterByUtilization().getAll() ); spec.getWholeStemVolumeByUtilization().setAll(wholeStemVolume); @@ -730,22 +730,22 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit var adjust = new Coefficients(new float[] { 0f, 0f, 0f, 0f }, 1); // EMP091 - EstimationMethods.estimateWholeStemVolume( - controlMap, utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, + estimators.estimateWholeStemVolume( + 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, + estimators.estimateCloseUtilizationVolume( + utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil ); adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); // EMP093 - EstimationMethods.estimateNetDecayVolume( - controlMap, vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, + estimators.estimateNetDecayVolume( + vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, vdypSpecies.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil ); @@ -758,7 +758,7 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit final var wasteModifierMap = Utils.>expectParsedControl( controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class ); - EstimationMethods.estimateNetDecayAndWasteVolume( + Estimators.estimateNetDecayAndWasteVolume( bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, netDecayCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil @@ -766,8 +766,8 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit if (getId().isStart()) { // EMP095 - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, + estimators.estimateNetDecayWasteAndBreakageVolume( + utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index c18389f6c..2ac51f657 100644 --- a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -56,6 +56,7 @@ import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; +import ca.bc.gov.nrs.vdyp.model.UtilizationVector; import ca.bc.gov.nrs.vdyp.model.VdypEntity; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; @@ -1884,13 +1885,13 @@ void setCompatibilityVariables() throws ProcessingException { float spLoreyHeight_All = start.loreyHeights[s][UtilizationClass.ALL.ordinal()]; - Coefficients basalAreas = Utils.utilizationVector(); - Coefficients wholeStemVolumes = Utils.utilizationVector(); - Coefficients closeUtilizationVolumes = Utils.utilizationVector(); - Coefficients closeUtilizationVolumesNetOfDecay = Utils.utilizationVector(); - Coefficients closeUtilizationVolumesNetOfDecayAndWaste = Utils.utilizationVector(); - Coefficients quadMeanDiameters = Utils.utilizationVector(); - Coefficients treesPerHectare = Utils.utilizationVector(); + UtilizationVector basalAreas = Utils.utilizationVector(); + UtilizationVector wholeStemVolumes = Utils.utilizationVector(); + UtilizationVector closeUtilizationVolumes = Utils.utilizationVector(); + UtilizationVector closeUtilizationVolumesNetOfDecay = Utils.utilizationVector(); + UtilizationVector closeUtilizationVolumesNetOfDecayAndWaste = Utils.utilizationVector(); + UtilizationVector quadMeanDiameters = Utils.utilizationVector(); + UtilizationVector treesPerHectare = Utils.utilizationVector(); cvVolume[s] = new MatrixMap3Impl( UtilizationClass.UTIL_CLASSES, VolumeVariable.ALL, LayerType.ALL_USED, (k1, k2, k3) -> 0f diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index 9efc7f8f4..ebc369e7b 100644 --- a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.vri; -import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.*; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.quadMeanDiameter; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.treesPerHectare; import java.io.Closeable; import java.io.IOException; @@ -23,6 +24,7 @@ import org.apache.commons.math3.exception.TooManyEvaluationsException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.RuntimeProcessingException; import ca.bc.gov.nrs.vdyp.application.RuntimeStandProcessingException; @@ -30,7 +32,6 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods.Limits; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.SiteIndex2Height; @@ -41,8 +42,6 @@ import ca.bc.gov.nrs.vdyp.io.parse.control.BaseControlParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; -import ca.bc.gov.nrs.vdyp.model.PolygonMode; -import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.BaseVdypSite; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies.Builder; @@ -50,11 +49,14 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.ModelClassBuilder; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; +import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.VdypLayer; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; @@ -441,7 +443,7 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws // HLPL1 // EMP050 Method 1 - var primaryHeight = estimationMethods.primaryHeightFromLeadHeight( + var primaryHeight = estimators.primaryHeightFromLeadHeight( leadHeight, primarySiteIn.getSiteGenus(), bec.getRegion(), primarySpeciesDensity ); @@ -463,14 +465,14 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws float speciesQuadMeanDiameter = Math.max(7.5f, height / leadHeight * layerQuadMeanDiameter); float speciesDensity = treesPerHectare(primaryBaseArea, speciesQuadMeanDiameter); // EMP050 Method 1 - float speciesLoreyHeight = estimationMethods.primaryHeightFromLeadHeight( + float speciesLoreyHeight = estimators.primaryHeightFromLeadHeight( vriSite.getHeight().get(), vriSite.getSiteGenus(), bec.getRegion(), speciesDensity ); return speciesLoreyHeight; }).orElseGet(() -> { try { // EMP053 - float speciesLoreyHeight = estimationMethods.estimateNonPrimaryLoreyHeight( + float speciesLoreyHeight = estimators.estimateNonPrimaryLoreyHeight( vriSite.getSiteGenus(), primarySiteIn.getSiteGenus(), bec, leadHeight, primaryHeight ); return speciesLoreyHeight; @@ -479,8 +481,8 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws } }); - float maxHeight = estimationMethods.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) - .maxLoreyHeight(); + float maxHeight = estimators.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) + .loreyHeightMaximum(); loreyHeight = Math.min(loreyHeight, maxHeight); sBuilder.loreyHeight(loreyHeight); } @@ -589,16 +591,16 @@ void getDqBySpeciesInitial( ) throws ProcessingException { for (var spec : layer.getSpecies().values()) { // EMP060 - float specDq = estimationMethods.estimateQuadMeanDiameterForSpecies( + float specDq = estimators.estimateQuadMeanDiameterForSpecies( spec, layer.getSpecies(), region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, loreyHeightTotal ); var limits = getLimitsForSpecies(spec, region); - float min = Math.max(7.6f, limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getAll()); + float min = Math.max(7.6f, limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll()); float loreyHeightToUse = Math.max(spec.getLoreyHeightByUtilization().getAll(), 7.0f); - float max = Math.min(limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() * loreyHeightToUse); + float max = Math.min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightToUse); max = Math.max(7.75f, max); minPerSpecies.put(spec.getGenus(), min); @@ -612,11 +614,11 @@ void getDqBySpeciesInitial( } } - protected Limits getLimitsForSpecies(VdypSpecies spec, Region region) { + protected ComponentSizeLimits getLimitsForSpecies(VdypSpecies spec, Region region) { // TODO for JPROGRAM = 7 implement this differently, see ROOTV01 L91-L99 // EMP061 - return estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), region); + return estimators.getLimitsForHeightAndDiameter(spec.getGenus(), region); } float quadMeanDiameterFractionalError( From 8478393a27364a9b8cebc20d1285cac74a0a6db7 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 30 Jul 2024 13:16:07 -0700 Subject: [PATCH 27/66] adapt to monorepo before merge attempt --- {vdyp-common => vdyp-lib/vdyp-common}/pom.xml | 0 .../java/ca/bc/gov/nrs/vdyp/application/LowValueException.java | 0 .../java/ca/bc/gov/nrs/vdyp/application/ProcessingException.java | 0 .../bc/gov/nrs/vdyp/application/RuntimeProcessingException.java | 0 .../gov/nrs/vdyp/application/RuntimeStandProcessingException.java | 0 .../ca/bc/gov/nrs/vdyp/application/StandProcessingException.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/application/VdypApplication.java | 0 .../ca/bc/gov/nrs/vdyp/application/VdypApplicationIdentifier.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/application/VdypComponent.java | 0 .../java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/Computed.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java | 0 .../java/ca/bc/gov/nrs/vdyp/common/ExpectationDifference.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/common/FloatBinaryOperator.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/common/FloatUnaryOperator.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/HoldFirst.java | 0 .../ca/bc/gov/nrs/vdyp/common/IndexedFloatBinaryOperator.java | 0 .../java/ca/bc/gov/nrs/vdyp/common/IndexedFloatUnaryOperator.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/LazyValue.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarker.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAge.java | 0 .../nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java | 0 .../bc/gov/nrs/vdyp/common_calculators/ForestInventoryZone.java | 0 .../ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java | 0 .../gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java | 0 .../java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java | 0 .../ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java | 0 .../gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothed.java | 0 .../ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNames.java | 0 .../ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexUtilities.java | 0 .../nrs/vdyp/common_calculators/SiteIndexYears2BreastHeight.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMap.java | 0 .../custom_exceptions/AgeTypeErrorException.java | 0 .../common_calculators/custom_exceptions/ClassErrorException.java | 0 .../common_calculators/custom_exceptions/CodeErrorException.java | 0 .../custom_exceptions/CommonCalculatorException.java | 0 .../common_calculators/custom_exceptions/CurveErrorException.java | 0 .../custom_exceptions/EstablishmentErrorException.java | 0 .../custom_exceptions/ForestInventoryZoneException.java | 0 .../custom_exceptions/GrowthInterceptMaximumException.java | 0 .../custom_exceptions/GrowthInterceptMinimumException.java | 0 .../custom_exceptions/GrowthInterceptTotalException.java | 0 .../common_calculators/custom_exceptions/LessThan13Exception.java | 0 .../common_calculators/custom_exceptions/NoAnswerException.java | 0 .../custom_exceptions/SpeciesErrorException.java | 0 .../vdyp/common_calculators/enumerations/SiteIndexAgeType.java | 0 .../vdyp/common_calculators/enumerations/SiteIndexEquation.java | 0 .../enumerations/SiteIndexEstablishmentType.java | 0 .../common_calculators/enumerations/SiteIndexEstimationType.java | 0 .../enumerations/SiteIndexForestInventoryZone.java | 0 .../vdyp/common_calculators/enumerations/SiteIndexSpecies.java | 0 .../bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java | 0 .../java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java | 0 .../ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/io/EndOfRecord.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java | 0 .../gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthFiatParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/BaseAreaCoefficientParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/BreakageEquationGroupParser.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/CompVarAdjustmentsParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/DecayEquationGroupParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/DefaultEquationNumberParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthFiatParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP1Parser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP2Parser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP3Parser.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParser.java | 0 .../vdyp/io/parse/coe/NonPrimarySpeciesBasalAreaGrowthParser.java | 0 .../nrs/vdyp/io/parse/coe/NonPrimarySpeciesDqGrowthParser.java | 0 .../vdyp/io/parse/coe/PrimarySpeciesBasalAreaGrowthParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/PrimarySpeciesDqGrowthParser.java | 0 .../nrs/vdyp/io/parse/coe/QuadMeanDiameterCoefficientParser.java | 0 .../nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/SmallComponentBaseAreaParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentDQParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentHLParser.java | 0 .../nrs/vdyp/io/parse/coe/SmallComponentProbabilityParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/SmallComponentWSVolumeParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/TotalStandWholeStemParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentDQParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/UtilComponentWSVolumeParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranBAParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/VeteranLayerVolumeAdjustParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/VolumeEquationGroupParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayWasteParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java | 0 .../vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/base/CoefficientParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/base/HLCoefficientParser.java | 0 .../nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java | 0 .../nrs/vdyp/io/parse/coe/base/OptionalCoefficientParser2.java | 0 .../nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java | 0 .../gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser1.java | 0 .../gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/base/UtilComponentParser.java | 0 .../gov/nrs/vdyp/io/parse/common/InvalidGenusDistributionSet.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/common/ParseEntryHandler.java | 0 .../bc/gov/nrs/vdyp/io/parse/common/ResourceParseException.java | 0 .../gov/nrs/vdyp/io/parse/common/ResourceParseLineException.java | 0 .../gov/nrs/vdyp/io/parse/common/ResourceParseValidException.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParser.java | 0 .../nrs/vdyp/io/parse/common/RuntimeResourceParseException.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapModifier.java | 0 .../nrs/vdyp/io/parse/control/ControlMapSubResourceParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacer.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java | 0 .../io/parse/control/OptionalControlMapSubResourceParser.java | 0 .../vdyp/io/parse/control/OptionalResourceControlMapModifier.java | 0 .../gov/nrs/vdyp/io/parse/control/ResourceControlMapModifier.java | 0 .../nrs/vdyp/io/parse/control/StartApplicationControlParser.java | 0 .../gov/nrs/vdyp/io/parse/streaming/AbstractStreamingParser.java | 0 .../gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParser.java | 0 .../gov/nrs/vdyp/io/parse/streaming/StreamingParserFactory.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParser.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/value/ValueParseException.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriter.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/AliasedEntity.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/BecDefinition.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/BecLookup.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/CommonData.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java | 0 .../java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/EnumIterator.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinition.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistribution.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSet.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2Impl.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3Impl.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4Impl.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMapImpl.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/ModelCoefficients.java | 0 .../java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonMode.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/Region.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/model/SiteCurveAgeMaximum.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/model/StockingClassFactor.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java | 0 .../java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSite.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeComputeMode.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeVariable.java | 0 .../java/ca/bc/gov/nrs/vdyp/application/ApplicationTestUtils.java | 0 .../java/ca/bc/gov/nrs/vdyp/application/VdypComponentTest.java | 0 .../ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java | 0 .../java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/application/test/TestSite.java | 0 .../java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java | 0 .../ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java | 0 .../java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/common/LazyValueTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarkerTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java | 0 .../vdyp/common_calculators/BaseAreaTreeDensityDiameterTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/common_calculators/FizCheckTest.java | 0 .../bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java | 0 .../nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java | 0 .../ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java | 0 .../nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java | 0 .../bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java | 0 .../ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNamesTest.java | 0 .../vdyp/common_calculators/SiteIndexYears2BreastHeightTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMapTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolverTest.java | 0 .../gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java | 0 .../gov/nrs/vdyp/io/parse/DqGrowthEmpiricalLimitsParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java | 0 .../vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java | 0 .../nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java | 0 .../vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java | 0 .../gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java | 0 .../nrs/vdyp/io/parse/QuadraticMeanDiameterYieldParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java | 0 .../nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/CoefficientParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/parse/coe/HLCoefficientParserTest.java | 0 .../nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java | 0 .../gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java | 0 .../vdyp/io/parse/coe/SmallComponentProbabilityParserTest.java | 0 .../gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java | 0 .../nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java | 0 .../nrs/vdyp/io/parse/control/ControlMapValueReplacerTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java | 0 .../nrs/vdyp/io/parse/streaming/GroupingStreamingParserTest.java | 0 .../bc/gov/nrs/vdyp/io/parse/streaming/MockStreamingParser.java | 0 .../bc/gov/nrs/vdyp/io/parse/value/ControlledValueParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java | 0 .../ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/CoefficientsTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSetTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonModeTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/test/MockFileResolver.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java | 0 .../vdyp-common}/src/test/resources/application.properties | 0 .../ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTestValid.csv | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/FIPSTART.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl | 0 .../test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYPBACK.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VRIADJST.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VRISTART.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm | 0 {vdyp-fip => vdyp-lib/vdyp-fip}/pom.xml | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java | 0 .../vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSite.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java | 0 .../vdyp-fip}/src/main/resources/application.properties | 0 .../test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParserTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/fip/test/FipTestUtils.java | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_l1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_ls1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_p1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vp_1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vs_1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vu_1.dat | 0 {vdyp-forward => vdyp-lib/vdyp-forward}/pom.xml | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardPass.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/PrimarySpeciesDetails.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java | 0 .../nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java | 0 .../vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/forward/model/FipMode.java | 0 .../ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java | 0 .../ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java | 0 .../nrs/vdyp/forward/parsers/ForwardControlVariableParser.java | 0 .../gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java | 0 .../nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java | 0 .../ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java | 0 .../ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java | 0 .../ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java | 0 .../vdyp-forward}/src/main/resources/application.properties | 0 .../vdyp-forward}/src/main/resources/logging.properties | 0 .../gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java | 0 .../ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java | 0 .../gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/GenusDefinitionMapTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java | 0 .../java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java | 0 .../ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java | 0 .../SetCompatibilityVariablesForwardProcessingEngineTest.java | 0 .../ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java | 0 .../ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java | 0 .../ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java | 0 .../bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java | 0 .../vdyp/forward/model/VdypForwardControlVariablesParserTest.java | 0 .../forward/test/VdypForwardControlParserTestApplication.java | 0 .../ca/bc/gov/nrs/vdyp/forward/test/VdypForwardTestUtils.java | 0 .../test/resources/ca/bc/gov/nrs/vdyp/test/VDYP-NoSiteCurves.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl | 0 .../test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_p1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_s1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_u1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_y1.dat | 0 {vdyp-si32 => vdyp-lib/vdyp-si32}/pom.xml | 0 .../vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32Errors.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZone.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZoneMethods.java | 0 .../nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDead.java | 0 .../vdyp/si32/cfs/CfsBiomassConversionCoefficientsDetails.java | 0 .../vdyp/si32/cfs/CfsBiomassConversionCoefficientsForGenus.java | 0 .../vdyp/si32/cfs/CfsBiomassConversionCoefficientsForSpecies.java | 0 .../nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsHelper.java | 0 .../nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedEcoZone.java | 0 .../nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedGenera.java | 0 .../nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedSpecies.java | 0 .../java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDeadConversionParams.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDensity.java | 0 .../java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsLiveConversionParams.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsMethods.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSP0Densities.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSpeciesMethods.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeClass.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeGenus.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeSpecies.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SI32Enum.java | 0 .../java/ca/bc/gov/nrs/vdyp/si32/enumerations/SpeciesRegion.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/site/NameFormat.java | 0 .../java/ca/bc/gov/nrs/vdyp/si32/site/ParamLookupFallback.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP0Name.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP64Name.java | 0 .../main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesDetails.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesTable.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/VdypMethods.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/si32/BecZoneMethodsTest.java | 0 .../gov/nrs/vdyp/si32/CfsBioMassConversionCoefficientsTests.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsMethodsTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/si32/SI32EnumIteratorTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/si32/SpeciesTableTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/si32/VdypMethodsTest.java | 0 {vdyp-sindex => vdyp-lib/vdyp-sindex}/pom.xml | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java | 0 {vdyp-vri => vdyp-lib/vdyp-vri}/pom.xml | 0 {vdyp-vri => vdyp-lib/vdyp-vri}/resources/application.properties | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java | 0 .../vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSite.java | 0 .../src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java | 0 .../test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java | 0 .../src/test/java/ca/bc/gov/nrs/vdyp/vri/test/VriTestUtils.java | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vp_1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_l1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_p1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_si1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_sp1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vs_1.dat | 0 .../src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vu_1.dat | 0 608 files changed, 0 insertions(+), 0 deletions(-) rename {vdyp-common => vdyp-lib/vdyp-common}/pom.xml (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/LowValueException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/ProcessingException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeProcessingException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeStandProcessingException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/StandProcessingException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplication.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplicationIdentifier.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypComponent.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/Computed.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/ExpectationDifference.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatBinaryOperator.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatUnaryOperator.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/HoldFirst.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatBinaryOperator.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatUnaryOperator.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/LazyValue.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarker.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAge.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/ForestInventoryZone.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothed.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNames.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexUtilities.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeight.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMap.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/AgeTypeErrorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ClassErrorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CodeErrorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CommonCalculatorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CurveErrorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/EstablishmentErrorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ForestInventoryZoneException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMaximumException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMinimumException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptTotalException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/LessThan13Exception.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/NoAnswerException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/SpeciesErrorException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexAgeType.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEquation.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstablishmentType.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstimationType.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexForestInventoryZone.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexSpecies.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/EndOfRecord.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthFiatParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BaseAreaCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageEquationGroupParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CompVarAdjustmentsParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DecayEquationGroupParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DefaultEquationNumberParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthFiatParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP1Parser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP2Parser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP3Parser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesBasalAreaGrowthParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesDqGrowthParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesBasalAreaGrowthParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesDqGrowthParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadMeanDiameterCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentBaseAreaParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentDQParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentHLParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentWSVolumeParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/TotalStandWholeStemParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentDQParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentWSVolumeParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranBAParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranLayerVolumeAdjustParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeEquationGroupParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayWasteParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/CoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/HLCoefficientParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/OptionalCoefficientParser2.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser1.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/UtilComponentParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/InvalidGenusDistributionSet.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ParseEntryHandler.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseLineException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseValidException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/RuntimeResourceParseException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapModifier.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapSubResourceParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacer.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalControlMapSubResourceParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalResourceControlMapModifier.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ResourceControlMapModifier.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/StartApplicationControlParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/AbstractStreamingParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParserFactory.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParseException.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriter.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/AliasedEntity.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/BecDefinition.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/BecLookup.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/CommonData.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/EnumIterator.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinition.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistribution.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSet.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2Impl.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3Impl.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4Impl.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMapImpl.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelCoefficients.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonMode.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/Region.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/SiteCurveAgeMaximum.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/StockingClassFactor.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSite.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeComputeMode.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeVariable.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/ApplicationTestUtils.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypComponentTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSite.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common/LazyValueTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarkerTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameterTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/FizCheckTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNamesTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeightTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMapTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolverTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalLimitsParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/QuadraticMeanDiameterYieldParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CoefficientParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLCoefficientParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacerTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/MockStreamingParser.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/CoefficientsTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSetTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonModeTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/test/MockFileResolver.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/application.properties (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTestValid.csv (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/FIPSTART.CTR (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYPBACK.CTR (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRIADJST.CTR (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRISTART.CTR (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE (100%) rename {vdyp-common => vdyp-lib/vdyp-common}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/pom.xml (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParser.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSite.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/main/resources/application.properties (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParserTest.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/java/ca/bc/gov/nrs/vdyp/fip/test/FipTestUtils.java (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_l1.dat (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_ls1.dat (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_p1.dat (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vp_1.dat (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vs_1.dat (100%) rename {vdyp-fip => vdyp-lib/vdyp-fip}/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vu_1.dat (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/pom.xml (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardPass.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/PrimarySpeciesDetails.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/FipMode.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/resources/application.properties (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/main/resources/logging.properties (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/GenusDefinitionMapTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardControlParserTestApplication.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardTestUtils.java (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP-NoSiteCurves.CTR (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_p1.dat (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_s1.dat (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_u1.dat (100%) rename {vdyp-forward => vdyp-lib/vdyp-forward}/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_y1.dat (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/pom.xml (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32Errors.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZone.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZoneMethods.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDead.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDetails.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForGenus.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForSpecies.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsHelper.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedEcoZone.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedGenera.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedSpecies.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDeadConversionParams.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDensity.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsLiveConversionParams.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsMethods.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSP0Densities.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSpeciesMethods.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeClass.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeGenus.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeSpecies.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SI32Enum.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SpeciesRegion.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/NameFormat.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/ParamLookupFallback.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP0Name.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP64Name.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesDetails.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesTable.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/VdypMethods.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/BecZoneMethodsTest.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsBioMassConversionCoefficientsTests.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsMethodsTest.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/SI32EnumIteratorTest.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/SpeciesTableTest.java (100%) rename {vdyp-si32 => vdyp-lib/vdyp-si32}/src/test/java/ca/bc/gov/nrs/vdyp/si32/VdypMethodsTest.java (100%) rename {vdyp-sindex => vdyp-lib/vdyp-sindex}/pom.xml (100%) rename {vdyp-sindex => vdyp-lib/vdyp-sindex}/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java (100%) rename {vdyp-sindex => vdyp-lib/vdyp-sindex}/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/pom.xml (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/resources/application.properties (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParser.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSite.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/java/ca/bc/gov/nrs/vdyp/vri/test/VriTestUtils.java (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vp_1.dat (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_l1.dat (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_p1.dat (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_si1.dat (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_sp1.dat (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vs_1.dat (100%) rename {vdyp-vri => vdyp-lib/vdyp-vri}/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vu_1.dat (100%) diff --git a/vdyp-common/pom.xml b/vdyp-lib/vdyp-common/pom.xml similarity index 100% rename from vdyp-common/pom.xml rename to vdyp-lib/vdyp-common/pom.xml diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/LowValueException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/LowValueException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/LowValueException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/LowValueException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/ProcessingException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/ProcessingException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/ProcessingException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/ProcessingException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeProcessingException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeProcessingException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeProcessingException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeProcessingException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeStandProcessingException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeStandProcessingException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeStandProcessingException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/RuntimeStandProcessingException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/StandProcessingException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/StandProcessingException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/StandProcessingException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/StandProcessingException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplication.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplication.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplication.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplicationIdentifier.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplicationIdentifier.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplicationIdentifier.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypApplicationIdentifier.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypComponent.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypComponent.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypComponent.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypComponent.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Computed.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Computed.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Computed.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Computed.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ExpectationDifference.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ExpectationDifference.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ExpectationDifference.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ExpectationDifference.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatBinaryOperator.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatBinaryOperator.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatBinaryOperator.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatBinaryOperator.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatUnaryOperator.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatUnaryOperator.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatUnaryOperator.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/FloatUnaryOperator.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/HoldFirst.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/HoldFirst.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/HoldFirst.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/HoldFirst.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatBinaryOperator.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatBinaryOperator.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatBinaryOperator.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatBinaryOperator.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatUnaryOperator.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatUnaryOperator.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatUnaryOperator.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/IndexedFloatUnaryOperator.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/LazyValue.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/LazyValue.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/LazyValue.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/LazyValue.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Reference.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarker.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarker.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarker.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarker.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAge.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAge.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAge.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAge.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/ForestInventoryZone.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/ForestInventoryZone.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/ForestInventoryZone.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/ForestInventoryZone.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothed.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothed.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothed.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothed.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNames.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNames.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNames.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNames.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexUtilities.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexUtilities.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexUtilities.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexUtilities.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeight.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeight.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeight.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeight.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMap.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMap.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMap.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/AgeTypeErrorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/AgeTypeErrorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/AgeTypeErrorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/AgeTypeErrorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ClassErrorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ClassErrorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ClassErrorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ClassErrorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CodeErrorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CodeErrorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CodeErrorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CodeErrorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CommonCalculatorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CommonCalculatorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CommonCalculatorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CommonCalculatorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CurveErrorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CurveErrorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CurveErrorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/CurveErrorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/EstablishmentErrorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/EstablishmentErrorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/EstablishmentErrorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/EstablishmentErrorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ForestInventoryZoneException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ForestInventoryZoneException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ForestInventoryZoneException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/ForestInventoryZoneException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMaximumException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMaximumException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMaximumException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMaximumException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMinimumException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMinimumException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMinimumException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptMinimumException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptTotalException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptTotalException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptTotalException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/GrowthInterceptTotalException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/LessThan13Exception.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/LessThan13Exception.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/LessThan13Exception.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/LessThan13Exception.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/NoAnswerException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/NoAnswerException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/NoAnswerException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/NoAnswerException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/SpeciesErrorException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/SpeciesErrorException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/SpeciesErrorException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/custom_exceptions/SpeciesErrorException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexAgeType.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexAgeType.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexAgeType.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexAgeType.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEquation.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEquation.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEquation.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEquation.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstablishmentType.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstablishmentType.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstablishmentType.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstablishmentType.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstimationType.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstimationType.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstimationType.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexEstimationType.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexForestInventoryZone.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexForestInventoryZone.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexForestInventoryZone.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexForestInventoryZone.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexSpecies.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexSpecies.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/enumerations/SiteIndexSpecies.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/EndOfRecord.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/EndOfRecord.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/EndOfRecord.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/EndOfRecord.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthFiatParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthFiatParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthFiatParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthFiatParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaYieldParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BaseAreaCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BaseAreaCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BaseAreaCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BaseAreaCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageEquationGroupParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageEquationGroupParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageEquationGroupParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageEquationGroupParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BreakageParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CompVarAdjustmentsParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CompVarAdjustmentsParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CompVarAdjustmentsParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CompVarAdjustmentsParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DebugSettingsParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DecayEquationGroupParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DecayEquationGroupParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DecayEquationGroupParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DecayEquationGroupParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DefaultEquationNumberParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DefaultEquationNumberParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DefaultEquationNumberParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DefaultEquationNumberParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthFiatParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthFiatParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthFiatParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthFiatParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP1Parser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP1Parser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP1Parser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP1Parser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP2Parser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP2Parser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP2Parser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP2Parser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP3Parser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP3Parser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP3Parser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLPrimarySpeciesEqnP3Parser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesBasalAreaGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesBasalAreaGrowthParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesBasalAreaGrowthParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesBasalAreaGrowthParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesDqGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesDqGrowthParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesDqGrowthParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/NonPrimarySpeciesDqGrowthParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesBasalAreaGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesBasalAreaGrowthParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesBasalAreaGrowthParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesBasalAreaGrowthParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesDqGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesDqGrowthParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesDqGrowthParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/PrimarySpeciesDqGrowthParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadMeanDiameterCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadMeanDiameterCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadMeanDiameterCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadMeanDiameterCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/QuadraticMeanDiameterYieldParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentBaseAreaParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentBaseAreaParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentBaseAreaParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentBaseAreaParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentDQParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentDQParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentDQParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentDQParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentHLParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentHLParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentHLParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentHLParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentWSVolumeParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentWSVolumeParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentWSVolumeParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentWSVolumeParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/TotalStandWholeStemParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/TotalStandWholeStemParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/TotalStandWholeStemParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/TotalStandWholeStemParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentDQParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentDQParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentDQParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentDQParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentWSVolumeParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentWSVolumeParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentWSVolumeParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentWSVolumeParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranBAParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranBAParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranBAParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranBAParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranLayerVolumeAdjustParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranLayerVolumeAdjustParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranLayerVolumeAdjustParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranLayerVolumeAdjustParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeEquationGroupParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeEquationGroupParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeEquationGroupParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeEquationGroupParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayWasteParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayWasteParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayWasteParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VolumeNetDecayWasteParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/CoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/CoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/CoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/CoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/HLCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/HLCoefficientParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/HLCoefficientParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/HLCoefficientParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/OptionalCoefficientParser2.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/OptionalCoefficientParser2.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/OptionalCoefficientParser2.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/OptionalCoefficientParser2.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser1.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser1.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser1.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser1.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/SimpleCoefficientParser2.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/UtilComponentParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/UtilComponentParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/UtilComponentParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/UtilComponentParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/InvalidGenusDistributionSet.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/InvalidGenusDistributionSet.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/InvalidGenusDistributionSet.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/InvalidGenusDistributionSet.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ParseEntryHandler.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ParseEntryHandler.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ParseEntryHandler.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ParseEntryHandler.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseLineException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseLineException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseLineException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseLineException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseValidException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseValidException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseValidException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParseValidException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/ResourceParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/RuntimeResourceParseException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/RuntimeResourceParseException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/RuntimeResourceParseException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/common/RuntimeResourceParseException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/BaseControlParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapModifier.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapModifier.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapModifier.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapModifier.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapSubResourceParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapSubResourceParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapSubResourceParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapSubResourceParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacer.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacer.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacer.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalControlMapSubResourceParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalControlMapSubResourceParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalControlMapSubResourceParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalControlMapSubResourceParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalResourceControlMapModifier.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalResourceControlMapModifier.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalResourceControlMapModifier.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/OptionalResourceControlMapModifier.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ResourceControlMapModifier.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ResourceControlMapModifier.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ResourceControlMapModifier.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/ResourceControlMapModifier.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/StartApplicationControlParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/StartApplicationControlParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/StartApplicationControlParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/StartApplicationControlParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/AbstractStreamingParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/AbstractStreamingParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/AbstractStreamingParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/AbstractStreamingParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParserFactory.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParserFactory.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParserFactory.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/StreamingParserFactory.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParseException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParseException.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParseException.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParseException.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriter.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriter.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriter.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/AliasedEntity.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/AliasedEntity.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/AliasedEntity.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/AliasedEntity.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecDefinition.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecDefinition.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecDefinition.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecDefinition.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecLookup.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecLookup.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecLookup.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BecLookup.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CommonData.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CommonData.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CommonData.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CommonData.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/EnumIterator.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/EnumIterator.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/EnumIterator.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/EnumIterator.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinition.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinition.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinition.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinition.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistribution.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistribution.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistribution.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistribution.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSet.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSet.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSet.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSet.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2Impl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2Impl.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2Impl.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap2Impl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3Impl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3Impl.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3Impl.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap3Impl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4Impl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4Impl.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4Impl.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMap4Impl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMapImpl.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMapImpl.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/MatrixMapImpl.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelCoefficients.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelCoefficients.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelCoefficients.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelCoefficients.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonMode.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonMode.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonMode.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonMode.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Region.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Region.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Region.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Region.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SiteCurveAgeMaximum.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SiteCurveAgeMaximum.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SiteCurveAgeMaximum.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SiteCurveAgeMaximum.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/StockingClassFactor.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/StockingClassFactor.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/StockingClassFactor.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/StockingClassFactor.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClass.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSite.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSite.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSite.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeComputeMode.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeComputeMode.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeComputeMode.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeComputeMode.java diff --git a/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeVariable.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeVariable.java similarity index 100% rename from vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeVariable.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VolumeVariable.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/ApplicationTestUtils.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/ApplicationTestUtils.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/ApplicationTestUtils.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/ApplicationTestUtils.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypComponentTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypComponentTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypComponentTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypComponentTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSite.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSite.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSite.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSite.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/LazyValueTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/LazyValueTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/LazyValueTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/LazyValueTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarkerTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarkerTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarkerTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ValueOrMarkerTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameterTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameterTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameterTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/FizCheckTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/FizCheckTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/FizCheckTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/FizCheckTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNamesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNamesTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNamesTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexNamesTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeightTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeightTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeightTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndexYears2BreastHeightTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMapTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMapTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMapTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SpecRMapTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolverTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolverTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolverTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalLimitsParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalLimitsParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalLimitsParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalLimitsParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/QuadraticMeanDiameterYieldParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/QuadraticMeanDiameterYieldParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/QuadraticMeanDiameterYieldParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/QuadraticMeanDiameterYieldParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CloseUtilVolumeParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CoefficientParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CoefficientParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/CoefficientParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationModifierParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLCoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLCoefficientParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLCoefficientParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLCoefficientParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/HLNonprimaryCoefficientParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SmallComponentProbabilityParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/VeteranDQParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacerTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacerTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacerTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlMapValueReplacerTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/GroupingStreamingParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/MockStreamingParser.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/MockStreamingParser.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/MockStreamingParser.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/streaming/MockStreamingParser.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ControlledValueParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CoefficientsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CoefficientsTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CoefficientsTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CoefficientsTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSetTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSetTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSetTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDistributionSetTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonModeTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonModeTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonModeTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/PolygonModeTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/MockFileResolver.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/MockFileResolver.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/MockFileResolver.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/MockFileResolver.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java diff --git a/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java similarity index 100% rename from vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java diff --git a/vdyp-common/src/test/resources/application.properties b/vdyp-lib/vdyp-common/src/test/resources/application.properties similarity index 100% rename from vdyp-common/src/test/resources/application.properties rename to vdyp-lib/vdyp-common/src/test/resources/application.properties diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTestValid.csv b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTestValid.csv similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTestValid.csv rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/model/PolygonIdentifierTestValid.csv diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/FIPSTART.CTR b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/FIPSTART.CTR similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/FIPSTART.CTR rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/FIPSTART.CTR diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYPBACK.CTR b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYPBACK.CTR similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYPBACK.CTR rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYPBACK.CTR diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRIADJST.CTR b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRIADJST.CTR similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRIADJST.CTR rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRIADJST.CTR diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRISTART.CTR b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRISTART.CTR similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRISTART.CTR rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/VRISTART.CTR diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE diff --git a/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm b/vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm similarity index 100% rename from vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm rename to vdyp-lib/vdyp-common/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm diff --git a/vdyp-fip/pom.xml b/vdyp-lib/vdyp-fip/pom.xml similarity index 100% rename from vdyp-fip/pom.xml rename to vdyp-lib/vdyp-fip/pom.xml diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParser.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParser.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParser.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSite.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSite.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSite.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSite.java diff --git a/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java similarity index 100% rename from vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java rename to vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java diff --git a/vdyp-fip/src/main/resources/application.properties b/vdyp-lib/vdyp-fip/src/main/resources/application.properties similarity index 100% rename from vdyp-fip/src/main/resources/application.properties rename to vdyp-lib/vdyp-fip/src/main/resources/application.properties diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParserTest.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParserTest.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipPolygonParserTest.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java diff --git a/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/test/FipTestUtils.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/test/FipTestUtils.java similarity index 100% rename from vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/test/FipTestUtils.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/test/FipTestUtils.java diff --git a/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_l1.dat b/vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_l1.dat similarity index 100% rename from vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_l1.dat rename to vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_l1.dat diff --git a/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_ls1.dat b/vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_ls1.dat similarity index 100% rename from vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_ls1.dat rename to vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_ls1.dat diff --git a/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_p1.dat b/vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_p1.dat similarity index 100% rename from vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_p1.dat rename to vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/fip_p1.dat diff --git a/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vp_1.dat b/vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vp_1.dat similarity index 100% rename from vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vp_1.dat rename to vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vp_1.dat diff --git a/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vs_1.dat b/vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vs_1.dat similarity index 100% rename from vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vs_1.dat rename to vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vs_1.dat diff --git a/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vu_1.dat b/vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vu_1.dat similarity index 100% rename from vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vu_1.dat rename to vdyp-lib/vdyp-fip/src/test/resources/ca/bc/gov/nrs/vdyp/fip/test/vu_1.dat diff --git a/vdyp-forward/pom.xml b/vdyp-lib/vdyp-forward/pom.xml similarity index 100% rename from vdyp-forward/pom.xml rename to vdyp-lib/vdyp-forward/pom.xml diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardPass.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardPass.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardPass.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardPass.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PrimarySpeciesDetails.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PrimarySpeciesDetails.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PrimarySpeciesDetails.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PrimarySpeciesDetails.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/FipMode.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/FipMode.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/FipMode.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/FipMode.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/ForwardControlVariableParser.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypForwardDefaultingParser.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonDescriptionParser.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java diff --git a/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java similarity index 100% rename from vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java diff --git a/vdyp-forward/src/main/resources/application.properties b/vdyp-lib/vdyp-forward/src/main/resources/application.properties similarity index 100% rename from vdyp-forward/src/main/resources/application.properties rename to vdyp-lib/vdyp-forward/src/main/resources/application.properties diff --git a/vdyp-forward/src/main/resources/logging.properties b/vdyp-lib/vdyp-forward/src/main/resources/logging.properties similarity index 100% rename from vdyp-forward/src/main/resources/logging.properties rename to vdyp-lib/vdyp-forward/src/main/resources/logging.properties diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngineTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GenusDefinitionMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GenusDefinitionMapTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GenusDefinitionMapTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GenusDefinitionMapTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/model/VdypForwardControlVariablesParserTest.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardControlParserTestApplication.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardControlParserTestApplication.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardControlParserTestApplication.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardControlParserTestApplication.java diff --git a/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardTestUtils.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardTestUtils.java similarity index 100% rename from vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardTestUtils.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/test/VdypForwardTestUtils.java diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP-NoSiteCurves.CTR b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP-NoSiteCurves.CTR similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP-NoSiteCurves.CTR rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP-NoSiteCurves.CTR diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.CTR diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.ini diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP.tcl diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/VDYP7LoggingConfig.txt diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE12A.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BACOE269.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BAFIP16.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP05.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BASP06.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BEC0.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/BGRP.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/Becdef.dat diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/COMPLIM.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/CVADJ.PRM diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DGRP.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQCOE12A.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQFIP16Z.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP05.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/DQSP06.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP111A1.PRM diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/EMP117A1.prm diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/FIPSTKR.PRM diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GB01.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD19.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD20.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GD23.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GMODBA1.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA11.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GROWBA27.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/GRPBA1.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_40.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/PCT_407.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REG01.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA25.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBA2C.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAC.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBAV01.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGBREAK.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ18.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ24.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ26.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQ4C.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQC.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQI04.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGDQL2.coe diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGHL1C.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGPR1C.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGV1C.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVCU.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVDU.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVU.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGVWU.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLP.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPA.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPB.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/REGYHLPC.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIAGEMAX.PRM diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SIEQN.PRM diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/SP0DEF_v0.dat diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP309.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/TOP98.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/UPPERB02.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI1.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI2.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VCG_VRI3.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETDQ2.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VETVOL1.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VGRPDEF1.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/VTOTREG4.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA309.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA405.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDBA407.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ259.DAT diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ309.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/YLDDQ45.COE diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/coe/mod19813.prm diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_p1.dat b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_p1.dat similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_p1.dat rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_p1.dat diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_s1.dat b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_s1.dat similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_s1.dat rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_s1.dat diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_u1.dat b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_u1.dat similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_u1.dat rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_u1.dat diff --git a/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_y1.dat b/vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_y1.dat similarity index 100% rename from vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_y1.dat rename to vdyp-lib/vdyp-forward/src/test/resources/ca/bc/gov/nrs/vdyp/test/vin_y1.dat diff --git a/vdyp-si32/pom.xml b/vdyp-lib/vdyp-si32/pom.xml similarity index 100% rename from vdyp-si32/pom.xml rename to vdyp-lib/vdyp-si32/pom.xml diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32Errors.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32Errors.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32Errors.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/SI32Errors.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZone.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZone.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZone.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZone.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZoneMethods.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZoneMethods.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZoneMethods.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/bec/BecZoneMethods.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDead.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDead.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDead.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDead.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDetails.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDetails.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDetails.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsDetails.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForGenus.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForGenus.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForGenus.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForGenus.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForSpecies.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForSpecies.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForSpecies.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsForSpecies.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsHelper.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsHelper.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsHelper.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionCoefficientsHelper.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedEcoZone.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedEcoZone.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedEcoZone.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedEcoZone.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedGenera.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedGenera.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedGenera.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedGenera.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedSpecies.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedSpecies.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedSpecies.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsBiomassConversionSupportedSpecies.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDeadConversionParams.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDeadConversionParams.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDeadConversionParams.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDeadConversionParams.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDensity.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDensity.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDensity.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsDensity.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsLiveConversionParams.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsLiveConversionParams.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsLiveConversionParams.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsLiveConversionParams.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsMethods.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsMethods.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsMethods.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsMethods.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSP0Densities.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSP0Densities.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSP0Densities.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSP0Densities.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSpeciesMethods.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSpeciesMethods.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSpeciesMethods.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsSpeciesMethods.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeClass.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeClass.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeClass.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeClass.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeGenus.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeGenus.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeGenus.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeGenus.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeSpecies.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeSpecies.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeSpecies.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/cfs/CfsTreeSpecies.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SI32Enum.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SI32Enum.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SI32Enum.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SI32Enum.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SpeciesRegion.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SpeciesRegion.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SpeciesRegion.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/enumerations/SpeciesRegion.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/NameFormat.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/NameFormat.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/NameFormat.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/NameFormat.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/ParamLookupFallback.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/ParamLookupFallback.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/ParamLookupFallback.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/ParamLookupFallback.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/site/SiteTool.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP0Name.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP0Name.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP0Name.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP0Name.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP64Name.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP64Name.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP64Name.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SP64Name.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesDetails.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesDetails.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesDetails.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesDetails.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesTable.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesTable.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesTable.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/SpeciesTable.java diff --git a/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/VdypMethods.java b/vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/VdypMethods.java similarity index 100% rename from vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/VdypMethods.java rename to vdyp-lib/vdyp-si32/src/main/java/ca/bc/gov/nrs/vdyp/si32/vdyp/VdypMethods.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/BecZoneMethodsTest.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/BecZoneMethodsTest.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/BecZoneMethodsTest.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/BecZoneMethodsTest.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsBioMassConversionCoefficientsTests.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsBioMassConversionCoefficientsTests.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsBioMassConversionCoefficientsTests.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsBioMassConversionCoefficientsTests.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsMethodsTest.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsMethodsTest.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsMethodsTest.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/CfsMethodsTest.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SI32EnumIteratorTest.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SI32EnumIteratorTest.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SI32EnumIteratorTest.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SI32EnumIteratorTest.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SiteToolTest.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SpeciesTableTest.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SpeciesTableTest.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SpeciesTableTest.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/SpeciesTableTest.java diff --git a/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/VdypMethodsTest.java b/vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/VdypMethodsTest.java similarity index 100% rename from vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/VdypMethodsTest.java rename to vdyp-lib/vdyp-si32/src/test/java/ca/bc/gov/nrs/vdyp/si32/VdypMethodsTest.java diff --git a/vdyp-sindex/pom.xml b/vdyp-lib/vdyp-sindex/pom.xml similarity index 100% rename from vdyp-sindex/pom.xml rename to vdyp-lib/vdyp-sindex/pom.xml diff --git a/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java b/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java similarity index 100% rename from vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java rename to vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java diff --git a/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java b/vdyp-lib/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java similarity index 100% rename from vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java rename to vdyp-lib/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java diff --git a/vdyp-vri/pom.xml b/vdyp-lib/vdyp-vri/pom.xml similarity index 100% rename from vdyp-vri/pom.xml rename to vdyp-lib/vdyp-vri/pom.xml diff --git a/vdyp-vri/resources/application.properties b/vdyp-lib/vdyp-vri/resources/application.properties similarity index 100% rename from vdyp-vri/resources/application.properties rename to vdyp-lib/vdyp-vri/resources/application.properties diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParser.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParser.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParser.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSite.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSite.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSite.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSite.java diff --git a/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java similarity index 100% rename from vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java rename to vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java diff --git a/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/test/VriTestUtils.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/test/VriTestUtils.java similarity index 100% rename from vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/test/VriTestUtils.java rename to vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/test/VriTestUtils.java diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vp_1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vp_1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vp_1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vp_1.dat diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_l1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_l1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_l1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_l1.dat diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_p1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_p1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_p1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_p1.dat diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_si1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_si1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_si1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_si1.dat diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_sp1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_sp1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_sp1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vri_sp1.dat diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vs_1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vs_1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vs_1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vs_1.dat diff --git a/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vu_1.dat b/vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vu_1.dat similarity index 100% rename from vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vu_1.dat rename to vdyp-lib/vdyp-vri/src/test/resources/ca/bc/gov/nrs/vdyp/vri/test/vu_1.dat From 3775ae5b1b0507c6b3f2baac45f26ccd939d1f56 Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Wed, 31 Jul 2024 15:42:27 -0700 Subject: [PATCH 28/66] Update model classes in Common to have Site be a child of Species --- .../application/VdypStartApplication.java | 12 +- .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 66 +- .../gov/nrs/vdyp/model/BaseVdypPolygon.java | 6 +- .../bc/gov/nrs/vdyp/model/BaseVdypSite.java | 1 + .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 97 ++- .../gov/nrs/vdyp/model/ModelClassBuilder.java | 8 + .../gov/nrs/vdyp/model/SingleSiteLayer.java | 24 +- .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 20 +- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 39 +- .../application/VdypStartApplicationTest.java | 579 +++++++++--------- .../nrs/vdyp/application/test/TestLayer.java | 8 - .../vdyp/application/test/TestSpecies.java | 25 +- .../test/TestStartApplication.java | 2 +- .../vdyp/common/EstimationMethodsTest.java | 11 +- .../io/write/VriAdjustInputWriterTest.java | 106 ++-- .../bc/gov/nrs/vdyp/model/VdypLayerTest.java | 139 +---- .../gov/nrs/vdyp/model/VdypSpeciesTest.java | 14 +- 17 files changed, 551 insertions(+), 606 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index e957a2ef8..e9372e8dd 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -69,7 +69,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; -public abstract class VdypStartApplication

      , S, I>, L extends BaseVdypLayer & InputLayer, S extends BaseVdypSpecies, I extends BaseVdypSite> +public abstract class VdypStartApplication

      , S, I>, L extends BaseVdypLayer & InputLayer, S extends BaseVdypSpecies, I extends BaseVdypSite> extends VdypApplication implements Closeable { private static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); @@ -170,8 +170,8 @@ protected static void doMain(VdypStartApplication app, final String. public EstimationMethods estimationMethods; - static final Comparator PERCENT_GENUS_DESCENDING = Utils - .compareUsing(BaseVdypSpecies::getPercentGenus).reversed(); + static final Comparator> PERCENT_GENUS_DESCENDING = Utils + .compareUsing(BaseVdypSpecies::getPercentGenus).reversed(); /** * When finding primary species these genera should be combined @@ -263,7 +263,7 @@ public void close() throws IOException { closeVriWriter(); } - protected Coefficients getCoeForSpecies(BaseVdypSpecies species, ControlKey controlKey) { + protected Coefficients getCoeForSpecies(BaseVdypSpecies species, ControlKey controlKey) { var coeMap = Utils.>expectParsedControl(controlMap, controlKey, java.util.Map.class); return coeMap.get(species.getGenus()); } @@ -300,7 +300,7 @@ protected float getPercentTotal(L layer) throws StandProcessingException { return percentTotal; } - protected abstract S copySpecies(S toCopy, Consumer> config); + protected abstract S copySpecies(S toCopy, Consumer> config); /** * Returns the primary, and secondary if present species records as a one or two element list. @@ -633,7 +633,7 @@ protected float estimatePrimaryBaseArea( public S leadGenus(L fipLayer) { return fipLayer.getSpecies().values().stream() - .sorted(Utils.compareUsing(BaseVdypSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); + .sorted(Utils.compareUsing(BaseVdypSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); } protected L getPrimaryLayer(P poly) throws StandProcessingException { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index 755757a3c..379680a8b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -11,12 +11,11 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -public abstract class BaseVdypLayer { +public abstract class BaseVdypLayer, I extends BaseVdypSite> { private final PolygonIdentifier polygonIdentifier; private final LayerType layerType; private LinkedHashMap species = new LinkedHashMap<>(); - private LinkedHashMap sites = new LinkedHashMap<>(); private Optional inventoryTypeGroup = Optional.empty(); protected BaseVdypLayer( @@ -52,17 +51,9 @@ public void setSpecies(Collection species) { } public LinkedHashMap getSites() { - return sites; - } - - public void setSites(Map sites) { - this.sites.clear(); - this.sites.putAll(sites); - } - - public void setSites(Collection sites) { - this.sites.clear(); - sites.forEach(spec -> this.sites.put(spec.getSiteGenus(), spec)); + var result = new LinkedHashMap(species.size()); + species.forEach((key,spec)->spec.getSite().ifPresent(site->result.put(key, site)) ); + return result; } public Optional getInventoryTypeGroup() { @@ -73,7 +64,7 @@ public void setInventoryTypeGroup(Optional inventoryTypeGroup) { this.inventoryTypeGroup = inventoryTypeGroup; } - public abstract static class Builder, S extends BaseVdypSpecies, I extends BaseVdypSite, SB extends BaseVdypSpecies.Builder, IB extends BaseVdypSite.Builder> + public abstract static class Builder, S extends BaseVdypSpecies, I extends BaseVdypSite, SB extends BaseVdypSpecies.Builder, IB extends BaseVdypSite.Builder> extends ModelClassBuilder { protected Optional polygonIdentifier = Optional.empty(); protected Optional layerType = Optional.empty(); @@ -124,16 +115,6 @@ public Builder addSpecies(S species) { return this; } - public Builder addSite(Consumer config) { - siteBuilders.add(config); - return this; - } - - public Builder addSite(I site) { - this.sites.add(site); - return this; - } - public Builder inventoryTypeGroup(int inventoryTypeGroup) { return this.inventoryTypeGroup(Optional.of(inventoryTypeGroup)); } @@ -155,37 +136,7 @@ public Builder copy(T toCopy) { return this; } - public Builder - adaptSites(BaseVdypLayer toCopy, BiConsumer config) { - toCopy.getSites().values().forEach(siteToCopy -> { - this.adaptSite(siteToCopy, config); - }); - return this; - } - - public Builder adaptSite(I2 toCopy, BiConsumer config) { - this.addSite(builder -> { - builder.adapt(toCopy); - builder.polygonIdentifier = Optional.empty(); - builder.layerType = Optional.empty(); - config.accept(builder, toCopy); - }); - return this; - } - - public Builder copySites(T toCopy, BiConsumer config) { - toCopy.getSites().values().forEach(siteToCopy -> { - this.addSite(builder -> { - builder.copy(siteToCopy); - builder.polygonIdentifier = Optional.empty(); - builder.layerType = Optional.empty(); - config.accept(builder, siteToCopy); - }); - }); - return this; - } - - public Builder + public , I2 extends BaseVdypSite> Builder adaptSpecies(BaseVdypLayer toCopy, BiConsumer config) { toCopy.getSpecies().values().forEach(speciesToCopy -> { this.addSpecies(builder -> { @@ -232,16 +183,12 @@ protected void check(Collection errors) { protected abstract S buildSpecies(Consumer config); - protected abstract I buildSite(Consumer config); - /** * Build any builders for child objects and store the results. This will clear the stored child builders. */ public void buildChildren() { speciesBuilders.stream().map(this::buildSpecies).collect(Collectors.toCollection(() -> species)); speciesBuilders.clear(); - siteBuilders.stream().map(this::buildSite).collect(Collectors.toCollection(() -> sites)); - siteBuilders.clear(); } @Override @@ -249,7 +196,6 @@ protected void postProcess(T result) { super.postProcess(result); buildChildren(); result.setSpecies(species); - result.setSites(sites); } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java index 465f1f750..fa1d3af5b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java @@ -12,7 +12,7 @@ import java.util.function.Function; import java.util.stream.Collectors; -public abstract class BaseVdypPolygon, PA, SP extends BaseVdypSpecies, SI extends BaseVdypSite> { +public abstract class BaseVdypPolygon, PA, SP extends BaseVdypSpecies, SI extends BaseVdypSite> { private PolygonIdentifier polygonIdentifier; // FIP_P/POLYDESC private PA percentAvailable; // FIP_P2/PCTFLAND @@ -107,10 +107,10 @@ protected abstract static class Builder< // T extends BaseVdypPolygon, // L extends BaseVdypLayer, // PA, // - SP extends BaseVdypSpecies, // + SP extends BaseVdypSpecies, // SI extends BaseVdypSite, // LB extends BaseVdypLayer.Builder, // - SPB extends BaseVdypSpecies.Builder, // + SPB extends BaseVdypSpecies.Builder, // SIB extends BaseVdypSite.Builder> // extends ModelClassBuilder { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java index 8710b16d0..13baa530a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java @@ -172,6 +172,7 @@ protected void check(Collection errors) { requirePresent(layerType, "layerType", errors); requirePresent(siteGenus, "siteGenus", errors); } + } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 46ff8fca3..4a9ef2af2 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -4,9 +4,12 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Consumer; + import ca.bc.gov.nrs.vdyp.common.Computed; -public abstract class BaseVdypSpecies { +public abstract class BaseVdypSpecies { private final PolygonIdentifier polygonIdentifier; // FIP_P/POLYDESC private final LayerType layerType; // This is also represents the distinction between data stored in // FIPL_1(A) and FIP_V(A). Where VDYP7 stores both and looks at certain values @@ -23,24 +26,16 @@ public abstract class BaseVdypSpecies { private float fractionGenus; // FRBASP0/FR private Map speciesPercent; // Map from + private Optional site; protected BaseVdypSpecies( - PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, float percentGenus + PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, float percentGenus, Optional site ) { this.polygonIdentifier = polygonIdentifier; this.layerType = layerType; this.genus = genus; this.setPercentGenus(percentGenus); - } - - protected BaseVdypSpecies(BaseVdypSpecies toCopy) { - this( - toCopy.getPolygonIdentifier(), // - toCopy.getLayerType(), // - toCopy.getGenus(), // - toCopy.getPercentGenus() - ); - setSpeciesPercent(toCopy.getSpeciesPercent()); + this.site = site; } public PolygonIdentifier getPolygonIdentifier() { @@ -82,61 +77,85 @@ public String getGenus() { return genus; } - public abstract static class Builder extends ModelClassBuilder { + public Optional getSite() { + return site; + } + + public abstract static class Builder, I extends BaseVdypSite, IB extends BaseVdypSite.Builder> + extends ModelClassBuilder { protected Optional polygonIdentifier = Optional.empty(); protected Optional layerType = Optional.empty(); protected Optional genus = Optional.empty(); protected Optional percentGenus = Optional.empty(); protected Optional fractionGenus = Optional.empty(); protected Map speciesPercent = new LinkedHashMap<>(); + protected Optional> siteBuilder = Optional.empty(); + protected Optional site = Optional.empty(); - public Builder polygonIdentifier(PolygonIdentifier polygonIdentifier) { + public Builder polygonIdentifier(PolygonIdentifier polygonIdentifier) { this.polygonIdentifier = Optional.of(polygonIdentifier); return this; } - public Builder polygonIdentifier(String polygonIdentifier) { + public Builder polygonIdentifier(String polygonIdentifier) { this.polygonIdentifier = Optional.of(PolygonIdentifier.split(polygonIdentifier)); return this; } - public Builder polygonIdentifier(String base, int year) { + public Builder polygonIdentifier(String base, int year) { this.polygonIdentifier = Optional.of(new PolygonIdentifier(base, year)); return this; } - public Builder layerType(LayerType layer) { + public Builder layerType(LayerType layer) { this.layerType = Optional.of(layer); return this; } - public Builder genus(String genus) { + public Builder genus(String genus) { this.genus = Optional.of(genus); return this; } - public Builder percentGenus(float percentGenus) { + public Builder percentGenus(float percentGenus) { this.percentGenus = Optional.of(percentGenus); return this; } - protected Builder fractionGenus(float fractionGenus) { + protected Builder fractionGenus(float fractionGenus) { this.fractionGenus = Optional.of(fractionGenus); return this; } - public Builder addSpecies(String id, float percent) { + public Builder addSpecies(String id, float percent) { this.speciesPercent.put(id, percent); return this; } - public Builder addSpecies(Map toAdd) { + public Builder addSpecies(Map toAdd) { this.speciesPercent.putAll(toAdd); return this; } - public Builder copy(T toCopy) { - return adapt(toCopy); + public Builder copy(T toCopy) { + return this.adapt(toCopy); + } + + public Builder addSite(Consumer config) { + this.siteBuilder = Optional.of(config); + this.site = Optional.empty(); + return this; + } + + public Builder addSite(I site) { + addSite(Optional.of(site)); + return this; + } + + public Builder addSite(Optional site) { + this.site = site; + this.siteBuilder = Optional.empty(); + return this; } @Override @@ -153,8 +172,14 @@ protected void postProcess(T result) { result.setSpeciesPercent(speciesPercent); this.fractionGenus.ifPresent(result::setFractionGenus); } + + @Override + protected void preProcess() { + super.preProcess(); + site = siteBuilder.map(this::buildSite).or(()->site); + } - public Builder adapt(BaseVdypSpecies toCopy) { + public Builder adapt(BaseVdypSpecies toCopy) { polygonIdentifier(toCopy.getPolygonIdentifier()); layerType(toCopy.getLayerType()); genus(toCopy.getGenus()); @@ -169,6 +194,28 @@ public Builder adapt(BaseVdypSpecies toCopy) { return this; } + public Builder adaptSite(I2 toCopy, BiConsumer config) { + this.addSite(builder -> { + builder.adapt(toCopy); + builder.polygonIdentifier = Optional.empty(); + builder.layerType = Optional.empty(); + config.accept(builder, toCopy); + }); + return this; + } + + public Builder copySite(I toCopy, BiConsumer config) { + this.addSite(builder -> { + builder.copy(toCopy); + builder.siteGenus = Optional.empty(); + builder.polygonIdentifier = Optional.empty(); + builder.layerType = Optional.empty(); + config.accept(builder, toCopy); + }); + return this; + } + + protected abstract I buildSite(Consumer config); } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java index c66e902ff..88291eb7f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java @@ -39,6 +39,7 @@ protected static void requirePresent(Optional holder, String name, Collection */ public T build() { Collection errors = new LinkedList<>(); + preProcess(); check(errors); if (!errors.isEmpty()) { throw new IllegalStateException(String.join(", ", errors)); @@ -48,6 +49,13 @@ public T build() { return result; } + /** + * Additional steps before building + */ + protected void preProcess() { + // Do Nothing + } + /** * Run the constructor, assuming all required properties are present */ diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java index 58f0c6d6b..7e3ee91d2 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/SingleSiteLayer.java @@ -1,11 +1,9 @@ package ca.bc.gov.nrs.vdyp.model; -import java.util.Collection; import java.util.LinkedHashMap; -import java.util.Map; import java.util.Optional; -public class SingleSiteLayer extends BaseVdypLayer { +public class SingleSiteLayer, I extends BaseVdypSite> extends BaseVdypLayer { protected SingleSiteLayer( PolygonIdentifier polygonIdentifier, LayerType layer, Optional inventoryTypeGroup @@ -57,24 +55,4 @@ public LinkedHashMap getSites() { return result; } - @Override - public void setSites(Map sites) { - if (sites.size() > 1) { - throw new IllegalArgumentException( - "Layer type " + this.getClass().getSimpleName() + " can only have one site" - ); - } - super.setSites(sites); - } - - @Override - public void setSites(Collection sites) { - if (sites.size() > 1) { - throw new IllegalArgumentException( - "Layer type " + this.getClass().getSimpleName() + " can only have one site" - ); - } - super.setSites(sites); - } - } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 71cc00a0e..b910126cc 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -240,6 +240,16 @@ public void quadMeanDiameter(float small, float u1, float u2, float u3, float u4 public void quadMeanDiameter(float height) { this.quadMeanDiameter = Utils.utilizationVector(height); } + + protected UtilizationVector wholeStemVolume = VdypUtilizationHolder.emptyUtilization(); + + public void wholeStemVolume(float small, float u1, float u2, float u3, float u4) { + this.wholeStemVolume = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void wholeStemVolume(float volume) { + this.wholeStemVolume = Utils.utilizationVector(volume); + } @Override protected void postProcess(VdypLayer layer) { @@ -248,6 +258,7 @@ protected void postProcess(VdypLayer layer) { layer.setBaseAreaByUtilization(baseArea); layer.setTreesPerHectareByUtilization(treesPerHectare); layer.setQuadraticMeanDiameterByUtilization(quadMeanDiameter); + layer.setWholeStemVolumeByUtilization(wholeStemVolume); } @Override @@ -269,15 +280,6 @@ protected VdypSpecies buildSpecies(Consumer config) { }); } - @Override - protected VdypSite buildSite(Consumer config) { - return VdypSite.build(builder -> { - config.accept(builder); - builder.polygonIdentifier(polygonIdentifier.get()); - builder.layerType(layerType.get()); - }); - } - public void baseAreaByUtilization(UtilizationVector utilizationVector) { // TODO Auto-generated method stub diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index e3de41be5..ce9c26025 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -6,7 +6,7 @@ import ca.bc.gov.nrs.vdyp.common.Utils; -public class VdypSpecies extends BaseVdypSpecies implements VdypUtilizationHolder { +public class VdypSpecies extends BaseVdypSpecies implements VdypUtilizationHolder { private UtilizationVector baseAreaByUtilization = Utils.utilizationVector(); // LVCOM/BA private UtilizationVector loreyHeightByUtilization = Utils.heightVector(); // LVCOM/HL @@ -24,20 +24,16 @@ public class VdypSpecies extends BaseVdypSpecies implements VdypUtilizationHolde int breakageGroup; public VdypSpecies( - PolygonIdentifier polygonIdentifier, LayerType layer, String genus, float percentGenus, // - int volumeGroup, int decayGroup, int breakageGroup + PolygonIdentifier polygonIdentifier, LayerType layer, String genus, float percentGenus, + Optional site, int volumeGroup, int decayGroup, int breakageGroup ) { - super(polygonIdentifier, layer, genus, percentGenus); + super(polygonIdentifier, layer, genus, percentGenus, site); this.volumeGroup = volumeGroup; this.decayGroup = decayGroup; this.breakageGroup = breakageGroup; } - public VdypSpecies(BaseVdypSpecies toCopy) { - super(toCopy); - } - /** * Base area for utilization index -1 through 4 */ @@ -210,7 +206,7 @@ public static VdypSpecies build(VdypLayer layer, Consumer config) { return result; } - public static class Builder extends BaseVdypSpecies.Builder { + public static class Builder extends BaseVdypSpecies.Builder { protected Optional volumeGroup = Optional.empty(); protected Optional decayGroup = Optional.empty(); protected Optional breakageGroup = Optional.empty(); @@ -254,6 +250,16 @@ public void quadMeanDiameter(float small, float u1, float u2, float u3, float u4 public void quadMeanDiameter(float height) { this.quadMeanDiameter = Utils.utilizationVector(height); } + + protected UtilizationVector wholeStemVolume = VdypUtilizationHolder.emptyUtilization(); + + public void wholeStemVolume(float small, float u1, float u2, float u3, float u4) { + this.wholeStemVolume = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void wholeStemVolume(float volume) { + this.wholeStemVolume = Utils.utilizationVector(volume); + } @Override protected void check(Collection errors) { @@ -279,21 +285,34 @@ protected void postProcess(VdypSpecies spec) { spec.setBaseAreaByUtilization(baseArea); spec.setTreesPerHectareByUtilization(treesPerHectare); spec.setQuadraticMeanDiameterByUtilization(quadMeanDiameter); + spec.setWholeStemVolumeByUtilization(wholeStemVolume); } @Override protected VdypSpecies doBuild() { + return new VdypSpecies( polygonIdentifier.get(), // layerType.get(), // genus.get(), // percentGenus.get(), // + site, volumeGroup.get(), // decayGroup.get(), // breakageGroup.get() // ); } - + + @Override + protected VdypSite buildSite(Consumer config) { + return VdypSite.build(builder -> { + config.accept(builder); + builder.polygonIdentifier(polygonIdentifier.get()); + builder.layerType(layerType.get()); + builder.siteGenus(genus); + }); + } + public Builder volumeGroup(int i) { this.volumeGroup = Optional.of(i); return this; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index b2d6252d4..042af5dd9 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -701,33 +701,29 @@ void testSimple() throws Exception { var bec = Utils.getBec("CWH", controlMap); - var layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(82.8000031f); - - }, s -> { - s.ageTotal(Optional.of(85f)); - s.height(Optional.of(38.2999992f)); - s.siteIndex(Optional.of(28.6000004f)); - s.yearsToBreastHeight(Optional.of(5.4000001f)); - s.siteCurveNumber(Optional.of(34)); - s.siteGenus(Optional.of("H")); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(82.8000031f); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(85f); + ib.height(38.2999992f); + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var result = app.estimatePrimaryBaseArea(layer, bec, 1f, 79.5999985f, 3.13497972f); assertThat(result, closeTo(62.6653595f)); @@ -742,32 +738,29 @@ void testHeightCloseToA2() throws Exception { var bec = Utils.getBec("CWH", controlMap); - var layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(82.8000031f); - }, s -> { - s.ageTotal(Optional.of(85f)); - s.height(Optional.of(10.1667995f)); // Altered this in the debugger while running VDYP7 - s.siteIndex(Optional.of(28.6000004f)); - s.yearsToBreastHeight(Optional.of(5.4000001f)); - s.siteCurveNumber(Optional.of(34)); - s.siteGenus(Optional.of("H")); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(82.8000031f); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(85f); + ib.height(10.1667995f); // Altered this in the debugger while running VDYP7 + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var result = app.estimatePrimaryBaseArea(layer, bec, 1f, 79.5999985f, 3.13497972f); assertThat(result, closeTo(23.1988659f)); @@ -782,32 +775,29 @@ void testLowCrownClosure() throws Exception { var bec = Utils.getBec("CWH", controlMap); - var layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(9f); // Altered this in the debugger while running VDYP7 - }, s -> { - s.ageTotal(Optional.of(85f)); - s.height(Optional.of(38.2999992f)); - s.siteIndex(Optional.of(28.6000004f)); - s.yearsToBreastHeight(Optional.of(5.4000001f)); - s.siteCurveNumber(Optional.of(34)); - s.siteGenus(Optional.of("H")); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(9f);// Altered this in the debugger while running VDYP7 + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(85f); + ib.height(38.2999992f); + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var result = app.estimatePrimaryBaseArea(layer, bec, 1f, 79.5999985f, 3.13497972f); assertThat(result, closeTo(37.6110077f)); @@ -822,32 +812,29 @@ void testLowResult() throws Exception { var bec = Utils.getBec("CWH", controlMap); - TestLayer layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(82.8000031f); - }, s -> { - s.ageTotal(85f); - s.height(7f); // Altered this in the debugger while running VDYP7 - s.siteIndex(28.6000004f); - s.yearsToBreastHeight(5.4000001f); - s.siteCurveNumber(34); - s.siteGenus("H"); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(82.8000031f); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(85f); + ib.height(7f); // Altered this in the debugger while running VDYP7 + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var ex = assertThrows( LowValueException.class, () -> app.estimatePrimaryBaseArea(layer, bec, 1f, 79.5999985f, 3.13497972f) @@ -872,32 +859,29 @@ void testSimple() throws Exception { var becLookup = BecDefinitionParser.getBecs(controlMap); var bec = becLookup.get("CWH").get(); - var layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(82.8000031f); - }, s -> { - s.ageTotal(85f); - s.height(38.2999992f); - s.siteIndex(28.6000004f); - s.yearsToBreastHeight(5.4000001f); - s.siteCurveNumber(34); - s.siteGenus("H"); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(82.8000031f); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(85f); + ib.height(38.2999992f); + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var result = app.estimatePrimaryQuadMeanDiameter(layer, bec, 79.5999985f, 3.13497972f); assertThat(result, closeTo(32.5390053f)); @@ -913,32 +897,29 @@ void testHeightLessThanA5() throws Exception { var becLookup = BecDefinitionParser.getBecs(controlMap); var bec = becLookup.get("CWH").get(); - var layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(82.8000031f); - }, s -> { - s.ageTotal(85f); - s.height(4.74730005f); - s.siteIndex(28.6000004f); - s.yearsToBreastHeight(5.4000001f); - s.siteCurveNumber(34); - s.siteGenus("H"); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(82.8000031f); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(85f); + ib.height(4.74730005f); + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var result = app.estimatePrimaryQuadMeanDiameter(layer, bec, 79.5999985f, 3.13497972f); assertThat(result, closeTo(7.6f)); @@ -954,33 +935,29 @@ void testResultLargerThanUpperBound() throws Exception { var becLookup = BecDefinitionParser.getBecs(controlMap); var bec = becLookup.get("CWH").get(); - // Tweak the values to produce a very large DQ - var layer = getTestPrimaryLayer(polygonId, l -> { - l.crownClosure(82.8000031f); - }, s -> { - s.ageTotal(350f); - s.height(80f); - s.siteIndex(28.6000004f); - s.yearsToBreastHeight(5.4000001f); - s.siteCurveNumber(34); - s.siteGenus("H"); - }); - - var spec1 = getTestSpecies(polygonId, LayerType.PRIMARY, "B", s -> { - s.setPercentGenus(33f); - s.setFractionGenus(0.330000013f); - }); - var spec2 = getTestSpecies(polygonId, LayerType.PRIMARY, "H", s -> { - s.setPercentGenus(67f); - s.setFractionGenus(0.670000017f); + var layer = TestLayer.build(lb -> { + lb.polygonIdentifier(polygonId); + lb.layerType(LayerType.PRIMARY); + lb.crownClosure(82.8000031f); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(33f); + sb.addSpecies("B", 100f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(67f); + sb.addSpecies("H", 100f); + sb.addSite(ib -> { + ib.ageTotal(350f); + ib.height(80f); + ib.siteIndex(28.6000004f); + ib.yearsToBreastHeight(5.4000001f); + ib.siteCurveNumber(34); + }); + }); }); - Map allSpecies = new LinkedHashMap<>(); - allSpecies.put(spec1.getGenus(), spec1); - allSpecies.put(spec2.getGenus(), spec2); - - layer.setSpecies(allSpecies); - var result = app.estimatePrimaryQuadMeanDiameter(layer, bec, 350f - 5.4000001f, 3.13497972f); assertThat(result, closeTo(61.1f)); // Clamp to the COE043/UPPER_BA_BY_CI_S0_P DQ value for this species @@ -1035,17 +1012,16 @@ void testWithoutVeteran() throws Exception { lb.crownClosure(60f); - lb.addSite(ib -> { - ib.siteGenus("L"); - ib.ageTotal(60f); - ib.height(15f); - ib.siteIndex(5f); - ib.yearsToBreastHeight(8.5f); - }); - lb.addSpecies(sb -> { sb.genus("L"); sb.percentGenus(10); + sb.addSite(ib -> { + ib.siteGenus("L"); + ib.ageTotal(60f); + ib.height(15f); + ib.siteIndex(5f); + ib.yearsToBreastHeight(8.5f); + }); }); lb.addSpecies(sb -> { sb.genus("PL"); @@ -1088,14 +1064,6 @@ public VdypApplicationIdentifier getId() { lb.crownClosure(82.8f); - lb.addSite(ib -> { - ib.siteGenus("H"); - ib.ageTotal(45f); - ib.height(24.3f); - ib.siteIndex(28.7f); - ib.yearsToBreastHeight(7.1f); - }); - lb.addSpecies(sb -> { sb.genus("B"); sb.percentGenus(15); @@ -1107,6 +1075,13 @@ public VdypApplicationIdentifier getId() { lb.addSpecies(sb -> { sb.genus("H"); sb.percentGenus(77); + sb.addSite(ib -> { + ib.ageTotal(45f); + ib.height(24.3f); + ib.siteIndex(28.7f); + ib.yearsToBreastHeight(7.1f); + }); + }); lb.addSpecies(sb -> { sb.genus("S"); @@ -1118,14 +1093,17 @@ public VdypApplicationIdentifier getId() { lb.crownClosure(4f); - lb.addSite(ib -> { - ib.siteGenus("H"); - ib.ageTotal(105f); - ib.height(26.2f); - ib.siteIndex(16.7f); - ib.yearsToBreastHeight(7.1f); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(100); + sb.addSite(ib -> { + ib.siteGenus("H"); + ib.ageTotal(105f); + ib.height(26.2f); + ib.siteIndex(16.7f); + ib.yearsToBreastHeight(7.1f); + }); }); - }); }); @@ -1221,122 +1199,132 @@ void testEstimate() throws ProcessingException, IOException { builder.biogeoclimaticZone("CWH"); builder.percentAvailable(Optional.of(100f)); }); - VdypLayer layer = VdypLayer.build(builder -> { - builder.polygonIdentifier("Test", 2024); - builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.ageTotal(55f); - siteBuilder.yearsToBreastHeight(1f); - siteBuilder.height(31f); - siteBuilder.siteGenus("H"); + + var layer = VdypLayer.build(lb -> { + lb.polygonIdentifier("Test", 2024); + lb.layerType(LayerType.PRIMARY); + lb.addSpecies(sb -> { + sb.genus("B"); + sb.percentGenus(20f); + sb.volumeGroup(-1); + sb.decayGroup(-1); + sb.breakageGroup(-1); + + sb.loreyHeight(38.6004372f); + sb.baseArea(0.397305071f); + sb.treesPerHectare(5.04602766f); + sb.quadMeanDiameter(31.6622887f); + sb.wholeStemVolume(635.659668f); }); - }); + lb.addSpecies(sb -> { + sb.genus("C"); + sb.percentGenus(20f); + sb.volumeGroup(-1); + sb.decayGroup(-1); + sb.breakageGroup(-1); + sb.loreyHeight(22.8001652f); + sb.baseArea(5.08774281f); + sb.treesPerHectare(92.4298019f); + sb.quadMeanDiameter(26.4735165f); + sb.wholeStemVolume(6.35662031f); + }); + lb.addSpecies(sb -> { + sb.genus("D"); + sb.percentGenus(20f); + sb.volumeGroup(-1); + sb.decayGroup(-1); + sb.breakageGroup(-1); + sb.loreyHeight(33.5375252f); + sb.baseArea(29.5411568f); + sb.treesPerHectare(326.800781f); + sb.quadMeanDiameter(33.9255791f); + sb.wholeStemVolume(44.496151f); + }); + lb.addSpecies(sb -> { + sb.genus("H"); + sb.percentGenus(20f); + sb.volumeGroup(-1); + sb.decayGroup(-1); + sb.breakageGroup(-1); + sb.loreyHeight(24.3451157f); + sb.baseArea(5.50214148f); + sb.treesPerHectare(152.482513f); + sb.quadMeanDiameter(21.4343796f); + sb.wholeStemVolume(470.388489f); + sb.addSite(siteBuilder -> { + siteBuilder.ageTotal(55f); + siteBuilder.yearsToBreastHeight(1f); + siteBuilder.height(31f); + }); - layer.getLoreyHeightByUtilization().setAll(31.3307209f); - layer.getBaseAreaByUtilization().setAll(44.6249847f); - layer.getTreesPerHectareByUtilization().setAll(620.484802f); - layer.getQuadraticMeanDiameterByUtilization().setAll(30.2606697f); - layer.getWholeStemVolumeByUtilization().setAll(635.659668f); - - var spec1 = VdypSpecies.build(layer, builder -> { - builder.genus("B"); - builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); - }); - spec1.getLoreyHeightByUtilization().setAll(38.6004372f); - spec1.getBaseAreaByUtilization().setAll(0.397305071f); - spec1.getTreesPerHectareByUtilization().setAll(5.04602766f); - spec1.getQuadraticMeanDiameterByUtilization().setAll(31.6622887f); - spec1.getWholeStemVolumeByUtilization().setAll(635.659668f); - var spec2 = VdypSpecies.build(layer, builder -> { - builder.genus("C"); - builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); - }); - spec2.getLoreyHeightByUtilization().setAll(22.8001652f); - spec2.getBaseAreaByUtilization().setAll(5.08774281f); - spec2.getTreesPerHectareByUtilization().setAll(92.4298019f); - spec2.getQuadraticMeanDiameterByUtilization().setAll(26.4735165f); - spec2.getWholeStemVolumeByUtilization().setAll(6.35662031f); - var spec3 = VdypSpecies.build(layer, builder -> { - builder.genus("D"); - builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); - }); - spec3.getLoreyHeightByUtilization().setAll(33.5375252f); - spec3.getBaseAreaByUtilization().setAll(29.5411568f); - spec3.getTreesPerHectareByUtilization().setAll(326.800781f); - spec3.getQuadraticMeanDiameterByUtilization().setAll(33.9255791f); - spec3.getWholeStemVolumeByUtilization().setAll(44.496151f); - var spec4 = VdypSpecies.build(layer, builder -> { - builder.genus("H"); - builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); - }); - spec4.getLoreyHeightByUtilization().setAll(24.3451157f); - spec4.getBaseAreaByUtilization().setAll(5.50214148f); - spec4.getTreesPerHectareByUtilization().setAll(152.482513f); - spec4.getQuadraticMeanDiameterByUtilization().setAll(21.4343796f); - spec4.getWholeStemVolumeByUtilization().setAll(470.388489f); - var spec5 = VdypSpecies.build(layer, builder -> { - builder.genus("S"); - builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); + }); + lb.addSpecies(sb -> { + sb.genus("S"); + sb.percentGenus(20f); + sb.volumeGroup(-1); + sb.decayGroup(-1); + sb.breakageGroup(-1); + sb.loreyHeight(34.6888771f); + sb.baseArea(4.0966382f); + sb.treesPerHectare(43.7256737f); + sb.quadMeanDiameter(34.5382729f); + sb.wholeStemVolume(57.2091446f); + }); + + lb.loreyHeight(31.3307209f); + lb.baseArea(44.6249847f); + lb.treesPerHectare(620.484802f); + lb.quadMeanDiameter(30.2606697f); + lb.wholeStemVolume(635.659668f); }); - spec5.getLoreyHeightByUtilization().setAll(34.6888771f); - spec5.getBaseAreaByUtilization().setAll(4.0966382f); - spec5.getTreesPerHectareByUtilization().setAll(43.7256737f); - spec5.getQuadraticMeanDiameterByUtilization().setAll(34.5382729f); - spec5.getWholeStemVolumeByUtilization().setAll(57.2091446f); + + var site = layer.getSite(); - layer.setSpecies(Arrays.asList(spec1, spec2, spec3, spec4, spec5)); app.estimateSmallComponents(fPoly, layer); + + var spec1 = layer.getSpecies().get("B"); + var spec2 = layer.getSpecies().get("C"); + var spec3 = layer.getSpecies().get("D"); + var spec4 = layer.getSpecies().get("H"); + var spec5 = layer.getSpecies().get("S"); - assertThat(layer.getLoreyHeightByUtilization().getSmall(), closeTo(7.14446497f)); assertThat(spec1.getLoreyHeightByUtilization().getSmall(), closeTo(8.39441967f)); assertThat(spec2.getLoreyHeightByUtilization().getSmall(), closeTo(6.61517191f)); assertThat(spec3.getLoreyHeightByUtilization().getSmall(), closeTo(10.8831682f)); assertThat(spec4.getLoreyHeightByUtilization().getSmall(), closeTo(7.93716192f)); assertThat(spec5.getLoreyHeightByUtilization().getSmall(), closeTo(8.63455391f)); - assertThat(layer.getBaseAreaByUtilization().getSmall(), closeTo(0.0153773092f)); assertThat(spec1.getBaseAreaByUtilization().getSmall(), closeTo(0f)); assertThat(spec2.getBaseAreaByUtilization().getSmall(), closeTo(0.0131671466f)); assertThat(spec3.getBaseAreaByUtilization().getSmall(), closeTo(0.00163476227f)); assertThat(spec4.getBaseAreaByUtilization().getSmall(), closeTo(0f)); assertThat(spec5.getBaseAreaByUtilization().getSmall(), closeTo(0.000575399841f)); - assertThat(layer.getTreesPerHectareByUtilization().getSmall(), closeTo(5.34804487f)); assertThat(spec1.getTreesPerHectareByUtilization().getSmall(), closeTo(0f)); assertThat(spec2.getTreesPerHectareByUtilization().getSmall(), closeTo(4.67143154f)); assertThat(spec3.getTreesPerHectareByUtilization().getSmall(), closeTo(0.498754263f)); assertThat(spec4.getTreesPerHectareByUtilization().getSmall(), closeTo(0f)); assertThat(spec5.getTreesPerHectareByUtilization().getSmall(), closeTo(0.17785944f)); - assertThat(layer.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(6.05059004f)); assertThat(spec1.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(6.13586617f)); assertThat(spec2.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(5.99067688f)); assertThat(spec3.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(6.46009731f)); assertThat(spec4.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(6.03505516f)); assertThat(spec5.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(6.41802597f)); - assertThat(layer.getWholeStemVolumeByUtilization().getSmall(), closeTo(0.0666879341f)); assertThat(spec1.getWholeStemVolumeByUtilization().getSmall(), closeTo(0f)); assertThat(spec2.getWholeStemVolumeByUtilization().getSmall(), closeTo(0.0556972362f)); assertThat(spec3.getWholeStemVolumeByUtilization().getSmall(), closeTo(0.0085867513f)); assertThat(spec4.getWholeStemVolumeByUtilization().getSmall(), closeTo(0f)); assertThat(spec5.getWholeStemVolumeByUtilization().getSmall(), closeTo(0.00240394124f)); + + assertThat(layer.getLoreyHeightByUtilization().getSmall(), closeTo(7.14446497f)); + assertThat(layer.getBaseAreaByUtilization().getSmall(), closeTo(0.0153773092f)); + assertThat(layer.getTreesPerHectareByUtilization().getSmall(), closeTo(5.34804487f)); + assertThat(layer.getQuadraticMeanDiameterByUtilization().getSmall(), closeTo(6.05059004f)); + assertThat(layer.getWholeStemVolumeByUtilization().getSmall(), closeTo(0.0666879341f)); + } } } @@ -1368,7 +1356,6 @@ void testApplyToBuilder() throws Exception { @Test void testApplyToObject() throws Exception { controlMap = TestUtils.loadControlMap(); - var bec = Utils.getBec("IDF", controlMap); try (var app = new TestStartApplication(controlMap, false)) { var poly = VdypPolygon.build(pb -> { @@ -1498,13 +1485,6 @@ void testComputeUtilizationComponentsPrimaryByUtilNoCV() throws ProcessingExcept var layer = VdypLayer.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.ageTotal(55f); - siteBuilder.yearsToBreastHeight(3.5f); - siteBuilder.height(20f); - siteBuilder.siteGenus("H"); - }); - }); layer.getLoreyHeightByUtilization().setAll(13.0660105f); @@ -1545,6 +1525,11 @@ void testComputeUtilizationComponentsPrimaryByUtilNoCV() throws ProcessingExcept builder.volumeGroup(54); builder.decayGroup(42); builder.breakageGroup(24); + builder.addSite(siteBuilder -> { + siteBuilder.ageTotal(55f); + siteBuilder.yearsToBreastHeight(3.5f); + siteBuilder.height(20f); + }); }); spec2.getLoreyHeightByUtilization().setAll(12.9176102f); @@ -1693,13 +1678,15 @@ TestLayer getTestPrimaryLayer( var result = TestLayer.build(builder -> { builder.polygonIdentifier(polygonId); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.ageTotal(8f); - siteBuilder.yearsToBreastHeight(7f); - siteBuilder.height(6f); - siteBuilder.siteIndex(5f); - siteBuilder.siteGenus("B"); - siteMutator.accept(siteBuilder); + builder.addSpecies(specBuilder -> { + specBuilder.genus("B"); + specBuilder.addSite(siteBuilder -> { + siteBuilder.ageTotal(8f); + siteBuilder.yearsToBreastHeight(7f); + siteBuilder.height(6f); + siteBuilder.siteIndex(5f); + siteMutator.accept(siteBuilder); + }); }); builder.crownClosure(0.9f); @@ -1716,13 +1703,15 @@ TestLayer getTestVeteranLayer( builder.polygonIdentifier(polygonId); builder.layerType(LayerType.VETERAN); - builder.addSite(siteBuilder -> { - siteBuilder.ageTotal(8f); - siteBuilder.yearsToBreastHeight(7f); - siteBuilder.height(6f); - siteBuilder.siteIndex(5f); - siteBuilder.siteGenus("B"); - siteMutator.accept(siteBuilder); + builder.addSpecies(specBuilder -> { + specBuilder.genus("B"); + specBuilder.addSite(siteBuilder -> { + siteBuilder.ageTotal(8f); + siteBuilder.yearsToBreastHeight(7f); + siteBuilder.height(6f); + siteBuilder.siteIndex(5f); + siteMutator.accept(siteBuilder); + }); }); builder.crownClosure(0.9f); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java index 188d077d9..6001ea669 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestLayer.java @@ -68,13 +68,5 @@ protected TestSpecies buildSpecies(Consumer config) { }); } - @Override - protected TestSite buildSite(Consumer config) { - return TestSite.build(si -> { - si.polygonIdentifier(polygonIdentifier.get()); - si.layerType(layerType.get()); - config.accept(si); - }); - } } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java index a9222921f..51815fb11 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java @@ -1,15 +1,19 @@ package ca.bc.gov.nrs.vdyp.application.test; +import java.util.Optional; import java.util.function.Consumer; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; -public class TestSpecies extends BaseVdypSpecies { +public class TestSpecies extends BaseVdypSpecies { - protected TestSpecies(PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, float percentGenus) { - super(polygonIdentifier, layerType, genus, percentGenus); + protected TestSpecies( + PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, float percentGenus, + Optional site + ) { + super(polygonIdentifier, layerType, genus, percentGenus, site); } public static TestSpecies build(Consumer config) { @@ -18,11 +22,22 @@ public static TestSpecies build(Consumer config) { return builder.build(); } - public static class Builder extends BaseVdypSpecies.Builder { + public static class Builder extends BaseVdypSpecies.Builder { @Override protected TestSpecies doBuild() { - return new TestSpecies(polygonIdentifier.get(), layerType.get(), genus.get(), percentGenus.get()); + return new TestSpecies(polygonIdentifier.get(), layerType.get(), genus.get(), percentGenus.get(), site); + } + + @Override + protected TestSite buildSite(Consumer config) { + return TestSite.build(builder -> { + builder.polygonIdentifier(this.polygonIdentifier.get()); + builder.layerType(this.layerType.get()); + builder.siteGenus(this.genus.get()); + + config.accept(builder); + }); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java index 3e79770ab..49077c062 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestStartApplication.java @@ -74,7 +74,7 @@ public VdypApplicationIdentifier getId() { } @Override - protected TestSpecies copySpecies(TestSpecies toCopy, Consumer> config) { + protected TestSpecies copySpecies(TestSpecies toCopy, Consumer> config) { return null; } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java index 7aafb41fb..e3333be28 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java @@ -444,12 +444,6 @@ void testSimple() throws Exception { var layer = VdypLayer.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.ageTotal(55f); - siteBuilder.yearsToBreastHeight(1f); - siteBuilder.height(32.2999992f); - siteBuilder.siteGenus("H"); - }); }); // sp 3, 4, 5, 8, 15 @@ -490,6 +484,11 @@ void testSimple() throws Exception { builder.decayGroup(31); builder.breakageGroup(17); builder.percentGenus(9f); + builder.addSite(siteBuilder -> { + siteBuilder.ageTotal(55f); + siteBuilder.yearsToBreastHeight(1f); + siteBuilder.height(32.2999992f); + }); }); spec4.getLoreyHeightByUtilization().setCoe(0, 24.3451157f); spec4.setFractionGenus(0.117043354f); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java index 49e7806e8..21d4f0699 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java @@ -101,13 +101,20 @@ void testWritePolygon() throws IOException { builder.polygonIdentifier("082E004 615 1988"); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(15f); - siteBuilder.siteIndex(14.7f); - siteBuilder.ageTotal(60f); - siteBuilder.yearsToBreastHeight(8.5f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.genus("PL"); + specBuilder.percentGenus(100); + specBuilder.volumeGroup(1); + specBuilder.decayGroup(2); + specBuilder.breakageGroup(3); + + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(15f); + siteBuilder.siteIndex(14.7f); + siteBuilder.ageTotal(60f); + siteBuilder.yearsToBreastHeight(8.5f); + siteBuilder.siteCurveNumber(0); + }); }); }); @@ -131,13 +138,20 @@ void testWriteSpecies() throws IOException { builder.polygonIdentifier("082E004 615 1988"); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(15f); - siteBuilder.siteIndex(14.7f); - siteBuilder.ageTotal(60f); - siteBuilder.yearsToBreastHeight(8.5f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.genus("PL"); + specBuilder.percentGenus(100); + specBuilder.volumeGroup(1); + specBuilder.decayGroup(2); + specBuilder.breakageGroup(3); + + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(15f); + siteBuilder.siteIndex(14.7f); + siteBuilder.ageTotal(60f); + siteBuilder.yearsToBreastHeight(8.5f); + siteBuilder.siteCurveNumber(0); + }); }); }); @@ -170,14 +184,22 @@ void testWriteUtilizationForLayer() throws IOException { builder.polygonIdentifier("082E004 615 1988"); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(15f); - siteBuilder.siteIndex(14.7f); - siteBuilder.ageTotal(60f); - siteBuilder.yearsToBreastHeight(8.5f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.genus("PL"); + specBuilder.percentGenus(100); + specBuilder.volumeGroup(1); + specBuilder.decayGroup(2); + specBuilder.breakageGroup(3); + + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(15f); + siteBuilder.siteIndex(14.7f); + siteBuilder.ageTotal(60f); + siteBuilder.yearsToBreastHeight(8.5f); + siteBuilder.siteCurveNumber(0); + }); }); + }); @SuppressWarnings("unused") @@ -247,13 +269,20 @@ void testWriteUtilizationZeroBaseArea() throws IOException { builder.polygonIdentifier("082E004 615 1988"); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(15f); - siteBuilder.siteIndex(14.7f); - siteBuilder.ageTotal(60f); - siteBuilder.yearsToBreastHeight(8.5f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.genus("PL"); + specBuilder.percentGenus(100); + specBuilder.volumeGroup(1); + specBuilder.decayGroup(2); + specBuilder.breakageGroup(3); + + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(15f); + siteBuilder.siteIndex(14.7f); + siteBuilder.ageTotal(60f); + siteBuilder.yearsToBreastHeight(8.5f); + siteBuilder.siteCurveNumber(0); + }); }); }); @@ -334,13 +363,20 @@ void testWritePolygonWithChildren() throws IOException { var layer = VdypLayer.build(polygon, builder -> { builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(15f); - siteBuilder.siteIndex(14.7f); - siteBuilder.ageTotal(60f); - siteBuilder.yearsToBreastHeight(8.5f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.genus("PL"); + specBuilder.percentGenus(100); + specBuilder.volumeGroup(1); + specBuilder.decayGroup(2); + specBuilder.breakageGroup(3); + + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(15f); + siteBuilder.siteIndex(14.7f); + siteBuilder.ageTotal(60f); + siteBuilder.yearsToBreastHeight(8.5f); + siteBuilder.siteCurveNumber(0); + }); }); }); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java index 58b1565f9..2f1623d0e 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java @@ -28,12 +28,14 @@ void build() throws Exception { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(10f); - siteBuilder.ageTotal(42f); - siteBuilder.yearsToBreastHeight(2f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(10f); + siteBuilder.ageTotal(42f); + siteBuilder.yearsToBreastHeight(2f); + siteBuilder.siteGenus("PL"); + siteBuilder.siteCurveNumber(0); + }); }); }); @@ -65,14 +67,17 @@ void buildForPolygon() throws Exception { var result = VdypLayer.build(poly, builder -> { builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(10f); - siteBuilder.ageTotal(42f); - siteBuilder.yearsToBreastHeight(2f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(10f); + siteBuilder.ageTotal(42f); + siteBuilder.yearsToBreastHeight(2f); + siteBuilder.siteGenus("PL"); + siteBuilder.siteCurveNumber(0); + }); }); + }); assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); @@ -94,13 +99,16 @@ void buildAddSpecies() throws Exception { var result = VdypLayer.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); - builder.addSite(siteBuilder -> { - siteBuilder.height(10f); - siteBuilder.ageTotal(42f); - siteBuilder.yearsToBreastHeight(2f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteCurveNumber(0); + builder.addSpecies(specBuilder -> { + specBuilder.addSite(siteBuilder -> { + siteBuilder.height(10f); + siteBuilder.ageTotal(42f); + siteBuilder.yearsToBreastHeight(2f); + siteBuilder.siteGenus("PL"); + siteBuilder.siteCurveNumber(0); + }); }); + builder.addSpecies(specBuilder -> { specBuilder.genus("B"); specBuilder.percentGenus(90f); @@ -139,105 +147,12 @@ void buildAdapt() throws Exception { } - @Test - void buildAdaptSites() throws Exception { - - var control = EasyMock.createControl(); - - BaseVdypLayer toCopy = control.createMock(BaseVdypLayer.class); - BaseVdypSite siteToCopy = control.createMock(BaseVdypSite.class); - - EasyMock.expect(toCopy.getPolygonIdentifier()).andStubReturn(new PolygonIdentifier("Test", 2024)); - EasyMock.expect(siteToCopy.getPolygonIdentifier()).andStubReturn(new PolygonIdentifier("Test", 2024)); - EasyMock.expect(toCopy.getLayerType()).andStubReturn(LayerType.PRIMARY); - EasyMock.expect(siteToCopy.getLayerType()).andStubReturn(LayerType.PRIMARY); - EasyMock.expect(toCopy.getInventoryTypeGroup()).andStubReturn(Optional.of(12)); - EasyMock.expect(toCopy.getSites()) - .andStubReturn(new LinkedHashMap<>(Collections.singletonMap("B", siteToCopy))); - EasyMock.expect(siteToCopy.getSiteGenus()).andStubReturn("B"); - EasyMock.expect(siteToCopy.getAgeTotal()).andStubReturn(Optional.of(30f)); - EasyMock.expect(siteToCopy.getYearsToBreastHeight()).andStubReturn(Optional.of(4f)); - EasyMock.expect(siteToCopy.getHeight()).andStubReturn(Optional.of(20f)); - EasyMock.expect(siteToCopy.getSiteIndex()).andStubReturn(Optional.of(19.7f)); - EasyMock.expect(siteToCopy.getSiteCurveNumber()).andStubReturn(Optional.of(13)); - - control.replay(); - - var result = VdypLayer.build(builder -> { - - builder.adapt(toCopy); - builder.adaptSites(toCopy, (siteBuilder, site) -> { - // Do Nothing - }); - - }); - assertThat(result, hasProperty("sites", hasEntry(is("B"), hasProperty("siteGenus", is("B"))))); - var resultSite = result.getSite().get(); - assertThat(resultSite, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); - assertThat(resultSite, hasProperty("layerType", is(LayerType.PRIMARY))); - assertThat(resultSite, hasProperty("siteGenus", is("B"))); - assertThat(resultSite, hasProperty("ageTotal", present(is(30f)))); - assertThat(resultSite, hasProperty("yearsToBreastHeight", present(is(4f)))); - assertThat(resultSite, hasProperty("height", present(is(20f)))); - assertThat(resultSite, hasProperty("siteIndex", present(is(19.7f)))); - assertThat(resultSite, hasProperty("siteCurveNumber", present(is(13)))); - - control.verify(); - - } - - @Test - void buildCopySites() throws Exception { - - var toCopy = VdypLayer.build(builder -> { - builder.polygonIdentifier("Test", 2024); - builder.layerType(LayerType.PRIMARY); - - builder.addSite(siteBuilder -> { - siteBuilder.height(10f); - siteBuilder.ageTotal(42f); - siteBuilder.yearsToBreastHeight(2f); - siteBuilder.siteGenus("PL"); - siteBuilder.siteIndex(19.7f); - siteBuilder.siteCurveNumber(13); - }); - - }); - - var result = VdypLayer.build(builder -> { - - builder.adapt(toCopy); - builder.adaptSites(toCopy, (siteBuilder, site) -> { - // Do Nothing - }); - - }); - assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); - assertThat(result, hasProperty("layerType", is(LayerType.PRIMARY))); - assertThat(result, hasProperty("ageTotal", present(is(42f)))); - assertThat(result, hasProperty("yearsToBreastHeight", present(is(2f)))); - assertThat(result, hasProperty("height", present(is(10f)))); - assertThat(result, hasProperty("species", anEmptyMap())); - - assertThat(result, hasProperty("sites", hasEntry(is("PL"), hasProperty("siteGenus", is("PL"))))); - var resultSite = result.getSite().get(); - assertThat(resultSite, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); - assertThat(resultSite, hasProperty("layerType", is(LayerType.PRIMARY))); - assertThat(resultSite, hasProperty("siteGenus", is("PL"))); - assertThat(resultSite, hasProperty("ageTotal", present(is(42f)))); - assertThat(resultSite, hasProperty("yearsToBreastHeight", present(is(2f)))); - assertThat(resultSite, hasProperty("height", present(is(10f)))); - assertThat(resultSite, hasProperty("siteIndex", present(is(19.7f)))); - assertThat(resultSite, hasProperty("siteCurveNumber", present(is(13)))); - - } - @Test void buildAdaptSpecies() throws Exception { var control = EasyMock.createControl(); - BaseVdypLayer toCopy = control.createMock(BaseVdypLayer.class); + BaseVdypLayer, BaseVdypSite> toCopy = control.createMock(BaseVdypLayer.class); BaseVdypSpecies speciesToCopy = control.createMock(BaseVdypSpecies.class); EasyMock.expect(toCopy.getPolygonIdentifier()).andStubReturn(new PolygonIdentifier("Test", 2024)); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java index cd26c893b..b66b18c8d 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java @@ -58,14 +58,6 @@ void buildForLayer() throws Exception { var layer = VdypLayer.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); - - builder.addSite(siteBuilder -> { - siteBuilder.siteGenus("B"); - siteBuilder.siteCurveNumber(0); - siteBuilder.ageTotal(42f); - siteBuilder.yearsToBreastHeight(2f); - siteBuilder.height(10f); - }); }); var result = VdypSpecies.build(layer, builder -> { @@ -75,6 +67,12 @@ void buildForLayer() throws Exception { builder.volumeGroup(1); builder.decayGroup(2); builder.breakageGroup(3); + builder.addSite(siteBuilder -> { + siteBuilder.siteCurveNumber(0); + siteBuilder.ageTotal(42f); + siteBuilder.yearsToBreastHeight(2f); + siteBuilder.height(10f); + }); }); assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); From 9756fedb1c77877764985cba049b4b15e80451db Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 31 Jul 2024 16:55:16 -0700 Subject: [PATCH 29/66] Next step in refactoring of Forward to use common Polygon data structures --- .../application/VdypStartApplication.java | 24 +- .../nrs/vdyp/common/EstimationMethods.java | 91 +- .../ca/bc/gov/nrs/vdyp/common/Estimators.java | 1087 ----------------- .../nrs/vdyp/common/GenusDefinitionMap.java | 2 +- .../vdyp/common/UtilizationOperations.java | 218 ++++ .../BaseAreaTreeDensityDiameter.java | 20 +- .../CachingResolvedControlMapImpl.java | 3 +- .../vdyp/controlmap/ResolvedControlMap.java | 38 +- .../controlmap/ResolvedControlMapImpl.java | 16 +- .../coe/BasalAreaGrowthEmpiricalParser.java | 25 +- .../vdyp/io/parse/coe/UpperBoundsParser.java | 2 +- .../BecZoneBySpeciesCoefficientParser.java | 25 +- .../io/parse/coe/base/GrowthFiatParser.java | 4 +- .../nrs/vdyp/model/CompVarAdjustments.java | 67 +- .../nrs/vdyp/model/ComponentSizeLimits.java | 4 +- .../bc/gov/nrs/vdyp/model/DebugSettings.java | 66 +- .../gov/nrs/vdyp/model/GrowthFiatDetails.java | 62 +- .../ca/bc/gov/nrs/vdyp/model/LayerType.java | 2 +- .../vdyp/model/NonprimaryHLCoefficients.java | 8 +- .../gov/nrs/vdyp/model/PolygonIdentifier.java | 4 +- .../vdyp/model/UtilizationClassVariable.java | 5 +- .../gov/nrs/vdyp/model/UtilizationVector.java | 4 + .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 6 - .../gov/nrs/vdyp/model/VdypUtilization.java | 153 --- .../nrs/vdyp/model/VdypUtilizationHolder.java | 33 +- .../vdyp/common/EstimationMethodsTest.java | 43 +- .../parse/BasalAreaGrowthFiatParserTest.java | 4 +- .../parse/CompVarAdjustmentsParserTest.java | 37 +- .../vdyp/io/parse/DqGrowthFiatParserTest.java | 4 +- .../io/parse/coe/ComponentSizeParserTest.java | 4 +- .../control/NonFipControlParserTest.java | 9 +- .../gov/nrs/vdyp/model/DebugSettingsTest.java | 5 +- .../vdyp/model/GrowthFiatDetailsTests.java | 45 +- .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 4 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 35 +- .../vdyp/forward/ForwardDataStreamReader.java | 101 +- .../vdyp/forward/ForwardProcessingEngine.java | 88 +- .../vdyp/forward/ForwardProcessingState.java | 31 +- .../vdyp/forward/PolygonProcessingState.java | 1 - .../forward/model/VdypSpeciesUtilization.java | 284 ----- .../parsers/VdypControlVariableParser.java | 34 - .../forward/PolygonProcessingStateTest.java | 62 +- .../forward/VdypForwardControlParserTest.java | 569 --------- .../forward/VdypForwardReadPolygonTest.java | 60 +- .../ca/bc/gov/nrs/vdyp/sindex/Reference.java | 32 - 45 files changed, 762 insertions(+), 2659 deletions(-) delete mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java create mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java delete mode 100644 vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java delete mode 100644 vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypControlVariableParser.java delete mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java delete mode 100644 vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 0159e2790..d8dea2f61 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -36,7 +36,7 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Estimators; +import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; @@ -169,7 +169,7 @@ protected static void doMain(VdypStartApplication app, final String. protected Map controlMap = new HashMap<>(); - protected Estimators estimators; + protected EstimationMethods estimators; static final Comparator PERCENT_GENUS_DESCENDING = Utils .compareUsing(BaseVdypSpecies::getPercentGenus).reversed(); @@ -241,7 +241,7 @@ void closeVriWriter() throws IOException { protected void setControlMap(Map controlMap) { this.controlMap = controlMap; - this.estimators = new Estimators(new ResolvedControlMapImpl(controlMap)); + this.estimators = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); } protected StreamingParser getStreamingParser(ControlKey key) throws ProcessingException { @@ -1260,21 +1260,19 @@ public void computeUtilizationComponentsPrimary( } } - spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, Estimators.COPY_IF_BAND); - spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, Estimators.COPY_IF_BAND); - spec.getQuadraticMeanDiameterByUtilization() - .pairwiseInPlace(quadMeanDiameterUtil, Estimators.COPY_IF_BAND); + spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, EstimationMethods.COPY_IF_BAND); + spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, EstimationMethods.COPY_IF_BAND); + spec.getQuadraticMeanDiameterByUtilization().pairwiseInPlace(quadMeanDiameterUtil, EstimationMethods.COPY_IF_BAND); - spec.getWholeStemVolumeByUtilization() - .pairwiseInPlace(wholeStemVolumeUtil, Estimators.COPY_IF_NOT_SMALL); + spec.getWholeStemVolumeByUtilization().pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeByUtilization() - .pairwiseInPlace(closeVolumeUtil, Estimators.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayByUtilization() - .pairwiseInPlace(closeVolumeNetDecayUtil, Estimators.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeNetDecayUtil, EstimationMethods.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteUtil, Estimators.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, Estimators.COPY_IF_NOT_SMALL); + .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); } computeLayerUtilizationComponentsFromSpecies(vdypLayer); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index dc16c7810..d6b9f53c5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -35,9 +35,9 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationVector.BinaryOperatorWithClass; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; -public class Estimators { +public class EstimationMethods { - public static final Logger log = LoggerFactory.getLogger(Estimators.class); + public static final Logger log = LoggerFactory.getLogger(EstimationMethods.class); /** * Returns the new value if the index is that of a utilization class that represents a size band, otherwise the old @@ -54,15 +54,15 @@ public class Estimators { oldX, newX, uc ) -> UtilizationClass.ALL_BUT_SMALL.contains(uc) ? newX : oldX; + public static final float EMPIRICAL_OCCUPANCY = 0.85f; + ResolvedControlMap controlMap; - public Estimators(ResolvedControlMap resolvedControlMap) { + public EstimationMethods(ResolvedControlMap resolvedControlMap) { this.controlMap = resolvedControlMap; } - private float heightMultiplier( - String genus, Region region, float treesPerHectarePrimary - ) { + private float heightMultiplier(String genus, Region region, float treesPerHectarePrimary) { final var coeMap = controlMap .>get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); var coe = coeMap.get(genus, region).reindex(0); @@ -106,9 +106,7 @@ public float leadHeightFromPrimaryHeight( * @param genus Primary species * @param region Region of the polygon */ - public float primaryHeightFromLeadHeightInitial( - float leadHeight, String genus, Region region - ) { + public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { final var coeMap = controlMap .>get(ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class); var coe = coeMap.get(genus, region); @@ -154,8 +152,8 @@ public float estimateNonPrimaryLoreyHeight( var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( () -> new ProcessingException( String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, bec - .getRegion() + "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, + bec.getRegion() ) ) ); @@ -279,7 +277,8 @@ public float estimateQuadMeanDiameterForSpecies( var limits = getLimitsForHeightAndDiameter(species, region); quadMeanDiameter1 = estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, + quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); return quadMeanDiameter1; } @@ -299,7 +298,8 @@ float estimateQuadMeanDiameterClampResult( final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); final float dqMaxSp = max( - 7.6f, min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) + 7.6f, + min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) ); if (quadMeanDiameter1 < dqMinSp) { quadMeanDiameter1 = dqMinSp; @@ -356,9 +356,8 @@ public void estimateBaseAreaByUtilization( BecDefinition bec, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus ) throws ProcessingException { - final var coeMap = controlMap.>get( - ControlKey.UTIL_COMP_BA, MatrixMap3.class - ); + final var coeMap = controlMap + .>get(ControlKey.UTIL_COMP_BA, MatrixMap3.class); estimateBaseAreaByUtilization(bec, coeMap, quadMeanDiameterUtil, baseAreaUtil, genus); } @@ -421,9 +420,8 @@ public void estimateQuadMeanDiameterByUtilization( BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus ) throws ProcessingException { - final var coeMap = controlMap.>get( - ControlKey.UTIL_COMP_DQ, MatrixMap3.class - ); + final var coeMap = controlMap + .>get(ControlKey.UTIL_COMP_DQ, MatrixMap3.class); estimateQuadMeanDiameterByUtilization(bec, coeMap, quadMeanDiameterUtil, genus); } @@ -521,9 +519,7 @@ public static void estimateQuadMeanDiameterByUtilization( */ public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - var coeMap = controlMap.>get( - ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class - ); + var coeMap = controlMap.>get(ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class); return estimateWholeStemVolumePerTree(volumeGroup, loreyHeight, quadMeanDiameter, coeMap); } @@ -584,7 +580,8 @@ public void estimateWholeStemVolume( ); estimateWholeStemVolume( - utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, + quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil ); } @@ -658,12 +655,12 @@ public void estimateCloseUtilizationVolume( UtilizationVector closeUtilizationVolumeUtil ) throws ProcessingException { - final var closeUtilizationCoeMap = controlMap - .>>get( - ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class - ); + final var closeUtilizationCoeMap = controlMap.>>get( + ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class + ); estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil + utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, + wholeStemVolumeUtil, closeUtilizationVolumeUtil ); } @@ -731,11 +728,11 @@ public void estimateNetDecayVolume( final var netDecayCoeMap = controlMap.>>get( ControlKey.VOLUME_NET_DECAY, MatrixMap2.class ); - final var decayModifierMap = controlMap.>get( - ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class - ); + final var decayModifierMap = controlMap + .>get(ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class); estimateNetDecayVolume( - genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil + genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, + quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil ); } @@ -813,15 +810,15 @@ public void estimateNetDecayAndWasteVolume( UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { - final var netDecayWasteCoeMap = controlMap.>get( - ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = controlMap.>get( - ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); + final var netDecayWasteCoeMap = controlMap + .>get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); + final var wasteModifierMap = controlMap + .>get(ControlKey.WASTE_MODIFIERS, MatrixMap2.class); estimateNetDecayAndWasteVolume( - region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil + region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, + quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, + closeUtilizationNetOfDecayAndWasteUtil ); } @@ -848,9 +845,8 @@ public static void estimateNetDecayAndWasteVolume( UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { estimateUtilization( - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( - i, netDecay - ) -> { + closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, + (i, netDecay) -> { if (Float.isNaN(netDecay) || netDecay <= 0f) { return 0f; } @@ -924,11 +920,11 @@ public void estimateNetDecayWasteAndBreakageVolume( UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil ) throws ProcessingException { - final var netBreakageCoeMap = controlMap - .>get(ControlKey.BREAKAGE, Map.class); + final var netBreakageCoeMap = controlMap.>get(ControlKey.BREAKAGE, Map.class); estimateNetDecayWasteAndBreakageVolume( - utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil + utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, + closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); } @@ -961,9 +957,8 @@ public static void estimateNetDecayWasteAndBreakageVolume( final var a4 = coefficients.getCoe(4); estimateUtilization( - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, utilizationClass, ( - uc, netWaste - ) -> { + closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, + utilizationClass, (uc, netWaste) -> { if (netWaste <= 0f) { return 0f; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java deleted file mode 100644 index dc16c7810..000000000 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Estimators.java +++ /dev/null @@ -1,1087 +0,0 @@ -package ca.bc.gov.nrs.vdyp.common; - -import static ca.bc.gov.nrs.vdyp.math.FloatMath.abs; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.clamp; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.exp; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.log; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.pow; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.ratio; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.sqrt; -import static java.lang.Math.max; -import static java.lang.Math.min; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.Predicate; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; -import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; -import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; -import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; -import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; -import ca.bc.gov.nrs.vdyp.model.Region; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; -import ca.bc.gov.nrs.vdyp.model.UtilizationVector; -import ca.bc.gov.nrs.vdyp.model.UtilizationVector.BinaryOperatorWithClass; -import ca.bc.gov.nrs.vdyp.model.VdypSpecies; - -public class Estimators { - - public static final Logger log = LoggerFactory.getLogger(Estimators.class); - - /** - * Returns the new value if the index is that of a utilization class that represents a size band, otherwise the old - * value - */ - public static final BinaryOperatorWithClass COPY_IF_BAND = ( - oldX, newX, uc - ) -> UtilizationClass.UTIL_CLASSES.contains(uc) ? newX : oldX; - - /** - * Returns the new value if the index is that of a utilization class is not the small band, otherwise the old value - */ - public static final BinaryOperatorWithClass COPY_IF_NOT_SMALL = ( - oldX, newX, uc - ) -> UtilizationClass.ALL_BUT_SMALL.contains(uc) ? newX : oldX; - - ResolvedControlMap controlMap; - - public Estimators(ResolvedControlMap resolvedControlMap) { - this.controlMap = resolvedControlMap; - } - - private float heightMultiplier( - String genus, Region region, float treesPerHectarePrimary - ) { - final var coeMap = controlMap - .>get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); - var coe = coeMap.get(genus, region).reindex(0); - return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); - } - - /** - * EMP050 Method 1: Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return - */ - public float - primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - - return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); - } - - /** - * EMP050 Method 2: Return the dominant height of the lead species based on the lorey height of the primary species. - * - * @param primaryHeight lorey height of the primary species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - */ - public float leadHeightFromPrimaryHeight( - float primaryHeight, String genus, Region region, float treesPerHectarePrimary - ) { - return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(genus, region, treesPerHectarePrimary); - } - - /** - * EMP051 Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param controlMap Control map containing coefficients - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - */ - public float primaryHeightFromLeadHeightInitial( - float leadHeight, String genus, Region region - ) { - final var coeMap = controlMap - .>get(ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class); - var coe = coeMap.get(genus, region); - return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); - } - - /** - * EMP053 Estimate the lorey height of a non-primary species of a primary layer. - *

      - * Using eqns N1 and N2 from ipsjf124.doc - * - * - * @param vspec The species. - * @param vspecPrime The primary species. - * @param leadHeight lead height of the layer - * @param primaryHeight height of the primary species - * @throws ProcessingException - */ - public float estimateNonPrimaryLoreyHeight( - BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight - ) throws ProcessingException { - return estimateNonPrimaryLoreyHeight(vspec.getGenus(), vspecPrime.getGenus(), bec, leadHeight, primaryHeight); - } - - /** - * EMP053 Estimate the lorey height of a non-primary species of a primary layer. - *

      - * Using eqns N1 and N2 from ipsjf124.doc - * - * @param vspec The species. - * @param vspecPrime The primary species. - * @param leadHeight lead height of the layer - * @param primaryHeight height of the primary species - * @throws ProcessingException - */ - public float estimateNonPrimaryLoreyHeight( - String vspec, String vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight - ) throws ProcessingException { - var coeMap = controlMap.>>get( - ControlKey.HL_NONPRIMARY, MatrixMap3.class - ); - - var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( - () -> new ProcessingException( - String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, bec - .getRegion() - ) - ) - ); - var heightToUse = coe.getEquationIndex() == 1 ? leadHeight : primaryHeight; - return 1.3f + coe.getCoe(1) * pow(heightToUse - 1.3f, coe.getCoe(2)); - } - - // EMP060 - /** - * Estimate DQ for a species (primary or not). Using eqn in jf125.doc. - * - * Enforces mins and maxes from EMP061. - * - * @param spec Species of insterest - * @param allSpecies Collection of all species on the layer - * @param region BEC Region of the stand - * @param standQuadMeanDiameter Quadratic mean diameter of the stand - * @param standBaseArea Base area of the stand - * @param standTreesPerHectare Density opf the stand - * @param standLoreyHeight Lorey height of the stand - * @return Quadratic mean diameter of the species of interest - * @throws ProcessingException - */ - public float estimateQuadMeanDiameterForSpecies( - VdypSpecies spec, // ISP, HLsp, DQsp - Map allSpecies, // FR - Region region, // INDEX_IC - float standQuadMeanDiameter, // DQ_TOT - float standBaseArea, // BA_TOT - float standTreesPerHectare, // TPH_TOT - float standLoreyHeight // HL_TOT - ) throws ProcessingException { - String species = spec.getGenus(); - - float c = 0.00441786467f; - - float minQuadMeanDiameter = min(7.6f, standQuadMeanDiameter); - - // Quick solution - if (spec.getFractionGenus() >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { - return standQuadMeanDiameter; - } - - var coeMap = controlMap.>get(ControlKey.BY_SPECIES_DQ, Map.class); - var specAliases = controlMap.getGenusDefinitionMap().getAliases(); - - // TODO we can probably remove these as they seem to only be used for debugging - // in VDYP7 - Map adjust = new HashMap<>(coeMap.size()); - Map mult = new HashMap<>(coeMap.size()); - - var specIt = specAliases.iterator(); - - var spec1 = specIt.next(); - - float a2 = coeMap.get(spec1).getCoe(2); - - float fractionOther = 1f - spec.getFractionGenus(); // FR_REST - - mult.put(spec1, 1f); - float a0 = coeMap.get(spec1).getCoe(0); - float a1 = coeMap.get(spec1).getCoe(1); - - while (specIt.hasNext()) { - var specIAlias = specIt.next(); - var specI = allSpecies.get(specIAlias); - if (specIAlias.equals(spec.getGenus())) { - float multI = 1f; - mult.put(specIAlias, multI); - a0 += multI * coeMap.get(specIAlias).getCoe(0); - a1 += multI * coeMap.get(specIAlias).getCoe(1); - } else { - if (specI != null && specI.getFractionGenus() > 0f) { - float multI = -specI.getFractionGenus() / fractionOther; - mult.put(specIAlias, multI); - a0 += multI * coeMap.get(specIAlias).getCoe(0); - a1 -= multI * coeMap.get(specIAlias).getCoe(1); - } - } - } - - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UtilizationClass.ALL.index); - float loreyHeight1 = max(4f, loreyHeightSpec); - float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spec.getFractionGenus()) / fractionOther; - float loreyHeightRatio = clamp( (loreyHeight1 - 3f) / (loreyHeight2 - 3f), 0.05f, 20f); - - float r = exp( - a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) + adjust.getOrDefault(species, 0f) - ); - - float baseArea1 = spec.getFractionGenus() * standBaseArea; - float baseArea2 = standBaseArea - baseArea1; - - float treesPerHectare1; - if (abs(r - 1f) < 0.0005) { - treesPerHectare1 = spec.getFractionGenus() * standTreesPerHectare; - } else { - float aa = (r - 1f) * c; - float bb = c * (1f - r) * standTreesPerHectare + baseArea1 + baseArea2 * r; - float cc = -baseArea1 * standTreesPerHectare; - float term = bb * bb - 4 * aa * cc; - if (term <= 0f) { - throw new ProcessingException( - "Term for trees per hectare calculation when estimating quadratic mean diameter for species " - + species + " was " + term + " but should be positive." - ); - } - treesPerHectare1 = (-bb + sqrt(term)) / (2f * aa); - if (treesPerHectare1 <= 0f || treesPerHectare1 > standTreesPerHectare) { - throw new ProcessingException( - "Trees per hectare 1 for species " + species + " was " + treesPerHectare1 - + " but should be positive and less than or equal to stand trees per hectare " - + standTreesPerHectare - ); - } - } - - float quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); - float treesPerHectare2 = standTreesPerHectare - treesPerHectare1; - float quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - var limits = getLimitsForHeightAndDiameter(species, region); - - quadMeanDiameter1 = estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 - ); - return quadMeanDiameter1; - } - - float estimateQuadMeanDiameterClampResult( - ComponentSizeLimits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, - float baseArea1, float baseArea2, float quadMeanDiameter1, float treesPerHectare2, float quadMeanDiameter2 - ) { - float treesPerHectare1; - if (quadMeanDiameter2 < minQuadMeanDiameter) { - // species 2 is too small. Make target species smaller. - quadMeanDiameter2 = minQuadMeanDiameter; - treesPerHectare2 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea2, quadMeanDiameter2); - treesPerHectare1 = standTreesPerHectare - treesPerHectare2; - quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); - } - - final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); - final float dqMaxSp = max( - 7.6f, min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) - ); - if (quadMeanDiameter1 < dqMinSp) { - quadMeanDiameter1 = dqMinSp; - treesPerHectare1 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea1, quadMeanDiameter1); - treesPerHectare2 = standTreesPerHectare - treesPerHectare2; - quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - } - if (quadMeanDiameter1 > dqMaxSp) { - // target species is too big. Make target species smaller, DQ2 bigger. - - quadMeanDiameter1 = dqMaxSp; - treesPerHectare1 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea1, quadMeanDiameter1); - treesPerHectare2 = standTreesPerHectare - treesPerHectare2; - - if (treesPerHectare2 > 0f && baseArea2 > 0f) { - quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - } else { - quadMeanDiameter2 = 1000f; - } - - // under rare circumstances, let DQ1 exceed DQMAXsp - if (quadMeanDiameter2 < minQuadMeanDiameter) { - quadMeanDiameter2 = minQuadMeanDiameter; - treesPerHectare2 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea2, quadMeanDiameter2); - treesPerHectare1 = standTreesPerHectare - treesPerHectare2; - quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); - } - - } - return quadMeanDiameter1; - } - - // EMP061 - public ComponentSizeLimits getLimitsForHeightAndDiameter(String genus, Region region) { - var coeMap = controlMap.>get( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class - ); - - var coe = coeMap.get(genus, region); - return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); - } - - /** - * EMP070. Estimate basal area by utilization class from the given parameters, after getting the estimation - * coefficients map from the control map. - * - * @param bec - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException - */ - public void estimateBaseAreaByUtilization( - BecDefinition bec, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus - ) throws ProcessingException { - - final var coeMap = controlMap.>get( - ControlKey.UTIL_COMP_BA, MatrixMap3.class - ); - - estimateBaseAreaByUtilization(bec, coeMap, quadMeanDiameterUtil, baseAreaUtil, genus); - } - - /** - * EMP070: estimate basal area by utilization class from the given parameters - * - * @param bec - * @param basalAreaUtilCompCoeMap - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateBaseAreaByUtilization( - BecDefinition bec, MatrixMap3 basalAreaUtilCompCoeMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus - ) throws ProcessingException { - - float dq = quadMeanDiameterUtil.getAll(); - var b = Utils.utilizationVector(); - b.setCoe(0, baseAreaUtil.getAll()); - - for (UtilizationClass uc : UtilizationClass.ALL_BANDS_BUT_LARGEST) { - var coe = basalAreaUtilCompCoeMap.get(uc.index, genus, bec.getGrowthBec().getAlias()); - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - - float logit; - if (uc == UtilizationClass.U75TO125) { - logit = a0 + a1 * pow(dq, 0.25f); - } else { - logit = a0 + a1 * dq; - } - b.set(uc, b.get(uc.previous().get()) * exponentRatio(logit)); - if (uc == UtilizationClass.U75TO125 && quadMeanDiameterUtil.getAll() < 12.5f) { - float ba12Max = (1f - - pow( (quadMeanDiameterUtil.getCoe(1) - 7.4f) / (quadMeanDiameterUtil.getAll() - 7.4f), 2f)) - * b.getCoe(0); - b.scalarInPlace(1, x -> min(x, ba12Max)); - } - } - - baseAreaUtil.setCoe(1, baseAreaUtil.getAll() - b.getCoe(1)); - baseAreaUtil.setCoe(2, b.getCoe(1) - b.getCoe(2)); - baseAreaUtil.setCoe(3, b.getCoe(2) - b.getCoe(3)); - baseAreaUtil.setCoe(4, b.getCoe(3)); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param bec - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public void estimateQuadMeanDiameterByUtilization( - BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus - ) throws ProcessingException { - - final var coeMap = controlMap.>get( - ControlKey.UTIL_COMP_DQ, MatrixMap3.class - ); - - estimateQuadMeanDiameterByUtilization(bec, coeMap, quadMeanDiameterUtil, genus); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param bec - * @param coeMap - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateQuadMeanDiameterByUtilization( - BecDefinition bec, MatrixMap3 coeMap, - UtilizationVector quadMeanDiameterUtil, String genus - ) throws ProcessingException { - log.atTrace().setMessage("Estimate DQ by utilization class for {} in BEC {}. DQ for all >7.5 is {}") - .addArgument(genus).addArgument(bec.getName()).addArgument(quadMeanDiameterUtil.getAll()); - - float quadMeanDiameter07 = quadMeanDiameterUtil.getAll(); - - for (var uc : UtilizationClass.UTIL_CLASSES) { - log.atDebug().setMessage("For util level {}").addArgument(uc.className); - var coe = coeMap.get(uc.index, genus, bec.getGrowthBec().getAlias()); - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - float a2 = coe.getCoe(3); - - log.atDebug().setMessage("a0={}, a1={}, a3={}").addArgument(a0).addArgument(a1).addArgument(a2); - - float logit; - - switch (uc) { - case U75TO125: - if (quadMeanDiameter07 < 7.5001f) { - quadMeanDiameterUtil.setAll(7.5f); - } else { - log.atDebug().setMessage("DQ = 7.5 + a0 * (1 - exp(a1 / a0*(DQ07 - 7.5) ))**a2' )"); - - logit = a1 / a0 * (quadMeanDiameter07 - 7.5f); - - quadMeanDiameterUtil - .setCoe(uc.index, min(7.5f + a0 * pow(1 - safeExponent(logit), a2), quadMeanDiameter07)); - } - break; - case U125TO175, U175TO225: - log.atDebug().setMessage( - "LOGIT = a0 + a1*(SQ07 / 7.5)**a2, DQ = (12.5 or 17.5) + 5 * exp(LOGIT) / (1 + exp(LOGIT))" - ); - logit = a0 + a1 * pow(quadMeanDiameter07 / 7.5f, a2); - - quadMeanDiameterUtil.setCoe(uc.index, uc.lowBound + 5f * exponentRatio(logit)); - break; - case OVER225: - float a3 = coe.getCoe(4); - - log.atDebug().setMessage( - "Coeff A3 {}, LOGIT = a2 + a1*DQ07**a3, DQ = DQ07 + a0 * (1 - exp(LOGIT) / (1 + exp(LOGIT)) )" - ); - - logit = a2 + a1 * pow(quadMeanDiameter07, a3); - - quadMeanDiameterUtil - .setCoe(uc.index, max(22.5f, quadMeanDiameter07 + a0 * (1f - exponentRatio(logit)))); - break; - case ALL, SMALL: - throw new IllegalStateException( - "Should not be attempting to process small component or all large components" - ); - default: - throw new IllegalStateException("Unknown utilization class " + uc); - } - - log.atDebug().setMessage("Util DQ for class {} is {}").addArgument(uc.className) - .addArgument(quadMeanDiameterUtil.getCoe(uc.index)); - } - - log.atTrace().setMessage("Estimated Diameters {}").addArgument( - () -> UtilizationClass.UTIL_CLASSES.stream() - .map(uc -> String.format("%s: %d", uc.className, quadMeanDiameterUtil.getCoe(uc.index))) - ); - - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - - var coeMap = controlMap.>get( - ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class - ); - - return estimateWholeStemVolumePerTree(volumeGroup, loreyHeight, quadMeanDiameter, coeMap); - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param controlMap the control map from which the total stand whole stem volume equation coefficients are - * retrieved - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public static float estimateWholeStemVolumePerTree( - int volumeGroup, float loreyHeight, float quadMeanDiameter, - Map totalStandWholeStemVolumeCoeMap - ) { - var coe = totalStandWholeStemVolumeCoeMap.get(volumeGroup).reindex(0); - - var logMeanVolume = // - coe.getCoe(UtilizationClass.ALL.index) + // - coe.getCoe(1) * log(quadMeanDiameter) + // - coe.getCoe(2) * log(loreyHeight) + // - coe.getCoe(3) * quadMeanDiameter + // - coe.getCoe(4) / quadMeanDiameter + // - coe.getCoe(5) * loreyHeight + // - coe.getCoe(6) * quadMeanDiameter * quadMeanDiameter + // - coe.getCoe(7) * loreyHeight * quadMeanDiameter + // - coe.getCoe(8) * loreyHeight / quadMeanDiameter; - - return exp(logMeanVolume); - } - - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values, getting wholeStemUtilizationComponentMap from the - * given controlMap. - * - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public void estimateWholeStemVolume( - UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, - UtilizationVector wholeStemVolumeUtil - ) throws ProcessingException { - - final var wholeStemUtilizationComponentMap = controlMap - .>>get( - ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class - ); - - estimateWholeStemVolume( - utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - } - - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values. - * - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param wholeStemUtilizationComponentMap - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public static void estimateWholeStemVolume( - UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - MatrixMap2> wholeStemUtilizationComponentMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, - UtilizationVector wholeStemVolumeUtil - ) throws ProcessingException { - var dqSp = quadMeanDiameterUtil.getAll(); - - estimateUtilization(baseAreaUtil, wholeStemVolumeUtil, utilizationClass, (uc, ba) -> { - Coefficients wholeStemCoe = wholeStemUtilizationComponentMap.get(uc.index, volumeGroup).orElseThrow( - () -> new ProcessingException( - "Could not find whole stem utilization coefficients for group " + volumeGroup - ) - ); - - // Fortran code uses 1 index into array when reading it here, but 0 index when - // writing into it in the parser. I use 0 for both. - var a0 = wholeStemCoe.getCoe(0); - var a1 = wholeStemCoe.getCoe(1); - var a2 = wholeStemCoe.getCoe(2); - 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); - - if (uc == utilizationClass) { - arg += adjustCloseUtil; - } - - var vbaruc = exp(arg); // volume base area ?? utilization class? - - return ba * vbaruc; - }, x -> x <= 0f, 0f); - - if (utilizationClass == UtilizationClass.ALL) { - normalizeUtilizationComponents(wholeStemVolumeUtil); - } - } - - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public void estimateCloseUtilizationVolume( - UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, float hlSp, - UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, - UtilizationVector closeUtilizationVolumeUtil - ) throws ProcessingException { - - final var closeUtilizationCoeMap = controlMap - .>>get( - ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class - ); - estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil - ); - } - - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param closeUtilizationCoeMap - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public static void estimateCloseUtilizationVolume( - UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, float hlSp, - MatrixMap2> closeUtilizationCoeMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, - UtilizationVector closeUtilizationVolumeUtil - ) throws ProcessingException { - estimateUtilization(wholeStemVolumeUtil, closeUtilizationVolumeUtil, utilizationClass, (uc, ws) -> { - Coefficients closeUtilCoe = closeUtilizationCoeMap.get(uc.index, volumeGroup).orElseThrow( - () -> new ProcessingException( - "Could not find whole stem utilization coefficients for group " + volumeGroup - ) - ); - var a0 = closeUtilCoe.getCoe(1); - var a1 = closeUtilCoe.getCoe(2); - var a2 = closeUtilCoe.getCoe(3); - - var arg = a0 + a1 * quadMeanDiameterUtil.getCoe(uc.index) + a2 * hlSp + aAdjust.getCoe(uc.index); - - float ratio = ratio(arg, 7.0f); - - return ws * ratio; - }); - - if (utilizationClass == UtilizationClass.ALL) { - storeSumUtilizationComponents(closeUtilizationVolumeUtil); - } - } - - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @throws ProcessingException - */ - public void estimateNetDecayVolume( - String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayUtil - ) throws ProcessingException { - - final var netDecayCoeMap = controlMap.>>get( - ControlKey.VOLUME_NET_DECAY, MatrixMap2.class - ); - final var decayModifierMap = controlMap.>get( - ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class - ); - estimateNetDecayVolume( - genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil - ); - } - - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param netDecayCoeMap - * @param decayModifierMap - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param lore // EMP053 Using eqns N1 and N2 from ipsjf124.doc yHeight - * @throws ProcessingException - */ - public static void estimateNetDecayVolume( - String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - float ageBreastHeight, MatrixMap2> netDecayCoeMap, - MatrixMap2 decayModifierMap, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil - ) throws ProcessingException { - var dqSp = quadMeanDiameterUtil.getAll(); - - final var ageTr = (float) Math.log(Math.max(20.0, ageBreastHeight)); - - estimateUtilization(closeUtilizationUtil, closeUtilizationNetOfDecayUtil, utilizationClass, (uc, cu) -> { - Coefficients netDecayCoe = netDecayCoeMap.get(uc.index, decayGroup).orElseThrow( - () -> new ProcessingException("Could not find net decay coefficients for group " + decayGroup) - ); - var a0 = netDecayCoe.getCoe(1); - var a1 = netDecayCoe.getCoe(2); - var a2 = netDecayCoe.getCoe(3); - - float arg; - if (uc != UtilizationClass.OVER225) { - arg = a0 + a1 * log(dqSp) + a2 * ageTr; - } else { - arg = a0 + a1 * log(quadMeanDiameterUtil.getCoe(uc.index)) + a2 * ageTr; - } - - arg += aAdjust.getCoe(uc.index) + decayModifierMap.get(genus, region); - - float ratio = ratio(arg, 8.0f); - - return cu * ratio; - }); - - if (utilizationClass == UtilizationClass.ALL) { - storeSumUtilizationComponents(closeUtilizationNetOfDecayUtil); - } - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public void estimateNetDecayAndWasteVolume( - Region region, UtilizationClass utilizationClass, Coefficients aAdjust, String genus, float loreyHeight, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { - - final var netDecayWasteCoeMap = controlMap.>get( - ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = controlMap.>get( - ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - - estimateNetDecayAndWasteVolume( - region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil - ); - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param netDecayWasteCoeMap - * @param wasteModifierMap - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public static void estimateNetDecayAndWasteVolume( - Region region, UtilizationClass utilizationClass, Coefficients aAdjust, String genus, float loreyHeight, - Map netDecayWasteCoeMap, MatrixMap2 wasteModifierMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { - estimateUtilization( - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( - i, netDecay - ) -> { - if (Float.isNaN(netDecay) || netDecay <= 0f) { - return 0f; - } - - Coefficients netWasteCoe = netDecayWasteCoeMap.get(genus); - if (netWasteCoe == null) { - throw new ProcessingException("Could not find net waste coefficients for genus " + genus); - } - - var a0 = netWasteCoe.getCoe(0); - var a1 = netWasteCoe.getCoe(1); - var a2 = netWasteCoe.getCoe(2); - var a3 = netWasteCoe.getCoe(3); - var a4 = netWasteCoe.getCoe(4); - var a5 = netWasteCoe.getCoe(5); - - if (i == UtilizationClass.OVER225) { - a0 += a5; - } - var frd = 1.0f - netDecay / closeUtilizationUtil.getCoe(i.index); - - float arg = a0 + a1 * frd + a3 * log(quadMeanDiameterUtil.getCoe(i.index)) + a4 * log(loreyHeight); - - arg += wasteModifierMap.get(genus, region); - - arg = clamp(arg, -10f, 10f); - - var frw = (1.0f - exp(a2 * frd)) * exp(arg) / (1f + exp(arg)) * (1f - frd); - frw = min(frd, frw); - - float result = closeUtilizationUtil.getCoe(i.index) * (1f - frd - frw); - - /* - * Check for an apply adjustments. This is done after computing the result above to allow for - * clamping frw to frd - */ - if (aAdjust.getCoe(i.index) != 0f) { - var ratio = result / netDecay; - if (ratio < 1f && ratio > 0f) { - arg = log(ratio / (1f - ratio)); - arg += aAdjust.getCoe(i.index); - arg = clamp(arg, -10f, 10f); - result = exp(arg) / (1f + exp(arg)) * netDecay; - } - } - - return result; - } - ); - - if (utilizationClass == UtilizationClass.ALL) { - storeSumUtilizationComponents(closeUtilizationNetOfDecayAndWasteUtil); - } - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public void estimateNetDecayWasteAndBreakageVolume( - UtilizationClass utilizationClass, int breakageGroup, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, - UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { - - final var netBreakageCoeMap = controlMap - .>get(ControlKey.BREAKAGE, Map.class); - - estimateNetDecayWasteAndBreakageVolume( - utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil - ); - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public static void estimateNetDecayWasteAndBreakageVolume( - UtilizationClass utilizationClass, int breakageGroup, Map netBreakageCoeMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, - UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { - final var coefficients = netBreakageCoeMap.get(breakageGroup); - if (coefficients == null) { - throw new ProcessingException("Could not find net breakage coefficients for group " + breakageGroup); - } - - final var a1 = coefficients.getCoe(1); - final var a2 = coefficients.getCoe(2); - final var a3 = coefficients.getCoe(3); - final var a4 = coefficients.getCoe(4); - - estimateUtilization( - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, utilizationClass, ( - uc, netWaste - ) -> { - - if (netWaste <= 0f) { - return 0f; - } - var percentBroken = a1 + a2 * log(quadMeanDiameterUtil.getCoe(uc.index)); - percentBroken = clamp(percentBroken, a3, a4); - var broken = min(percentBroken / 100 * closeUtilizationUtil.getCoe(uc.index), netWaste); - return netWaste - broken; - } - ); - - if (utilizationClass == UtilizationClass.ALL) { - storeSumUtilizationComponents(closeUtilizationNetOfDecayWasteAndBreakageUtil); - } - } - - @FunctionalInterface - public static interface UtilizationProcessor { - float apply(UtilizationClass utilizationClass, float inputValue) throws ProcessingException; - } - - /** - * Estimate values for one utilization vector from another - * - * @param input source utilization - * @param output result utilization - * @param utilizationClass the utilization class for which to do the computation, UtilizationClass.ALL for all of - * them. - * @param processor Given a utilization class, and the source utilization for that class, return the result - * utilization - * @param skip a utilization class will be skipped and the result set to the default value if this is - * true for the value of the source utilization - * @param defaultValue the default value - * @throws ProcessingException - */ - private static void estimateUtilization( - UtilizationVector input, UtilizationVector output, UtilizationClass utilizationClass, - UtilizationProcessor processor, Predicate skip, float defaultValue - ) throws ProcessingException { - for (var uc : UtilizationClass.UTIL_CLASSES) { - var inputValue = input.getCoe(uc.index); - - // it seems like this should be done after checking i against utilizationClass, - // which could just be done as part of the processor definition, but this is how - // VDYP7 did it. - if (skip.test(inputValue)) { - output.setCoe(uc.index, defaultValue); - continue; - } - - if (utilizationClass != UtilizationClass.ALL && utilizationClass != uc) { - continue; - } - - var result = processor.apply(uc, inputValue); - output.setCoe(uc.index, result); - } - } - - /** - * Estimate values for one utilization vector from another - * - * @param input source utilization - * @param output result utilization - * @param utilizationClass the utilization class for which to do the computation, UtilizationClass.ALL for all of - * them. - * @param processor Given a utilization class, and the source utilization for that class, return the result - * utilization - * @throws ProcessingException - */ - private static void estimateUtilization( - UtilizationVector input, UtilizationVector output, UtilizationClass utilizationClass, - UtilizationProcessor processor - ) throws ProcessingException { - estimateUtilization(input, output, utilizationClass, processor, x -> false, 0f); - } - - private static float exponentRatio(float logit) throws ProcessingException { - float exp = safeExponent(logit); - return exp / (1f + exp); - } - - private static float safeExponent(float logit) throws ProcessingException { - if (logit > 88f) { - throw new ProcessingException("logit " + logit + " exceeds 88"); - } - return exp(logit); - } - - /** - * Normalizes the utilization components 1-4 so they sum to the value of component UtilizationClass.ALL - * - * @throws ProcessingException if the sum is not positive - */ - private static float normalizeUtilizationComponents(UtilizationVector components) throws ProcessingException { - var sum = sumUtilizationComponents(components); - var k = components.getAll() / sum; - if (sum <= 0f) { - throw new ProcessingException("Total volume " + sum + " was not positive."); - } - UtilizationClass.UTIL_CLASSES.forEach(uc -> components.setCoe(uc.index, components.getCoe(uc.index) * k)); - return k; - } - - /** - * Sums the individual utilization components (1-4) - */ - private static float sumUtilizationComponents(UtilizationVector components) { - return (float) UtilizationClass.UTIL_CLASSES.stream().mapToInt(x -> x.index).mapToDouble(components::getCoe) - .sum(); - } - - /** - * Sums the individual utilization components (1-4) and stores the results in coefficient UtilizationClass.ALL - */ - private static float storeSumUtilizationComponents(UtilizationVector components) { - var sum = sumUtilizationComponents(components); - components.setCoe(UtilizationClass.ALL.index, sum); - return sum; - } -} diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java index 31583f5b9..85e5ab5d8 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java @@ -34,7 +34,7 @@ public GenusDefinitionMap(List genusDefinitionList) { public boolean contains(String alias) { return genusByAliasMap.get(alias) != null; } - + public List getAliases() { return genusByAliasMap.values().stream().map(GenusDefinition::getAlias).toList(); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java new file mode 100644 index 000000000..3915d517f --- /dev/null +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java @@ -0,0 +1,218 @@ +package ca.bc.gov.nrs.vdyp.common; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.math.FloatMath; +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.VdypUtilizationHolder; + +public class UtilizationOperations { + + /** + * Perform the following operations on the UtilizationVectors of the given polygon. + *

        + *
      1. Scale the per-hectare values of all the utilizations of the primary layer of the given polygon, and + *
      2. For all utilizations of both the primary and veteran layer (if present) of the polygon: + *
          + *
        • Adjust the basal area to be within bounds of the utilization class, and + *
        • Calculate the quad-mean-diameter value from the basal area and trees per hectare. + *
        + *
      + * + * @param polygon the polygon on which to operate + */ + public static void doPostCreateAdjustments(VdypPolygon polygon) throws ProcessingException { + + float percentForestedLand = polygon.getPercentAvailable(); + assert !Float.isNaN(percentForestedLand); + float scalingFactor = 100.0f / percentForestedLand; + + List utilizationsToAdjust = new ArrayList<>(); + + for (VdypLayer l : polygon.getLayers().values()) { + + utilizationsToAdjust.add(l); + + l.getSpecies().values().stream().forEach(s -> utilizationsToAdjust.add(s)); + } + + for (VdypUtilizationHolder uh : utilizationsToAdjust) { + + if (percentForestedLand > 0.0f && percentForestedLand < 100.0f) { + scale(uh, scalingFactor); + } + + // Implements the logic in BANKIN2 (ICHECK == 2) adjusting the utilization values according to various rules. + + resetOnMissingValues(uh); + + adjustBasalAreaToMatchTreesPerHectare(uh); + + doCalculateQuadMeanDiameter(uh); + } + } + + /** + * Implements VDYPGETU lines 224 - 229, in which the utilization-per-hectare values are scaled by + * the given factor - the % coverage of the primary layer. + * + * @param scalingFactor the factor by which the uh is to be scaled + */ + public static void scale(VdypUtilizationHolder uh, float scalingFactor) { + + for (UtilizationClass uc: UtilizationClass.values()) { + float basalArea = uh.getBaseAreaByUtilization().get(uc); + if (basalArea > 0) { + uh.getBaseAreaByUtilization().set(uc, basalArea * scalingFactor); + } + float treesPerHectare = uh.getTreesPerHectareByUtilization().get(uc); + if (treesPerHectare > 0) { + uh.getTreesPerHectareByUtilization().set(uc, treesPerHectare * scalingFactor); + } + // lorey height is not a per-hectare value and therefore + // is excluded from scaling. + float wholeStemVolume = uh.getWholeStemVolumeByUtilization().get(uc); + if (wholeStemVolume > 0) { + uh.getWholeStemVolumeByUtilization().set(uc, wholeStemVolume * scalingFactor); + } + float closeUtilizationVolume = uh.getCloseUtilizationVolumeByUtilization().get(uc); + if (closeUtilizationVolume > 0) { + uh.getCloseUtilizationVolumeByUtilization().set(uc, closeUtilizationVolume * scalingFactor); + } + float cuVolumeMinusDecay = uh.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc); + if (cuVolumeMinusDecay > 0) { + uh.getCloseUtilizationVolumeNetOfDecayByUtilization().set(uc, cuVolumeMinusDecay * scalingFactor); + } + float cuVolumeMinusDecayWastage = uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc); + if (cuVolumeMinusDecayWastage > 0) { + uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set(uc, cuVolumeMinusDecayWastage * scalingFactor); + } + float cuVolumeMinusDecayWastageBreakage = uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().get(uc); + if (cuVolumeMinusDecayWastageBreakage > 0) { + uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().set(uc, cuVolumeMinusDecayWastageBreakage * scalingFactor); + } + // quadratic mean diameter is not a per-hectare value and + // therefore not scaled. + } + } + + private static final float MAX_ACCEPTABLE_BASAL_AREA_ERROR = 0.1f; + private static final float[] CLASS_LOWER_BOUNDS = { 4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f }; + private static final float[] CLASS_UPPER_BOUNDS = { 7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f }; + private static final float DQ_EPS = 0.005f; + + /** + * If either basalArea or liveTreesPerHectare is not positive, clear everything. + */ + private static void resetOnMissingValues(VdypUtilizationHolder uh) { + + for (UtilizationClass uc: UtilizationClass.values()) { + if (uh.getBaseAreaByUtilization().get(uc) <= 0.0f || uh.getLoreyHeightByUtilization().get(uc) <= 0.0f) { + uh.getBaseAreaByUtilization().set(uc, 0.0f); + uh.getTreesPerHectareByUtilization().set(uc, 0.0f); + // DO NOT zero-out the lorey height value. + uh.getWholeStemVolumeByUtilization().set(uc, 0.0f); + uh.getCloseUtilizationVolumeByUtilization().set(uc, 0.0f); + uh.getCloseUtilizationVolumeNetOfDecayByUtilization().set(uc, 0.0f); + uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set(uc, 0.0f); + uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().set(uc, 0.0f); + } + } + } + + /** + * Adjust Basal Area to match the Trees-Per-Hectare value. + * + * @throws ProcessingException + */ + private static void adjustBasalAreaToMatchTreesPerHectare(VdypUtilizationHolder uh) throws ProcessingException { + + for (UtilizationClass uc: UtilizationClass.values()) { + float tph = uh.getTreesPerHectareByUtilization().get(0); + if (tph > 0.0f) { + float basalAreaLowerBound = BaseAreaTreeDensityDiameter + .basalArea(CLASS_LOWER_BOUNDS[uc.ordinal()] + DQ_EPS, tph); + float basalAreaUpperBound = BaseAreaTreeDensityDiameter + .basalArea(CLASS_UPPER_BOUNDS[uc.ordinal()] - DQ_EPS, tph); + + float basalAreaError; + float newBasalArea; + String message = null; + + float basalArea = uh.getBaseAreaByUtilization().get(0); + if (basalArea < basalAreaLowerBound) { + basalAreaError = FloatMath.abs(basalArea - basalAreaLowerBound); + newBasalArea = basalAreaLowerBound; + message = MessageFormat.format( + "{0}: Error 6: basal area {1} is {2} below threshold, exceeding the maximum error of {3}.", + uh, basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR + ); + } else if (basalArea > basalAreaUpperBound) { + basalAreaError = FloatMath.abs(basalArea - basalAreaUpperBound); + message = MessageFormat.format( + "{0}: Error 6: basal area {1} is {2} above threshold, exceeding the maximum error of {3}.", + uh, basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR + ); + newBasalArea = basalAreaUpperBound; + } else { + basalAreaError = 0.0f; + newBasalArea = basalArea; + } + + if (basalAreaError > MAX_ACCEPTABLE_BASAL_AREA_ERROR) { + throw new ProcessingException(message); + } else { + uh.getBaseAreaByUtilization().set(uc, newBasalArea); + } + } + } + } + + /** + * Calculate QuadMeanDiameter for the given utilization. + * + * The value supplied in the input is IGNORED REPEAT IGNORED + * + * @throws ProcessingException + */ + private static void doCalculateQuadMeanDiameter(VdypUtilizationHolder uh) throws ProcessingException { + + for (UtilizationClass uc: UtilizationClass.values()) { + float basalArea = uh.getBaseAreaByUtilization().get(uc); + if (basalArea > 0.0f) { + float tph = uh.getTreesPerHectareByUtilization().get(uc); + float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, tph); + + if (qmd < CLASS_LOWER_BOUNDS[uc.ordinal()]) { + qmd = qmd + DQ_EPS; + if (qmd /* is still */ < CLASS_LOWER_BOUNDS[uc.ordinal()]) { + throw new ProcessingException( + MessageFormat.format( + "{0}: Error 6: calculated quad-mean-diameter value {1} is below lower limit {2}", + uh, qmd, CLASS_LOWER_BOUNDS[uc.ordinal()] + ) + ); + } + } else if (qmd > CLASS_UPPER_BOUNDS[uc.ordinal()]) { + qmd = qmd - DQ_EPS; + if (qmd /* is still */ > CLASS_UPPER_BOUNDS[uc.ordinal()]) { + throw new ProcessingException( + MessageFormat.format( + "{0}: Error 6: calculated quad-mean-diameter value {1} is above upper limit {2}", + uh, qmd, CLASS_UPPER_BOUNDS[uc.ordinal()] + ) + ); + } + } + + uh.getQuadraticMeanDiameterByUtilization().set(uc, qmd); + } + } + } +} diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java index 8a0597d9a..c782e4072 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/BaseAreaTreeDensityDiameter.java @@ -16,13 +16,13 @@ private BaseAreaTreeDensityDiameter() { public static final float PI_40K = (float) (Math.PI / 40_000); /** - * FT_BD - return an estimate of the number of trees per hectare based on a given base area (a) and quadratic mean diameter - * (q) according to the formula + * FT_BD - return an estimate of the number of trees per hectare based on a given base area (a) and quadratic mean + * diameter (q) according to the formula *

      * a / PI_40K / q**2 *

      * - * @param baseArea the base area (m**2 / hectare) + * @param baseArea the base area (m**2 / hectare) * @param quadraticMeanDiameter the quadratic mean diameter (cm / tree) * @return as described. If baseArea or quadraticMeanDiameter is not positive, 0 is returned. */ @@ -35,15 +35,16 @@ public static float treesPerHectare(float baseArea, float quadraticMeanDiameter) } /** - * FD_BT - return an estimate of the quadratic mean diameter based on a given number of trees per hectare (t) and base area - * (a) according to the formula + * FD_BT - return an estimate of the quadratic mean diameter based on a given number of trees per hectare (t) and + * base area (a) according to the formula *

      * (b / t / PI_40K)**1/2 *

      * * @param baseArea the base area value * @param treesPerHectare the trees per hectare value - * @return as described. If baseArea or treesPerHectare is Nan, not positive or more than 1,000,000, 0.0 is returned. + * @return as described. If baseArea or treesPerHectare is Nan, not positive or more than 1,000,000, 0.0 is + * returned. */ public static float quadMeanDiameter(float baseArea, float treesPerHectare) { if (baseArea > 1e6f || treesPerHectare > 1e6f || Float.isNaN(baseArea) || Float.isNaN(treesPerHectare)) { @@ -54,16 +55,17 @@ public static float quadMeanDiameter(float baseArea, float treesPerHectare) { return 0f; } - + /** * FB_DT - return an estimate of the basal area based on a given quad-mean-diameter value (q) and a * trees-per-hectare value according to the formula *

      * q**2 * PI_40K * t *

      + * * @param quadraticMeanDiameter the quadratic mean diameter (cm / tree) - * @param treesPerHectare the trees per hectare value - * @return as described. If either parameter is NaN, 0f is returned. + * @param treesPerHectare the trees per hectare value + * @return as described. If either parameter is NaN, 0f is returned. */ public static float basalArea(float quadraticMeanDiameter, float treesPerHectare) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index e0140a4c5..b05bab9cd 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -39,6 +39,7 @@ public class CachingResolvedControlMapImpl extends ResolvedControlMapImpl implem final MatrixMap2 defaultEquationGroup; final MatrixMap2> equationModifierGroup; final MatrixMap2 hl1Coefficients; + public CachingResolvedControlMapImpl(Map controlMap) { super(controlMap); @@ -48,7 +49,7 @@ public CachingResolvedControlMapImpl(Map controlMap) { List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); this.genusDefinitionMap = new GenusDefinitionMap(genusDefinitions); - this.netDecayWasteCoeMap = this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); + this.netDecayWasteCoeMap = this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); this.netDecayCoeMap = this.get(ControlKey.VOLUME_NET_DECAY, MatrixMap2.class); this.wasteModifierMap = this.get(ControlKey.WASTE_MODIFIERS, MatrixMap2.class); this.decayModifierMap = this.get(ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index 72d3ce54f..a949c0e96 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -12,63 +12,63 @@ import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; -public interface ResolvedControlMap { +public interface ResolvedControlMap { U get(ControlKey key, Class clazz); /** 9 - BEC_DEF */ BecLookup getBecLookup(); - + /** 10 - SP0_DEF */ GenusDefinitionMap getGenusDefinitionMap(); - + /** 26 - SITE_CURVE_AGE_MAX */ Map getMaximumAgeBySiteCurveNumber(); - + /** 30 - DEFAULT_EQ_NUM */ MatrixMap2 getDefaultEquationGroup(); - + /** 31 - EQN_MODIFIERS */ MatrixMap2> getEquationModifierGroup(); - + /** 50 - HL_PRIMARY_SP_EQN_P1 */ MatrixMap2 getHl1Coefficients(); - + /** 70 - UTIL_COMP_BA */ MatrixMap3 getBasalAreaDiameterUtilizationComponentMap(); - + /** 71 - UTIL_COMP_DQ */ MatrixMap3 getQuadMeanDiameterUtilizationComponentMap(); - + /** 80 - SMALL_COMP_PROBABILITY */ Map getSmallComponentProbabilityCoefficients(); - + /** 81 - SMALL_COMP_BA */ Map getSmallComponentBasalAreaCoefficients(); - + /** 82 - SMALL_COMP_DQ */ Map getSmallComponentQuadMeanDiameterCoefficients(); - + /** 85 - SMALL_COMP_HL */ Map getSmallComponentLoreyHeightCoefficients(); - + /** 86 - SMALL_COMP_WS_VOLUME */ Map getSmallComponentWholeStemVolumeCoefficients(); - - /** 90 - TOTAL_STAND_WHOLE_STEM_VOL*/ + + /** 90 - TOTAL_STAND_WHOLE_STEM_VOL */ Map getTotalStandWholeStepVolumeCoeMap(); - + /** 91 - UTIL_COMP_WS_VOLUME */ MatrixMap2> getWholeStemUtilizationComponentMap(); - + /** 92 - CLOSE_UTIL_VOLUME */ MatrixMap2> getCloseUtilizationCoeMap(); - + /** 93 - VOLUME_NET_DECAY */ MatrixMap2> getNetDecayCoeMap(); /** 94 - VOLUME_NET_DECAY_WASTE */ Map getNetDecayWasteCoeMap(); - + /** 108 - BA_DQ_UPPER_BOUNDS */ Map getUpperBounds(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 7a62f22cc..40bf7d872 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -18,25 +18,25 @@ import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; public class ResolvedControlMapImpl implements ResolvedControlMap { - + private final Map controlMap; - + private final Map entityCache = new HashMap<>(); - + public ResolvedControlMapImpl(Map controlMap) { this.controlMap = controlMap; } - + @SuppressWarnings("unchecked") @Override public U get(ControlKey key, Class clazz) { - + U entity = (U) entityCache.get(key); if (entity == null) { entity = (U) Utils.expectParsedControl(controlMap, key.name(), clazz); entityCache.put(key, entity); } - + return entity; } @@ -48,12 +48,12 @@ public GenusDefinitionMap getGenusDefinitionMap() { @Override public BecLookup getBecLookup() { - return this.get(ControlKey.BEC_DEF, BecLookup.class); + return this.get(ControlKey.BEC_DEF, BecLookup.class); } @Override public Map getNetDecayWasteCoeMap() { - return this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); + return this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); } @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java index 32d8b248b..590498c6c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BasalAreaGrowthEmpiricalParser.java @@ -27,10 +27,9 @@ *

    * All lines are parsed. A BEC Zone Alias value, trimmed, of "" results in the line being skipped. *

    - * The result of the parse is a map from BEC Zone Alias and Species to a (zero-based) eight-element coefficient - * array. If, for a given line "indicator" is zero, only the first coefficient is recorded (for species 0) and - * all others are set to zero. If "indicator" is one, all coefficients on the line are assigned to their respective - * species. + * The result of the parse is a map from BEC Zone Alias and Species to a (zero-based) eight-element coefficient array. + * If, for a given line "indicator" is zero, only the first coefficient is recorded (for species 0) and all others are + * set to zero. If "indicator" is one, all coefficients on the line are assigned to their respective species. *

    * Control index: 121 *

    @@ -39,7 +38,8 @@ * @author Michael Junkin, Vivid Solutions * @see BecZoneBySpeciesCoefficientParser */ -public class BasalAreaGrowthEmpiricalParser implements ControlMapSubResourceParser> { +public class BasalAreaGrowthEmpiricalParser + implements ControlMapSubResourceParser> { private static final int NUM_SPECIES = 16; private static final int NUM_COEFFICIENTS = 8; @@ -58,11 +58,14 @@ public boolean isIgnoredLine(String line) { } } // - .value(4, BEC_ZONE_ID_KEY, ControlledValueParser.BEC) // - .space(2) // - .value(1, INDEX_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, NUM_COEFFICIENTS, false, "Index value")) // - .value(2, INDICATOR_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, 1, true, "Indicator value")) // - .multiValue(NUM_SPECIES, 8, COEFFICIENTS_KEY, ValueParser.FLOAT); + .value(4, BEC_ZONE_ID_KEY, ControlledValueParser.BEC) // + .space(2) // + .value( + 1, INDEX_KEY, + ValueParser.range(ValueParser.INTEGER, 0, true, NUM_COEFFICIENTS, false, "Index value") + ) // + .value(2, INDICATOR_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, 1, true, "Indicator value")) // + .multiValue(NUM_SPECIES, 8, COEFFICIENTS_KEY, ValueParser.FLOAT); } private LineParser lineParser; @@ -107,7 +110,7 @@ public MatrixMap2 parse(InputStream is, Map parse(InputStream is, Map) value.get(COEFFICIENTS_KEY); var specIt = sp0Aliases.iterator(); - + Float first = null; int coefficientIndex = 0; while (specIt.hasNext()) { var spec = specIt.next(); - + Float coe = specCoefficients.get(coefficientIndex); if (coefficientIndex == 0) { first = coe; @@ -96,7 +99,7 @@ public MatrixMap2 parse(InputStream is, Map parse(InputStream is, Map try { details = new GrowthFiatDetails(regionId, coefficients); } catch (ResourceParseException e) { - throw new ValueParseException(String.valueOf(regionId), "Error constructing GrowthFiatDetails instance", e); + throw new ValueParseException( + String.valueOf(regionId), "Error constructing GrowthFiatDetails instance", e + ); } if (details.getNAgesSupplied() == 0) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java index 675d8312d..217d424d4 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompVarAdjustments.java @@ -15,16 +15,17 @@ public class CompVarAdjustments { private static final int LOREY_HEIGHT_PRIMARY_PARAM = 51; private static final int LOREY_HEIGHT_OTHER_PARAM = 52; - + private final Map smallUtilizationClassVariables = new HashMap<>(); private final Map utilizationClassBasalAreaVariables = new HashMap<>(); private final Map utilizationClassQuadMeanDiameterVariables = new HashMap<>(); - private final MatrixMap2 utilizationClassVolumeVariables - = new MatrixMap2Impl<>(VolumeVariable.ALL, UtilizationClass.UTIL_CLASSES, (k1, k2) -> 1.0f); + private final MatrixMap2 utilizationClassVolumeVariables = new MatrixMap2Impl<>( + VolumeVariable.ALL, UtilizationClass.UTIL_CLASSES, (k1, k2) -> 1.0f + ); private float loreyHeightPrimary; private float loreyHeightOther; - + static { assert UtilizationClassVariable.BASAL_AREA.ordinal() == 0; assert UtilizationClassVariable.QUAD_MEAN_DIAMETER.ordinal() == 1; @@ -35,26 +36,26 @@ public class CompVarAdjustments { assert UtilizationClass.U125TO175.ordinal() == 3; assert UtilizationClass.U175TO225.ordinal() == 4; assert UtilizationClass.OVER225.ordinal() == 5; - + assert VolumeVariable.WHOLE_STEM_VOL.ordinal() == 0; assert VolumeVariable.CLOSE_UTIL_VOL.ordinal() == 1; assert VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY.ordinal() == 2; assert VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE.ordinal() == 3; } - + private final static Map ucOffsets = new HashMap<>(); private final static Map defaultValuesMap = new HashMap<>(); - + static { ucOffsets.put(UtilizationClass.U75TO125, 11); ucOffsets.put(UtilizationClass.U125TO175, 21); ucOffsets.put(UtilizationClass.U175TO225, 31); ucOffsets.put(UtilizationClass.OVER225, 41); - + for (int i = MIN_INDEX; i <= MAX_INDEX; i++) defaultValuesMap.put(i, 1.0f); } - + /** * Constructs a default instance, one in which all index values are 1.0f. See rd_e028.for. */ @@ -67,26 +68,26 @@ public CompVarAdjustments() { */ public CompVarAdjustments(Map values) { - for (UtilizationClassVariable ucv: UtilizationClassVariable.values()) { + for (UtilizationClassVariable ucv : UtilizationClassVariable.values()) { smallUtilizationClassVariables.put(ucv, values.get(SMALL_VARIABLE_START_INDEX + ucv.ordinal())); } - - for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { utilizationClassBasalAreaVariables.put(uc, values.get(BA_ADJ_UC_START_INDEX + uc.ordinal() - 2)); } - - for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { utilizationClassQuadMeanDiameterVariables.put(uc, values.get(DQ_ADJ_UC_START_INDEX + uc.ordinal() - 2)); } - - for (VolumeVariable vv: VolumeVariable.ALL) { - for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + + for (VolumeVariable vv : VolumeVariable.ALL) { + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { utilizationClassVolumeVariables.put(vv, uc, values.get(ucOffsets.get(uc) + vv.ordinal())); } } - + loreyHeightPrimary = values.get(LOREY_HEIGHT_PRIMARY_PARAM); - loreyHeightOther = values.get(LOREY_HEIGHT_OTHER_PARAM); + loreyHeightOther = values.get(LOREY_HEIGHT_OTHER_PARAM); } public float getLoreyHeightPrimaryParam() { @@ -96,26 +97,36 @@ public float getLoreyHeightPrimaryParam() { public float getLoreyHeightOther() { return loreyHeightOther; } - + public float getValue(UtilizationClass uc, UtilizationClassVariable v) { if (UtilizationClass.SMALL.equals(uc)) { - return smallUtilizationClassVariables.get(v); + return smallUtilizationClassVariables.get(v); } else if (!UtilizationClass.ALL.equals(uc)) { switch (v) { - case BASAL_AREA: return utilizationClassBasalAreaVariables.get(uc); - case QUAD_MEAN_DIAMETER: return utilizationClassQuadMeanDiameterVariables.get(uc); - default: break; + case BASAL_AREA: + return utilizationClassBasalAreaVariables.get(uc); + case QUAD_MEAN_DIAMETER: + return utilizationClassQuadMeanDiameterVariables.get(uc); + default: + break; } } - - throw new IllegalArgumentException(MessageFormat.format("getValue({}, {}) - combination of UtilizationClass and UtilizationClassVariable is invalid", uc, v)); + + throw new IllegalArgumentException( + MessageFormat.format( + "getValue({}, {}) - combination of UtilizationClass and UtilizationClassVariable is invalid", + uc, v + ) + ); } - + public float getVolumeValue(UtilizationClass uc, VolumeVariable vv) { if (uc.ordinal() >= UtilizationClass.U75TO125.ordinal()) { return utilizationClassVolumeVariables.get(vv, uc); } - throw new IllegalArgumentException(MessageFormat.format("getVolumeValue({}, {}) - UtilizationClass is invalid", uc, vv)); + throw new IllegalArgumentException( + MessageFormat.format("getVolumeValue({}, {}) - UtilizationClass is invalid", uc, vv) + ); } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java index de9900227..08d9e23ea 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ComponentSizeLimits.java @@ -1,8 +1,8 @@ package ca.bc.gov.nrs.vdyp.model; public record ComponentSizeLimits( - float loreyHeightMaximum, // - float quadMeanDiameterMaximum, // + float loreyHeightMaximum, // + float quadMeanDiameterMaximum, // float minQuadMeanDiameterLoreyHeightRatio, // float maxQuadMeanDiameterLoreyHeightRatio ) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java index 5727fb043..57da8d0f3 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/DebugSettings.java @@ -2,24 +2,21 @@ import java.util.Arrays; -/** +/** * Stores the debug flag values provided in key 199 of the control files. *

    - * This class accepts an array of Integers (if null, or the default constructor - * is used, an empty integer array is used). The array cannot have more than - * 25 elements, but may have fewer. + * This class accepts an array of Integers (if null, or the default constructor is used, an empty integer array is + * used). The array cannot have more than 25 elements, but may have fewer. *

    - * The class provides one operation: debugValue, which takes - * the number of debug setting whose value is needed. In keeping with the - * original FORTRAN code, these values are one-based - so, debug - * setting "5" is actually stored at settings[4]. + * The class provides one operation: debugValue, which takes the number of debug setting whose value is + * needed. In keeping with the original FORTRAN code, these values are one-based - so, debug setting "5" is + * actually stored at settings[4]. *

    - * It is an error to supply a setting number above 25. If 25 or less but - * higher than the number of elements in the array, the default value of - * "0" is returned. Otherwise, the value is read from the array. + * It is an error to supply a setting number above 25. If 25 or less but higher than the number of elements in the + * array, the default value of "0" is returned. Otherwise, the value is read from the array. *

    - * Instances of class are typically wrapped by an application-specific class - * that understands the settings in use by the application. + * Instances of class are typically wrapped by an application-specific class that understands the settings in use by the + * application. *

    * See IPSJF155, appendix IX, details. */ @@ -27,28 +24,30 @@ public class DebugSettings { public static final int MAX_DEBUG_SETTINGS = 25; private static final int DEFAULT_DEBUG_SETTING = 0; - + final int[] settings; - + /** - * Create a DebugSettings instance from the given values. If settings is null, this - * is equivalent to calling DebugSettings(new Integer[0]). If an entry in settings - * is null, the default value (0) is assigned to that variable. If more than - * MAX_DEBUG_SETTINGS are supplied, those in excess are ignored. + * Create a DebugSettings instance from the given values. If settings is null, this is equivalent to + * calling DebugSettings(new Integer[0]). If an entry in settings is null, the default value (0) is + * assigned to that variable. If more than MAX_DEBUG_SETTINGS are supplied, those in excess are + * ignored. */ public DebugSettings(Integer[] settings) { - + if (settings == null) { settings = new Integer[0]; } - + if (settings.length > MAX_DEBUG_SETTINGS) { - throw new IllegalArgumentException("Debug settings array has length " + settings.length - + ", which exceeds the maximum length of " + MAX_DEBUG_SETTINGS); + throw new IllegalArgumentException( + "Debug settings array has length " + settings.length + ", which exceeds the maximum length of " + + MAX_DEBUG_SETTINGS + ); } - + this.settings = new int[MAX_DEBUG_SETTINGS]; - + for (int i = 0; i < MAX_DEBUG_SETTINGS; i++) { if (i < settings.length && settings[i] != null) { this.settings[i] = settings[i]; @@ -57,26 +56,29 @@ public DebugSettings(Integer[] settings) { } } } - + /** * Create a DebugSettings instance with all settings set to zero. */ public DebugSettings() { this(new Integer[0]); } - + /** - * Return the value of the debug variable with setting number settingNumber. This is a - * one-based value. + * Return the value of the debug variable with setting number settingNumber. This is a one-based + * value. + * * @param settingNumber the number of the debug variable whose value is to be returned. * @return as described. */ public int getValue(int settingNumber) { if (settingNumber < 1 || settingNumber > MAX_DEBUG_SETTINGS) { - throw new IllegalArgumentException("Debug setting number " + settingNumber + " is out of range -" - + " must be between 1 and " + MAX_DEBUG_SETTINGS); + throw new IllegalArgumentException( + "Debug setting number " + settingNumber + " is out of range -" + " must be between 1 and " + + MAX_DEBUG_SETTINGS + ); } - + return settings[settingNumber - 1]; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java index 25ab17534..9134e64c1 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetails.java @@ -9,47 +9,53 @@ public class GrowthFiatDetails { private static final int N_AGES = 4; private static final int N_MIXED_COEFFICIENTS = 3; private static final int N_ENTRIES = N_AGES * 2 + N_MIXED_COEFFICIENTS; - + private final Region region; - + private int nAgesSupplied; private final Float[] ages; private final Float[] coefficients; private final Float[] mixedCoefficients; /** - * Create a GrowthFiat model. The first 8 values is a list of four pairs of (age, coefficient.) The list - * may be terminated by supplying 0 as the age value in entries that are not to be considered part of - * the list. The ages in all previous entries must be monatonically increasing. The coefficients of all - * pairs whose age is 0 must be 0, too. + * Create a GrowthFiat model. The first 8 values is a list of four pairs of (age, coefficient.) The list may be + * terminated by supplying 0 as the age value in entries that are not to be considered part of the list. The ages in + * all previous entries must be monatonically increasing. The coefficients of all pairs whose age is 0 must be 0, + * too. * * @param regionId either 1 (coast) or 2 (interior) * @param coefficients (11: 0-7 N_AGES pairs of (age, coefficient), 8-10 mixed coefficients) - * - * @throws ResourceParseException + * + * @throws ResourceParseException */ public GrowthFiatDetails(int regionId, List numbers) throws ResourceParseException { if (numbers == null || numbers.size() != N_ENTRIES) { throw new ResourceParseException("numbers is null or does not contain " + N_ENTRIES + " entries"); } - + if (regionId == 1) { - region = Region.COASTAL; + region = Region.COASTAL; } else if (regionId == 2) { region = Region.INTERIOR; } else { - throw new ResourceParseException("region must have the value \"1\" or \"2\"; instead, saw \"" + regionId + "\""); + throw new ResourceParseException( + "region must have the value \"1\" or \"2\"; instead, saw \"" + regionId + "\"" + ); } nAgesSupplied = N_AGES; for (int i = 0; i < N_AGES; i++) { if (nAgesSupplied < N_AGES) { if (numbers.get(i * 2) != 0.0) { - throw new ResourceParseException(MessageFormat.format("All ages after the first 0 must be 0, too. Instead, saw \"{0}\"", - numbers.get(i * 2))); + throw new ResourceParseException( + MessageFormat.format( + "All ages after the first 0 must be 0, too. Instead, saw \"{0}\"", + numbers.get(i * 2) + ) + ); } - } else if (numbers.get(i * 2) == 0.0) { + } else if (numbers.get(i * 2) == 0.0) { nAgesSupplied = i; } } @@ -59,9 +65,13 @@ public GrowthFiatDetails(int regionId, List numbers) throws ResourceParse for (int i = 1; i < N_AGES; i++) { ages[i] = numbers.get(i * 2); if (i < nAgesSupplied && ages[i] < ages[i - 1]) { - throw new ResourceParseException(MessageFormat.format("Non-zero age values must be monatonically increasing" - + " Instead, saw \"{0}\" followed by \"{1}\"", - ages[i - 1], ages[i])); + throw new ResourceParseException( + MessageFormat.format( + "Non-zero age values must be monatonically increasing" + + " Instead, saw \"{0}\" followed by \"{1}\"", + ages[i - 1], ages[i] + ) + ); } } @@ -70,8 +80,12 @@ public GrowthFiatDetails(int regionId, List numbers) throws ResourceParse for (int i = 1; i < N_AGES; i++) { coefficients[i] = numbers.get(i * 2 + 1); if (i >= nAgesSupplied && coefficients[i] != 0.0f) { - throw new ResourceParseException(MessageFormat.format("Coefficients of ages with value 0 must also have value 0" - + " Instead, saw \"{0}\"", coefficients[i])); + throw new ResourceParseException( + MessageFormat.format( + "Coefficients of ages with value 0 must also have value 0" + " Instead, saw \"{0}\"", + coefficients[i] + ) + ); } } @@ -121,9 +135,9 @@ public Float[] getCoefficients() { public Float[] getMixedCoefficients() { return mixedCoefficients; } - + public float calculateCoefficient(float age) { - + if (nAgesSupplied == 0 || age <= ages[0]) { return getCoefficient(0); } else if (age >= ages[nAgesSupplied - 1]) { @@ -133,13 +147,11 @@ public float calculateCoefficient(float age) { if (age >= ages[i] && age < ages[j]) { return getCoefficient(i) - + (getCoefficient(j) - getCoefficient(i)) - * (age - ages[i]) - / (ages[j] - ages[i]); + + (getCoefficient(j) - getCoefficient(i)) * (age - ages[i]) / (ages[j] - ages[i]); } } } - + throw new IllegalStateException(MessageFormat.format("age {} was not found to be in range ", age)); } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java index afe68469d..a34e68d9a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/LayerType.java @@ -32,7 +32,7 @@ public enum LayerType { public String getAlias() { return alias; } - + public int getIndex() { if (index == null) { throw new UnsupportedOperationException("LayerType " + this.getAlias() + " is not supported"); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java index 5978f320b..6da86a0c5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/NonprimaryHLCoefficients.java @@ -20,9 +20,11 @@ public int getEquationIndex() { return equationIndex; } - private static final NonprimaryHLCoefficients DEFAULT_VALUE = new NonprimaryHLCoefficients(new float[] { 1.0f, 1.0f }, 2); - - public static final NonprimaryHLCoefficients getDefault() { + private static final NonprimaryHLCoefficients DEFAULT_VALUE = new NonprimaryHLCoefficients( + new float[] { 1.0f, 1.0f }, 2 + ); + + public static final NonprimaryHLCoefficients getDefault() { return DEFAULT_VALUE; } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java index 6da96a5dd..5cb52e148 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/PolygonIdentifier.java @@ -4,7 +4,7 @@ import java.util.function.IntUnaryOperator; public class PolygonIdentifier { - + public static final int ID_LENGTH = 25; public static final int YEAR_LENGTH = 4; public static final int BASE_LENGTH = ID_LENGTH - YEAR_LENGTH; @@ -37,6 +37,7 @@ public static PolygonIdentifier split(String polygonIdentifier) throws IllegalAr /** * Return the base (a.k.a. name) of the Polygon. These terms are synonomous. + * * @return as described */ public String getBase() { @@ -45,6 +46,7 @@ public String getBase() { /** * Return the name (a.k.a. base) of the Polygon. These terms are synonomous. + * * @return as described */ public String getName() { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java index bd359dae9..c3642057e 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationClassVariable.java @@ -6,7 +6,6 @@ public enum UtilizationClassVariable { BASAL_AREA, QUAD_MEAN_DIAMETER, LOREY_HEIGHT, WHOLE_STEM_VOLUME; - public static final List ALL = Collections.unmodifiableList( - List.of(BASAL_AREA, QUAD_MEAN_DIAMETER, LOREY_HEIGHT, WHOLE_STEM_VOLUME) - ); + public static final List ALL = Collections + .unmodifiableList(List.of(BASAL_AREA, QUAD_MEAN_DIAMETER, LOREY_HEIGHT, WHOLE_STEM_VOLUME)); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java index 514c5394f..1f63471f4 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java @@ -8,6 +8,10 @@ public class UtilizationVector extends Coefficients { + public UtilizationVector() { + super(new float[] { Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN }, UtilizationClass.SMALL.index); + } + public UtilizationVector(float small, float all, float uc1, float uc2, float uc3, float uc4) { super(new float[] { small, all, uc1, uc2, uc3, uc4 }, UtilizationClass.SMALL.index); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 71cc00a0e..f7f9d38e2 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -277,11 +277,5 @@ protected VdypSite buildSite(Consumer config) { builder.layerType(layerType.get()); }); } - - public void baseAreaByUtilization(UtilizationVector utilizationVector) { - // TODO Auto-generated method stub - - } - } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java index 055b243c4..e28e3ccc6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java @@ -128,157 +128,4 @@ public float getQuadraticMeanDiameterAtBH() { public VdypSpecies getParent() { return parent; } - - /** - * Implements VDYPGETU lines 224 - 229, in which the utilization- per-hectare values are scaled by the given factor - * - the % coverage of the primary layer. - * - * @param scalingFactor - */ - public void scale(float scalingFactor) { - - if (this.basalArea > 0) { - this.basalArea *= scalingFactor; - } - if (this.liveTreesPerHectare > 0) { - this.liveTreesPerHectare *= scalingFactor; - } - // lorey height is not a per-hectare value and therefore - // is excluded from scaling. - if (this.wholeStemVolume > 0) { - this.wholeStemVolume *= scalingFactor; - } - if (this.closeUtilizationVolume > 0) { - this.closeUtilizationVolume *= scalingFactor; - } - if (this.cuVolumeMinusDecay > 0) { - this.cuVolumeMinusDecay *= scalingFactor; - } - if (this.cuVolumeMinusDecayWastage > 0) { - this.cuVolumeMinusDecayWastage *= scalingFactor; - } - if (this.cuVolumeMinusDecayWastageBreakage > 0) { - this.cuVolumeMinusDecayWastageBreakage *= scalingFactor; - } - // quadratic mean diameter is not a per-hectare value and - // therefore not scaled. - } - - private static final float MAX_ACCEPTABLE_BASAL_AREA_ERROR = 0.1f; - private static final float[] CLASS_LOWER_BOUNDS = { 4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f }; - private static final float[] CLASS_UPPER_BOUNDS = { 7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f }; - private static final float DQ_EPS = 0.005f; - - /** - * Implements the logic in BANKIN2 (ICHECK == 2) adjusting the utilization values according to various rules. - * - * @throws ProcessingException when calculated values are out of range - */ - public void doPostCreateAdjustments() throws ProcessingException { - - resetOnMissingValues(); - - adjustBasalAreaToMatchTreesPerHectare(); - - doCalculateQuadMeanDiameter(); - } - - /** - * If either basalArea or liveTreesPerHectare is not positive, clear everything. - */ - private void resetOnMissingValues() { - - if (this.basalArea <= 0.0f || this.liveTreesPerHectare <= 0.0f) { - this.basalArea = 0.0f; - this.liveTreesPerHectare = 0.0f; - // DO NOT zero-out the lorey height value. - this.wholeStemVolume = 0.0f; - this.closeUtilizationVolume = 0.0f; - this.cuVolumeMinusDecay = 0.0f; - this.cuVolumeMinusDecayWastage = 0.0f; - this.cuVolumeMinusDecayWastageBreakage = 0.0f; - } - } - - /** - * Adjust Basal Area to match the Trees-Per-Hectare value. - * - * @throws ProcessingException - */ - private void adjustBasalAreaToMatchTreesPerHectare() throws ProcessingException { - - if (this.liveTreesPerHectare > 0.0f) { - float basalAreaLowerBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()] + DQ_EPS, this.liveTreesPerHectare); - float basalAreaUpperBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - DQ_EPS, this.liveTreesPerHectare); - - float basalAreaError; - float newBasalArea; - String message = null; - - if (this.basalArea < basalAreaLowerBound) { - basalAreaError = FloatMath.abs(this.basalArea - basalAreaLowerBound); - newBasalArea = basalAreaLowerBound; - message = MessageFormat.format( - "{0}: Error 6: basal area {1} is {2} below threshold, exceeding the maximum error of {3}.", this, - this.basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR - ); - } else if (this.basalArea > basalAreaUpperBound) { - basalAreaError = FloatMath.abs(this.basalArea - basalAreaUpperBound); - message = MessageFormat.format( - "{0}: Error 6: basal area {1} is {2} above threshold, exceeding the maximum error of {3}.", this, - this.basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR - ); - newBasalArea = basalAreaUpperBound; - } else { - basalAreaError = 0.0f; - newBasalArea = this.basalArea; - } - - if (basalAreaError > MAX_ACCEPTABLE_BASAL_AREA_ERROR) { - throw new ProcessingException(message); - } else { - this.basalArea = newBasalArea; - } - } - } - - /** - * Calculate QuadMeanDiameter for the given utilization. - * - * The value supplied in the input is IGNORED REPEAT IGNORED - * - * @throws ProcessingException - */ - private void doCalculateQuadMeanDiameter() throws ProcessingException { - - if (this.basalArea > 0.0f) { - float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, liveTreesPerHectare); - - if (qmd < CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()]) { - qmd = qmd + DQ_EPS; - if (qmd /* is still */ < CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()]) { - throw new ProcessingException( - MessageFormat.format( - "{0}: Error 6: calculated quad-mean-diameter value {1} is below lower limit {2}", - this, qmd, CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()] - ) - ); - } - } else if (qmd > CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()]) { - qmd = qmd - DQ_EPS; - if (qmd /* is still */ > CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()]) { - throw new ProcessingException( - MessageFormat.format( - "{0}: Error 6: calculated quad-mean-diameter value {1} is above upper limit {2}", - this, qmd, CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - ) - ); - } - } - - this.quadraticMeanDiameterAtBH = qmd; - } - } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java index 4e3f21af1..a9d219518 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationHolder.java @@ -1,88 +1,85 @@ package ca.bc.gov.nrs.vdyp.model; -import java.util.Arrays; - /** - * Common accessors for utilization vecors shared by Layer and Species + * Common accessors for utilization vectors shared by Layer and Species * * @author Kevin Smith, Vivid Solutions - * */ public interface VdypUtilizationHolder { /** - * Close utilization volume net of decay, waste and breakage for utilization index -1 through 0 + * Close utilization volume net of decay, waste and breakage for utilization index -1 through 4 */ void setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization ); /** - * Close utilization volume net of decay, waste and breakage for utilization index -1 through 0 + * Close utilization volume net of decay, waste and breakage for utilization index -1 through 4 */ UtilizationVector getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(); /** - * Close utilization volume net of decay and waste for utilization index -1 through 0 + * Close utilization volume net of decay and waste for utilization index -1 through 4 */ void setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization( UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization ); /** - * Close utilization volume net of decay and waste for utilization index -1 through 0 + * Close utilization volume net of decay and waste for utilization index -1 through 4 */ UtilizationVector getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(); /** - * Close utilization volume net of decay for utilization index -1 through 0 + * Close utilization volume net of decay for utilization index -1 through 4 */ void setCloseUtilizationVolumeNetOfDecayByUtilization( UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization ); /** - * Close utilization volume net of decay for utilization index -1 through 0 + * Close utilization volume net of decay for utilization index -1 through 4 */ UtilizationVector getCloseUtilizationVolumeNetOfDecayByUtilization(); /** - * Close utilization volume for utilization index -1 through 0 + * Close utilization volume for utilization index -1 through 4 */ void setCloseUtilizationVolumeByUtilization(UtilizationVector closeUtilizationVolumeByUtilization); /** - * Close utilization volume for utilization index -1 through 0 + * Close utilization volume for utilization index -1 through 4 */ UtilizationVector getCloseUtilizationVolumeByUtilization(); /** - * Whole stem volume for utilization index -1 through 0 + * Whole stem volume for utilization index -1 through 4 */ void setWholeStemVolumeByUtilization(UtilizationVector wholeStemVolumeByUtilization); /** - * Whole stem volume for utilization index -1 through 0 + * Whole stem volume for utilization index -1 through 4 */ UtilizationVector getWholeStemVolumeByUtilization(); /** - * Trees per hectare for utilization index -1 through 0 + * Trees per hectare for utilization index -1 through 4 */ void setTreesPerHectareByUtilization(UtilizationVector treesPerHectareByUtilization); /** - * Trees per hectare for utilization index -1 through 0 + * Trees per hectare for utilization index -1 through 4 */ UtilizationVector getTreesPerHectareByUtilization(); /** - * Quadratic mean of diameter for utilization index -1 through 0 + * Quadratic mean of diameter for utilization index -1 through 4 */ void setQuadraticMeanDiameterByUtilization(UtilizationVector quadraticMeanDiameterByUtilization); /** - * Quadratic mean of diameter for utilization index -1 through 0 + * Quadratic mean of diameter for utilization index -1 through 4 */ UtilizationVector getQuadraticMeanDiameterByUtilization(); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java index 740194241..c6979b554 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java @@ -36,13 +36,13 @@ class EstimatorsTest { Map controlMap; BecLookup becLookup; - Estimators emp; + EstimationMethods emp; @BeforeEach void setup() { controlMap = TestUtils.loadControlMap(); var resolvedControlMap = new ResolvedControlMapImpl(controlMap); - emp = new Estimators(resolvedControlMap); + emp = new EstimationMethods(resolvedControlMap); becLookup = (BecLookup) controlMap.get(ControlKey.BEC_DEF.name()); } @@ -164,8 +164,8 @@ void testWhenWholeStemVolumeIsZero() throws ProcessingException { float loreyHeight = 30.0f; emp.estimateCloseUtilizationVolume( - UtilizationClass.U75TO125, aAdjust, volumeGroup, loreyHeight, - quadMeanDiameterByUtilization, wholeStemVolumeByUtilization, closeUtilizationVolume + UtilizationClass.U75TO125, aAdjust, volumeGroup, loreyHeight, quadMeanDiameterByUtilization, + wholeStemVolumeByUtilization, closeUtilizationVolume ); assertThat(closeUtilizationVolume, contains(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); @@ -194,8 +194,8 @@ void testTypical() throws ProcessingException { float loreyHeight = 36.7552986f; emp.estimateCloseUtilizationVolume( - UtilizationClass.U175TO225, aAdjust, volumeGroup, loreyHeight, - quadMeanDiameterByUtilization, wholeStemVolumeByUtilization, closeUtilizationVolume + UtilizationClass.U175TO225, aAdjust, volumeGroup, loreyHeight, quadMeanDiameterByUtilization, + wholeStemVolumeByUtilization, closeUtilizationVolume ); // Result of run in FORTRAN VDYP7 with the above parameters. @@ -247,8 +247,8 @@ void testWhenCloseUtilizationIsZero() throws ProcessingException { int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); emp.estimateNetDecayVolume( - genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, - volumeGroup, 0.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay + genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, volumeGroup, 0.0f, + quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay ); assertThat(closeUtilizationNetOfDecay, contains(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); @@ -276,8 +276,8 @@ void testTypical() throws ProcessingException { int decayGroup = decayEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); emp.estimateNetDecayVolume( - genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, - decayGroup, 54.0f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay + genus.getAlias(), becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, decayGroup, 54.0f, + quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay ); // Result of run in FORTRAN VDYP7 with the above parameters. @@ -330,8 +330,8 @@ void testTypical() throws ProcessingException { UtilizationVector closeUtilizationNetOfDecayAndWastage = Utils.utilizationVector(0.0f); emp.estimateNetDecayAndWasteVolume( - becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), - 36.7552986f, quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay, + becDefinition.getRegion(), UtilizationClass.U175TO225, aAdjust, genus.getAlias(), 36.7552986f, + quadMeanDiameterByUtilization, closeUtilization, closeUtilizationNetOfDecay, closeUtilizationNetOfDecayAndWastage ); @@ -363,8 +363,8 @@ void testWhenCloseUtilizationLessDecayAndWastageIsZero() throws ProcessingExcept int breakageGroup = breakageEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); emp.estimateNetDecayWasteAndBreakageVolume( - UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, - closeUtilization, closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage + UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, closeUtilization, + closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage ); assertThat(closeUtilizationNetOfDecayAndWastage, contains(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); @@ -393,8 +393,8 @@ void testTypical() throws ProcessingException { int breakageGroup = breakageEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); emp.estimateNetDecayWasteAndBreakageVolume( - UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, - closeUtilization, closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage + UtilizationClass.U175TO225, breakageGroup, quadMeanDiameterByUtilization, closeUtilization, + closeUtilizationNetOfDecayAndWastage, closeUtilizationNetOfDecayWastageAndBreakage ); // Result of run in FORTRAN VDYP7 with the above parameters. @@ -693,8 +693,7 @@ void testWholeStemVolumePerTreeEstimation() { ); int volumeGroup = volumeEquationGroupMatrix.get(genus.getAlias(), becDefinition.getAlias()); - float result = emp - .estimateWholeStemVolumePerTree(volumeGroup, 36.7552986f, 31.5006275f); + float result = emp.estimateWholeStemVolumePerTree(volumeGroup, 36.7552986f, 31.5006275f); // Result of run in FORTRAN VDYP7 with the above parameters. assertThat(result, is(1.2011181f)); @@ -727,7 +726,9 @@ void testEqn1() throws Exception { builder.breakageGroup(-1); }); - var result = emp.estimateNonPrimaryLoreyHeight(spec.getGenus(), specPrime.getGenus(), bec, 24.2999992f, 20.5984688f); + var result = emp.estimateNonPrimaryLoreyHeight( + spec.getGenus(), specPrime.getGenus(), bec, 24.2999992f, 20.5984688f + ); assertThat(result, closeTo(21.5356998f)); @@ -757,7 +758,9 @@ void testEqn2() throws Exception { builder.breakageGroup(-1); }); - var result = emp.estimateNonPrimaryLoreyHeight(spec.getGenus(), specPrime.getGenus(), bec, 35.2999992f, 33.6889763f); + var result = emp.estimateNonPrimaryLoreyHeight( + spec.getGenus(), specPrime.getGenus(), bec, 35.2999992f, 33.6889763f + ); assertThat(result, closeTo(38.7456512f)); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java index 07eaf0375..998fffd3c 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java @@ -33,9 +33,7 @@ void testParseSimple() throws Exception { .get(ControlKey.BA_GROWTH_FIAT.name()); assertThat(m, Matchers.aMapWithSize(2)); - assertThat( - m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3) - ); + assertThat(m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3)); assertThat( m.get(Region.COASTAL), Matchers.allOf( diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java index 598e5a9ec..89d7b327b 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/CompVarAdjustmentsParserTest.java @@ -84,10 +84,19 @@ void testParseSimple() throws Exception { assertThat(m.getValue(UtilizationClass.U175TO225, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.60f)); assertThat(m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.QUAD_MEAN_DIAMETER), is(0.61f)); - assertThrows(IllegalArgumentException.class, () -> m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.LOREY_HEIGHT)); - assertThrows(IllegalArgumentException.class, () -> m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.WHOLE_STEM_VOLUME)); - assertThrows(IllegalArgumentException.class, () -> m.getValue(UtilizationClass.ALL, UtilizationClassVariable.BASAL_AREA)); - + assertThrows( + IllegalArgumentException.class, + () -> m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.LOREY_HEIGHT) + ); + assertThrows( + IllegalArgumentException.class, + () -> m.getValue(UtilizationClass.OVER225, UtilizationClassVariable.WHOLE_STEM_VOLUME) + ); + assertThrows( + IllegalArgumentException.class, + () -> m.getValue(UtilizationClass.ALL, UtilizationClassVariable.BASAL_AREA) + ); + assertThat(m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.WHOLE_STEM_VOL), is(0.91f)); assertThat(m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.WHOLE_STEM_VOL), is(0.92f)); assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.WHOLE_STEM_VOL), is(0.93f)); @@ -103,10 +112,22 @@ void testParseSimple() throws Exception { assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY), is(0.95f)); assertThat(m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY), is(0.96f)); - assertThat(m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.94f)); - assertThat(m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.95f)); - assertThat(m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.96f)); - assertThat(m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), is(0.97f)); + assertThat( + m.getVolumeValue(UtilizationClass.U75TO125, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), + is(0.94f) + ); + assertThat( + m.getVolumeValue(UtilizationClass.U125TO175, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), + is(0.95f) + ); + assertThat( + m.getVolumeValue(UtilizationClass.U175TO225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), + is(0.96f) + ); + assertThat( + m.getVolumeValue(UtilizationClass.OVER225, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE), + is(0.97f) + ); } @Test diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java index 59d22baba..65fed56ab 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthFiatParserTest.java @@ -35,9 +35,7 @@ void testParseSimple() throws Exception { .get(ControlKey.DQ_GROWTH_FIAT.name()); assertThat(m, Matchers.aMapWithSize(2)); - assertThat( - m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3) - ); + assertThat(m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3)); assertThat( m.get(Region.COASTAL), Matchers.allOf( diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java index 6dc067692..62f1bf6cc 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ComponentSizeParserTest.java @@ -35,7 +35,9 @@ void testParseSimpleP1() throws Exception { var result = parser.parse(is, controlMap); - assertThat(result, mmHasEntry(is(new ComponentSizeLimits(49.4f, 153.3f, 0.726f, 3.647f)), "S1", Region.COASTAL)); + assertThat( + result, mmHasEntry(is(new ComponentSizeLimits(49.4f, 153.3f, 0.726f, 3.647f)), "S1", Region.COASTAL) + ); } @Test diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java index 493d687d9..858b1b520 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java @@ -325,9 +325,12 @@ void testParseE061() throws Exception { result, (Matcher) controlMapHasEntry( ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL)) - ); - var cslMap = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL) + ) + ); + var cslMap = Utils.>expectParsedControl( + result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class + ); var csl = cslMap.get("AC", Region.COASTAL); assertThat(csl.loreyHeightMaximum(), is(49.4f)); assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java index 1dc6c4782..26821cff0 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/DebugSettingsTest.java @@ -34,7 +34,10 @@ void testSizeOneArray() { @Test void testTooLargeArray() { - assertThrows(IllegalArgumentException.class, () -> new DebugSettings(new Integer[DebugSettings.MAX_DEBUG_SETTINGS + 1])); + assertThrows( + IllegalArgumentException.class, + () -> new DebugSettings(new Integer[DebugSettings.MAX_DEBUG_SETTINGS + 1]) + ); } @Test diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java index 716d59f98..316cf01b9 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GrowthFiatDetailsTests.java @@ -17,7 +17,9 @@ public class GrowthFiatDetailsTests { @Test void test0Ages() { try { - GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f)); + GrowthFiatDetails details = new GrowthFiatDetails( + 1, List.of(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f) + ); Assertions.assertTrue(details.getNAgesSupplied() == 0); assertThat(details.getAges(), arrayContaining(0.0f, 0.0f, 0.0f, 0.0f)); assertThat(details.getCoefficients(), arrayContaining(0.0f, 0.0f, 0.0f, 0.0f)); @@ -30,7 +32,9 @@ void test0Ages() { @Test void test4Ages() { try { - GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f)); + GrowthFiatDetails details = new GrowthFiatDetails( + 1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f) + ); Assertions.assertTrue(details.getNAgesSupplied() == 4); assertThat(details.getAges(), arrayContaining(1.0f, 2.0f, 3.0f, 4.0f)); assertThat(details.getCoefficients(), arrayContaining(1.0f, 2.0f, 3.0f, 4.0f)); @@ -43,7 +47,9 @@ void test4Ages() { @Test void test3Ages() { try { - GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f)); + GrowthFiatDetails details = new GrowthFiatDetails( + 1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f) + ); Assertions.assertTrue(details.getNAgesSupplied() == 3); assertThat(details.getAges(), arrayContaining(1.0f, 2.0f, 3.0f, 0.0f)); assertThat(details.getCoefficients(), arrayContaining(1.0f, 2.0f, 3.0f, 0.0f)); @@ -53,11 +59,12 @@ void test3Ages() { } } - @Test void testInterpolation() { try { - GrowthFiatDetails details = new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f)); + GrowthFiatDetails details = new GrowthFiatDetails( + 1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 0.0f, 0.0f, 0.1f, 0.2f, 0.3f) + ); Assertions.assertTrue(details.getNAgesSupplied() == 3); assertThat(details.calculateCoefficient(0.5f), is(1.0f)); assertThat(details.calculateCoefficient(1.0f), is(1.0f)); @@ -73,21 +80,41 @@ void testInterpolation() { @Test void testAgeListNotEndedProperly() { - assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 0.0f, 0.0f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + assertThrows( + ResourceParseException.class, + () -> new GrowthFiatDetails( + 1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 0.0f, 0.0f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f) + ) + ); } @Test void testBadCoefficient() { - assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + assertThrows( + ResourceParseException.class, + () -> new GrowthFiatDetails( + 1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.1f, 0.2f, 0.3f) + ) + ); } @Test void testAgesNotMonatonicallyIncreasing() { - assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 2.5f, 4.0f, 0.1f, 0.2f, 0.3f))); + assertThrows( + ResourceParseException.class, + () -> new GrowthFiatDetails( + 1, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 2.5f, 4.0f, 0.1f, 0.2f, 0.3f) + ) + ); } @Test void testRegionValueNot1Or2() { - assertThrows(ResourceParseException.class, () -> new GrowthFiatDetails(0, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 1.5f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f))); + assertThrows( + ResourceParseException.class, + () -> new GrowthFiatDetails( + 0, List.of(1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 1.5f, 4.0f, 4.0f, 0.1f, 0.2f, 0.3f) + ) + ); } } diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index 416e63b90..6f54e650a 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -46,7 +46,7 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Estimators; +import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; @@ -758,7 +758,7 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit final var wasteModifierMap = Utils.>expectParsedControl( controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class ); - Estimators.estimateNetDecayAndWasteVolume( + EstimationMethods.estimateNetDecayAndWasteVolume( bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, netDecayCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 8204eac48..af0f5a698 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.function.Predicate; import java.util.stream.IntStream; @@ -15,7 +14,7 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VdypLayer; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; -import ca.bc.gov.nrs.vdyp.model.VdypUtilization; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; class Bank { @@ -102,9 +101,7 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai treesPerHectare = new float[nSpecies + 1][nUtilizationClasses]; wholeStemVolumes = new float[nSpecies + 1][nUtilizationClasses]; - if (layer.getDefaultUtilizationMap().isPresent()) { - recordUtilizations(0, layer.getDefaultUtilizationMap().get()); - } + recordUtilizations(0, layer); int nextSlot = 1; for (VdypSpecies s : speciesToRetain) { @@ -212,27 +209,23 @@ private void recordSpecies(int index, VdypSpecies species) { speciesIndices[index] = species.getGenusIndex(); // percentForestedLand is output-only and so not assigned here. - if (species.getUtilizations().isPresent()) { - recordUtilizations(index, species.getUtilizations().get()); - } else { - recordDefaultUtilizations(index); - } + recordUtilizations(index, species); } - private void recordUtilizations(int index, Map suMap) { + private void recordUtilizations(int index, VdypUtilizationHolder uh) { - for (var su : suMap.entrySet()) { - int ucIndex = su.getKey().ordinal(); - basalAreas[index][ucIndex] = su.getValue().getBasalArea(); - closeUtilizationVolumes[index][ucIndex] = su.getValue().getCloseUtilizationVolume(); - cuVolumesMinusDecay[index][ucIndex] = su.getValue().getCuVolumeMinusDecay(); - cuVolumesMinusDecayAndWastage[index][ucIndex] = su.getValue().getCuVolumeMinusDecayWastage(); + 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] = su.getValue().getLoreyHeight(); + loreyHeights[index][ucIndex] = uh.getLoreyHeightByUtilization().get(uc); } - quadMeanDiameters[index][ucIndex] = su.getValue().getQuadraticMeanDiameterAtBH(); - treesPerHectare[index][ucIndex] = su.getValue().getLiveTreesPerHectare(); - wholeStemVolumes[index][ucIndex] = su.getValue().getWholeStemVolume(); + quadMeanDiameters[index][ucIndex] = uh.getQuadraticMeanDiameterByUtilization().get(uc); + treesPerHectare[index][ucIndex] = uh.getTreesPerHectareByUtilization().get(uc); + wholeStemVolumes[index][ucIndex] = uh.getWholeStemVolumeByUtilization().get(uc); } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 338cdf707..bfdc69803 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -15,6 +15,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.UtilizationOperations; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; @@ -22,10 +23,12 @@ import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; 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.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.model.VdypUtilization; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; public class ForwardDataStreamReader { @@ -101,8 +104,8 @@ public Optional readNextPolygon() throws ProcessingException { } var speciesCollection = layerSpeciesStream.next(); - var primarySpecies = new HashMap(); - var veteranSpecies = new HashMap(); + var primarySpecies = new HashMap(); + var veteranSpecies = new HashMap(); for (var species : speciesCollection) { logger.trace("Saw species {}", species); @@ -110,13 +113,33 @@ public Optional readNextPolygon() throws ProcessingException { var speciesUtilizations = utilizationsBySpeciesMap.get(key); if (speciesUtilizations != null) { - species.setUtilizations(Optional.of(speciesUtilizations)); - - for (VdypUtilization u : speciesUtilizations.values()) { - u.setParent(species); + + UtilizationVector basalAreaUtilizations = new UtilizationVector(); + UtilizationVector liveTreesPerHectareUtilizations = new UtilizationVector(); + UtilizationVector loreyHeightUtilizations = new UtilizationVector(); + UtilizationVector wholeStemVolumeUtilizations = new UtilizationVector(); + UtilizationVector closeUtilizationVolumeUtilizations = new UtilizationVector(); + UtilizationVector cuVolumeMinusDecayUtilizations = new UtilizationVector(); + UtilizationVector cuVolumeMinusDecayWastageUtilizations = new UtilizationVector(); + UtilizationVector cuVolumeMinusDecayWastageBreakageUtilizations = new UtilizationVector(); + UtilizationVector quadraticMeanDiameterAtBHUtilizations = new UtilizationVector(); + + for (var e: speciesUtilizations.entrySet()) { + var uc = e.getKey(); + var ucUtilizations = e.getValue(); + + basalAreaUtilizations.set(uc, ucUtilizations.getBasalArea()); + liveTreesPerHectareUtilizations.set(uc, ucUtilizations.getLiveTreesPerHectare()); + if (uc == UtilizationClass.SMALL || uc == UtilizationClass.ALL) { + loreyHeightUtilizations.set(uc, ucUtilizations.getLoreyHeight()); + } + wholeStemVolumeUtilizations.set(uc, ucUtilizations.getWholeStemVolume()); + closeUtilizationVolumeUtilizations.set(uc, ucUtilizations.getCloseUtilizationVolume()); + cuVolumeMinusDecayUtilizations.set(uc, ucUtilizations.getCuVolumeMinusDecay()); + cuVolumeMinusDecayWastageUtilizations.set(uc, ucUtilizations.getCuVolumeMinusDecayWastage()); + cuVolumeMinusDecayWastageBreakageUtilizations.set(uc, ucUtilizations.getCuVolumeMinusDecayWastageBreakage()); + quadraticMeanDiameterAtBHUtilizations.set(uc, ucUtilizations.getQuadraticMeanDiameterAtBH()); } - } else { - species.setUtilizations(Optional.empty()); } if (LayerType.PRIMARY.equals(species.getLayerType())) { @@ -133,6 +156,8 @@ public Optional readNextPolygon() throws ProcessingException { } } + Map layerMap = new HashMap<>(); + VdypLayer primaryLayer = null; if (primarySpecies.size() > 0) { @@ -143,10 +168,8 @@ public Optional readNextPolygon() throws ProcessingException { primaryLayer = new VdypLayer( LayerType.PRIMARY, polygon, primarySpecies, Optional.ofNullable(defaultSpeciesUtilization) ); - - for (VdypSpecies v : primarySpecies.values()) { - v.setParent(primaryLayer); - } + + layerMap.put(LayerType.PRIMARY, primaryLayer); } VdypLayer veteranLayer = null; @@ -159,16 +182,14 @@ public Optional readNextPolygon() throws ProcessingException { veteranLayer = new VdypLayer( LayerType.VETERAN, polygon, veteranSpecies, Optional.ofNullable(defaultSpeciesUtilization) ); - - for (VdypSpecies v : veteranSpecies.values()) { - v.setParent(veteranLayer); - } + + layerMap.put(LayerType.VETERAN, veteranLayer); } - polygon.setLayers(primaryLayer, veteranLayer); + polygon.setLayers(layerMap); thePolygon = Optional.of(polygon); - adjustUtilizations(polygon); + UtilizationOperations.doPostCreateAdjustments(polygon); } } catch (ResourceParseException | IOException e) { throw new ProcessingException(e); @@ -177,53 +198,19 @@ public Optional readNextPolygon() throws ProcessingException { return thePolygon; } - /** - * Both scale the per-hectare values of all the utilizations of the primary layer of the given polygon, and for all - * utilizations of both the primary and veteran layer (if present) of the polygon, 1. Adjust the basal area to be - * within bounds of the utilization class, and 2. Calculate the quad-mean-diameter value from the basal area and - * trees per hectare. - * - * @param polygon - */ - private void adjustUtilizations(VdypPolygon polygon) throws ProcessingException { - - float percentForestedLand = polygon.getPercentAvailable(); - assert !Float.isNaN(percentForestedLand); - float scalingFactor = 100.0f / percentForestedLand; - - List utilizationsToAdjust = new ArrayList<>(); - - for (VdypLayer l : polygon.getLayers().values()) { - - l.getDefaultUtilizationMap().ifPresent(m -> utilizationsToAdjust.addAll(m.values())); - - l.getGenera().values().stream() - .forEach(s -> s.getUtilizations().ifPresent(m -> utilizationsToAdjust.addAll(m.values()))); - } - - for (VdypUtilization u : utilizationsToAdjust) { - - if (percentForestedLand > 0.0f && percentForestedLand < 100.0f) { - u.scale(scalingFactor); - } - - u.doPostCreateAdjustments(); - } - } - private class UtilizationBySpeciesKey { private final LayerType layerType; - private final Integer genusIndex; + private final Integer speciesIndex; - public UtilizationBySpeciesKey(LayerType layerType, Integer genusIndex) { + public UtilizationBySpeciesKey(LayerType layerType, Integer speciesIndex) { this.layerType = layerType; - this.genusIndex = genusIndex; + this.speciesIndex = speciesIndex; } @Override public boolean equals(Object other) { if (other instanceof UtilizationBySpeciesKey that) { - return layerType.equals(that.layerType) && genusIndex.equals(that.genusIndex); + return layerType.equals(that.layerType) && speciesIndex.equals(that.speciesIndex); } else { return false; } @@ -231,7 +218,7 @@ public boolean equals(Object other) { @Override public int hashCode() { - return layerType.hashCode() * 17 + genusIndex.hashCode(); + return layerType.hashCode() * 17 + speciesIndex.hashCode(); } } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 2ac51f657..1293cdbdb 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -23,7 +23,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.StandProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Estimators; +import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Reference; import ca.bc.gov.nrs.vdyp.common.Utils; @@ -182,7 +182,10 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank bank = fps.getBank(0, LayerType.PRIMARY); - logger.info("Beginning processing of polygon {} layer {}", pps.getLayer().getParent(), pps.getLayer()); + logger.info( + "Beginning processing of polygon {} layer {}", pps.getLayer().getPolygonIdentifier() + .toStringCompact(), pps.getLayer() + ); // BANKCHK1, simplified for the parameters METH_CHK = 4, LayerI = 1, and INSTANCE = 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CHECK_FOR_WORK.ordinal()) { @@ -349,7 +352,7 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) float tphMultiplier = tphEnd / tphStart; // Begin storing computed results - dq, ba and tph for the layer - + end.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; end.basalAreas[0][UC_ALL_INDEX] = baEnd; end.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; @@ -384,7 +387,9 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) start.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; // Now do the actual updates of DQ by species - wasSolutionFound = growUsingPartialSpeciesDynamics(end, dqDelta, baDelta, baStart, dqStart, tphStart, currentLoreyHeights); + wasSolutionFound = growUsingPartialSpeciesDynamics( + end, dqDelta, baDelta, baStart, dqStart, tphStart, currentLoreyHeights + ); // Restore the Lorey Heights back to the values at the beginning of the period. // They will be updated below using the new estimate of TPH-primary species. @@ -423,7 +428,7 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) ); // Calculate Lorey heights over all species, uc UC_ALL_INDEX - + float pspTphEnd = end.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; growLoreyHeights(end, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); @@ -469,7 +474,7 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) computeUtilizationComponentsPrimary(); calculateSmallComponentYields(end); - + return end; } @@ -520,19 +525,19 @@ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphC * * @return true if and only if a solution was found. */ - private boolean growUsingPartialSpeciesDynamics(Bank end, float dqDelta, float baDelta, float baStart, - float dqStart, float tphStart, float[] currentLoreyHeights) { + private boolean growUsingPartialSpeciesDynamics( + Bank end, float dqDelta, float baDelta, float baStart, + float dqStart, float tphStart, float[] currentLoreyHeights + ) { boolean wasSuccessful = true; - PolygonProcessingState pps = fps.getPolygonProcessingState(); + PolygonProcessingState pps = fps.getPolygonProcessingState(); if (dqDelta == 0 || baDelta == 0 || pps.getNSpecies() == 1) { return false /* no solution available */; } - - - + return wasSuccessful; } @@ -739,7 +744,8 @@ private void growUsingFullSpeciesDynamics( end.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; end.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; if (spBaEnd[i] > 0.0f) { - end.quadMeanDiameters[i][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter(spBaEnd[i], spTphNew[i]); + end.quadMeanDiameters[i][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter + .quadMeanDiameter(spBaEnd[i], spTphNew[i]); } } } @@ -892,8 +898,7 @@ private float growBasalAreaForNonPrimarySpecies( throw new ProcessingException( MessageFormat.format( "No nonPrimarySpeciesBasalAreaGrowthCoefficients exist for stratum {0}" - + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", - pspStratumNumber, speciesName, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart + + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", pspStratumNumber, speciesName, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart ) ); } @@ -999,7 +1004,7 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException float spBaAll = end.basalAreas[speciesIndex][UC_ALL_INDEX]; float spDqAll = end.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; - Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); + Region region = pps.getBecZone().getRegion(); String speciesName = start.speciesNames[speciesIndex]; // EMP080 @@ -1095,8 +1100,10 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException * @param pspTphEnd primary species trees-per-hectare at end * @param pspLhStart primary species Lorey height at end */ - private void growLoreyHeights(Bank end, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart) { - + private void growLoreyHeights( + Bank end, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart + ) { + PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); @@ -1177,7 +1184,7 @@ private float estimateNonPrimarySpeciesLoreyHeight( ) { PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - + float spLh; int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); @@ -1342,7 +1349,8 @@ float growQuadMeanDiameter( * * @return the change in primary layer basal area from start to start + 1 year */ - private float calculateQuadMeanDiameterGrowthEmpirical(float pspYabhStart, float dhStart, + private float calculateQuadMeanDiameterGrowthEmpirical( + float pspYabhStart, float dhStart, float baStart, float dqStart, float hdGrowth, float dqYieldStart, float dqYieldEnd ) { // Compute the growth in quadratic mean diameter @@ -1383,8 +1391,10 @@ private float calculateQuadMeanDiameterGrowthEmpirical(float pspYabhStart, float float x = dqStart - 7.5f; float xsq = x * x; - var dqGrowthMin = Math.max(dqDeltaLimits[0] + dqDeltaLimits[1] * x + dqDeltaLimits[2] * xsq / 100.0f, dqDeltaLimits[6]); - var dqGrowthMax = Math.min(dqDeltaLimits[3] + dqDeltaLimits[4] * x + dqDeltaLimits[5] * xsq / 100.0f, dqDeltaLimits[7]); + var dqGrowthMin = Math + .max(dqDeltaLimits[0] + dqDeltaLimits[1] * x + dqDeltaLimits[2] * xsq / 100.0f, dqDeltaLimits[6]); + var dqGrowthMax = Math + .min(dqDeltaLimits[3] + dqDeltaLimits[4] * x + dqDeltaLimits[5] * xsq / 100.0f, dqDeltaLimits[7]); dqGrowthMax = Math.max(dqGrowthMax, dqGrowthMin); @@ -1397,7 +1407,7 @@ private float[] getSpeciesProportionsByBasalArea() { PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - + float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; for (int i = 1; i <= pps.getNSpecies(); i++) { @@ -1427,7 +1437,7 @@ float growBasalArea( PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); @@ -1451,8 +1461,8 @@ float growBasalArea( int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, fps - .getPolygonProcessingState().getBecZone(), pspGroupNumber + estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhStart, pspYabhStart, veteranLayerBa, + isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), pspGroupNumber ); float pspDhEnd = pspDhStart + dhDelta; @@ -1507,7 +1517,7 @@ float growBasalArea( // UPPERGEN( 1, BATOP98, DQTOP98) var baUpperBound = growBasalAreaUpperBound(); - baUpperBound = baUpperBound / Estimators.EMPIRICAL_OCCUPANCY; + baUpperBound = baUpperBound / EstimationMethods.EMPIRICAL_OCCUPANCY; var baLimit = Math.max(baUpperBound, baStart); // Enforce upper limit on growth @@ -1608,7 +1618,7 @@ private float calculateBasalAreaGrowthEmpirical( private float growBasalAreaUpperBound() { PolygonProcessingState pps = fps.getPolygonProcessingState(); - + int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { @@ -1633,7 +1643,7 @@ private float growQuadraticMeanDiameterUpperBound() { int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { - + var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); Region region = pps.getBecZone().getRegion(); int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); @@ -1858,13 +1868,13 @@ private void writeLayers(Bank endBank, int veteranLayerInstance, boolean b) { @SuppressWarnings("unchecked") void setCompatibilityVariables() throws ProcessingException { - + Coefficients aAdjust = new Coefficients(new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, 1); var growthDetails = fps.fcm.getForwardControlVariables(); var pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - + // Note: L1COM2 (INL1VGRP, INL1DGRP, INL1BGRP) is initialized when // PolygonProcessingState (volumeEquationGroups, decayEquationGroups // breakageEquationGroups, respectively) is constructed. Copying @@ -2070,7 +2080,7 @@ void setCompatibilityVariables() throws ProcessingException { var pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - Region region = pps.getPolygon().getBiogeoclimaticZone().getRegion(); + Region region = pps.getBecZone().getRegion(); String speciesName = start.speciesNames[speciesIndex]; float spLoreyHeight_All = start.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp @@ -2300,7 +2310,7 @@ static void calculateDominantHeightAgeSiteIndex( ) throws ProcessingException { Bank startBank = pps.getStartBank(); - + // Calculate primary species values int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); @@ -2418,7 +2428,7 @@ static void calculateDominantHeightAgeSiteIndex( static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState pps) { Bank start = pps.getStartBank(); - + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; @@ -2480,7 +2490,7 @@ static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState pps) static void estimateMissingSiteIndices(PolygonProcessingState pps) throws ProcessingException { Bank start = pps.getStartBank(); - + int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); SiteIndexEquation primarySiteCurve = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(primarySpeciesIndex)); @@ -2580,7 +2590,7 @@ void calculateCoverages() { PolygonProcessingState pps = this.fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - + logger.atDebug().addArgument(pps.getNSpecies()).addArgument(start.basalAreas[0][0]).log( "Calculating coverages as a ratio of Species BA over Total BA. # species: {}; Layer total 7.5cm+ basal area: {}" ); @@ -2682,8 +2692,8 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing if (state.getNSpecies() == 0) { throw new ProcessingException( MessageFormat.format( - "Polygon {0} layer 0 has no species with basal area above {1}", state.getLayer().getParent() - .getDescription().getName(), MIN_BASAL_AREA + "Polygon {0} layer 0 has no species with basal area above {1}", state.getLayer() + .getPolygonIdentifier().toStringCompact(), MIN_BASAL_AREA ) ); } @@ -2710,7 +2720,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { PolygonProcessingState pps = fps.getPolygonProcessingState(); Bank start = pps.getStartBank(); - + if (pps.getNSpecies() == 0) { throw new IllegalArgumentException("Can not find primary species as there are no species"); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 7e4d213e0..18f2d752f 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -1,10 +1,13 @@ package ca.bc.gov.nrs.vdyp.forward; +import java.text.MessageFormat; import java.util.Map; -import ca.bc.gov.nrs.vdyp.common.Estimators; +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; @@ -22,7 +25,7 @@ class ForwardProcessingState { final ForwardResolvedControlMap fcm; /** The estimators instance used by this engine */ - final Estimators estimators; + final EstimationMethods estimators; /** The storage banks */ private final Bank[/* instances */][/* layers of instance */] banks; @@ -35,27 +38,25 @@ public ForwardProcessingState(Map controlMap) { new Bank[LAYERS_PER_INSTANCE] }; this.fcm = new ForwardResolvedControlMapImpl(controlMap); - this.estimators = new Estimators(this.fcm); + this.estimators = new EstimationMethods(this.fcm); } private static final float MIN_BASAL_AREA = 0.001f; - public void setPolygon(VdypPolygon polygon) { + public void setPolygon(VdypPolygon polygon) throws ProcessingException { + + BecDefinition becZone = fcm.getBecLookup().get(polygon.getBiogeoclimaticZone()).orElseThrow(() -> + new ProcessingException(MessageFormat.format("{0}: BEC zone {1} is unsupported", polygon.getPolygonIdentifier(), + polygon.getBiogeoclimaticZone()))); // Move the primary layer of the given polygon to bank zero. Bank primaryBank = banks[0][LayerType.PRIMARY.getIndex()] = new Bank( - polygon.getLayers().get(LayerType.PRIMARY), polygon.getBiogeoclimaticZone(), - s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA - : true - ); + polygon.getLayers().get(LayerType.PRIMARY), becZone, + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= MIN_BASAL_AREA); - polygon.getLayers().get(LayerType.VETERAN).ifPresent(l -> - banks[0][LayerType.VETERAN.getIndex()] = new Bank( - l, polygon.getBiogeoclimaticZone(), - s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= MIN_BASAL_AREA - : true)); + banks[0][LayerType.VETERAN.getIndex()] = new Bank( + polygon.getLayers().get(LayerType.VETERAN), becZone, + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= MIN_BASAL_AREA); pps = new PolygonProcessingState(this, polygon, primaryBank); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 4c4003cab..469796f43 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -118,7 +118,6 @@ public PolygonProcessingState( this.fps = fps; this.polygon = polygon; - this.start = bank.copy(); var volumeEquationGroupMatrix = this.fps.fcm.>get( diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java deleted file mode 100644 index 055b243c4..000000000 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypSpeciesUtilization.java +++ /dev/null @@ -1,284 +0,0 @@ -package ca.bc.gov.nrs.vdyp.model; - -import java.text.MessageFormat; -import java.util.Optional; - -import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.math.FloatMath; - -public class VdypUtilization implements VdypEntity { - - // See IPSJF155.doc - - private PolygonIdentifier polygonId; // POLYDESC - private final LayerType layerType; // LAYERG - private final int genusIndex; // ISP - private final Optional genus; // SP0 - private final UtilizationClass ucIndex; // J - utilization index - - // The following are not final because post construction the values - // may be scaled by the scale method below. - - private float basalArea; - private float liveTreesPerHectare; - private float loreyHeight; - private float wholeStemVolume; - private float closeUtilizationVolume; - private float cuVolumeMinusDecay; - private float cuVolumeMinusDecayWastage; - private float cuVolumeMinusDecayWastageBreakage; - private float quadraticMeanDiameterAtBH; - - // Set after construction - private VdypSpecies parent; - - public VdypUtilization( - PolygonIdentifier polygonId, LayerType layerType, Integer genusIndex, Optional genus, - UtilizationClass ucIndex, float basalArea, float liveTreesPerHectare, float loreyHeight, - float wholeStemVolume, float closeUtilizationVolume, float cuVolumeMinusDecay, - float cuVolumeMinusDecayWastage, float cuVolumeMinusDecayWastageBreakage, float quadraticMeanDiameterAtBH - ) { - this.polygonId = polygonId; - this.layerType = layerType; - this.genusIndex = genusIndex; - this.genus = genus; - this.ucIndex = ucIndex; - this.basalArea = basalArea; - this.liveTreesPerHectare = liveTreesPerHectare; - this.loreyHeight = loreyHeight; - this.wholeStemVolume = wholeStemVolume; - this.closeUtilizationVolume = closeUtilizationVolume; - this.quadraticMeanDiameterAtBH = quadraticMeanDiameterAtBH; - this.cuVolumeMinusDecay = cuVolumeMinusDecay; - this.cuVolumeMinusDecayWastage = cuVolumeMinusDecayWastage; - this.cuVolumeMinusDecayWastageBreakage = cuVolumeMinusDecayWastageBreakage; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - sb.append(polygonId).append(' ').append(layerType).append(' ').append(genusIndex).append(' ') - .append(ucIndex.index); - - return sb.toString(); - } - - public void setParent(VdypSpecies parent) { - this.parent = parent; - } - - public PolygonIdentifier getPolygonId() { - return polygonId; - } - - public LayerType getLayerType() { - return layerType; - } - - public Integer getGenusIndex() { - return genusIndex; - } - - public Optional getGenus() { - return genus; - } - - public UtilizationClass getUcIndex() { - return ucIndex; - } - - public float getBasalArea() { - return basalArea; - } - - public float getLiveTreesPerHectare() { - return liveTreesPerHectare; - } - - public float getLoreyHeight() { - return loreyHeight; - } - - public float getWholeStemVolume() { - return wholeStemVolume; - } - - public float getCloseUtilizationVolume() { - return closeUtilizationVolume; - } - - public float getCuVolumeMinusDecay() { - return cuVolumeMinusDecay; - } - - public float getCuVolumeMinusDecayWastage() { - return cuVolumeMinusDecayWastage; - } - - public float getCuVolumeMinusDecayWastageBreakage() { - return cuVolumeMinusDecayWastageBreakage; - } - - public float getQuadraticMeanDiameterAtBH() { - return quadraticMeanDiameterAtBH; - } - - public VdypSpecies getParent() { - return parent; - } - - /** - * Implements VDYPGETU lines 224 - 229, in which the utilization- per-hectare values are scaled by the given factor - * - the % coverage of the primary layer. - * - * @param scalingFactor - */ - public void scale(float scalingFactor) { - - if (this.basalArea > 0) { - this.basalArea *= scalingFactor; - } - if (this.liveTreesPerHectare > 0) { - this.liveTreesPerHectare *= scalingFactor; - } - // lorey height is not a per-hectare value and therefore - // is excluded from scaling. - if (this.wholeStemVolume > 0) { - this.wholeStemVolume *= scalingFactor; - } - if (this.closeUtilizationVolume > 0) { - this.closeUtilizationVolume *= scalingFactor; - } - if (this.cuVolumeMinusDecay > 0) { - this.cuVolumeMinusDecay *= scalingFactor; - } - if (this.cuVolumeMinusDecayWastage > 0) { - this.cuVolumeMinusDecayWastage *= scalingFactor; - } - if (this.cuVolumeMinusDecayWastageBreakage > 0) { - this.cuVolumeMinusDecayWastageBreakage *= scalingFactor; - } - // quadratic mean diameter is not a per-hectare value and - // therefore not scaled. - } - - private static final float MAX_ACCEPTABLE_BASAL_AREA_ERROR = 0.1f; - private static final float[] CLASS_LOWER_BOUNDS = { 4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f }; - private static final float[] CLASS_UPPER_BOUNDS = { 7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f }; - private static final float DQ_EPS = 0.005f; - - /** - * Implements the logic in BANKIN2 (ICHECK == 2) adjusting the utilization values according to various rules. - * - * @throws ProcessingException when calculated values are out of range - */ - public void doPostCreateAdjustments() throws ProcessingException { - - resetOnMissingValues(); - - adjustBasalAreaToMatchTreesPerHectare(); - - doCalculateQuadMeanDiameter(); - } - - /** - * If either basalArea or liveTreesPerHectare is not positive, clear everything. - */ - private void resetOnMissingValues() { - - if (this.basalArea <= 0.0f || this.liveTreesPerHectare <= 0.0f) { - this.basalArea = 0.0f; - this.liveTreesPerHectare = 0.0f; - // DO NOT zero-out the lorey height value. - this.wholeStemVolume = 0.0f; - this.closeUtilizationVolume = 0.0f; - this.cuVolumeMinusDecay = 0.0f; - this.cuVolumeMinusDecayWastage = 0.0f; - this.cuVolumeMinusDecayWastageBreakage = 0.0f; - } - } - - /** - * Adjust Basal Area to match the Trees-Per-Hectare value. - * - * @throws ProcessingException - */ - private void adjustBasalAreaToMatchTreesPerHectare() throws ProcessingException { - - if (this.liveTreesPerHectare > 0.0f) { - float basalAreaLowerBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()] + DQ_EPS, this.liveTreesPerHectare); - float basalAreaUpperBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - DQ_EPS, this.liveTreesPerHectare); - - float basalAreaError; - float newBasalArea; - String message = null; - - if (this.basalArea < basalAreaLowerBound) { - basalAreaError = FloatMath.abs(this.basalArea - basalAreaLowerBound); - newBasalArea = basalAreaLowerBound; - message = MessageFormat.format( - "{0}: Error 6: basal area {1} is {2} below threshold, exceeding the maximum error of {3}.", this, - this.basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR - ); - } else if (this.basalArea > basalAreaUpperBound) { - basalAreaError = FloatMath.abs(this.basalArea - basalAreaUpperBound); - message = MessageFormat.format( - "{0}: Error 6: basal area {1} is {2} above threshold, exceeding the maximum error of {3}.", this, - this.basalArea, basalAreaError, MAX_ACCEPTABLE_BASAL_AREA_ERROR - ); - newBasalArea = basalAreaUpperBound; - } else { - basalAreaError = 0.0f; - newBasalArea = this.basalArea; - } - - if (basalAreaError > MAX_ACCEPTABLE_BASAL_AREA_ERROR) { - throw new ProcessingException(message); - } else { - this.basalArea = newBasalArea; - } - } - } - - /** - * Calculate QuadMeanDiameter for the given utilization. - * - * The value supplied in the input is IGNORED REPEAT IGNORED - * - * @throws ProcessingException - */ - private void doCalculateQuadMeanDiameter() throws ProcessingException { - - if (this.basalArea > 0.0f) { - float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, liveTreesPerHectare); - - if (qmd < CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()]) { - qmd = qmd + DQ_EPS; - if (qmd /* is still */ < CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()]) { - throw new ProcessingException( - MessageFormat.format( - "{0}: Error 6: calculated quad-mean-diameter value {1} is below lower limit {2}", - this, qmd, CLASS_LOWER_BOUNDS[this.ucIndex.ordinal()] - ) - ); - } - } else if (qmd > CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()]) { - qmd = qmd - DQ_EPS; - if (qmd /* is still */ > CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()]) { - throw new ProcessingException( - MessageFormat.format( - "{0}: Error 6: calculated quad-mean-diameter value {1} is above upper limit {2}", - this, qmd, CLASS_UPPER_BOUNDS[this.ucIndex.ordinal()] - ) - ); - } - } - - this.quadraticMeanDiameterAtBH = qmd; - } - } -} diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypControlVariableParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypControlVariableParser.java deleted file mode 100644 index d596b98ae..000000000 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypControlVariableParser.java +++ /dev/null @@ -1,34 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward.parsers; - -import java.util.List; - -import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; -import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; -import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; - -public class ForwardControlVariableParser implements ValueParser { - - @Override - public ForwardControlVariables parse(String string) throws ValueParseException { - - if (string == null) { - throw new ValueParseException(null, "VdypControlVariableParser: supplied string is null"); - } - if (string.trim().length() == 0) { - throw new ValueParseException( - string, "VdypControlVariableParser: supplied string \"" + string + "\" is empty" - ); - } - - var parser = ValueParser.list(ValueParser.INTEGER); - List controlVariableValues = parser.parse(string); - - if (controlVariableValues.isEmpty()) { - throw new ValueParseException( - string, "VdypControlVariableParser: supplied string \"" + string + "\" is empty" - ); - } - - return new ForwardControlVariables(controlVariableValues.toArray(new Integer[controlVariableValues.size()])); - } -} diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index 51e502797..6443ee4fb 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -18,6 +18,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -27,6 +28,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypLayer; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.model.VdypUtilization; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; class PolygonProcessingStateTest { @@ -57,9 +59,9 @@ void testConstruction() throws IOException, ResourceParseException, ProcessingEx VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); - Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + Bank pps = new Bank(pLayer, Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap), s -> true); - int nSpecies = pLayer.getGenera().size(); + int nSpecies = pLayer.getSpecies().size(); assertThat(pps, notNullValue()); assertThat(pps.yearsAtBreastHeight.length, is(nSpecies + 1)); @@ -118,7 +120,7 @@ void testSetCopy() throws IOException, ResourceParseException, ProcessingExcepti VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); - Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + Bank pps = new Bank(pLayer, Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap), s -> true); verifyProcessingStateMatchesLayer(pps, pLayer); @@ -138,19 +140,17 @@ void testRemoveSmallLayers() throws IOException, ResourceParseException, Process assertThat(pLayer, notNullValue()); Bank bank1 = new Bank( - pLayer, polygon.getBiogeoclimaticZone(), - s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= 0.5 : true + pLayer, Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap), + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 0.5 ); // the filter should have removed genus B (index 3) since it's ALL basal area is below 0.5 - assertThat(bank1.getNSpecies(), is(pLayer.getGenera().size() - 1)); + assertThat(bank1.getNSpecies(), is(pLayer.getSpecies().size() - 1)); assertThat(bank1.speciesIndices, is(new int[] { 0, 4, 5, 8, 15 })); Bank bank2 = new Bank( - pLayer, polygon.getBiogeoclimaticZone(), - s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= 100.0 : true + pLayer, Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap), + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 100.0 ); // the filter should have removed all genera. @@ -168,7 +168,7 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); - Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + Bank pps = new Bank(pLayer, Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap), s -> true); Bank ppsCopy = new Bank(pps, CopyMode.CopyAll); @@ -177,44 +177,34 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin private void verifyProcessingStateMatchesLayer(Bank pps, VdypLayer layer) { - List sortedSpIndices = layer.getGenera().keySet().stream().sorted().toList(); + List sortedSpIndices = layer.getSpecies().keySet().stream().sorted().toList(); for (int i = 0; i < sortedSpIndices.size(); i++) { int arrayIndex = i + 1; - VdypSpecies genus = layer.getGenera().get(sortedSpIndices.get(i)); - verifyProcessingStateSpeciesMatchesSpecies(pps, arrayIndex, genus); - - if (genus.getUtilizations().isPresent()) { - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - pps, arrayIndex, genus.getUtilizations().get() - ); - } + VdypSpecies species = layer.getSpecies().get(sortedSpIndices.get(i)); + verifyProcessingStateSpeciesMatchesSpecies(pps, arrayIndex, species); } - if (layer.getDefaultUtilizationMap().isPresent()) { - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(pps, 0, layer.getDefaultUtilizationMap().get()); - } + verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(pps, 0, layer); } private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - Bank pps, int spIndex, Map map + Bank pps, int spIndex, VdypUtilizationHolder uh ) { for (UtilizationClass uc : UtilizationClass.values()) { - VdypUtilization u = map.get(uc); - - assertThat(pps.basalAreas[spIndex][uc.index + 1], is(u.getBasalArea())); - assertThat(pps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolume())); - assertThat(pps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCuVolumeMinusDecay())); - assertThat(pps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCuVolumeMinusDecayWastage())); + assertThat(pps.basalAreas[spIndex][uc.index + 1], is(uh.getBaseAreaByUtilization().get(uc))); + assertThat(pps.closeUtilizationVolumes[spIndex][uc.index + 1], is(uh.getCloseUtilizationVolumeByUtilization().get(uc))); + assertThat(pps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(uh.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); + assertThat(pps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(uh.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); if (uc.index <= 0) { - assertThat(pps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeight())); + assertThat(pps.loreyHeights[spIndex][uc.index + 1], is(uh.getLoreyHeightByUtilization().get(uc))); } - assertThat(pps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterAtBH())); - assertThat(pps.treesPerHectare[spIndex][uc.index + 1], is(u.getLiveTreesPerHectare())); - assertThat(pps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolume())); + assertThat(pps.quadMeanDiameters[spIndex][uc.index + 1], is(uh.getQuadraticMeanDiameterByUtilization().get(uc))); + assertThat(pps.treesPerHectare[spIndex][uc.index + 1], is(uh.getTreesPerHectareByUtilization().get(uc))); + assertThat(pps.wholeStemVolumes[spIndex][uc.index + 1], is(uh.getWholeStemVolumeByUtilization().get(uc))); } } @@ -227,5 +217,9 @@ private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, Vdy assertThat(pps.speciesIndices[index], is(species.getGenusIndex())); assertThat(pps.speciesNames[index], is(species.getGenus())); assertThat(pps.yearsToBreastHeight[index], is(species.getYearsToBreastHeight())); + + verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( + pps, index, species + ); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java deleted file mode 100644 index 6ea3ea52f..000000000 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardControlParserTest.java +++ /dev/null @@ -1,569 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward; - -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.controlMapHasEntry; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.hasBec; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.mmEmpty; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.mmHasEntry; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.allOf; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasEntry; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.hasKey; -import static org.hamcrest.Matchers.instanceOf; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.isA; -import static org.hamcrest.Matchers.not; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.SequenceInputStream; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.Test; - -import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; -import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; -import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; -import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.BecLookup; -import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; -import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; -import ca.bc.gov.nrs.vdyp.model.GenusDefinition; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; -import ca.bc.gov.nrs.vdyp.model.Region; -import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; -import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; -import ca.bc.gov.nrs.vdyp.test.TestUtils; - -@SuppressWarnings({ "unchecked", "rawtypes" }) -class ForwardControlParserTest { - - @Test - void testParseBec_9() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.BEC_DEF, - allOf(instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class)))) - ) - ); - } - - @Test - void testParseSP0_10() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SP0_DEF, allOf(instanceOf(List.class), hasItem(instanceOf(GenusDefinition.class))) - ) - ); - } - - @Test - void testParseVGRP_20() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.VOLUME_EQN_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(7), "AT", "CDF")) - ) - ); - } - - @Test - void testParseDGRP_21() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.DECAY_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(5), "AT", "CDF")) - ) - ); - } - - @Test - void testParseBGRP_22() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.BREAKAGE_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(3), "AT", "CDF")) - ) - ); - } - - @Test - void testParseGRBA1_30() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.DEFAULT_EQ_NUM, allOf(isA(MatrixMap2.class), mmHasEntry(is(11), "AT", "CDF")) - ) - ); - } - - @Test - void testParseGMBA1_31() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.EQN_MODIFIERS, allOf( - // Default Equation - isA(MatrixMap2.class), mmHasEntry(present(is(34)), 33, 9) - ) - ) - ); - } - - @Test - void testParseE025() throws Exception { - var parser = new ForwardControlParser(); - var result = parseWithAppendix(parser, "025 coe/SIEQN.PRM"); - assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SITE_CURVE_NUMBERS, allOf( - // Species - isA(MatrixMap2.class), mmHasEntry(isA(SiteIndexEquation.class), "MB", Region.COASTAL) - ) - ) - ); - } - - @Test - void testParseE025Empty() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP-NoSiteCurves.CTR"); - assertThat(result, (Matcher) controlMapHasEntry(ControlKey.SITE_CURVE_NUMBERS, mmEmpty())); - } - - @Test - void testParseE026() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SITE_CURVE_AGE_MAX, allOf( - // Species - isA(Map.class), hasEntry(isA(Integer.class), isA(SiteCurveAgeMaximum.class)) - ) - ) - ); - } - - @Test - void testParseE026Empty() throws Exception { - var parser = new ForwardControlParser(); - var result = parseWithAppendix(parser, "026 "); - // Map is empty but gives appropriate default values - assertThat(result, (Matcher) controlMapHasEntry(ControlKey.SITE_CURVE_AGE_MAX, Matchers.anEmptyMap())); - assertThat( - ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())).get(1), - (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) - ); - } - - @Test - void testParseE028() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, (Matcher) controlMapHasEntry(ControlKey.PARAM_ADJUSTMENTS, allOf(isA(CompVarAdjustments.class))) - ); - } - - @Test - void testParseE028Empty() throws Exception { - var parser = new ForwardControlParser(); - var result = parseWithAppendix(parser, "028 "); - - // Test that we got the appropriate default values - assertThat(result, Matchers.hasKey(ControlKey.PARAM_ADJUSTMENTS.name())); - - CompVarAdjustments m = (CompVarAdjustments) result.get(ControlKey.PARAM_ADJUSTMENTS.name()); - - assertThat(m.getValue(UtilizationClass.SMALL, UtilizationClassVariable.BASAL_AREA), is(1.0f)); - } - - @Test - void testParseE043() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.UPPER_BA_BY_CI_S0_P, allOf(mmHasEntry(is(109.27f), Region.COASTAL, "AC", 1)) - ) - ); - } - - @Test - void testParseE050() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P1, - allOf(mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL)) - ) - ); - } - - @Test - void testParseE051() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P2, - allOf(mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL)) - ) - ); - } - - @Test - void testParseE052() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P3, - allOf( - mmHasEntry( - coe(1, contains(1.04422f, 0.93010f, -0.05745f, -2.50000f)), "AC", Region.COASTAL - ) - ) - ) - ); - } - - @Test - void testParseE053() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.HL_NONPRIMARY, - allOf(mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL)) - ) - ); - } - - @Test - void testParseE060() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162f)) - ) - ); - } - - @Test - void testParseE061() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - mmHasEntry(isA(ComponentSizeLimits.class), "AC", Region.COASTAL)) - ); - var cslMap = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); - var csl = cslMap.get("AC", Region.COASTAL); - assertThat(csl.loreyHeightMaximum(), is(49.4f)); - assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); - assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); - assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); - } - - @Test - void testParseUBA1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_BA, - allOf(mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH")) - ) - ); - } - - @Test - void testParseYVC1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.CLOSE_UTIL_VOLUME, - allOf(mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53)) - ) - ); - } - - @Test - void testParseYVD1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY, - allOf(mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53)) - ) - ); - } - - @Test - void testParseSBA1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_PROBABILITY, - allOf(hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f))) - ) - ); - } - - @Test - void testParseSBA2() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_BA, - allOf(hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f))) - ) - ); - } - - @Test - void testParseSDQ1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_DQ, allOf(hasEntry(is("B"), contains(-0.33485f, 0.02029f))) - ) - ); - } - - @Test - void testParseSHL1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_HL, allOf(hasEntry(is("B"), contains(-8.5269f, -0.20000f))) - ) - ); - } - - @Test - void testParseSVT1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_WS_VOLUME, - allOf(hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f))) - ) - ); - } - - @Test - void testParseYVT1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, - allOf( - hasEntry( - is(2), - contains( - -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, - 0.0000000f, 0.0000000f, 0.19884f - ) - ) - ) - ) - ); - } - - @Test - void testParseYVT2() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_WS_VOLUME, - allOf(mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11)) - ) - ); - } - - @Test - void testParseYVW1() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY_WASTE, - allOf(hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f))) - ) - ); - } - - @Test - void testParseE095() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.BREAKAGE, allOf(hasEntry(is(10), contains(-0.7153f, 2.0108f, 4.00f, 8.00f))) - ) - ); - } - - @Test - void testParseYVVET() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_VOLUME_ADJUST, - allOf(hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f))) - ) - ); - } - - @Test - void testParseYDQV() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_DQ, - allOf( - mmHasEntry(coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL), - mmHasEntry(coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR), - mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL), - mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) - ) - ) - ); - } - - @Test - void testParseMinima() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - - // VDYP Forward does not load MINIMA - assertThat(result, not(hasKey(ControlKey.MINIMA))); - } - - @Test - void testParseV7O_VIP() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.FORWARD_INPUT_VDYP_POLY, instanceOf(StreamingParserFactory.class) - ) - ); - } - - @Test - void testParseV7O_VIU() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL, instanceOf(StreamingParserFactory.class) - ) - ); - } - - @Test - void testParseV7O_VIS() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry( - ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SPECIES, instanceOf(StreamingParserFactory.class) - ) - ); - } - - @Test - void testParseV7O_VIY() throws Exception { - var parser = new ForwardControlParser(); - var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry(ControlKey.FORWARD_INPUT_GROWTO, instanceOf(StreamingParserFactory.class)) - ); - } - - static InputStream addToEnd(InputStream is, String... lines) { - var appendix = new ByteArrayInputStream(String.join("\r\n", lines).getBytes(StandardCharsets.US_ASCII)); - return new SequenceInputStream(is, appendix); - } - - static Map parseWithAppendix(ForwardControlParser parser, String... lines) - throws IOException, ResourceParseException { - - Class klazz = TestUtils.class; - try (InputStream baseIs = klazz.getResourceAsStream("VDYP.CTR"); InputStream is = addToEnd(baseIs, lines);) { - return parser.parse(is, TestUtils.fileResolver(klazz), new HashMap<>()); - } - } -} diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index 81525f463..534d8a4b0 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -68,64 +68,42 @@ void testReadPolygons() throws Exception { { assertThat(primaryLayer, hasProperty("layerType", is(LayerType.PRIMARY))); assertThat(primaryLayer, hasProperty("defaultUtilizationMap")); - assertThat(primaryLayer.getParent(), is(polygon)); + assertThat(primaryLayer.getPolygonIdentifier().getName(), is(polygon.getPolygonIdentifier().getName())); + assertThat(primaryLayer.getPolygonIdentifier().getYear(), is(polygon.getPolygonIdentifier().getYear())); - if (primaryLayer.getDefaultUtilizationMap().isPresent()) { - var utilizationMap = primaryLayer.getDefaultUtilizationMap().get(); + assertThat(UtilizationClass.values().length, is(primaryLayer.getBaseAreaByUtilization().size())); - assertThat(utilizationMap.size(), greaterThan(0)); - assertThat(utilizationMap.size(), lessThanOrEqualTo(UtilizationClass.values().length)); - for (UtilizationClass uc : UtilizationClass.values()) { - assertThat(utilizationMap.get(uc), hasProperty("genusIndex", is(0))); - } - } - - var genusMap = primaryLayer.getGenera(); - assertThat(genusMap.size(), is(5)); + var speciesMap = primaryLayer.getSpecies(); + assertThat(speciesMap.size(), is(5)); - var genus = genusMap.values().iterator().next(); - - assertThat(genus, hasProperty("parent", is(primaryLayer))); - assertThat(genus, hasProperty("utilizations")); + var species = speciesMap.values().iterator().next(); - var genusUtilizationMap = genus.getUtilizations(); + assertThat(species, hasProperty("layerType", is(primaryLayer.getLayerType()))); + assertThat(species, hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier()))); + assertThat(species, hasProperty("utilizations")); - if (genusUtilizationMap.isPresent()) { - for (var u : genusUtilizationMap.get().values()) { - assertThat(u, hasProperty("genusIndex", is(genus.getGenusIndex()))); - assertThat(u, hasProperty("parent", is(genus))); - } + for (var u : UtilizationClass.values()) { + assertThat(u, hasProperty("genusIndex", is(species.getGenusIndex()))); + assertThat(u, hasProperty("polygonIdentifier", is("01002 S000001 00 (1970)"))); } } var veteranLayer = polygon.getLayers().get(LayerType.VETERAN); if (veteranLayer != null) { - if (veteranLayer.getDefaultUtilizationMap().isPresent()) { - var utilizationMap = veteranLayer.getDefaultUtilizationMap().get(); - - assertThat(utilizationMap.size(), greaterThan(0)); - assertThat(utilizationMap.size(), lessThanOrEqualTo(UtilizationClass.values().length)); - for (UtilizationClass uc : UtilizationClass.values()) { - assertThat(utilizationMap.get(uc), hasProperty("genusIndex", is(0))); - } + assertThat(primaryLayer.getBaseAreaByUtilization().size(), is(UtilizationClass.values().length)); + assertThat(primaryLayer.getLoreyHeightByUtilization().size(), is(2)); + for (UtilizationClass uc : UtilizationClass.values()) { + assertThat(primaryLayer.getBaseAreaByUtilization(), hasProperty("genusIndex", is(0))); } - var genusMap = veteranLayer.getGenera(); - assertThat(genusMap.size(), is(5)); + var speciesMap = veteranLayer.getSpecies(); + assertThat(speciesMap.size(), is(5)); - var genus = genusMap.values().iterator().next(); + var genus = speciesMap.values().iterator().next(); assertThat(genus, hasProperty("parent", is(veteranLayer))); assertThat(genus, hasProperty("utilizations")); - - var genusUtilizationMap = genus.getUtilizations(); - if (genusUtilizationMap.isPresent()) { - for (var u : genusUtilizationMap.get().values()) { - assertThat(u, hasProperty("genusIndex", is(genus.getGenusIndex()))); - assertThat(u, hasProperty("parent", is(genus))); - } - } } } catch (ResourceParseException | IOException e) { throw new ProcessingException(e); diff --git a/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java b/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java deleted file mode 100644 index 026e7ace3..000000000 --- a/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Reference.java +++ /dev/null @@ -1,32 +0,0 @@ -package ca.bc.gov.nrs.vdyp.common; - -import java.util.Optional; - -public class Reference { - - private Optional value; - - public Reference(T initialValue) { - value = Optional.of(initialValue); - } - - public Reference() { - value = Optional.empty(); - } - - public void set(T newValue) { - value = Optional.of(newValue); - } - - public T get() { - if (value.isPresent()) { - return value.get(); - } else { - throw new IllegalStateException("Attempting to get the value of a Reference that hasn't one"); - } - } - - public boolean isPresent() { - return value.isPresent(); - } -} From 0169f9a769ba7c41d221f330ead0f7bf8c86852b Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 31 Jul 2024 17:33:39 -0700 Subject: [PATCH 30/66] Continue integration to common Polygon classes. --- .../application/VdypStartApplication.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 26 ++++++++++++++----- .../forward/PolygonProcessingStateTest.java | 14 +++++----- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 5cb6c6c06..8df7b4c67 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -634,7 +634,7 @@ protected float estimatePrimaryBaseArea( public S leadGenus(L fipLayer) { return fipLayer.getSpecies().values().stream() - .sorted(Utils.compareUsing(BaseVdypSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); + .sorted(Utils.compareUsing(BaseVdypSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); } protected L getPrimaryLayer(P poly) throws StandProcessingException { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index af0f5a698..465db99c7 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -1,5 +1,6 @@ package ca.bc.gov.nrs.vdyp.forward; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -9,10 +10,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDistributionSet; 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; @@ -198,14 +202,22 @@ public VdypLayer getLayer() { private void recordSpecies(int index, VdypSpecies species) { + VdypSite site = species.getSite().orElseThrow(() -> new ProcessingException(MessageFormat.format( + "Species {0} of Polygon {1} must contain a Site definition but does not.", + species.getGenus(), species.getPolygonIdentifier().toStringCompact()))); + speciesNames[index] = species.getGenus(); - sp64Distributions[index] = species.getSpeciesPercent(); - siteIndices[index] = species.getSiteIndex(); - dominantHeights[index] = species.getDominantHeight(); - ageTotals[index] = species.getAgeTotal(); - yearsAtBreastHeight[index] = species.getAgeAtBreastHeight(); - yearsToBreastHeight[index] = species.getYearsToBreastHeight(); - siteCurveNumbers[index] = species.getSiteCurveNumber(); + sp64Distributions[index] = new GenusDistributionSet(species.getSpeciesPercent()); + siteIndices[index] = site.getSiteIndex().orElse(VdypEntity.MISSING_FLOAT_VALUE); + dominantHeights[index] = site.getHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); + ageTotals[index] = site.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE); + yearsToBreastHeight[index] = site.getYearsToBreastHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); + if (ageTotals[index] != VdypEntity.MISSING_FLOAT_VALUE && yearsToBreastHeight[index] != VdypEntity.MISSING_FLOAT_VALUE) { + ageTotals[index] = ageTotals[index] - yearsToBreastHeight[index]; + } else { + ageTotals[index] = VdypEntity.MISSING_FLOAT_VALUE; + } + siteCurveNumbers[index] = site.getSiteCurveNumber().orElse(VdypEntity.MISSING_INTEGER_VALUE); speciesIndices[index] = species.getGenusIndex(); // percentForestedLand is output-only and so not assigned here. diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index 6443ee4fb..0fa829413 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -25,9 +25,10 @@ import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; 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.VdypUtilization; import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; class PolygonProcessingStateTest { @@ -209,14 +210,15 @@ private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( } private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, VdypSpecies species) { - assertThat(pps.yearsAtBreastHeight[index], is(species.getAgeAtBreastHeight())); - assertThat(pps.ageTotals[index], is(species.getAgeTotal())); - assertThat(pps.dominantHeights[index], is(species.getDominantHeight())); - assertThat(pps.siteIndices[index], is(species.getSiteIndex())); + VdypSite site = species.getSite().get(); + + assertThat(pps.ageTotals[index], is(site.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE))); + assertThat(pps.dominantHeights[index], is(site.getHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE))); + assertThat(pps.siteIndices[index], is(site.getSiteIndex().orElse(VdypEntity.MISSING_FLOAT_VALUE))); assertThat(pps.sp64Distributions[index], is(species.getSpeciesDistributions())); assertThat(pps.speciesIndices[index], is(species.getGenusIndex())); assertThat(pps.speciesNames[index], is(species.getGenus())); - assertThat(pps.yearsToBreastHeight[index], is(species.getYearsToBreastHeight())); + assertThat(pps.yearsToBreastHeight[index], is(site.getYearsToBreastHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE))); verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( pps, index, species From a04109ca6fd8992b8eef0727bd3e69bacd1253ec Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 1 Aug 2024 14:43:09 -0700 Subject: [PATCH 31/66] Added estimateBaseAreaYield and estimateQuadMeanDiameterYield back into EstimationMethods --- .../nrs/vdyp/common/EstimationMethods.java | 245 +++++++++++++++++- .../vdyp/forward/ForwardProcessingEngine.java | 16 +- 2 files changed, 250 insertions(+), 11 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index d6b9f53c5..b79f1e19b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -10,18 +10,25 @@ import static java.lang.Math.max; import static java.lang.Math.min; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.ToDoubleFunction; +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.application.StandProcessingException; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; +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.Coefficients; @@ -33,6 +40,7 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationVector; import ca.bc.gov.nrs.vdyp.model.UtilizationVector.BinaryOperatorWithClass; +import ca.bc.gov.nrs.vdyp.model.VdypSite; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; public class EstimationMethods { @@ -78,9 +86,8 @@ private float heightMultiplier(String genus, Region region, float treesPerHectar * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species * @return */ - public float - primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - + public float primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary + ) { return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); } @@ -126,7 +133,8 @@ public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, * @throws ProcessingException */ public float estimateNonPrimaryLoreyHeight( - BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight + BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, + float leadHeight, float primaryHeight ) throws ProcessingException { return estimateNonPrimaryLoreyHeight(vspec.getGenus(), vspecPrime.getGenus(), bec, leadHeight, primaryHeight); } @@ -524,6 +532,235 @@ public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, return estimateWholeStemVolumePerTree(volumeGroup, loreyHeight, quadMeanDiameter, coeMap); } + /** + * EMP106 - estimate basal area yield for the primary layer (from IPSJF160.doc) + * + * @param coefficients estimate basal area yield coefficients + * @param controlVariable2Setting the value of control variable 2 + * @param dominantHeight dominant height (m) + * @param breastHeightAge breast height age (years) + * @param veteranBaseArea basal area of overstory (>= 0) + * @param basalAreaGroup index of the basal area group + * @param fullOccupancy if true, the empirically fitted curve is increased to become + * a full occupancy curve. If false, BAP is for mean conditions. + * @return + * @throws StandProcessingException + */ + public float estimateBaseAreaYield( + Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, + float breastHeightAge, Optional veteranBasalArea, boolean fullOccupancy, int baseAreaGroup + ) throws StandProcessingException { + float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); + + // The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea + // (BATOP98): + + /* + * And one POSSIBLY one last vestige of grouping by ITG. + * + * That limit applies to full occupancy and Empirical occupancy. They were derived as the 98th percentile + * of Empirical stocking, though adjusted PSPs were included. If the ouput of this routine is bumped up + * from empirical to full, MIGHT adjust this limit DOWN here, so that at end, it is correct. Tentatively + * decide NOT to do this: + */ + +// if (fullOccupancy) { +// upperBoundsBaseArea *= EMPOC; +// } + + float ageToUse = breastHeightAge; + + if (controlVariable2Setting > 0) { + ageToUse = Math.min(ageToUse, controlVariable2Setting * 100); + } + + if (ageToUse <= 0f) { + throw new StandProcessingException("Age was not positive"); + } + + float trAge = FloatMath.log(ageToUse); + + float a0 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a1 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a2 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a3 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a4 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a5 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a6 = estimateBasalAreaYieldCoefficients.getCoe(0); + + float a00 = Math.max(a0 + a1 * trAge, 0); + float ap = Math.max(a3 + a4 * trAge, 0); + + float bap; + if (dominantHeight <= a2) { + bap = 0; + } else { + bap = a00 * FloatMath.pow(dominantHeight - a2, ap) + * FloatMath.exp(a5 * dominantHeight + a6 * veteranBasalArea.orElse(0f)); + bap = Math.min(bap, upperBoundBaseArea); + } + + if (fullOccupancy) { + bap /= EMPIRICAL_OCCUPANCY; + } + + return bap; + } + + /** + * EMP107 - estimate DQ yield for the primary layer (from IPSJF161.doc) + * + * @param coefficients coefficients weighted by species and decay bec zone + * @param controlVariable2Setting the value of control variable 2 + * @param dominantHeight dominant height (m) + * @param breastHeightAge breast height age (years) + * @param veteranBaseArea basal area of overstory (>= 0) + * @param basalAreaGroup index of the basal area group + * + * @return quad-mean-diameter of primary layer (with DBH >= 7.5) + * + * @throws StandProcessingException in the event of a processing error + */ + public float estimateQuadMeanDiameterYield( + Coefficients coefficients, int controlVariable2Setting, float dominantHeight, + float breastHeightAge, Optional veteranBaseArea, int basalAreaGroup + ) throws StandProcessingException { + + if (dominantHeight <= 5) { + return 7.6f; + } + + final float upperBoundsQuadMeanDiameter = upperBoundsQuadMeanDiameter(basalAreaGroup); + + final float ageUse = breastHeightAge; + + if (ageUse <= 0f) { + throw new StandProcessingException("Primary breast height age must be positive but was " + ageUse); + } + + final float trAge = FloatMath.log(ageUse); + + final float c0 = coefficients.getCoe(0); + final float c1 = Math.max(coefficients.getCoe(1) + coefficients.getCoe(2) * trAge, 0f); + final float c2 = Math.max(coefficients.getCoe(3) + coefficients.getCoe(4) * trAge, 0f); + + float dq = c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2); + + return FloatMath.clamp(dq, 7.6f, upperBoundsQuadMeanDiameter); + } + + /** + * @param basalAreaGroup the basal area group in question + * @return the quad-mean-diameter upper bound for the given basal area group + */ + float upperBoundsQuadMeanDiameter(int basalAreaGroup) { + return upperBounds(basalAreaGroup).getCoe(2); + } + + /** + * @param basalAreaGroup the basal area group in question + * @return the basal area upper bound for the given basal area group + */ + float upperBoundsBaseArea(int basalAreaGroup) { + return upperBounds(basalAreaGroup).getCoe(1); + } + + /** + * UPPERGEN Method 1 - return the upper bounds of basal area and quad-mean-diameter for a given + * basal area group as a list of (two) floats. + * @param basalAreaGroup the basal area group in question + * @return as described + */ + Coefficients upperBounds(int basalAreaGroup) { + var upperBoundsMap = controlMap.>get(ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); + return Utils.optSafe(upperBoundsMap.get(basalAreaGroup)).orElseThrow( + () -> new IllegalStateException("Could not find limits for basal area group " + basalAreaGroup) + ); + } + + Coefficients sumCoefficientsWeightedBySpeciesAndDecayBec( + Collection> species, BecDefinition bec, ControlKey key, int size + ) { + var coeMap = controlMap.>get(key, MatrixMap2.class); + + final String decayBecAlias = bec.getDecayBec().getAlias(); + + return weightedCoefficientSum( + size, 0, // + species, // + BaseVdypSpecies::getFractionGenus, // Weight by fraction + spec -> coeMap.get(decayBecAlias, spec.getGenus()) + ); + } + + /** + * Create a coefficients object where its values are either a weighted sum of those for each of the given entities, + * or the value from one arbitrarily chose entity. + * + * @param The type of entity + * @param size Size of the resulting coefficients object + * @param indexFrom index from of the resulting coefficients object + * @param entities the entities to do weighted sums over + * @param weight the weight for a given entity + * @param getCoefficients the coefficients for a given entity + */ + public static Coefficients weightedCoefficientSum( + int size, int indexFrom, Collection entities, ToDoubleFunction weight, + Function getCoefficients + ) { + var weighted = IntStream.range(indexFrom, size + indexFrom).boxed().toList(); + return weightedCoefficientSum(weighted, size, indexFrom, entities, weight, getCoefficients); + } + + /** + * Create a coefficients object where its values are either a weighted sum of those for each of the given entities, + * or the value from one arbitrarily chose entity. + * + * @param The type of entity + * @param weighted the indicies of the coefficients that should be weighted sums, those that are not included + * are assumed to be constant across all entities and one is choses arbitrarily. + * @param size Size of the resulting coefficients object + * @param indexFrom index from of the resulting coefficients object + * @param entities the entities to do weighted sums over + * @param weight the weight for a given entity + * @param getCoefficients the coefficients for a given entity + */ + public static Coefficients weightedCoefficientSum( + Collection weighted, int size, int indexFrom, Collection entities, ToDoubleFunction weight, + Function getCoefficients + ) { + Coefficients coe = Coefficients.empty(size, indexFrom); + + // Do the summation in double precision + var coeWorking = new double[size]; + Arrays.fill(coeWorking, 0.0); + + for (var entity : entities) { + var entityCoe = getCoefficients.apply(entity); + double fraction = weight.applyAsDouble(entity); + log.atInfo().addArgument(entity).addArgument(fraction).addArgument(entityCoe) + .setMessage("For entity {} with fraction {} adding coefficients {}").log(); + for (int i : weighted) { + coeWorking[i - indexFrom] += (entityCoe.getCoe(i)) * fraction; + } + } + // Reduce back to float once done + for (int i : weighted) { + coe.setCoe(i, (float) coeWorking[i - indexFrom]); + } + + // Pick one entity to fill in the fixed coefficients + // Choice is arbitrary, they should all be the same + var anyCoe = getCoefficients.apply(entities.iterator().next()); + + for (int i = indexFrom; i < size + indexFrom; i++) { + if (weighted.contains(i)) + continue; + coe.setCoe(i, anyCoe.getCoe(i)); + } + return coe; + } + /** * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad * mean diameter. diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 1293cdbdb..3bdeda7ba 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -1253,8 +1253,11 @@ float growQuadMeanDiameter( coefficientsWeightedBySpeciesAndDecayBec.setCoe(i, sum); } + int controlVariable2Value = fps.fcm.get(ControlKey.VTROL, ForwardControlVariables.class) + .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); + float dqYieldStart = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, dhStart, pspYabhStart, veteranBaStart, becZone, pps + coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhStart, pspYabhStart, veteranBaStart, pps .getPrimarySpeciesGroupNumber() ); @@ -1262,7 +1265,7 @@ float growQuadMeanDiameter( float pspYabhEnd = pspYabhStart + 1.0f; float dqYieldEnd = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, dhEnd, pspYabhEnd, veteranBaEnd, becZone, pps + coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhEnd, pspYabhEnd, veteranBaEnd, pps .getPrimarySpeciesGroupNumber() ); @@ -1458,19 +1461,18 @@ float growBasalArea( boolean isFullOccupancy = true; int pspGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - int debugSetting2Value = debugSettings.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2); + int controlVariable2Value = fps.fcm.get(ControlKey.VTROL, ForwardControlVariables.class) + .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhStart, pspYabhStart, veteranLayerBa, - isFullOccupancy, fps.getPolygonProcessingState().getBecZone(), pspGroupNumber + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, pspGroupNumber ); float pspDhEnd = pspDhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float baYieldEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, debugSetting2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, isFullOccupancy, fps - .getPolygonProcessingState().getBecZone(), pspGroupNumber + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, isFullOccupancy, pspGroupNumber ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() From 27dc8291ee0e9a2c6876711009d56d4e28b90c90 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 2 Aug 2024 11:20:01 -0700 Subject: [PATCH 32/66] Next steps in changing underlying model --- vdyp-lib/pom.xml | 2 -- .../gov/nrs/vdyp/application/VdypStartApplication.java | 5 +++-- .../ca/bc/gov/nrs/vdyp/common/EstimationMethods.java | 8 ++++---- .../ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java | 7 ------- .../java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 10 ---------- .../java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java | 5 ----- 6 files changed, 7 insertions(+), 30 deletions(-) diff --git a/vdyp-lib/pom.xml b/vdyp-lib/pom.xml index 0282fd2e2..63566ca19 100644 --- a/vdyp-lib/pom.xml +++ b/vdyp-lib/pom.xml @@ -3,9 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - ca.bc.gov.nrs.vdyp vdyp-lib - 0.0.1-SNAPSHOT pom Variable Density Yield Project - Library diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index e9372e8dd..a989da254 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -41,6 +41,7 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperCoefficientParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -240,7 +241,7 @@ void closeVriWriter() throws IOException { protected void setControlMap(Map controlMap) { this.controlMap = controlMap; - this.estimationMethods = new EstimationMethods(controlMap); + this.estimationMethods = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); } protected StreamingParser getStreamingParser(ControlKey key) throws ProcessingException { @@ -633,7 +634,7 @@ protected float estimatePrimaryBaseArea( public S leadGenus(L fipLayer) { return fipLayer.getSpecies().values().stream() - .sorted(Utils.compareUsing(BaseVdypSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); + .sorted(Utils.compareUsing(BaseVdypSpecies::getFractionGenus).reversed()).findFirst().orElseThrow(); } protected L getPrimaryLayer(P poly) throws StandProcessingException { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index b79f1e19b..ae6a27119 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -29,6 +29,7 @@ import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; +import ca.bc.gov.nrs.vdyp.model.BaseVdypSite; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; @@ -40,7 +41,6 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationVector; import ca.bc.gov.nrs.vdyp.model.UtilizationVector.BinaryOperatorWithClass; -import ca.bc.gov.nrs.vdyp.model.VdypSite; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; public class EstimationMethods { @@ -133,7 +133,7 @@ public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, * @throws ProcessingException */ public float estimateNonPrimaryLoreyHeight( - BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, + BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight ) throws ProcessingException { return estimateNonPrimaryLoreyHeight(vspec.getGenus(), vspecPrime.getGenus(), bec, leadHeight, primaryHeight); @@ -565,7 +565,7 @@ public float estimateBaseAreaYield( */ // if (fullOccupancy) { -// upperBoundsBaseArea *= EMPOC; +// upperBoundsBaseArea *= EMPIRICAL_OCCUPANCY; // } float ageToUse = breastHeightAge; @@ -679,7 +679,7 @@ Coefficients upperBounds(int basalAreaGroup) { } Coefficients sumCoefficientsWeightedBySpeciesAndDecayBec( - Collection> species, BecDefinition bec, ControlKey key, int size + Collection> species, BecDefinition bec, ControlKey key, int size ) { var coeMap = controlMap.>get(key, MatrixMap2.class); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java index fbd35786c..bd41f903d 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/ModelClassBuilder.java @@ -61,13 +61,6 @@ protected void preProcess() { // Do Nothing } - /** - * Additional steps before building - */ - protected void preProcess() { - // Do Nothing - } - /** * Run the constructor, assuming all required properties are present */ diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index e235447ee..30e73e757 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -261,16 +261,6 @@ public void wholeStemVolume(float volume) { this.wholeStemVolume = Utils.utilizationVector(volume); } - protected UtilizationVector wholeStemVolume = VdypUtilizationHolder.emptyUtilization(); - - public void wholeStemVolume(float small, float u1, float u2, float u3, float u4) { - this.wholeStemVolume = Utils.utilizationVector(small, u1, u2, u3, u4); - } - - public void wholeStemVolume(float volume) { - this.wholeStemVolume = Utils.utilizationVector(volume); - } - @Override protected void check(Collection errors) { super.check(errors); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java index e28e3ccc6..6bd32dd78 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java @@ -1,12 +1,7 @@ package ca.bc.gov.nrs.vdyp.model; -import java.text.MessageFormat; import java.util.Optional; -import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.math.FloatMath; - public class VdypUtilization implements VdypEntity { // See IPSJF155.doc From 5c218b76a34f3c0f9571ea191cd3c3b626e52cfb Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 6 Aug 2024 13:45:20 -0700 Subject: [PATCH 33/66] Next swath of changes for "grow", including promoting a calculation method from VdypStartApplication to its own class: ComputationMethods. --- .../application/VdypStartApplication.java | 321 +--------------- .../nrs/vdyp/common/ComputationMethods.java | 350 ++++++++++++++++++ .../nrs/vdyp/common/EstimationMethods.java | 150 +++++--- .../application/VdypStartApplicationTest.java | 7 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 92 +++-- .../vdyp/forward/ForwardProcessingEngine.java | 120 ++++-- .../vdyp/forward/ForwardProcessingState.java | 6 + .../vdyp/forward/PolygonProcessingState.java | 6 - 8 files changed, 606 insertions(+), 446 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index a989da254..55834e207 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -8,13 +8,9 @@ import static java.lang.Math.max; import static java.lang.Math.min; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -29,7 +25,6 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.ToDoubleFunction; -import java.util.stream.Collectors; import java.util.stream.IntStream; import org.slf4j.Logger; @@ -37,7 +32,6 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.EstimationMethods; -import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; @@ -56,7 +50,6 @@ import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap; @@ -64,16 +57,13 @@ import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; 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; -import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; -import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; public abstract class VdypStartApplication

    , S, I>, L extends BaseVdypLayer & InputLayer, S extends BaseVdypSpecies, I extends BaseVdypSite> extends VdypApplication implements Closeable { - private static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); + public static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); public static final int CONFIG_LOAD_ERROR = 1; public static final int PROCESSING_ERROR = 2; @@ -130,41 +120,6 @@ protected static void doMain(VdypStartApplication app, final String. } } - /** - * Accessor methods for utilization vectors, except for Lorey Height, on Layer and Species objects. - */ - protected static final Collection UTILIZATION_VECTOR_ACCESSORS; - - /** - * Accessor methods for utilization vectors, except for Lorey Height and Quadratic Mean Diameter, on Layer and - * Species objects. These are properties where the values for the layer are the sum of those for its species. - */ - static final Collection SUMMABLE_UTILIZATION_VECTOR_ACCESSORS; - - /** - * Accessor methods for utilization vectors, except for Lorey Height,and Volume on Layer and Species objects. - */ - protected static final Collection NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS; - - static { - try { - var bean = Introspector.getBeanInfo(VdypUtilizationHolder.class); - UTILIZATION_VECTOR_ACCESSORS = Arrays.stream(bean.getPropertyDescriptors()) // - .filter(p -> p.getName().endsWith("ByUtilization")) // - .filter(p -> !p.getName().startsWith("loreyHeight")) // - .filter(p -> p.getPropertyType() == UtilizationVector.class) // - .toList(); - } catch (IntrospectionException e) { - throw new IllegalStateException(e); - } - - SUMMABLE_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() - .filter(x -> !x.getName().startsWith("quadraticMeanDiameter")).toList(); - - NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() - .filter(x -> !x.getName().contains("Volume")).toList(); - } - protected VriAdjustInputWriter vriWriter; protected Map controlMap = new HashMap<>(); @@ -1117,278 +1072,4 @@ private float meanVolumeSmall(VdypSpecies spec, float quadMeanDiameterSpecSmall, ); } - // YUC1 - public void computeUtilizationComponentsPrimary( - BecDefinition bec, VdypLayer vdypLayer, VolumeComputeMode volumeComputeMode, - CompatibilityVariableMode compatibilityVariableMode - ) throws ProcessingException { - log.atTrace().setMessage("computeUtilizationComponentsPrimary for {}, stand total age is {}") - .addArgument(vdypLayer.getPolygonIdentifier()).addArgument(vdypLayer.getAgeTotal()).log(); - - log.atDebug().setMessage("Primary layer for {} has {} species/genera: {}") - .addArgument(vdypLayer::getPolygonIdentifier) // - .addArgument(() -> vdypLayer.getSpecies().size()) // - .addArgument(() -> vdypLayer.getSpecies().keySet().stream().collect(Collectors.joining(", "))) // - .log(); - - for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getAll(); - float baseAreaSpec = spec.getBaseAreaByUtilization().getAll(); - float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getAll(); - float treesPerHectareSpec = spec.getTreesPerHectareByUtilization().getAll(); - - log.atDebug().setMessage("Working with species {} LH: {} DQ: {} BA: {} TPH: {}") - .addArgument(spec.getClass()).addArgument(loreyHeightSpec).addArgument(quadMeanDiameterSpec) - .addArgument(baseAreaSpec).addArgument(treesPerHectareSpec); - - if (volumeComputeMode == VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC) { - log.atDebug().log("Estimating tree volume"); - - var volumeGroup = spec.getVolumeGroup(); - var meanVolume = this.estimationMethods - .estimateWholeStemVolumePerTree(volumeGroup, loreyHeightSpec, quadMeanDiameterSpec); - var specWholeStemVolume = treesPerHectareSpec * meanVolume; - - spec.getWholeStemVolumeByUtilization().setAll(specWholeStemVolume); - } - float wholeStemVolumeSpec = spec.getWholeStemVolumeByUtilization().getAll(); - - var baseAreaUtil = Utils.utilizationVector(); - var quadMeanDiameterUtil = Utils.utilizationVector(); - var treesPerHectareUtil = Utils.utilizationVector(); - var wholeStemVolumeUtil = Utils.utilizationVector(); - var closeVolumeUtil = Utils.utilizationVector(); - var closeVolumeNetDecayUtil = Utils.utilizationVector(); - var closeVolumeNetDecayWasteUtil = Utils.utilizationVector(); - var closeVolumeNetDecayWasteBreakUtil = Utils.utilizationVector(); - - baseAreaUtil.setAll(baseAreaSpec); // BAU - quadMeanDiameterUtil.setAll(quadMeanDiameterSpec); // DQU - treesPerHectareUtil.setAll(treesPerHectareSpec); // TPHU - wholeStemVolumeUtil.setAll(wholeStemVolumeSpec); // WSU - - var adjustCloseUtil = Utils.utilizationVector(); // ADJVCU - @SuppressWarnings("unused") - var adjustDecayUtil = Utils.utilizationVector(); // ADJVD - @SuppressWarnings("unused") - var adjustDecayWasteUtil = Utils.utilizationVector(); // ADJVDW - - // EMP071 - estimationMethods.estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec.getGenus()); - - // EMP070 - estimationMethods.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus()); - - // Calculate tree density components - for (var uc : VdypStartApplication.UTIL_CLASSES) { - treesPerHectareUtil.set( - uc, - BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) - ); - } - - // reconcile components with totals - - // YUC1R - ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - - if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { - throw new UnsupportedOperationException("TODO"); - } - - // Recalculate TPH's - - for (var uc : VdypStartApplication.UTIL_CLASSES) { - treesPerHectareUtil.setCoe( - uc.index, - BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - ); - } - - // Since DQ's may have changed, MUST RECONCILE AGAIN - // Seems this might only be needed when compatibilityVariableMode is not NONE? - - // YUC1R - ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - - if (volumeComputeMode == VolumeComputeMode.ZERO) { - throw new UnsupportedOperationException("TODO"); - } else { - - // EMP091 - estimationMethods.estimateWholeStemVolume( - UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, - quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - - if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { - // apply compatibity variables to WS volume - - // Set the adjustment factors for next three volume types - - throw new UnsupportedOperationException("TODO"); - } else { - // Do nothing as the adjustment vectors are already set to 0 - } - - // EMP092 - estimationMethods.estimateCloseUtilizationVolume( - UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, - quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil - ); - - // EMP093 - estimationMethods.estimateNetDecayVolume( - spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), - vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, - closeVolumeNetDecayUtil - ); - - // EMP094 - estimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, - quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil - ); - - if (this.getId().isStart()) { - // EMP095 - estimationMethods.estimateNetDecayWasteAndBreakageVolume( - UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, - closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil - ); - } - } - - spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, EstimationMethods.COPY_IF_BAND); - spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, EstimationMethods.COPY_IF_BAND); - spec.getQuadraticMeanDiameterByUtilization() - .pairwiseInPlace(quadMeanDiameterUtil, EstimationMethods.COPY_IF_BAND); - - spec.getWholeStemVolumeByUtilization() - .pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); - spec.getCloseUtilizationVolumeByUtilization() - .pairwiseInPlace(closeVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); - spec.getCloseUtilizationVolumeNetOfDecayByUtilization() - .pairwiseInPlace(closeVolumeNetDecayUtil, EstimationMethods.COPY_IF_NOT_SMALL); - spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_SMALL); - spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); - - } - computeLayerUtilizationComponentsFromSpecies(vdypLayer); - - for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - if (vdypLayer.getBaseAreaByUtilization().getAll() > 0f) { - spec.setFractionGenus( - spec.getBaseAreaByUtilization().getAll() / vdypLayer.getBaseAreaByUtilization().getAll() - ); - } - log.atDebug().addArgument(spec.getGenus()).addArgument(spec.getFractionGenus()) - .setMessage("Species {} base area {}%").log(); - } - - log.atDebug().setMessage("Calculating Stand Lorey Height").log(); - - vdypLayer.getLoreyHeightByUtilization().setSmall(0f); - vdypLayer.getLoreyHeightByUtilization().setAll(0f); - - for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - log.atDebug() // - .addArgument(spec.getGenus()) // - .addArgument(() -> spec.getLoreyHeightByUtilization().getAll()) - .addArgument(() -> spec.getBaseAreaByUtilization().getAll()) - .addArgument( - () -> spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() - ) - .setMessage( - "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" - ).log(); - vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.SMALL, - x -> x + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() - ); - vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.ALL, - x -> x + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() - ); - } - { - float baSmall = vdypLayer.getBaseAreaByUtilization().getSmall(); - float baAll = vdypLayer.getBaseAreaByUtilization().getAll(); - - if (baSmall > 0) { - vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.SMALL, x -> x / baSmall); - } - if (baAll > 0) { - vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.ALL, x -> x / baAll); - } - - } - - } - - /** - * Sets the Layer's utilization components based on those of its species. - * - * @param vdypLayer - */ - protected void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { - // Layer utilization vectors other than quadratic mean diameter are the pairwise - // sums of those of their species - sumSpeciesUtilizationVectorsToLayer(vdypLayer); - - { - var hlVector = Utils.heightVector(); - vdypLayer.getSpecies().values().stream().forEach(spec -> { - var ba = spec.getBaseAreaByUtilization(); - hlVector.pairwiseInPlace( - spec.getLoreyHeightByUtilization(), - (float x, float y, UtilizationClass uc) -> x + y * ba.get(uc) - ); - }); - var ba = vdypLayer.getBaseAreaByUtilization(); - hlVector.scalarInPlace((float x, UtilizationClass uc) -> ba.get(uc) > 0 ? x / ba.get(uc) : x); - vdypLayer.setLoreyHeightByUtilization(hlVector); - } - // Quadratic mean diameter for the layer is computed from the BA and TPH after - // they have been found from the species - { - var utilVector = vdypLayer.getBaseAreaByUtilization().pairwise( - vdypLayer.getTreesPerHectareByUtilization(), BaseAreaTreeDensityDiameter::quadMeanDiameter - ); - vdypLayer.setQuadraticMeanDiameterByUtilization(utilVector); - } - } - - // TODO De-reflectify this when we want to make it work in GralVM - void sumSpeciesUtilizationVectorsToLayer(VdypLayer vdypLayer) throws IllegalStateException { - try { - for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { - var utilVector = Utils.utilizationVector(); - for (var vdypSpecies : vdypLayer.getSpecies().values()) { - var speciesVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); - utilVector.pairwiseInPlace(speciesVector, (x, y) -> x + y); - } - accessors.getWriteMethod().invoke(vdypLayer, utilVector); - } - } catch (IllegalAccessException | InvocationTargetException ex) { - throw new IllegalStateException(ex); - } - } - - // TODO De-reflectify this when we want to make it work in GralVM - protected void scaleAllSummableUtilization(VdypUtilizationHolder holder, float factor) - throws IllegalStateException { - try { - for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { - ((Coefficients) accessors.getReadMethod().invoke(holder)).scalarInPlace(x -> x * factor); - } - } catch (IllegalAccessException | InvocationTargetException ex) { - throw new IllegalStateException(ex); - } - } - } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java new file mode 100644 index 000000000..0326ec454 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java @@ -0,0 +1,350 @@ +package ca.bc.gov.nrs.vdyp.common; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; +import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; +import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.model.BecDefinition; +import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; +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; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; +import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; + +public class ComputationMethods { + + public static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); + + /** + * Accessor methods for utilization vectors, except for Lorey Height, on Layer and Species objects. + */ + protected static final Collection UTILIZATION_VECTOR_ACCESSORS; + + /** + * Accessor methods for utilization vectors, except for Lorey Height and Quadratic Mean Diameter, on Layer and + * Species objects. These are properties where the values for the layer are the sum of those for its species. + */ + public static final Collection SUMMABLE_UTILIZATION_VECTOR_ACCESSORS; + + /** + * Accessor methods for utilization vectors, except for Lorey Height,and Volume on Layer and Species objects. + */ + protected static final Collection NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS; + + static { + try { + var bean = Introspector.getBeanInfo(VdypUtilizationHolder.class); + UTILIZATION_VECTOR_ACCESSORS = Arrays.stream(bean.getPropertyDescriptors()) // + .filter(p -> p.getName().endsWith("ByUtilization")) // + .filter(p -> !p.getName().startsWith("loreyHeight")) // + .filter(p -> p.getPropertyType() == UtilizationVector.class) // + .toList(); + } catch (IntrospectionException e) { + throw new IllegalStateException(e); + } + + SUMMABLE_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() + .filter(x -> !x.getName().startsWith("quadraticMeanDiameter")).toList(); + + NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() + .filter(x -> !x.getName().contains("Volume")).toList(); + } + + private final EstimationMethods estimationMethods; + + private final VdypApplicationIdentifier context; + + public ComputationMethods(EstimationMethods estimationMethods, VdypApplicationIdentifier context) { + this.estimationMethods = estimationMethods; + this.context = context; + } + + // YUC1 + public void computeUtilizationComponentsPrimary( + BecDefinition bec, VdypLayer vdypLayer, VolumeComputeMode volumeComputeMode, + CompatibilityVariableMode compatibilityVariableMode + ) throws ProcessingException { + log.atTrace().setMessage("computeUtilizationComponentsPrimary for {}, stand total age is {}") + .addArgument(vdypLayer.getPolygonIdentifier()).addArgument(vdypLayer.getAgeTotal()).log(); + + log.atDebug().setMessage("Primary layer for {} has {} species/genera: {}") + .addArgument(vdypLayer::getPolygonIdentifier) // + .addArgument(() -> vdypLayer.getSpecies().size()) // + .addArgument(() -> vdypLayer.getSpecies().keySet().stream().collect(Collectors.joining(", "))) // + .log(); + + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { + float loreyHeightSpec = spec.getLoreyHeightByUtilization().getAll(); + float baseAreaSpec = spec.getBaseAreaByUtilization().getAll(); + float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getAll(); + float treesPerHectareSpec = spec.getTreesPerHectareByUtilization().getAll(); + + log.atDebug().setMessage("Working with species {} LH: {} DQ: {} BA: {} TPH: {}") + .addArgument(spec.getClass()).addArgument(loreyHeightSpec).addArgument(quadMeanDiameterSpec) + .addArgument(baseAreaSpec).addArgument(treesPerHectareSpec); + + if (volumeComputeMode == VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC) { + log.atDebug().log("Estimating tree volume"); + + var volumeGroup = spec.getVolumeGroup(); + var meanVolume = this.estimationMethods + .estimateWholeStemVolumePerTree(volumeGroup, loreyHeightSpec, quadMeanDiameterSpec); + var specWholeStemVolume = treesPerHectareSpec * meanVolume; + + spec.getWholeStemVolumeByUtilization().setAll(specWholeStemVolume); + } + float wholeStemVolumeSpec = spec.getWholeStemVolumeByUtilization().getAll(); + + var baseAreaUtil = Utils.utilizationVector(); + var quadMeanDiameterUtil = Utils.utilizationVector(); + var treesPerHectareUtil = Utils.utilizationVector(); + var wholeStemVolumeUtil = Utils.utilizationVector(); + var closeVolumeUtil = Utils.utilizationVector(); + var closeVolumeNetDecayUtil = Utils.utilizationVector(); + var closeVolumeNetDecayWasteUtil = Utils.utilizationVector(); + var closeVolumeNetDecayWasteBreakUtil = Utils.utilizationVector(); + + baseAreaUtil.setAll(baseAreaSpec); // BAU + quadMeanDiameterUtil.setAll(quadMeanDiameterSpec); // DQU + treesPerHectareUtil.setAll(treesPerHectareSpec); // TPHU + wholeStemVolumeUtil.setAll(wholeStemVolumeSpec); // WSU + + var adjustCloseUtil = Utils.utilizationVector(); // ADJVCU + @SuppressWarnings("unused") + var adjustDecayUtil = Utils.utilizationVector(); // ADJVD + @SuppressWarnings("unused") + var adjustDecayWasteUtil = Utils.utilizationVector(); // ADJVDW + + // EMP071 + estimationMethods.estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec.getGenus()); + + // EMP070 + estimationMethods.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus()); + + // Calculate tree density components + for (var uc : VdypStartApplication.UTIL_CLASSES) { + treesPerHectareUtil.set( + uc, + BaseAreaTreeDensityDiameter + .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) + ); + } + + // reconcile components with totals + + // YUC1R + ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); + + if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { + throw new UnsupportedOperationException("TODO"); + } + + // Recalculate TPH's + + for (var uc : VdypStartApplication.UTIL_CLASSES) { + treesPerHectareUtil.setCoe( + uc.index, + BaseAreaTreeDensityDiameter + .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) + ); + } + + // Since DQ's may have changed, MUST RECONCILE AGAIN + // Seems this might only be needed when compatibilityVariableMode is not NONE? + + // YUC1R + ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); + + if (volumeComputeMode == VolumeComputeMode.ZERO) { + throw new UnsupportedOperationException("TODO"); + } else { + + // EMP091 + estimationMethods.estimateWholeStemVolume( + UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + ); + + if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { + // apply compatibity variables to WS volume + + // Set the adjustment factors for next three volume types + + throw new UnsupportedOperationException("TODO"); + } else { + // Do nothing as the adjustment vectors are already set to 0 + } + + // EMP092 + estimationMethods.estimateCloseUtilizationVolume( + UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil + ); + + // EMP093 + estimationMethods.estimateNetDecayVolume( + spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), + vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayUtil + ); + + // EMP094 + estimationMethods.estimateNetDecayAndWasteVolume( + bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, + quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil + ); + + if (context.isStart()) { + // EMP095 + estimationMethods.estimateNetDecayWasteAndBreakageVolume( + UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil + ); + } + } + + spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, EstimationMethods.COPY_IF_BAND); + spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, EstimationMethods.COPY_IF_BAND); + spec.getQuadraticMeanDiameterByUtilization() + .pairwiseInPlace(quadMeanDiameterUtil, EstimationMethods.COPY_IF_BAND); + + spec.getWholeStemVolumeByUtilization() + .pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeByUtilization() + .pairwiseInPlace(closeVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeNetOfDecayByUtilization() + .pairwiseInPlace(closeVolumeNetDecayUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() + .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() + .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); + + } + computeLayerUtilizationComponentsFromSpecies(vdypLayer); + + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { + if (vdypLayer.getBaseAreaByUtilization().getAll() > 0f) { + spec.setFractionGenus( + spec.getBaseAreaByUtilization().getAll() / vdypLayer.getBaseAreaByUtilization().getAll() + ); + } + log.atDebug().addArgument(spec.getGenus()).addArgument(spec.getFractionGenus()) + .setMessage("Species {} base area {}%").log(); + } + + log.atDebug().setMessage("Calculating Stand Lorey Height").log(); + + vdypLayer.getLoreyHeightByUtilization().setSmall(0f); + vdypLayer.getLoreyHeightByUtilization().setAll(0f); + + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { + log.atDebug() // + .addArgument(spec.getGenus()) // + .addArgument(() -> spec.getLoreyHeightByUtilization().getAll()) + .addArgument(() -> spec.getBaseAreaByUtilization().getAll()) + .addArgument( + () -> spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + ) + .setMessage( + "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" + ).log(); + vdypLayer.getLoreyHeightByUtilization().scalarInPlace( + UtilizationClass.SMALL, + x -> x + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() + ); + vdypLayer.getLoreyHeightByUtilization().scalarInPlace( + UtilizationClass.ALL, + x -> x + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + ); + } + { + float baSmall = vdypLayer.getBaseAreaByUtilization().getSmall(); + float baAll = vdypLayer.getBaseAreaByUtilization().getAll(); + + if (baSmall > 0) { + vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.SMALL, x -> x / baSmall); + } + if (baAll > 0) { + vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.ALL, x -> x / baAll); + } + + } + + } + + /** + * Sets the Layer's utilization components based on those of its species. + * + * @param vdypLayer + */ + protected static void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { + // Layer utilization vectors other than quadratic mean diameter are the pairwise + // sums of those of their species + sumSpeciesUtilizationVectorsToLayer(vdypLayer); + + { + var hlVector = Utils.heightVector(); + vdypLayer.getSpecies().values().stream().forEach(spec -> { + var ba = spec.getBaseAreaByUtilization(); + hlVector.pairwiseInPlace( + spec.getLoreyHeightByUtilization(), + (float x, float y, UtilizationClass uc) -> x + y * ba.get(uc) + ); + }); + var ba = vdypLayer.getBaseAreaByUtilization(); + hlVector.scalarInPlace((float x, UtilizationClass uc) -> ba.get(uc) > 0 ? x / ba.get(uc) : x); + vdypLayer.setLoreyHeightByUtilization(hlVector); + } + // Quadratic mean diameter for the layer is computed from the BA and TPH after + // they have been found from the species + { + var utilVector = vdypLayer.getBaseAreaByUtilization().pairwise( + vdypLayer.getTreesPerHectareByUtilization(), BaseAreaTreeDensityDiameter::quadMeanDiameter + ); + vdypLayer.setQuadraticMeanDiameterByUtilization(utilVector); + } + } + + // TODO De-reflectify this when we want to make it work in GralVM + private static void sumSpeciesUtilizationVectorsToLayer(VdypLayer vdypLayer) throws IllegalStateException { + try { + for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { + var utilVector = Utils.utilizationVector(); + for (var vdypSpecies : vdypLayer.getSpecies().values()) { + var speciesVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); + utilVector.pairwiseInPlace(speciesVector, (x, y) -> x + y); + } + accessors.getWriteMethod().invoke(vdypLayer, utilVector); + } + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalStateException(ex); + } + } + + // TODO De-reflectify this when we want to make it work in GralVM + protected static void scaleAllSummableUtilization(VdypUtilizationHolder holder, float factor) + throws IllegalStateException { + try { + for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { + ((Coefficients) accessors.getReadMethod().invoke(holder)).scalarInPlace(x -> x * factor); + } + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index ae6a27119..cb89c6436 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -86,7 +86,8 @@ private float heightMultiplier(String genus, Region region, float treesPerHectar * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species * @return */ - public float primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary + public float primaryHeightFromLeadHeight( + float leadHeight, String genus, Region region, float treesPerHectarePrimary ) { return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); } @@ -133,7 +134,8 @@ public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, * @throws ProcessingException */ public float estimateNonPrimaryLoreyHeight( - BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, BecDefinition bec, + BaseVdypSpecies vspec, BaseVdypSpecies vspecPrime, + BecDefinition bec, float leadHeight, float primaryHeight ) throws ProcessingException { return estimateNonPrimaryLoreyHeight(vspec.getGenus(), vspecPrime.getGenus(), bec, leadHeight, primaryHeight); @@ -160,8 +162,8 @@ public float estimateNonPrimaryLoreyHeight( var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( () -> new ProcessingException( String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, - bec.getRegion() + "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, bec + .getRegion() ) ) ); @@ -194,70 +196,105 @@ public float estimateQuadMeanDiameterForSpecies( float standTreesPerHectare, // TPH_TOT float standLoreyHeight // HL_TOT ) throws ProcessingException { - String species = spec.getGenus(); + + Map basalAreaFractionPerSpecies = new HashMap<>(); + allSpecies.values().stream().forEach(s -> basalAreaFractionPerSpecies.put(s.getGenus(), s.getFractionGenus())); + + return estimateQuadMeanDiameterForSpecies( + spec.getGenus(), spec.getLoreyHeightByUtilization().get( + UtilizationClass.ALL + ), spec.getQuadraticMeanDiameterByUtilization().get( + UtilizationClass.ALL + ), basalAreaFractionPerSpecies, region, standQuadMeanDiameter, standBaseArea, standTreesPerHectare, standLoreyHeight + ); + + } + + // EMP060 + /** + * Estimate DQ for a species (primary or not). Using eqn in jf125.doc. + * + * Enforces mins and maxes from EMP061. + * + * @param spAlias The alias of the species + * @param spLoreyHeight The lorey height (all utilizations) of the species + * @param spQuadMeanDiameter The quad-mean-diameter (all utilizations) of the species + * @param basalAreaFractionPerSpecies Basal area fractions of the per species in the stand + * @param region BEC Region of the stand + * @param standQuadMeanDiameter Quadratic mean diameter of the stand + * @param standBaseArea Base area of the stand + * @param standTreesPerHectare Density opf the stand + * @param standLoreyHeight Lorey height of the stand + * @return Quadratic mean diameter of the species of interest + * @throws ProcessingException + */ + public float estimateQuadMeanDiameterForSpecies( + String spAlias, + float spLoreyHeight, // HLsp + float spQuadMeanDiameter, // DQsp + Map basalAreaFractionPerSpecies, // FR + Region region, // INDEX_IC + float standQuadMeanDiameter, // DQ_TOT + float standBaseArea, // BA_TOT + float standTreesPerHectare, // TPH_TOT + float standLoreyHeight // HL_TOT + ) throws ProcessingException { float c = 0.00441786467f; float minQuadMeanDiameter = min(7.6f, standQuadMeanDiameter); + Float spFraction = basalAreaFractionPerSpecies.get(spAlias); + // Quick solution - if (spec.getFractionGenus() >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { + if (spFraction >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { return standQuadMeanDiameter; } var coeMap = controlMap.>get(ControlKey.BY_SPECIES_DQ, Map.class); var specAliases = controlMap.getGenusDefinitionMap().getAliases(); - // TODO we can probably remove these as they seem to only be used for debugging - // in VDYP7 - Map adjust = new HashMap<>(coeMap.size()); - Map mult = new HashMap<>(coeMap.size()); - var specIt = specAliases.iterator(); - var spec1 = specIt.next(); float a2 = coeMap.get(spec1).getCoe(2); - float fractionOther = 1f - spec.getFractionGenus(); // FR_REST + float fractionOther = 1f - spFraction; // FR_REST - mult.put(spec1, 1f); float a0 = coeMap.get(spec1).getCoe(0); float a1 = coeMap.get(spec1).getCoe(1); while (specIt.hasNext()) { var specIAlias = specIt.next(); - var specI = allSpecies.get(specIAlias); - if (specIAlias.equals(spec.getGenus())) { + if (spAlias.equals(specIAlias)) { float multI = 1f; - mult.put(specIAlias, multI); a0 += multI * coeMap.get(specIAlias).getCoe(0); a1 += multI * coeMap.get(specIAlias).getCoe(1); } else { - if (specI != null && specI.getFractionGenus() > 0f) { - float multI = -specI.getFractionGenus() / fractionOther; - mult.put(specIAlias, multI); + float spIFraction = basalAreaFractionPerSpecies.get(specIAlias); + if (spIFraction > 0f) { + float multI = -spIFraction / fractionOther; a0 += multI * coeMap.get(specIAlias).getCoe(0); a1 -= multI * coeMap.get(specIAlias).getCoe(1); } } } - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UtilizationClass.ALL.index); + float loreyHeightSpec = spLoreyHeight; float loreyHeight1 = max(4f, loreyHeightSpec); - float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spec.getFractionGenus()) / fractionOther; + float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spFraction) / fractionOther; float loreyHeightRatio = clamp( (loreyHeight1 - 3f) / (loreyHeight2 - 3f), 0.05f, 20f); float r = exp( - a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) + adjust.getOrDefault(species, 0f) + a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) ); - float baseArea1 = spec.getFractionGenus() * standBaseArea; + float baseArea1 = spFraction * standBaseArea; float baseArea2 = standBaseArea - baseArea1; float treesPerHectare1; if (abs(r - 1f) < 0.0005) { - treesPerHectare1 = spec.getFractionGenus() * standTreesPerHectare; + treesPerHectare1 = spFraction * standTreesPerHectare; } else { float aa = (r - 1f) * c; float bb = c * (1f - r) * standTreesPerHectare + baseArea1 + baseArea2 * r; @@ -266,13 +303,13 @@ public float estimateQuadMeanDiameterForSpecies( if (term <= 0f) { throw new ProcessingException( "Term for trees per hectare calculation when estimating quadratic mean diameter for species " - + species + " was " + term + " but should be positive." + + spAlias + " was " + term + " but should be positive." ); } treesPerHectare1 = (-bb + sqrt(term)) / (2f * aa); if (treesPerHectare1 <= 0f || treesPerHectare1 > standTreesPerHectare) { throw new ProcessingException( - "Trees per hectare 1 for species " + species + " was " + treesPerHectare1 + "Trees per hectare 1 for species " + spAlias + " was " + treesPerHectare1 + " but should be positive and less than or equal to stand trees per hectare " + standTreesPerHectare ); @@ -282,11 +319,10 @@ public float estimateQuadMeanDiameterForSpecies( float quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); float treesPerHectare2 = standTreesPerHectare - treesPerHectare1; float quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - var limits = getLimitsForHeightAndDiameter(species, region); + var limits = getLimitsForHeightAndDiameter(spAlias, region); quadMeanDiameter1 = estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, - quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); return quadMeanDiameter1; } @@ -306,8 +342,9 @@ float estimateQuadMeanDiameterClampResult( final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); final float dqMaxSp = max( - 7.6f, - min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) + 7.6f, min( + limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec + ) ); if (quadMeanDiameter1 < dqMinSp) { quadMeanDiameter1 = dqMinSp; @@ -547,7 +584,7 @@ public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, * @throws StandProcessingException */ public float estimateBaseAreaYield( - Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, + Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, float breastHeightAge, Optional veteranBasalArea, boolean fullOccupancy, int baseAreaGroup ) throws StandProcessingException { float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); @@ -564,10 +601,10 @@ public float estimateBaseAreaYield( * decide NOT to do this: */ -// if (fullOccupancy) { -// upperBoundsBaseArea *= EMPIRICAL_OCCUPANCY; -// } - + // if (fullOccupancy) { + // upperBoundsBaseArea *= EMPIRICAL_OCCUPANCY; + // } + float ageToUse = breastHeightAge; if (controlVariable2Setting > 0) { @@ -587,7 +624,7 @@ public float estimateBaseAreaYield( float a4 = estimateBasalAreaYieldCoefficients.getCoe(0); float a5 = estimateBasalAreaYieldCoefficients.getCoe(0); float a6 = estimateBasalAreaYieldCoefficients.getCoe(0); - + float a00 = Math.max(a0 + a1 * trAge, 0); float ap = Math.max(a3 + a4 * trAge, 0); @@ -603,7 +640,7 @@ public float estimateBaseAreaYield( if (fullOccupancy) { bap /= EMPIRICAL_OCCUPANCY; } - + return bap; } @@ -622,14 +659,14 @@ public float estimateBaseAreaYield( * @throws StandProcessingException in the event of a processing error */ public float estimateQuadMeanDiameterYield( - Coefficients coefficients, int controlVariable2Setting, float dominantHeight, + Coefficients coefficients, int controlVariable2Setting, float dominantHeight, float breastHeightAge, Optional veteranBaseArea, int basalAreaGroup ) throws StandProcessingException { if (dominantHeight <= 5) { return 7.6f; } - + final float upperBoundsQuadMeanDiameter = upperBoundsQuadMeanDiameter(basalAreaGroup); final float ageUse = breastHeightAge; @@ -645,7 +682,7 @@ public float estimateQuadMeanDiameterYield( final float c2 = Math.max(coefficients.getCoe(3) + coefficients.getCoe(4) * trAge, 0f); float dq = c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2); - + return FloatMath.clamp(dq, 7.6f, upperBoundsQuadMeanDiameter); } @@ -679,7 +716,8 @@ Coefficients upperBounds(int basalAreaGroup) { } Coefficients sumCoefficientsWeightedBySpeciesAndDecayBec( - Collection> species, BecDefinition bec, ControlKey key, int size + Collection> species, BecDefinition bec, ControlKey key, + int size ) { var coeMap = controlMap.>get(key, MatrixMap2.class); @@ -817,8 +855,7 @@ public void estimateWholeStemVolume( ); estimateWholeStemVolume( - utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, - quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil ); } @@ -896,8 +933,7 @@ public void estimateCloseUtilizationVolume( ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class ); estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, - wholeStemVolumeUtil, closeUtilizationVolumeUtil + utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil ); } @@ -968,8 +1004,7 @@ public void estimateNetDecayVolume( final var decayModifierMap = controlMap .>get(ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class); estimateNetDecayVolume( - genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, - quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil + genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil ); } @@ -1053,9 +1088,7 @@ public void estimateNetDecayAndWasteVolume( .>get(ControlKey.WASTE_MODIFIERS, MatrixMap2.class); estimateNetDecayAndWasteVolume( - region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, - quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, - closeUtilizationNetOfDecayAndWasteUtil + region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil ); } @@ -1082,8 +1115,9 @@ public static void estimateNetDecayAndWasteVolume( UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { estimateUtilization( - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, - (i, netDecay) -> { + closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( + i, netDecay + ) -> { if (Float.isNaN(netDecay) || netDecay <= 0f) { return 0f; } @@ -1160,8 +1194,7 @@ public void estimateNetDecayWasteAndBreakageVolume( final var netBreakageCoeMap = controlMap.>get(ControlKey.BREAKAGE, Map.class); estimateNetDecayWasteAndBreakageVolume( - utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil + utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); } @@ -1194,8 +1227,9 @@ public static void estimateNetDecayWasteAndBreakageVolume( final var a4 = coefficients.getCoe(4); estimateUtilization( - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, - utilizationClass, (uc, netWaste) -> { + closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, utilizationClass, ( + uc, netWaste + ) -> { if (netWaste <= 0f) { return 0f; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index 67b02fd1b..df9804a58 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -41,8 +41,11 @@ import ca.bc.gov.nrs.vdyp.application.test.TestSite; import ca.bc.gov.nrs.vdyp.application.test.TestSpecies; import ca.bc.gov.nrs.vdyp.application.test.TestStartApplication; +import ca.bc.gov.nrs.vdyp.common.ComputationMethods; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.io.parse.coe.BecDefinitionParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; @@ -1542,7 +1545,9 @@ void testComputeUtilizationComponentsPrimaryByUtilNoCV() throws ProcessingExcept layer.setSpecies(Arrays.asList(spec1, spec2)); - app.computeUtilizationComponentsPrimary( + EstimationMethods estimationMethods = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); + ComputationMethods computationMethods = new ComputationMethods(estimationMethods, null); + computationMethods.computeUtilizationComponentsPrimary( bec, layer, VolumeComputeMode.BY_UTIL, CompatibilityVariableMode.NONE ); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 465db99c7..e41de35f6 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -66,17 +66,8 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai this.layer = layer; this.becZone = becZone; - this.indices = IntStream.range(1, nSpecies + 1).toArray(); - - List speciesToRetain = new ArrayList<>(); - - for (VdypSpecies s : layer.getSpecies().values()) { - if (retainCriteria.test(s)) { - speciesToRetain.add(s); - } - } - - speciesToRetain.sort((o1, o2) -> o1.getGenusIndex().compareTo(o2.getGenusIndex())); + List speciesToRetain = layer.getSpecies().values().stream().filter(s -> retainCriteria.test(s)) + .sorted((s1, s2) -> s1.getGenusIndex().compareTo(s2.getGenusIndex())).toList(); this.nSpecies = speciesToRetain.size(); this.indices = IntStream.range(1, nSpecies + 1).toArray(); @@ -105,11 +96,11 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai treesPerHectare = new float[nSpecies + 1][nUtilizationClasses]; wholeStemVolumes = new float[nSpecies + 1][nUtilizationClasses]; - recordUtilizations(0, layer); + transferUtilizationsIntoBank(0, layer); int nextSlot = 1; for (VdypSpecies s : speciesToRetain) { - recordSpecies(nextSlot++, s); + transferSpeciesIntoBank(nextSlot++, s); } } @@ -188,19 +179,27 @@ public int getNSpecies() { return nSpecies; } - public int[] getIndices() { + int[] getIndices() { return indices; } - public BecDefinition getBecZone() { + BecDefinition getBecZone() { return becZone; } - - public VdypLayer getLayer() { + + /** + * 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 getUpdatedLayer() { + transferLayerFromBank(); return layer; } - private void recordSpecies(int index, VdypSpecies species) { + private void transferSpeciesIntoBank(int index, VdypSpecies species) { VdypSite site = species.getSite().orElseThrow(() -> new ProcessingException(MessageFormat.format( "Species {0} of Polygon {1} must contain a Site definition but does not.", @@ -213,18 +212,18 @@ private void recordSpecies(int index, VdypSpecies species) { ageTotals[index] = site.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE); yearsToBreastHeight[index] = site.getYearsToBreastHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); if (ageTotals[index] != VdypEntity.MISSING_FLOAT_VALUE && yearsToBreastHeight[index] != VdypEntity.MISSING_FLOAT_VALUE) { - ageTotals[index] = ageTotals[index] - yearsToBreastHeight[index]; + yearsAtBreastHeight[index] = ageTotals[index] - yearsToBreastHeight[index]; } else { - ageTotals[index] = VdypEntity.MISSING_FLOAT_VALUE; + yearsAtBreastHeight[index] = VdypEntity.MISSING_FLOAT_VALUE; } siteCurveNumbers[index] = site.getSiteCurveNumber().orElse(VdypEntity.MISSING_INTEGER_VALUE); speciesIndices[index] = species.getGenusIndex(); // percentForestedLand is output-only and so not assigned here. - recordUtilizations(index, species); + transferUtilizationsIntoBank(index, species); } - private void recordUtilizations(int index, VdypUtilizationHolder uh) { + private void transferUtilizationsIntoBank(int index, VdypUtilizationHolder uh) { for (UtilizationClass uc: UtilizationClass.values()) { int ucIndex = uc.ordinal(); @@ -241,7 +240,7 @@ private void recordUtilizations(int index, VdypUtilizationHolder uh) { } } - private void recordDefaultUtilizations(int index) { + private void transferDefaultUtilizationsIntoBank(int index) { for (var uc : UtilizationClass.values()) { int ucIndex = uc.ordinal(); @@ -258,10 +257,55 @@ private void recordDefaultUtilizations(int index) { } } + private void transferLayerFromBank() { + + transferUtilizationsFromBank(0, layer); + + for (int i: indices) { + transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i])); + } + } + + private void transferSpeciesFromBank(int index, VdypSpecies species) { + + VdypSite site = species.getSite().get(); + + VdypSite updatedSite = new VdypSite.Builder() + .adapt(site) + .siteIndex(siteIndices[index]) + .ageTotal(ageTotals[index]) + .height(dominantHeights[index]) + .yearsToBreastHeight(yearsToBreastHeight[index]) + .build(); + + VdypSpecies speciesBuilder = new VdypSpecies.Builder() + .addSite(updatedSite) + .adapt(species).build(); + + transferUtilizationsIntoBank(index, species); + } + + 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, CopyMode.CopyAll); } - + private GenusDistributionSet[] copy(GenusDistributionSet[] a) { return Arrays.stream(a).map(g -> g == null ? null : g.copy()).toArray(GenusDistributionSet[]::new); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 3bdeda7ba..f119e3e47 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -58,7 +58,9 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; 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.VolumeVariable; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; @@ -180,11 +182,21 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilYear) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); - Bank bank = fps.getBank(0, LayerType.PRIMARY); + Bank primaryBank = fps.getBank(0, LayerType.PRIMARY); + + Optional veteranLayer; + Optional veteranBank; + if (pps.getPolygon().getLayers().containsKey(LayerType.VETERAN)){ + veteranLayer = Optional.of(pps.getPolygon().getLayers().get(LayerType.VETERAN)); + veteranBank = Optional.of(fps.getBank(0, LayerType.VETERAN)); + } else { + veteranLayer = Optional.empty(); + veteranBank = Optional.empty(); + } logger.info( - "Beginning processing of polygon {} layer {}", pps.getLayer().getPolygonIdentifier() - .toStringCompact(), pps.getLayer() + "Beginning processing of polygon {} Primary layer {}", pps.getPolygon().getPolygonIdentifier() + .toStringCompact() ); // BANKCHK1, simplified for the parameters METH_CHK = 4, LayerI = 1, and INSTANCE = 1 @@ -194,7 +206,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // SCINXSET - note these are calculated directly from the Primary bank of instance 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { - calculateMissingSiteCurves(bank, fps.fcm.getSiteCurveMap(), fps.getPolygonProcessingState()); + calculateMissingSiteCurves(primaryBank, fps.fcm.getSiteCurveMap(), fps.getPolygonProcessingState()); } // VPRIME1, method == 1 @@ -227,15 +239,13 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // VGROW1 if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { - int veteranLayerInstance = 0; - int startingYear = fps.getPolygonProcessingState().getPolygon().getPolygonIdentifier().getYear(); - Bank startBank = pps.getStartBank(); - int primaryLayerSourceInstance = 2; - fps.storeActive(pps.getStartBank(), primaryLayerSourceInstance, LayerType.PRIMARY); - - writeLayers(startBank, veteranLayerInstance, false); + VdypPolygon vdypPolygon = pps.getPolygon(); + + VdypLayer primaryLayer = vdypPolygon.getLayers().get(LayerType.PRIMARY); + + writeLayers(primaryLayer, veteranLayer, false); boolean createNewGroups = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 @@ -245,18 +255,12 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY int currentYear = startingYear; while (currentYear <= untilYear) { - Bank endBank = grow(startBank, currentYear, veteranLayerInstance); + primaryLayer = grow(primaryBank, currentYear, veteranBank); // Store polygon (both primary and veteran layers) to output - writeLayers(endBank, veteranLayerInstance, createNewGroups); + writeLayers(primaryLayer, veteranLayer, createNewGroups); currentYear += 1; - - int newPrimaryLayerSourceInstance = primaryLayerTargetInstance; - primaryLayerTargetInstance = primaryLayerSourceInstance; - primaryLayerSourceInstance = newPrimaryLayerSourceInstance; - - startBank = endBank; } } } @@ -274,7 +278,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY * * @throws ProcessingException */ - private Bank grow(Bank start, int currentYear, int veteranLayerInstance) + private Bank grow(Bank start, int currentYear, Optional veteranBank) throws ProcessingException { PolygonProcessingState pps = fps.getPolygonProcessingState(); @@ -284,8 +288,6 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) Bank end = new Bank(start, CopyMode.CopyStructure); - Optional veteranBank = Optional.ofNullable(fps.getBank(veteranLayerInstance, LayerType.VETERAN)); - // If update-during-growth is set, and this is not the starting year, update the context int startingYear = polygon.getPolygonIdentifier().getYear(); if (currentYear > startingYear @@ -471,7 +473,8 @@ private Bank grow(Bank start, int currentYear, int veteranLayerInstance) pps.updateCompatibilityVariablesAfterGrowth(); - computeUtilizationComponentsPrimary(); + VdypLayer primaryLayer = pps.getStartBank().getUpdatedLayer(); + pps.getFps().computers.computeUtilizationComponentsPrimary(pps.getBecZone(), primaryLayer, null, null); calculateSmallComponentYields(end); @@ -524,20 +527,69 @@ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphC * (indices 1 - # species) | overall (index 0) the start of the growth period * * @return true if and only if a solution was found. + * @throws ProcessingException */ private boolean growUsingPartialSpeciesDynamics( Bank end, float dqDelta, float baDelta, float baStart, float dqStart, float tphStart, float[] currentLoreyHeights - ) { - + ) throws ProcessingException { boolean wasSuccessful = true; PolygonProcessingState pps = fps.getPolygonProcessingState(); + Bank start = pps.getStartBank(); if (dqDelta == 0 || baDelta == 0 || pps.getNSpecies() == 1) { return false /* no solution available */; } + + float[] dqs1 = new float[pps.getNSpecies() + 1]; + float[] dqs2 = new float[pps.getNSpecies() + 1]; + + float[] baNew = new float[pps.getNSpecies() + 1]; + baNew[0] = baStart + baDelta; + for (int i : pps.getIndices()) { + baNew[i] = start.basalAreas[i][0] * baNew[0] / start.basalAreas[0][0]; + } + + float[] dqNew = new float[pps.getNSpecies() + 1]; + dqNew[0] = dqStart + dqDelta; + float[] tphNew = new float[pps.getNSpecies() + 1]; + tphNew[0] = tphStart + BaseAreaTreeDensityDiameter.treesPerHectare(baNew[0], dqNew[0]); + + Map basalAreaPercentagesPerSpecies = new HashMap<>(); + for (String spAlias : fps.fcm.getGenusDefinitionMap().getAliases()) { + basalAreaPercentagesPerSpecies.put(spAlias, 0.0f); + } + for (int i : pps.getIndices()) { + basalAreaPercentagesPerSpecies.put(start.speciesNames[i], start.percentagesOfForestedLand[i]); + } + + for (int i : pps.getIndices()) { + + dqs1[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( + start.speciesNames[i], + start.basalAreas[i][0], + start.quadMeanDiameters[i][0], + basalAreaPercentagesPerSpecies, + pps.getBecZone().getRegion(), + dqStart, + baStart, + tphStart, + currentLoreyHeights[0]); + + dqs2[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( + start.speciesNames[i], + baNew[0], + dqNew[0], + basalAreaPercentagesPerSpecies, + pps.getBecZone().getRegion(), + dqStart, + baStart, + tphStart, + start.loreyHeights[i][0]); + } + return wasSuccessful; } @@ -976,13 +1028,6 @@ private float growBasalAreaForPrimarySpecies( return baDelta; } - /** - * YUC1 - */ - private void computeUtilizationComponentsPrimary() { - // TODO Auto-generated method stub - } - /** * Record small component utilization values for primary layer. * @@ -1857,10 +1902,11 @@ private static double ageAndSiteIndexToHeight( } } - private void writeLayers(Bank endBank, int veteranLayerInstance, boolean b) { + private void writeLayers(VdypLayer primaryLayer, Optional veteranLayer, boolean doCreateNewGroups) { logger.info( - "Writing primary layer, and veteran layer from instance {}", endBank, veteranLayerInstance + "Writing primary layer {}{}", primaryLayer.getPolygonIdentifier(), + veteranLayer.isPresent() ? veteranLayer.get().getPolygonIdentifier() : "" ); } @@ -2682,7 +2728,7 @@ private static void validatePolygon(VdypPolygon polygon) throws ProcessingExcept } } - private static void stopIfNoWork(PolygonProcessingState state) throws ProcessingException { + private static void stopIfNoWork(PolygonProcessingState pps) throws ProcessingException { // The following is extracted from BANKCHK1, simplified for the parameters // METH_CHK = 4, LayerI = 1, and INSTANCE = 1. So IR = 1, which is the first @@ -2691,10 +2737,10 @@ private static void stopIfNoWork(PolygonProcessingState state) throws Processing // => all that is done is that an exception is thrown if there are no species to // process. - if (state.getNSpecies() == 0) { + if (pps.getNSpecies() == 0) { throw new ProcessingException( MessageFormat.format( - "Polygon {0} layer 0 has no species with basal area above {1}", state.getLayer() + "Polygon {0} layer 0 has no species with basal area above {1}", pps.getPolygon() .getPolygonIdentifier().toStringCompact(), MIN_BASAL_AREA ) ); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 18f2d752f..649102ade 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -4,6 +4,8 @@ import java.util.Map; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; +import ca.bc.gov.nrs.vdyp.common.ComputationMethods; import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; @@ -27,6 +29,9 @@ class ForwardProcessingState { /** The estimators instance used by this engine */ final EstimationMethods estimators; + /** The compuation instance used by this engine */ + final ComputationMethods computers; + /** The storage banks */ private final Bank[/* instances */][/* layers of instance */] banks; @@ -39,6 +44,7 @@ public ForwardProcessingState(Map controlMap) { this.fcm = new ForwardResolvedControlMapImpl(controlMap); this.estimators = new EstimationMethods(this.fcm); + this.computers = new ComputationMethods(estimators, VdypApplicationIdentifier.VDYP_FORWARD); } private static final float MIN_BASAL_AREA = 0.001f; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java index 469796f43..2e48d9932 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java @@ -16,7 +16,6 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; 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.VolumeVariable; @@ -167,11 +166,6 @@ public BecDefinition getBecZone() { return start.getBecZone(); } - public VdypLayer getLayer() { - return start.getLayer(); - } - - public int getPrimarySpeciesIndex() { if (!areRankingDetailsSet) { throw new IllegalStateException("unset primarySpeciesIndex"); From d27762c1f37b4d30b8acc5c2698231ee03b1c552 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 14 Aug 2024 17:27:53 -0700 Subject: [PATCH 34/66] Converting Forward to use the new polygon model --- .../application/VdypStartApplication.java | 325 ++- .../nrs/vdyp/common/EstimationMethods.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/common/Utils.java | 1 + .../CachingResolvedControlMapImpl.java | 2 +- .../vdyp/controlmap/ResolvedControlMap.java | 2 +- .../controlmap/ResolvedControlMapImpl.java | 2 +- .../io/parse/coe/GenusDefinitionParser.java | 2 +- .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 33 +- .../gov/nrs/vdyp/model/BaseVdypPolygon.java | 25 +- .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 18 +- .../{common => model}/GenusDefinitionMap.java | 4 +- .../ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 19 +- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 2 +- .../vdyp/application/test/TestPolygon.java | 15 +- .../vdyp/common/EstimationMethodsTest.java | 2 + .../parse/coe/GenusDefinitionParserTest.java | 2 +- .../io/parse/coe/SiteCurveParserTest.java | 2 +- .../parse/coe/UpperCoefficientParserTest.java | 2 +- .../control/NonFipControlParserTest.java | 2 +- .../vdyp/model/GenusDefinitionMapTest.java | 1 - .../ca/bc/gov/nrs/vdyp/test/TestUtils.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 28 +- .../ca/bc/gov/nrs/vdyp/fip/FipStart.java.orig | 2048 ----------------- .../bc/gov/nrs/vdyp/fip/model/FipPolygon.java | 2 +- .../bc/gov/nrs/vdyp/fip/model/FipSpecies.java | 2 +- .../nrs/vdyp/fip/FipControlParserTest.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 27 +- .../vdyp/forward/ForwardDataStreamReader.java | 99 +- .../vdyp/forward/ForwardProcessingEngine.java | 6 +- .../vdyp/forward/ForwardProcessingState.java | 4 +- .../forward/model/VdypPolygonDescription.java | 45 + .../forward/parsers/VdypPolygonParser.java | 16 +- .../forward/parsers/VdypSpeciesParser.java | 45 +- .../forward/ForwardControlParserTest.java | 4 +- .../forward/PolygonProcessingStateTest.java | 119 +- .../forward/VdypForwardReadPolygonTest.java | 2 - .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 10 +- .../bc/gov/nrs/vdyp/vri/model/VriPolygon.java | 2 +- .../bc/gov/nrs/vdyp/vri/model/VriSpecies.java | 2 +- .../nrs/vdyp/vri/VriControlParserTest.java | 2 +- 40 files changed, 651 insertions(+), 2279 deletions(-) rename vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/{common => model}/GenusDefinitionMap.java (96%) delete mode 100644 vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java.orig create mode 100644 vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 5a0b0e47e..86b299a5c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -8,9 +8,13 @@ import static java.lang.Math.max; import static java.lang.Math.min; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; @@ -25,6 +29,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.ToDoubleFunction; +import java.util.stream.Collectors; import java.util.stream.IntStream; import org.slf4j.Logger; @@ -32,10 +37,11 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.EstimationMethods; +import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperCoefficientParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -50,6 +56,7 @@ import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap; @@ -57,13 +64,16 @@ import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; 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; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; +import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; public abstract class VdypStartApplication

    , S, I>, L extends BaseVdypLayer & InputLayer, S extends BaseVdypSpecies, I extends BaseVdypSite> extends VdypApplication implements Closeable { - public static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); + private static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); public static final int CONFIG_LOAD_ERROR = 1; public static final int PROCESSING_ERROR = 2; @@ -120,6 +130,41 @@ protected static void doMain(VdypStartApplication app, final String. } } + /** + * Accessor methods for utilization vectors, except for Lorey Height, on Layer and Species objects. + */ + protected static final Collection UTILIZATION_VECTOR_ACCESSORS; + + /** + * Accessor methods for utilization vectors, except for Lorey Height and Quadratic Mean Diameter, on Layer and + * Species objects. These are properties where the values for the layer are the sum of those for its species. + */ + static final Collection SUMMABLE_UTILIZATION_VECTOR_ACCESSORS; + + /** + * Accessor methods for utilization vectors, except for Lorey Height,and Volume on Layer and Species objects. + */ + protected static final Collection NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS; + + static { + try { + var bean = Introspector.getBeanInfo(VdypUtilizationHolder.class); + UTILIZATION_VECTOR_ACCESSORS = Arrays.stream(bean.getPropertyDescriptors()) // + .filter(p -> p.getName().endsWith("ByUtilization")) // + .filter(p -> !p.getName().startsWith("loreyHeight")) // + .filter(p -> p.getPropertyType() == UtilizationVector.class) // + .toList(); + } catch (IntrospectionException e) { + throw new IllegalStateException(e); + } + + SUMMABLE_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() + .filter(x -> !x.getName().startsWith("quadraticMeanDiameter")).toList(); + + NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() + .filter(x -> !x.getName().contains("Volume")).toList(); + } + protected VriAdjustInputWriter vriWriter; protected Map controlMap = new HashMap<>(); @@ -196,7 +241,7 @@ void closeVriWriter() throws IOException { protected void setControlMap(Map controlMap) { this.controlMap = controlMap; - this.estimationMethods = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); + this.estimationMethods = new EstimationMethods(new CachingResolvedControlMapImpl(controlMap)); } protected StreamingParser getStreamingParser(ControlKey key) throws ProcessingException { @@ -1083,4 +1128,278 @@ private float meanVolumeSmall(VdypSpecies spec, float quadMeanDiameterSpecSmall, ); } + // YUC1 + public void computeUtilizationComponentsPrimary( + BecDefinition bec, VdypLayer vdypLayer, VolumeComputeMode volumeComputeMode, + CompatibilityVariableMode compatibilityVariableMode + ) throws ProcessingException { + log.atTrace().setMessage("computeUtilizationComponentsPrimary for {}, stand total age is {}") + .addArgument(vdypLayer.getPolygonIdentifier()).addArgument(vdypLayer.getAgeTotal()).log(); + + log.atDebug().setMessage("Primary layer for {} has {} species/genera: {}") + .addArgument(vdypLayer::getPolygonIdentifier) // + .addArgument(() -> vdypLayer.getSpecies().size()) // + .addArgument(() -> vdypLayer.getSpecies().keySet().stream().collect(Collectors.joining(", "))) // + .log(); + + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { + float loreyHeightSpec = spec.getLoreyHeightByUtilization().getAll(); + float baseAreaSpec = spec.getBaseAreaByUtilization().getAll(); + float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getAll(); + float treesPerHectareSpec = spec.getTreesPerHectareByUtilization().getAll(); + + log.atDebug().setMessage("Working with species {} LH: {} DQ: {} BA: {} TPH: {}") + .addArgument(spec.getClass()).addArgument(loreyHeightSpec).addArgument(quadMeanDiameterSpec) + .addArgument(baseAreaSpec).addArgument(treesPerHectareSpec); + + if (volumeComputeMode == VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC) { + log.atDebug().log("Estimating tree volume"); + + var volumeGroup = spec.getVolumeGroup(); + var meanVolume = this.estimationMethods + .estimateWholeStemVolumePerTree(volumeGroup, loreyHeightSpec, quadMeanDiameterSpec); + var specWholeStemVolume = treesPerHectareSpec * meanVolume; + + spec.getWholeStemVolumeByUtilization().setAll(specWholeStemVolume); + } + float wholeStemVolumeSpec = spec.getWholeStemVolumeByUtilization().getAll(); + + var baseAreaUtil = Utils.utilizationVector(); + var quadMeanDiameterUtil = Utils.utilizationVector(); + var treesPerHectareUtil = Utils.utilizationVector(); + var wholeStemVolumeUtil = Utils.utilizationVector(); + var closeVolumeUtil = Utils.utilizationVector(); + var closeVolumeNetDecayUtil = Utils.utilizationVector(); + var closeVolumeNetDecayWasteUtil = Utils.utilizationVector(); + var closeVolumeNetDecayWasteBreakUtil = Utils.utilizationVector(); + + baseAreaUtil.setAll(baseAreaSpec); // BAU + quadMeanDiameterUtil.setAll(quadMeanDiameterSpec); // DQU + treesPerHectareUtil.setAll(treesPerHectareSpec); // TPHU + wholeStemVolumeUtil.setAll(wholeStemVolumeSpec); // WSU + + var adjustCloseUtil = Utils.utilizationVector(); // ADJVCU + @SuppressWarnings("unused") + var adjustDecayUtil = Utils.utilizationVector(); // ADJVD + @SuppressWarnings("unused") + var adjustDecayWasteUtil = Utils.utilizationVector(); // ADJVDW + + // EMP071 + estimationMethods.estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec.getGenus()); + + // EMP070 + estimationMethods.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus()); + + // Calculate tree density components + for (var uc : VdypStartApplication.UTIL_CLASSES) { + treesPerHectareUtil.set( + uc, + BaseAreaTreeDensityDiameter + .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) + ); + } + + // reconcile components with totals + + // YUC1R + ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); + + if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { + throw new UnsupportedOperationException("TODO"); + } + + // Recalculate TPH's + + for (var uc : VdypStartApplication.UTIL_CLASSES) { + treesPerHectareUtil.setCoe( + uc.index, + BaseAreaTreeDensityDiameter + .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) + ); + } + + // Since DQ's may have changed, MUST RECONCILE AGAIN + // Seems this might only be needed when compatibilityVariableMode is not NONE? + + // YUC1R + ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); + + if (volumeComputeMode == VolumeComputeMode.ZERO) { + throw new UnsupportedOperationException("TODO"); + } else { + + // EMP091 + estimationMethods.estimateWholeStemVolume( + UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + ); + + if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { + // apply compatibity variables to WS volume + + // Set the adjustment factors for next three volume types + + throw new UnsupportedOperationException("TODO"); + } else { + // Do nothing as the adjustment vectors are already set to 0 + } + + // EMP092 + estimationMethods.estimateCloseUtilizationVolume( + UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil + ); + + // EMP093 + estimationMethods.estimateNetDecayVolume( + spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), + vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayUtil + ); + + // EMP094 + estimationMethods.estimateNetDecayAndWasteVolume( + bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, + quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil + ); + + if (this.getId().isStart()) { + // EMP095 + estimationMethods.estimateNetDecayWasteAndBreakageVolume( + UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil + ); + } + } + + spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, EstimationMethods.COPY_IF_BAND); + spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, EstimationMethods.COPY_IF_BAND); + spec.getQuadraticMeanDiameterByUtilization() + .pairwiseInPlace(quadMeanDiameterUtil, EstimationMethods.COPY_IF_BAND); + + spec.getWholeStemVolumeByUtilization() + .pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeByUtilization() + .pairwiseInPlace(closeVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeNetOfDecayByUtilization() + .pairwiseInPlace(closeVolumeNetDecayUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() + .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_SMALL); + spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() + .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); + + } + computeLayerUtilizationComponentsFromSpecies(vdypLayer); + + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { + if (vdypLayer.getBaseAreaByUtilization().getAll() > 0f) { + spec.setFractionGenus( + spec.getBaseAreaByUtilization().getAll() / vdypLayer.getBaseAreaByUtilization().getAll() + ); + } + log.atDebug().addArgument(spec.getGenus()).addArgument(spec.getFractionGenus()) + .setMessage("Species {} base area {}%").log(); + } + + log.atDebug().setMessage("Calculating Stand Lorey Height").log(); + + vdypLayer.getLoreyHeightByUtilization().setSmall(0f); + vdypLayer.getLoreyHeightByUtilization().setAll(0f); + + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { + log.atDebug() // + .addArgument(spec.getGenus()) // + .addArgument(() -> spec.getLoreyHeightByUtilization().getAll()) + .addArgument(() -> spec.getBaseAreaByUtilization().getAll()) + .addArgument( + () -> spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + ) + .setMessage( + "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" + ).log(); + vdypLayer.getLoreyHeightByUtilization().scalarInPlace( + UtilizationClass.SMALL, + x -> x + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() + ); + vdypLayer.getLoreyHeightByUtilization().scalarInPlace( + UtilizationClass.ALL, + x -> x + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + ); + } + { + float baSmall = vdypLayer.getBaseAreaByUtilization().getSmall(); + float baAll = vdypLayer.getBaseAreaByUtilization().getAll(); + + if (baSmall > 0) { + vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.SMALL, x -> x / baSmall); + } + if (baAll > 0) { + vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.ALL, x -> x / baAll); + } + + } + + } + + /** + * Sets the Layer's utilization components based on those of its species. + * + * @param vdypLayer + */ + protected void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { + // Layer utilization vectors other than quadratic mean diameter are the pairwise + // sums of those of their species + sumSpeciesUtilizationVectorsToLayer(vdypLayer); + + { + var hlVector = Utils.heightVector(); + vdypLayer.getSpecies().values().stream().forEach(spec -> { + var ba = spec.getBaseAreaByUtilization(); + hlVector.pairwiseInPlace( + spec.getLoreyHeightByUtilization(), + (float x, float y, UtilizationClass uc) -> x + y * ba.get(uc) + ); + }); + var ba = vdypLayer.getBaseAreaByUtilization(); + hlVector.scalarInPlace((float x, UtilizationClass uc) -> ba.get(uc) > 0 ? x / ba.get(uc) : x); + vdypLayer.setLoreyHeightByUtilization(hlVector); + } + // Quadratic mean diameter for the layer is computed from the BA and TPH after + // they have been found from the species + { + var utilVector = vdypLayer.getBaseAreaByUtilization().pairwise( + vdypLayer.getTreesPerHectareByUtilization(), BaseAreaTreeDensityDiameter::quadMeanDiameter + ); + vdypLayer.setQuadraticMeanDiameterByUtilization(utilVector); + } + } + + // TODO De-reflectify this when we want to make it work in GralVM + void sumSpeciesUtilizationVectorsToLayer(VdypLayer vdypLayer) throws IllegalStateException { + try { + for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { + var utilVector = Utils.utilizationVector(); + for (var vdypSpecies : vdypLayer.getSpecies().values()) { + var speciesVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); + utilVector.pairwiseInPlace(speciesVector, (x, y) -> x + y); + } + accessors.getWriteMethod().invoke(vdypLayer, utilVector); + } + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalStateException(ex); + } + } + + // TODO De-reflectify this when we want to make it work in GralVM + protected void scaleAllSummableUtilization(VdypUtilizationHolder holder, float factor) + throws IllegalStateException { + try { + for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { + ((Coefficients) accessors.getReadMethod().invoke(holder)).scalarInPlace(x -> x * factor); + } + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalStateException(ex); + } + } + } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index cb89c6436..20a1697ba 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -252,7 +252,7 @@ public float estimateQuadMeanDiameterForSpecies( } var coeMap = controlMap.>get(ControlKey.BY_SPECIES_DQ, Map.class); - var specAliases = controlMap.getGenusDefinitionMap().getAliases(); + var specAliases = controlMap.getGenusDefinitionMap().getAllGeneraAliases(); var specIt = specAliases.iterator(); var spec1 = specIt.next(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java index 626b3be2a..f53c8a799 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java @@ -24,6 +24,7 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationVector; import ca.bc.gov.nrs.vdyp.model.VdypLayer; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index b05bab9cd..bbd13edbc 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -5,12 +5,12 @@ import java.util.Optional; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index a949c0e96..175b2249f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -4,9 +4,9 @@ import java.util.Optional; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 40bf7d872..f4653158e 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -6,12 +6,12 @@ import java.util.Optional; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; import ca.bc.gov.nrs.vdyp.model.Region; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java index b4ef61319..d3abaffb7 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java @@ -9,7 +9,6 @@ import java.util.Optional; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -18,6 +17,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParseException; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; /** * Parser for a Genus (SP0; Species) Definition data file. diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index 16b2907f6..f17242b9f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -3,6 +3,7 @@ import java.text.MessageFormat; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -16,7 +17,8 @@ public abstract class BaseVdypLayer, I extends Base private final PolygonIdentifier polygonIdentifier; private final LayerType layerType; - private LinkedHashMap species = new LinkedHashMap<>(); + private LinkedHashMap speciesBySp0 = new LinkedHashMap<>(); + private HashMap speciesByIndex = new HashMap<>(); private Optional inventoryTypeGroup = Optional.empty(); protected BaseVdypLayer( @@ -38,22 +40,35 @@ public LayerType getLayerType() { } public LinkedHashMap getSpecies() { - return species; + return speciesBySp0; } public void setSpecies(Map species) { - this.species.clear(); - this.species.putAll(species); + this.speciesBySp0.clear(); + this.speciesByIndex.clear(); + this.speciesBySp0.putAll(species); } public void setSpecies(Collection species) { - this.species.clear(); - species.forEach(spec -> this.species.put(spec.getGenus(), spec)); + this.speciesBySp0.clear(); + this.speciesByIndex.clear(); + species.forEach(spec -> { + this.speciesBySp0.put(spec.getGenus(), spec); + this.speciesByIndex.put(spec.getGenusIndex(), spec); + }); } + public S getSpeciesBySp0(String sp0) { + return speciesBySp0.get(sp0); + } + + public S getSpeciesByIndex(int index) { + return speciesByIndex.get(index); + } + public LinkedHashMap getSites() { - var result = new LinkedHashMap(species.size()); - species.forEach((key, spec) -> spec.getSite().ifPresent(site -> result.put(key, site))); + var result = new LinkedHashMap(speciesBySp0.size()); + speciesBySp0.forEach((key, spec) -> spec.getSite().ifPresent(site -> result.put(key, site))); return result; } @@ -207,7 +222,5 @@ protected String getBuilderId() { layerType.map(Object::toString).orElse("N/A") // ); } - } - } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java index 0ea9ac8b6..6f7f6e95a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java @@ -21,10 +21,11 @@ public abstract class BaseVdypPolygon, PA, SP ex protected BecDefinition biogeoclimaticZone; protected String forestInventoryZone; protected Optional mode; + protected Optional inventoryTypeGroup; protected BaseVdypPolygon( PolygonIdentifier polygonIdentifier, PA percentAvailable, String fiz, BecDefinition biogeoclimaticZone, - Optional mode + Optional mode, Optional inventoryTypeGroup ) { super(); this.forestInventoryZone = fiz; @@ -32,6 +33,7 @@ protected BaseVdypPolygon( this.mode = mode; this.polygonIdentifier = polygonIdentifier; this.percentAvailable = percentAvailable; + this.inventoryTypeGroup = inventoryTypeGroup; } /** @@ -47,7 +49,8 @@ protected BaseVdypPolygon( ) { this( toCopy.getPolygonIdentifier(), convertPercentAvailable.apply(toCopy.getPercentAvailable()), - toCopy.getForestInventoryZone(), toCopy.getBiogeoclimaticZone(), toCopy.getMode() + toCopy.getForestInventoryZone(), toCopy.getBiogeoclimaticZone(), toCopy.getMode(), + toCopy.getInventoryTypeGroup() ); } @@ -96,6 +99,14 @@ public void setForestInventoryZone(String forestInventoryZone) { this.forestInventoryZone = forestInventoryZone; } + public Optional getInventoryTypeGroup() { + return inventoryTypeGroup; + } + + public void setInventoryTypeGroup(Optional inventoryTypeGroup) { + this.inventoryTypeGroup = inventoryTypeGroup; + } + public Optional getMode() { return mode; } @@ -120,6 +131,7 @@ protected abstract static class Builder< // protected Optional biogeoclimaticZone = Optional.empty(); protected Optional forestInventoryZone = Optional.empty(); protected Optional mode = Optional.empty(); + protected Optional inventoryTypeGroup = Optional.empty(); protected List layers = new LinkedList<>(); protected List> layersBuilders = new LinkedList<>(); @@ -163,6 +175,15 @@ public Builder mode(PolygonMode mode) { return mode(Optional.of(mode)); } + public Builder inventoryTypeGroup(Optional inventoryTypeGroup) { + this.inventoryTypeGroup = inventoryTypeGroup; + return this; + } + + public Builder inventoryTypeGroup(int inventoryTypeGroup) { + return inventoryTypeGroup(Optional.of(inventoryTypeGroup)); + } + public Builder addLayer(L layer) { this.layers.add(layer); return this; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 27348d274..ccce2fc73 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -101,7 +101,8 @@ public void setSpeciesPercentages(Map speciesPercentages) { } // sort the unindexed distributions in order of decreasing percentage - unindexedSp64Distributions = unindexedSp64Distributions.stream().sorted((o1, o2) -> o2.getPercentage().compareTo(o1.getPercentage())).toList(); + unindexedSp64Distributions = unindexedSp64Distributions.stream() + .sorted((o1, o2) -> o2.getPercentage().compareTo(o1.getPercentage())).toList(); // and assign them an index, starting with one. int index = 1; @@ -137,7 +138,7 @@ public abstract static class Builder, I extends Bas protected Optional genusIndex = Optional.empty(); protected Optional percentGenus = Optional.empty(); protected Optional fractionGenus = Optional.empty(); - protected List sp64DistributionList = new ArrayList<>(); + protected Optional sp64DistributionSet = Optional.empty(); protected Optional> siteBuilder = Optional.empty(); protected Optional site = Optional.empty(); @@ -182,7 +183,12 @@ protected Builder fractionGenus(float fractionGenus) { } public Builder sp64DistributionList(List sp64DistributionList) { - this.sp64DistributionList = sp64DistributionList; + this.sp64DistributionSet = Optional.of(new Sp64DistributionSet(sp64DistributionList)); + return this; + } + + public Builder sp64DistributionSet(Sp64DistributionSet sp64DistributionSet) { + this.sp64DistributionSet = Optional.of(sp64DistributionSet); return this; } @@ -208,8 +214,9 @@ public Builder addSite(Optional site) { } public void addSp64Distribution(String sp64Alias, float f) { - int index = sp64DistributionList.size() + 1; - sp64DistributionList.add(new Sp64Distribution(index, sp64Alias, f)); + var sp64DistributionList = sp64DistributionSet.map(set -> set.getSp64DistributionList()).orElse(new ArrayList()); + sp64DistributionList.add(new Sp64Distribution(sp64DistributionList.size() + 1, sp64Alias, f)); + sp64DistributionSet = Optional.of(new Sp64DistributionSet(sp64DistributionList)); } @Override @@ -219,6 +226,7 @@ protected void check(Collection errors) { requirePresent(genus, "genus", errors); requirePresent(genusIndex, "genusIndex", errors); requirePresent(percentGenus, "percentGenus", errors); + requirePresent(sp64DistributionSet, "sp64DistributionSet", errors); } @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMap.java similarity index 96% rename from vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java rename to vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMap.java index af3bfc74b..fcfcc4d47 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/GenusDefinitionMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMap.java @@ -1,4 +1,4 @@ -package ca.bc.gov.nrs.vdyp.common; +package ca.bc.gov.nrs.vdyp.model; import java.text.MessageFormat; import java.util.ArrayList; @@ -8,8 +8,6 @@ import java.util.List; import java.util.Map; -import ca.bc.gov.nrs.vdyp.model.GenusDefinition; - public class GenusDefinitionMap { private final Map genusByAliasMap = new HashMap<>(); private final Map indexByAliasMap = new HashMap<>(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index 32effdd16..50f7a395c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -1,25 +1,26 @@ package ca.bc.gov.nrs.vdyp.model; +import java.text.MessageFormat; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; public class VdypPolygon extends BaseVdypPolygon { - private final Optional targetYear; + private Optional targetYear; public VdypPolygon( PolygonIdentifier polygonIdentifier, Float percentAvailable, String fiz, BecDefinition bec, - Optional modeFip + Optional modeFip, Optional inventoryTypeGroup ) { - this(polygonIdentifier, percentAvailable, fiz, bec, modeFip, Optional.empty()); + this(polygonIdentifier, percentAvailable, fiz, bec, modeFip, inventoryTypeGroup, Optional.empty()); } public VdypPolygon( PolygonIdentifier polygonIdentifier, Float percentAvailable, String fiz, BecDefinition bec, - Optional modeFip, Optional targetYear + Optional modeFip, Optional inventoryTypeGroup, Optional targetYear ) { - super(polygonIdentifier, percentAvailable, fiz, bec, modeFip); + super(polygonIdentifier, percentAvailable, fiz, bec, modeFip, inventoryTypeGroup); this.targetYear = targetYear; } @@ -89,4 +90,12 @@ public void targetYear(Optional targetYear) { this.targetYear = targetYear; } } + + public void setTargetYear(int year) { + if (targetYear.isPresent()) { + throw new IllegalStateException(MessageFormat.format("Polygon {} has already had a target year ({}) assigned", this.getPolygonIdentifier(), this.getTargetYear())); + } else { + this.targetYear = Optional.of(year); + } + } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index 9e0f88b1f..2ee3e3b0c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -297,7 +297,7 @@ protected VdypSpecies doBuild() { genus.get(), // genusIndex.get(), // percentGenus.get(), // - new Sp64DistributionSet(sp64DistributionList), // + sp64DistributionSet.get(), // site, // volumeGroup.get(), // decayGroup.get(), // diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java index cb18bb543..9e29e107a 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java @@ -20,7 +20,14 @@ protected TestPolygon( PolygonIdentifier polygonIdentifier, Optional percentAvailable, String fiz, BecDefinition becIdentifier, Optional mode ) { - super(polygonIdentifier, percentAvailable, fiz, becIdentifier, mode); + super(polygonIdentifier, percentAvailable, fiz, becIdentifier, mode, Optional.empty()); + } + + protected TestPolygon( + PolygonIdentifier polygonIdentifier, Optional percentAvailable, String fiz, + BecDefinition becIdentifier, Optional mode, Optional inventoryTypeGroup + ) { + super(polygonIdentifier, percentAvailable, fiz, becIdentifier, mode, inventoryTypeGroup); } public static class Builder extends @@ -39,11 +46,9 @@ protected TestPolygon doBuild() { percentAvailable.flatMap(x -> x), // forestInventoryZone.get(), // biogeoclimaticZone.get(), // - mode // + mode, // + inventoryTypeGroup )); - } - } - } \ No newline at end of file diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java index a7a817558..d14eefcd2 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java @@ -19,6 +19,8 @@ import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java index 9c7f1ecaa..b1b483fa1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java @@ -19,10 +19,10 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseLineException; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseValidException; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.test.TestUtils; public class GenusDefinitionParserTest { diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java index 13076c984..ea2bb407d 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveParserTest.java @@ -14,10 +14,10 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseValidException; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.test.TestUtils; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java index 08c490b14..08ec03cd1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperCoefficientParserTest.java @@ -13,9 +13,9 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseLineException; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.test.TestUtils; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java index b40c33e74..cd0cc36a2 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java @@ -28,13 +28,13 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMapTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMapTest.java index 1c5e152f4..105336037 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMapTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/GenusDefinitionMapTest.java @@ -13,7 +13,6 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.test.TestUtils; diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java index b28dd997e..78b1a04fb 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java @@ -34,7 +34,6 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.BecDefinitionParser; import ca.bc.gov.nrs.vdyp.io.parse.coe.BreakageParser; @@ -57,6 +56,7 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index deefac920..448a49149 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -420,7 +420,7 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, final float maxHeightMultiplier = fipLayer.getPrimaryGenus() .orElseThrow(() -> new IllegalStateException("primaryGenus has not been set")) .equals(spec.getGenus()) ? 1.5f : 1.0f; - final float heightMax = limits.maxLoreyHeight() * maxHeightMultiplier; + final float heightMax = limits.loreyHeightMaximum() * maxHeightMultiplier; spec.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.ALL, x -> min(x, heightMax)); } @@ -467,10 +467,10 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, // EMP061 var limits = estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - var dqMin = limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getAll(); + var dqMin = limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll(); var dqMax = max( - limits.maxQuadMeanDiameter(), - limits.maxDiameterHeight() * spec.getLoreyHeightByUtilization().getAll() + limits.maxQuadMeanDiameterLoreyHeightRatio(), + limits.maxQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll() ); // EMP060 @@ -548,8 +548,8 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, for (var spec : result.getSpecies().values()) { // EMP090 var wholeStemVolume = spec.getTreesPerHectareByUtilization().getAll() - * EstimationMethods.estimateWholeStemVolumePerTree( - controlMap, spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getAll(), + * estimationMethods.estimateWholeStemVolumePerTree( + spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getAll(), spec.getQuadraticMeanDiameterByUtilization().getAll() ); spec.getWholeStemVolumeByUtilization().setAll(wholeStemVolume); @@ -730,22 +730,22 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit var adjust = new Coefficients(new float[] { 0f, 0f, 0f, 0f }, 1); // EMP091 - EstimationMethods.estimateWholeStemVolume( - controlMap, utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, + estimationMethods.estimateWholeStemVolume( + 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, + estimationMethods.estimateCloseUtilizationVolume( + utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil ); adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); // EMP093 - EstimationMethods.estimateNetDecayVolume( - controlMap, vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, + estimationMethods.estimateNetDecayVolume( + vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, vdypSpecies.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil ); @@ -766,8 +766,8 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit if (getId().isStart()) { // EMP095 - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, + estimationMethods.estimateNetDecayWasteAndBreakageVolume( + utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java.orig b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java.orig deleted file mode 100644 index 92d20c230..000000000 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java.orig +++ /dev/null @@ -1,2048 +0,0 @@ -package ca.bc.gov.nrs.vdyp.fip; - -import static ca.bc.gov.nrs.vdyp.math.FloatMath.abs; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.clamp; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.exp; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.log; -import static ca.bc.gov.nrs.vdyp.math.FloatMath.pow; -<<<<<<< HEAD -======= -import static ca.bc.gov.nrs.vdyp.math.FloatMath.sqrt; ->>>>>>> origin/feature/VDYP-362-compatibility-variables -import static java.lang.Math.max; -import static java.lang.Math.min; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.EnumMap; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.ToDoubleFunction; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import org.apache.commons.math3.analysis.MultivariateMatrixFunction; -import org.apache.commons.math3.analysis.MultivariateVectorFunction; -import org.apache.commons.math3.fitting.leastsquares.LeastSquaresFactory; -import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem; -import org.apache.commons.math3.fitting.leastsquares.LevenbergMarquardtOptimizer; -import org.apache.commons.math3.linear.DiagonalMatrix; -import org.apache.commons.math3.linear.RealMatrix; -import org.apache.commons.math3.linear.RealVector; -import org.apache.commons.math3.util.FastMath; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import ca.bc.gov.nrs.vdyp.application.LowValueException; -import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.application.StandProcessingException; -import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; -import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; -import ca.bc.gov.nrs.vdyp.common.ControlKey; -<<<<<<< HEAD -======= -import ca.bc.gov.nrs.vdyp.common.EstimationMethods; -import ca.bc.gov.nrs.vdyp.common.IndexedFloatBinaryOperator; -import ca.bc.gov.nrs.vdyp.common.ReconcilationMethods; ->>>>>>> origin/feature/VDYP-362-compatibility-variables -import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; -import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.fip.model.FipLayer; -import ca.bc.gov.nrs.vdyp.fip.model.FipLayerPrimary; -import ca.bc.gov.nrs.vdyp.fip.model.FipPolygon; -import ca.bc.gov.nrs.vdyp.fip.model.FipSite; -import ca.bc.gov.nrs.vdyp.fip.model.FipSpecies; -import ca.bc.gov.nrs.vdyp.io.parse.coe.BecDefinitionParser; -<<<<<<< HEAD -======= -import ca.bc.gov.nrs.vdyp.io.parse.coe.GenusDefinitionParser; ->>>>>>> origin/feature/VDYP-362-compatibility-variables -import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.io.parse.control.BaseControlParser; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; -import ca.bc.gov.nrs.vdyp.model.BaseVdypLayer; -import ca.bc.gov.nrs.vdyp.model.BaseVdypPolygon; -import ca.bc.gov.nrs.vdyp.model.BaseVdypSite; -import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; -import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.Coefficients; -<<<<<<< HEAD -import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; -import ca.bc.gov.nrs.vdyp.model.PolygonMode; -import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.MatrixMap; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; -======= -import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.MatrixMap; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; -import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; -import ca.bc.gov.nrs.vdyp.model.PolygonMode; ->>>>>>> origin/feature/VDYP-362-compatibility-variables -import ca.bc.gov.nrs.vdyp.model.Region; -import ca.bc.gov.nrs.vdyp.model.StockingClassFactor; -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.VdypSpecies; -import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; -import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; - -public class FipStart extends VdypStartApplication { - - public static final Comparator PERCENT_GENUS_DESCENDING = Utils - .compareUsing(FipSpecies::getPercentGenus).reversed(); - - public static final Logger log = LoggerFactory.getLogger(FipStart.class); -<<<<<<< HEAD -======= - - public static final int UTIL_ALL = UtilizationClass.ALL.index; - public static final int UTIL_LARGEST = UtilizationClass.OVER225.index; - public static final int UTIL_SMALL = UtilizationClass.SMALL.index; ->>>>>>> origin/feature/VDYP-362-compatibility-variables - - public static final float TOLERANCE = 2.0e-3f; - - public static void main(final String... args) throws IOException { - - try (var app = new FipStart();) { - doMain(app, args); - } - } - - // FIP_SUB - // TODO Fortran takes a vector of flags (FIPPASS) controlling which stages are - // implemented. FIPSTART always uses the same vector so far now that's not - // implemented. - @Override - public void process() throws ProcessingException { - int polygonsRead = 0; - int polygonsWritten = 0; - try ( - var polyStream = this.getStreamingParser(ControlKey.FIP_INPUT_YIELD_POLY); - var layerStream = this.>getStreamingParser(ControlKey.FIP_INPUT_YIELD_LAYER); - var speciesStream = this.>getStreamingParser(ControlKey.FIP_INPUT_YIELD_LX_SP0); - ) { - log.atDebug().setMessage("Start Stand processing").log(); - - while (polyStream.hasNext()) { - - // FIP_GET - log.atInfo().setMessage("Getting polygon {}").addArgument(polygonsRead + 1).log(); - var polygon = getPolygon(polyStream, layerStream, speciesStream); - try { - - var resultPoly = processPolygon(polygonsRead, polygon); - if (resultPoly.isPresent()) { - polygonsRead++; - - // Output - vriWriter.writePolygonWithSpeciesAndUtilization(resultPoly.get()); - - polygonsWritten++; - } - - log.atInfo().setMessage("Read {} polygons and wrote {}").addArgument(polygonsRead) - .addArgument(polygonsWritten); - - } catch (StandProcessingException ex) { - // TODO include some sort of hook for different forms of user output - // TODO Implement single stand mode that propagates the exception - - log.atWarn().setMessage("Polygon {} bypassed").addArgument(polygon.getPolygonIdentifier()) - .setCause(ex); - } - - } - } catch (IOException | ResourceParseException ex) { - throw new ProcessingException("Error while reading or writing data.", ex); - } - } - - static final EnumSet ACCEPTABLE_MODES = EnumSet.of(PolygonMode.START, PolygonMode.YOUNG); - - Optional processPolygon(int polygonsRead, FipPolygon polygon) - throws ProcessingException, LowValueException { - VdypPolygon resultPoly; - log.atInfo().setMessage("Read polygon {}, preparing to process").addArgument(polygon.getPolygonIdentifier()) - .log(); - - // if (MODE .eq. -1) go to 100 - - final var mode = polygon.getMode().orElse(PolygonMode.START); - - if (!ACCEPTABLE_MODES.contains(mode)) { - log.atInfo().setMessage("Skipping polygon with mode {}").addArgument(mode).log(); - return Optional.empty(); - } - - // IP_IN = IP_IN+1 - // if (IP_IN .gt. MAXPOLY) go to 200 - - // IPASS = 1 - // CALL FIP_CHK( IPASS, IER) - // if (ier .gt. 0) go to 1000 - // - // if (IPASS .le. 0) GO TO 120 - - log.atInfo().setMessage("Checking validity of polygon {}:{}").addArgument(polygonsRead) - .addArgument(polygon.getPolygonIdentifier()).log(); - checkPolygon(polygon); - - // CALL FIPCALCV( BAV, IER) - // CALL FIPCALC1( BAV, BA_TOTL1, IER) - - Map processedLayers = new EnumMap<>(LayerType.class); - - var fipLayers = polygon.getLayers(); - var fipVetLayer = Optional.ofNullable(fipLayers.get(LayerType.VETERAN)); - Optional resultVetLayer; - if (fipVetLayer.isPresent()) { - resultVetLayer = Optional.of(processLayerAsVeteran(polygon, fipVetLayer.get())); - } else { - resultVetLayer = Optional.empty(); - } - resultVetLayer.ifPresent(layer -> processedLayers.put(LayerType.VETERAN, layer)); - - FipLayerPrimary fipPrimeLayer = (FipLayerPrimary) fipLayers.get(LayerType.PRIMARY); - assert fipPrimeLayer != null; - var resultPrimeLayer = processLayerAsPrimary( - polygon, fipPrimeLayer, - resultVetLayer.map(VdypLayer::getBaseAreaByUtilization).map(coe -> coe.getCoe(UTIL_ALL)).orElse(0f) - ); - processedLayers.put(LayerType.PRIMARY, resultPrimeLayer); - - resultPoly = createVdypPolygon(polygon, processedLayers); - - float baseAreaTotalPrime = resultPrimeLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL); // BA_TOTL1 - - // if (FIPPASS(6) .eq. 0 .or. FIPPASS(6) .eq. 2) then - if (true /* TODO */) { - var minima = Utils.>expectParsedControl(controlMap, ControlKey.MINIMA, Map.class); - - float minimumBaseArea = minima.get(BaseControlParser.MINIMUM_BASE_AREA); - float minimumPredictedBaseArea = minima.get(BaseControlParser.MINIMUM_FULLY_STOCKED_AREA); - if (baseAreaTotalPrime < minimumBaseArea) { - throw new LowValueException("Base area", baseAreaTotalPrime, minimumBaseArea); - } - float predictedBaseArea = baseAreaTotalPrime * (100f / resultPoly.getPercentAvailable()); - if (predictedBaseArea < minimumPredictedBaseArea) { - throw new LowValueException("Predicted base area", predictedBaseArea, minimumPredictedBaseArea); - } - } - BecDefinition bec = BecDefinitionParser.getBecs(controlMap).get(polygon.getBiogeoclimaticZone()) - .orElseThrow(() -> new ProcessingException("Missing Bec " + polygon.getBiogeoclimaticZone())); - // FIPSTK - adjustForStocking(resultPoly.getLayers().get(LayerType.PRIMARY), fipPrimeLayer, bec); - return Optional.of(resultPoly); - } - - // FIPSTK - void adjustForStocking(VdypLayer vdypLayer, FipLayerPrimary fipLayerPrimary, BecDefinition bec) { - - MatrixMap2> stockingClassMap = Utils - .expectParsedControl(controlMap, ControlKey.STOCKING_CLASS_FACTORS, MatrixMap2.class); - - Region region = bec.getRegion(); - - var factorEntry = fipLayerPrimary.getStockingClass() - .flatMap(stockingClass -> MatrixMap.safeGet(stockingClassMap, stockingClass, region)); - - if (!factorEntry.isPresent()) { - return; - } - - float factor = factorEntry.get().getFactor(); - - scaleAllSummableUtilization(vdypLayer, factor); - vdypLayer.getSpecies().values().forEach(spec -> scaleAllSummableUtilization(spec, factor)); - - log.atInfo().addArgument(fipLayerPrimary.getStockingClass()).addArgument(factor).setMessage( - "Foregoing Primary Layer has stocking class {} Yield values will be multiplied by {} before being written to output file." - ); - } - - VdypPolygon createVdypPolygon(FipPolygon fipPolygon, Map processedLayers) - throws ProcessingException { - Optional fipVetLayer = Utils.optSafe(fipPolygon.getLayers().get(LayerType.VETERAN)); - FipLayerPrimary fipPrimaryLayer = (FipLayerPrimary) fipPolygon.getLayers().get(LayerType.PRIMARY); - - float percentAvailable = estimatePercentForestLand(fipPolygon, fipVetLayer, fipPrimaryLayer); - - var vdypPolygon = VdypPolygon.build(builder -> builder.adapt(fipPolygon, x -> percentAvailable)); - vdypPolygon.setLayers(processedLayers); - return vdypPolygon; - } - - // FIPCALC1 - VdypLayer processLayerAsPrimary(FipPolygon fipPolygon, FipLayerPrimary fipLayer, float baseAreaOverstory) - throws ProcessingException { - - // PRIMFIND - var primarySpecies = findPrimarySpecies(fipLayer.getSpecies().values()); - - // There's always at least one entry and we want the first. - fipLayer.setPrimaryGenus(Optional.of(primarySpecies.iterator().next().getGenus())); - - // VDYP7 stores this in the common FIPL_1C/ITGL1 but only seems to use it - // locally - var itg = findItg(primarySpecies); - - BecDefinition bec = Utils.getBec(fipPolygon.getBiogeoclimaticZone(), controlMap); - - // GRPBA1FD - int empiricalRelationshipParameterIndex = findEmpiricalRelationshipParameterIndex( - primarySpecies.get(0).getGenus(), bec, itg - ); - - var result = VdypLayer.build(builder -> { - builder.adapt(fipLayer); - builder.inventoryTypeGroup(itg); - builder.empiricalRelationshipParameterIndex(empiricalRelationshipParameterIndex); - fipLayer.getSite().ifPresent(site -> { - builder.addSite(siteBuilder -> { - siteBuilder.adapt(site); - }); - }); - - }); - - // EMP040 - var baseArea = estimatePrimaryBaseArea( - fipLayer, bec, fipPolygon.getYieldFactor(), result.getBreastHeightAge().orElse(0f), baseAreaOverstory - ); // BA_TOT - - result.getBaseAreaByUtilization().setCoe(UTIL_ALL, baseArea); - - var quadMeanDiameter = estimatePrimaryQuadMeanDiameter( - fipLayer, bec, result.getBreastHeightAge().orElse(0f), baseAreaOverstory - ); - - result.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_ALL, quadMeanDiameter); - - var tphTotal = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea, quadMeanDiameter); - - result.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, tphTotal); - - // Copy over Species entries. - // LVCOM/ISPL1=ISPV - // LVCOM4/SP0L1=FIPSA/SP0V - // LVCOM4/SP64DISTL1=FIPSA/VDISTRV - // LVCOM1/PCLT1=FIPS/PCTVOLV - var vdypSpecies = fipLayer.getSpecies().values().stream() // - .map(VdypSpecies::new) // - .collect(Collectors.toMap(VdypSpecies::getGenus, Function.identity())); - - var vdypPrimarySpecies = vdypSpecies.get(primarySpecies.get(0).getGenus()); - - Map targetPercentages = applyGroups(fipPolygon, vdypSpecies.values()); - - var maxPass = fipLayer.getSpecies().size() > 1 ? 2 : 1; - - result.setSpecies(vdypSpecies); - - float primaryHeight; - float leadHeight = fipLayer.getHeight().orElse(0f); - for (var iPass = 1; iPass <= maxPass; iPass++) { - if (iPass == 2) { - for (var vSpec : vdypSpecies.values()) { - vSpec.setPercentGenus(targetPercentages.get(vSpec.getGenus())); - } - } - // Estimate lorey height for primary species - if (iPass == 1 && vdypSpecies.size() == 1) { - primaryHeight = emp.primaryHeightFromLeadHeight( - leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), tphTotal - ); - } else if (iPass == 1) { - primaryHeight = emp - .primaryHeightFromLeadHeightInitial(leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion()); - } else { - primaryHeight = emp.primaryHeightFromLeadHeight( - leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), - vdypPrimarySpecies.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - ); - } - vdypPrimarySpecies.getLoreyHeightByUtilization().setCoe(UTIL_ALL, primaryHeight); - - // Estimate lorey height for non-primary species - for (var vspec : vdypSpecies.values()) { - if (vspec == vdypPrimarySpecies) - continue; - - // EMP053 - vspec.getLoreyHeightByUtilization().setCoe( - UTIL_ALL, - emp.estimateNonPrimaryLoreyHeight(vspec, vdypPrimarySpecies, bec, leadHeight, primaryHeight) - ); - } - - // ROOTF01 - findRootsForDiameterAndBaseArea(result, fipLayer, bec, iPass + 1); - } - - estimateSmallComponents(fipPolygon, result); - - // YUC1 - computeUtilizationComponentsPrimary(bec, result, VolumeComputeMode.BY_UTIL, CompatibilityVariableMode.NONE); - - return result; - } - - public static List utilizationArray(VdypLayer layer, Function accessor) { - return Stream.concat(Stream.of(layer), layer.getSpecies().values().stream()).map(accessor).toList(); - } - - // ROOTF01 - void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, BecDefinition bec, int source) - throws ProcessingException { - - var quadMeanDiameterTotal = result.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL); // DQ_TOT - var baseAreaTotal = result.getBaseAreaByUtilization().getCoe(UTIL_ALL); // BA_TOT - var treesPerHectareTotal = result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL); // TPH_TOT - Map goal = new LinkedHashMap<>(); // GOAL - Map xMap = new LinkedHashMap<>(); // X - - float treesPerHectareSum; - - assert result.getSpecies().size() > 0; - - if (result.getSpecies().size() == 1) { - var spec = result.getSpecies().values().iterator().next(); - for (var accessors : NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS) { - - try { - Coefficients specVector = (Coefficients) accessors.getReadMethod().invoke(spec); - Coefficients layerVector = (Coefficients) accessors.getReadMethod().invoke(result); - specVector.setCoe(UTIL_ALL, layerVector.getCoe(UTIL_ALL)); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - throw new IllegalStateException(e); - } - } - - result.getLoreyHeightByUtilization().setCoe(UTIL_ALL, spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL)); - spec.setPercentGenus(100f); - treesPerHectareSum = treesPerHectareTotal; - } else { - // Multiple Species - for (var spec : result.getSpecies().values()) { - - var limits = emp.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - - final float maxHeightMultiplier = fipLayer.getPrimaryGenus() - .orElseThrow(() -> new IllegalStateException("primaryGenus has not been set")) - .equals(spec.getGenus()) ? 1.5f : 1.0f; - final float heightMax = limits.maxLoreyHeight() * maxHeightMultiplier; - - spec.getLoreyHeightByUtilization().scalarInPlace(UTIL_ALL, x -> min(x, heightMax)); - } - ToDoubleFunction accessor; - - switch (source) { - case 1: - accessor = x -> x.getPercentGenus(); - break; - case 2: - accessor = x -> x.getPercentGenus() / x.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - break; - case 3: - accessor = x -> x.getBaseAreaByUtilization().getCoe(UTIL_ALL); - break; - default: - throw new UnsupportedOperationException("Unknown source for root finding " + source); - } - - var sumSourceArea = result.getSpecies().values().stream().mapToDouble(accessor).sum(); - - // FRJ - var fractionMap = result.getSpecies().values().stream().collect( - Collectors.toMap( - VdypSpecies::getGenus, spec -> (float) (accessor.applyAsDouble(spec) / sumSourceArea) - ) - ); - - // HL_TOT - float loreyHeightTotal = (float) fractionMap.entrySet().stream().mapToDouble( - e -> e.getValue() * result.getSpecies().get(e.getKey()).getLoreyHeightByUtilization().getCoe(0) - ).sum(); - // FRJ(ISP) = FRJ(J) // We aren't using the remapping between global species - // index and index for the species within the layer, so we can probably assign - // directly to the fraction attribute on the species object. - fractionMap.entrySet().forEach(e -> result.getSpecies().get(e.getKey()).setFractionGenus(e.getValue())); - - double[] quadMeanDiameterBase = new double[result.getSpecies().size()]; // DQspbase - - { - int i = 0; - for (var spec : result.getSpecies().values()) { - - // EMP061 - var limits = emp.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - - var dqMin = limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - var dqMax = max( - limits.maxQuadMeanDiameter(), - limits.maxDiameterHeight() * spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) - ); - - // EMP060 - float quadMeanDiameter = clamp( - emp.estimateQuadMeanDiameterForSpecies( - spec, result.getSpecies(), bec.getRegion(), quadMeanDiameterTotal, baseAreaTotal, - treesPerHectareTotal, loreyHeightTotal - ), // - dqMin, dqMax - ); - - quadMeanDiameterBase[i++] = quadMeanDiameter; - } - } - // VDYP7 checks the number of species here, but this is already inside a branch - // that must be more than 1 - // Fill in target and trial values - - Utils.eachButLast(result.getSpecies().values(), spec -> { - goal.put(spec.getGenus(), spec.getPercentGenus()); - xMap.put(spec.getGenus(), spec.getPercentGenus()); - }, spec -> { - goal.put(spec.getGenus(), quadMeanDiameterTotal); - xMap.put(spec.getGenus(), 0f); - }); - - var xVec = xMap.values().stream().mapToDouble(v -> (double) v).toArray(); - var goalVec = goal.values().stream().mapToDouble(v -> (double) v).toArray(); - - // SNQSOL - var rootVec = this.findRoot(quadMeanDiameterBase, goalVec, xVec, result, TOLERANCE); - - var rootMap = new LinkedHashMap(); - { - float percentSum = 0; - var it = result.getSpecies().values().iterator(); - for (int i = 0; it.hasNext(); i++) { - var spec = it.next(); - rootMap.put(spec.getGenus(), (float) rootVec.getEntry(i)); - if (it.hasNext()) { - spec.setPercentGenus((float) rootVec.getEntry(i)); - percentSum += rootVec.getEntry(i); - } else { - spec.setPercentGenus(100 - percentSum); - } - } - } - - float loreyHeightSum = 0; - treesPerHectareSum = 0; - - { - int i = 0; - for (var spec : result.getSpecies().values()) { - float dqBase = (float) quadMeanDiameterBase[i++]; - float dq = 7.5f + (dqBase - 7.5f) * exp((float) rootVec.getEntry(rootVec.getDimension() - 1) / 20f); - assert dq >= 0; - float ba = baseAreaTotal * spec.getPercentGenus() / 100f; - assert ba >= 0; - float tph = BaseAreaTreeDensityDiameter.treesPerHectare(ba, dq); - assert tph >= 0; - spec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_ALL, dq); - spec.getBaseAreaByUtilization().setCoe(UTIL_ALL, ba); - spec.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, tph); - treesPerHectareSum += tph; - loreyHeightSum += spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) * ba; - } - } - result.getLoreyHeightByUtilization().setCoe(UTIL_ALL, loreyHeightSum / baseAreaTotal); - - } // end of Multiple Species branch - - var volumeSum = 0f; - - for (var spec : result.getSpecies().values()) { - // EMP090 - var wholeStemVolume = spec.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - * EstimationMethods.estimateWholeStemVolumePerTree( - controlMap, spec.getVolumeGroup(), spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL), - spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL) - ); - spec.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, wholeStemVolume); - volumeSum += wholeStemVolume; - } - - result.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, volumeSum); - var treesPerHectareStart = result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL); - result.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, treesPerHectareSum); - result.getQuadraticMeanDiameterByUtilization().setCoe( - UTIL_ALL, - BaseAreaTreeDensityDiameter.quadMeanDiameter( - result.getBaseAreaByUtilization().getCoe(UTIL_ALL), - result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - ) - ); - - if (abs(treesPerHectareStart / result.getTreesPerHectareByUtilization().getCoe(UTIL_ALL) - 1f) > 0.002) { - throw new ProcessingException("TODO"); - } - - if (result.getSpecies().size() > 1) { - for (var spec : result.getSpecies().values()) { - if (spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL) / volumeSum - - goal.get(spec.getGenus()) > 0.1) { - throw new ProcessingException("TODO"); - } - } - } - } - -<<<<<<< HEAD - // EMP090 - private float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class - ); - var coe = coeMap.get(volumeGroup).reindex(0); - - var logMeanVolume = coe.getCoe(UTIL_ALL) + // - coe.getCoe(1) * log(quadMeanDiameter) + // - coe.getCoe(2) * log(loreyHeight) + // - coe.getCoe(3) * quadMeanDiameter + // - coe.getCoe(4) / quadMeanDiameter + // - coe.getCoe(5) * loreyHeight + // - coe.getCoe(6) * quadMeanDiameter * quadMeanDiameter + // - coe.getCoe(7) * loreyHeight * quadMeanDiameter // - + coe.getCoe(8) * loreyHeight / quadMeanDiameter; - - return exp(logMeanVolume); -======= - // EMP060 - /** - * Estimate DQ for a species (primary or not). Using eqn in jf125.doc. - * - * Enforces mins and maxes from EMP061. - * - * @param spec Species of insterest - * @param allSpecies Collection of all species on the layer - * @param region BEC Region of the stand - * @param standQuadMeanDiameter Quadratic mean diameter of the stand - * @param standBaseArea Base area of the stand - * @param standTreesPerHectare Density opf the stand - * @param standLoreyHeight Lorey height of the stand - * @return Quadratic mean diameter of the species of interest - * @throws ProcessingException - */ - float estimateQuadMeanDiameterForSpecies( - VdypSpecies spec, // ISP, HLsp, DQsp - Map allSpecies, // FR - Region region, // INDEX_IC - float standQuadMeanDiameter, // DQ_TOT - float standBaseArea, // BA_TOT - float standTreesPerHectare, // TPH_TOT - float standLoreyHeight // HL_TOT - ) throws ProcessingException { - String species = spec.getGenus(); - - float c = 0.00441786467f; - - float minQuadMeanDiameter = min(7.6f, standQuadMeanDiameter); - - // Quick solution - if (spec.getFractionGenus() >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { - return standQuadMeanDiameter; - } - - var coeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BY_SPECIES_DQ, Map.class); - var specAliases = GenusDefinitionParser.getSpeciesAliases(controlMap); - - // TODO we can probably remove these as they seem to only be used for debugging - // in VDYP7 - Map adjust = new HashMap<>(coeMap.size()); - Map mult = new HashMap<>(coeMap.size()); - - var specIt = specAliases.iterator(); - - var spec1 = specIt.next(); - - float a2 = coeMap.get(spec1).getCoe(2); - - float fractionOther = 1f - spec.getFractionGenus(); // FR_REST - - mult.put(spec1, 1f); - float a0 = coeMap.get(spec1).getCoe(0); - float a1 = coeMap.get(spec1).getCoe(1); - - while (specIt.hasNext()) { - var specIAlias = specIt.next(); - var specI = allSpecies.get(specIAlias); - if (specIAlias.equals(spec.getGenus())) { - float multI = 1f; - mult.put(specIAlias, multI); - a0 += multI * coeMap.get(specIAlias).getCoe(0); - a1 += multI * coeMap.get(specIAlias).getCoe(1); - } else { - if (specI != null && specI.getFractionGenus() > 0f) { - float multI = -specI.getFractionGenus() / fractionOther; - mult.put(specIAlias, multI); - a0 += multI * coeMap.get(specIAlias).getCoe(0); - a1 -= multI * coeMap.get(specIAlias).getCoe(1); - } - } - } - - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - float loreyHeight1 = max(4f, loreyHeightSpec); - float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spec.getFractionGenus()) / fractionOther; - float loreyHeightRatio = clamp( (loreyHeight1 - 3f) / (loreyHeight2 - 3f), 0.05f, 20f); - - float r = exp( - a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) + adjust.getOrDefault(species, 0f) - ); - - float baseArea1 = spec.getFractionGenus() * standBaseArea; - float baseArea2 = standBaseArea - baseArea1; - - float treesPerHectare1; - if (abs(r - 1f) < 0.0005) { - treesPerHectare1 = spec.getFractionGenus() * standTreesPerHectare; - } else { - float aa = (r - 1f) * c; - float bb = c * (1f - r) * standTreesPerHectare + baseArea1 + baseArea2 * r; - float cc = -baseArea1 * standTreesPerHectare; - float term = bb * bb - 4 * aa * cc; - if (term <= 0f) { - throw new ProcessingException( - "Term for trees per hectare calculation when estimating quadratic mean diameter for species " - + species + " was " + term + " but should be positive." - ); - } - treesPerHectare1 = (-bb + sqrt(term)) / (2f * aa); - if (treesPerHectare1 <= 0f || treesPerHectare1 > standTreesPerHectare) { - throw new ProcessingException( - "Trees per hectare 1 for species " + species + " was " + treesPerHectare1 - + " but should be positive and less than or equal to stand trees per hectare " - + standTreesPerHectare - ); - } - } - - float quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); - float treesPerHectare2 = standTreesPerHectare - treesPerHectare1; - float quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - - if (quadMeanDiameter2 < minQuadMeanDiameter) { - // species 2 is too small. Make target species smaller. - quadMeanDiameter2 = minQuadMeanDiameter; - treesPerHectare2 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea2, quadMeanDiameter2); - treesPerHectare1 = standTreesPerHectare - treesPerHectare2; - quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); - } - var limitCoe = getLimitsForHeightAndDiameter(species, region); - - final var dqMinSp = max(minQuadMeanDiameter, limitCoe.getCoe(3) * loreyHeightSpec); - final var dqMaxSp = max(7.6f, min(limitCoe.getCoe(2), limitCoe.getCoe(4) * loreyHeightSpec)); - if (quadMeanDiameter1 < dqMinSp) { - quadMeanDiameter1 = dqMinSp; - treesPerHectare1 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea1, quadMeanDiameter1); - treesPerHectare2 = standTreesPerHectare - treesPerHectare2; - quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - } - if (quadMeanDiameter1 > dqMaxSp) { - // target species is too big. Make target species smaller, DQ2 bigger. - - quadMeanDiameter1 = dqMaxSp; - treesPerHectare1 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea1, quadMeanDiameter1); - treesPerHectare2 = standTreesPerHectare - treesPerHectare2; - - if (treesPerHectare2 > 0f && baseArea2 > 0f) { - quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - } else { - quadMeanDiameter2 = 1000f; - } - - // under rare circumstances, let DQ1 exceed DQMAXsp - if (quadMeanDiameter2 < minQuadMeanDiameter) { - quadMeanDiameter2 = minQuadMeanDiameter; - treesPerHectare2 = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea2, quadMeanDiameter2); - treesPerHectare1 = standTreesPerHectare - treesPerHectare2; - quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); - } - - } - return quadMeanDiameter1; - } - - // EMP061 - private Coefficients getLimitsForHeightAndDiameter(String genus, Region region) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class - ); - - return coeMap.get(genus, region); - } - - // EMP053 Using eqns N1 and N2 from ipsjf124.doc - /** - * Estimate the lorey height of a non-primary species of a primary layer. - * - * @param vspec The species. - * @param vspecPrime The primary species. - * @param leadHeight lead height of the layer - * @param primaryHeight height of the primary species - * @throws ProcessingException - */ - float estimateNonPrimaryLoreyHeight( - VdypSpecies vspec, VdypSpecies vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight - ) throws ProcessingException { - var coeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.HL_NONPRIMARY, MatrixMap3.class - ); - - var coe = coeMap.get(vspec.getGenus(), vspecPrime.getGenus(), bec.getRegion()).orElseThrow( - () -> new ProcessingException( - String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec.getGenus(), - vspecPrime.getGenus(), bec.getRegion() - ) - ) - ); - var heightToUse = coe.getEquationIndex() == 1 ? leadHeight : primaryHeight; - return 1.3f + coe.getCoe(1) * pow(heightToUse - 1.3f, coe.getCoe(2)); ->>>>>>> origin/feature/VDYP-362-compatibility-variables - } - - VdypLayer processLayerAsVeteran(FipPolygon fipPolygon, FipLayer fipLayer) throws ProcessingException { - - var polygonIdentifier = fipLayer.getPolygonIdentifier(); - - assert fipLayer.getLayerType().equals(LayerType.VETERAN) : "Layer must be VETERAN"; - assert fipPolygon.getPolygonIdentifier().equals(fipLayer.getPolygonIdentifier()) : String.format( - "Polygon polygonIdentifier '%s' doesn't match that of layer '%s'", fipPolygon.getPolygonIdentifier(), - fipLayer.getPolygonIdentifier() - ); - - var layer = LayerType.VETERAN; - - // find Primary genus (highest percentage) ISPPVET - - var primaryGenus = fipLayer.getSpecies().values().stream() // - .max(Utils.compareUsing(FipSpecies::getPercentGenus)) // - .orElseThrow(() -> new IllegalStateException("No primarty genus (SP0) found. This should not happen.")) - .getGenus(); - - // ageTotal copy, LVCOM3/AGETOTLV copied from FIPL_V/AGETOT_LV - var ageTotal = fipLayer.getAgeTotal().orElse(0f); - - // yearsToBreastHeight copy, minimum 6.0, LVCOM3/YTBHLV copied from - // FIPL_V/YTBH_L - var yearsToBreastHeight = Math.max(fipLayer.getYearsToBreastHeight().orElse(0f), 6.0f); - - // height? copy LVCOM3/HDLV = FIPL_V/HT_LV - var height = fipLayer.getHeight().orElse(0f); - - var crownClosure = fipLayer.getCrownClosure(); - - var becId = fipPolygon.getBiogeoclimaticZone(); - var bec = Utils.getBec(becId, controlMap); - var region = bec.getRegion(); - - // Call EMP098 to get Veteran Basal Area, store in LVCOM1/BA array at positions - // 0,0 and 0,4 - var estimatedBaseArea = estimateVeteranBaseArea(height, crownClosure, primaryGenus, region); - var baseAreaByUtilization = Utils.utilizationVector(estimatedBaseArea); - // Copy over Species entries. - // LVCOM/ISPLV=ISPV - // LVCOM4/SP0LV=FIPSA/SP0V - // LVCOM4/SP64DISTLV=FIPSA/VDISTRV - // LVCOM1/PCLTV=FIPS/PCTVOLV - // LVCOM1/HL=FIPL_V/HT_LV - var vdypSpecies = fipLayer.getSpecies().values().stream() // - .map(fipSpec -> { - var vs = new VdypSpecies(fipSpec); - vs.setLoreyHeightByUtilization(new Coefficients(new float[] { 0f, height }, -1)); - return vs; - }) // - .collect(Collectors.toMap(VdypSpecies::getGenus, Function.identity())); - - applyGroups(fipPolygon, vdypSpecies.values()); - - /* - * From VDYP7 - * - * At this point we SHOULD invoke a root finding procedure sets species percents and adjusts DQ by species. - * fills in main components, through whole-stem volume INSTEAD, I will assume %volumes apply to % BA's - */ - - for (var vSpec : vdypSpecies.values()) { - vSpec.getBaseAreaByUtilization() - .setCoe(UTIL_LARGEST, baseAreaByUtilization.getCoe(UTIL_LARGEST) * vSpec.getPercentGenus() / 100f); - } - - var vetDqMap = Utils.>expectParsedControl( - controlMap, ControlKey.VETERAN_LAYER_DQ, MatrixMap2.class - ); - - for (var vSpec : vdypSpecies.values()) { - var genus = vSpec.getGenus(); - var coe = vetDqMap.get(genus, region); - var a0 = coe.getCoe(1); - var a1 = coe.getCoe(2); - var a2 = coe.getCoe(3); - float hl = vSpec.getLoreyHeightByUtilization().getCoe(0); - float dq = max(a0 + a1 * pow(hl, a2), 22.5f); - vSpec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_LARGEST, dq); - vSpec.getTreesPerHectareByUtilization().setCoe( - UTIL_LARGEST, - BaseAreaTreeDensityDiameter - .treesPerHectare(vSpec.getBaseAreaByUtilization().getCoe(UTIL_LARGEST), dq) - ); - } - - var vdypLayer = VdypLayer.build(builder -> { - builder.polygonIdentifier(polygonIdentifier); - builder.layerType(layer); - - builder.addSite(siteBuilder -> { - siteBuilder.ageTotal(ageTotal); - siteBuilder.yearsToBreastHeight(yearsToBreastHeight); - siteBuilder.height(height); - siteBuilder.siteGenus(fipLayer.getSiteGenus()); - siteBuilder.siteIndex(fipLayer.getSiteIndex()); - }); - - builder.addSpecies(vdypSpecies.values()); - }); - - vdypLayer.setBaseAreaByUtilization(baseAreaByUtilization); - - computeUtilizationComponentsVeteran(vdypLayer, bec); - - return vdypLayer; - } - -<<<<<<< HEAD -======= - enum VolumeComputeMode { - /** - * set volume components to zero - */ - ZERO, // 0 - /** - * compute volumes by utilization component - */ - BY_UTIL, // 1 - /** - * As BY_UTIL but also compute Whole Stem Volume for every species - */ - BY_UTIL_WITH_WHOLE_STEM_BY_SPEC // 2 - } - - enum CompatibilityVariableMode { - /** - * Don't apply compatibility variables - */ - NONE, // 0 - /** - * Apply compatibility variables to all but volume - */ - NO_VOLUME, // 1 - /** - * Apply compatibility variables to all components - */ - ALL // 2 - } - - // YUC1 - void computeUtilizationComponentsPrimary( - BecDefinition bec, VdypLayer vdypLayer, VolumeComputeMode volumeComputeMode, - CompatibilityVariableMode compatibilityVariableMode - ) throws ProcessingException { - log.atTrace().setMessage("computeUtilizationComponentsPrimary for {}, stand total age is {}") - .addArgument(vdypLayer.getPolygonIdentifier()).addArgument(vdypLayer.getAgeTotal()).log(); - log.atDebug().setMessage("Primary layer for {} has {} species/genera: {}") - .addArgument(vdypLayer::getPolygonIdentifier) // - .addArgument(() -> vdypLayer.getSpecies().size()) // - .addArgument(() -> vdypLayer.getSpecies().keySet().stream().collect(Collectors.joining(", "))) // - .log(); - - for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - float baseAreaSpec = spec.getBaseAreaByUtilization().getCoe(UTIL_ALL); - float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL); - float treesPerHectareSpec = spec.getTreesPerHectareByUtilization().getCoe(UTIL_ALL); - - log.atDebug().setMessage("Working with species {} LH: {} DQ: {} BA: {} TPH: {}") - .addArgument(spec.getClass()).addArgument(loreyHeightSpec).addArgument(quadMeanDiameterSpec) - .addArgument(baseAreaSpec).addArgument(treesPerHectareSpec); - - if (volumeComputeMode == VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC) { - log.atDebug().log("Estimating tree volume"); - - // EMP090 - throw new UnsupportedOperationException("TODO"); // Not used yet - - // log.atDebug().setMessage("Species WS stand volume {}") - // .addArgument(() -> spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL)); - - } - float wholeStemVolumeSpec = spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL); - - var baseAreaUtil = Utils.utilizationVector(); - var quadMeanDiameterUtil = Utils.utilizationVector(); - var treesPerHectareUtil = Utils.utilizationVector(); - var wholeStemVolumeUtil = Utils.utilizationVector(); - var closeVolumeUtil = Utils.utilizationVector(); - var closeVolumeNetDecayUtil = Utils.utilizationVector(); - var closeVolumeNetDecayWasteUtil = Utils.utilizationVector(); - var closeVolumeNetDecayWasteBreakUtil = Utils.utilizationVector(); - - baseAreaUtil.setCoe(UTIL_ALL, baseAreaSpec); // BAU - quadMeanDiameterUtil.setCoe(UTIL_ALL, quadMeanDiameterSpec); // DQU - treesPerHectareUtil.setCoe(UTIL_ALL, treesPerHectareSpec); // TPHU - wholeStemVolumeUtil.setCoe(UTIL_ALL, wholeStemVolumeSpec); // WSU - - var adjustCloseUtil = Utils.utilizationVector(); // ADJVCU - @SuppressWarnings("unused") - var adjustDecayUtil = Utils.utilizationVector(); // ADJVD - @SuppressWarnings("unused") - var adjustDecayWasteUtil = Utils.utilizationVector(); // ADJVDW - - // EMP071 - EstimationMethods - .estimateQuadMeanDiameterByUtilization(controlMap, bec, quadMeanDiameterUtil, spec.getGenus()); - - // EMP070 - EstimationMethods.estimateBaseAreaByUtilization( - controlMap, bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus() - ); - - // Calculate tree density components - for (var uc : UtilizationClass.UTIL_CLASSES) { - treesPerHectareUtil.setCoe( - uc.index, - BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - ); - } - - // reconcile components with totals - - // YUC1R - ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - - if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { - throw new UnsupportedOperationException("TODO"); - } - - // Recalculate TPH's - - for (var uc : UtilizationClass.UTIL_CLASSES) { - treesPerHectareUtil.setCoe( - uc.index, - BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) - ); - } - - // Since DQ's may have changed, MUST RECONCILE AGAIN - // Seems this might only be needed when compatibilityVariableMode is not NONE? - - // YUC1R - ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - - if (volumeComputeMode == VolumeComputeMode.ZERO) { - throw new UnsupportedOperationException("TODO"); - } else { - - // EMP091 - EstimationMethods.estimateWholeStemVolume( - controlMap, UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), - loreyHeightSpec, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - - if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { - // apply compatibity variables to WS volume - - // Set the adjustment factors for next three volume types - - throw new UnsupportedOperationException("TODO"); - } else { - // Do nothing as the adjustment vectors are already set to 0 - } - - // EMP092 - EstimationMethods.estimateCloseUtilizationVolume( - controlMap, UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, - quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil - ); - - // EMP093 - EstimationMethods.estimateNetDecayVolume( - controlMap, spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, - spec.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, - closeVolumeUtil, closeVolumeNetDecayUtil - ); - - // EMP094 - EstimationMethods.estimateNetDecayAndWasteVolume( - controlMap, bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), - loreyHeightSpec, quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, - closeVolumeNetDecayWasteUtil - ); - - if (getId().isStart()) { - // EMP095 - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, - closeVolumeUtil, closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil - ); - } - } - - spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, COPY_IF_BAND); - spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, COPY_IF_BAND); - spec.getQuadraticMeanDiameterByUtilization().pairwiseInPlace(quadMeanDiameterUtil, COPY_IF_BAND); - - spec.getWholeStemVolumeByUtilization().pairwiseInPlace(wholeStemVolumeUtil, COPY_IF_NOT_TOTAL); - spec.getCloseUtilizationVolumeByUtilization().pairwiseInPlace(closeVolumeUtil, COPY_IF_NOT_TOTAL); - spec.getCloseUtilizationVolumeNetOfDecayByUtilization() - .pairwiseInPlace(closeVolumeNetDecayUtil, COPY_IF_NOT_TOTAL); - spec.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteUtil, COPY_IF_NOT_TOTAL); - spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() - .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, COPY_IF_NOT_TOTAL); - - } - computeLayerUtilizationComponentsFromSpecies(vdypLayer); - - for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - if (vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL) > 0f) { - spec.setFractionGenus( - spec.getBaseAreaByUtilization().getCoe(UTIL_ALL) - / vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL) - ); - } - log.atDebug().addArgument(spec.getGenus()).addArgument(spec.getFractionGenus()) - .setMessage("Species {} base area {}%").log(); - } - - log.atDebug().setMessage("Calculating Stand Lorey Height").log(); - - vdypLayer.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, 0f); - vdypLayer.getLoreyHeightByUtilization().setCoe(UTIL_ALL, 0f); - - for (VdypSpecies spec : vdypLayer.getSpecies().values()) { - log.atDebug() // - .addArgument(spec.getGenus()) // - .addArgument(() -> spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL)) - .addArgument(() -> spec.getBaseAreaByUtilization().getCoe(UTIL_ALL)) - .addArgument( - () -> spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) - * spec.getBaseAreaByUtilization().getCoe(UTIL_ALL) - ) - .setMessage( - "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" - ).log(); - vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UTIL_SMALL, - x -> x + spec.getLoreyHeightByUtilization().getCoe(UTIL_SMALL) - * spec.getBaseAreaByUtilization().getCoe(UTIL_SMALL) - ); - vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UTIL_ALL, - x -> x + spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL) - * spec.getBaseAreaByUtilization().getCoe(UTIL_ALL) - ); - } - { - float baSmall = vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_SMALL); - float baAll = vdypLayer.getBaseAreaByUtilization().getCoe(UTIL_ALL); - - if (baSmall > 0) { - vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UTIL_SMALL, x -> x / baSmall); - } - if (baAll > 0) { - vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UTIL_ALL, x -> x / baAll); - } - - } - - } - - private static final IndexedFloatBinaryOperator COPY_IF_BAND = (oldX, newX, i) -> i <= UTIL_ALL ? oldX : newX; - private static final IndexedFloatBinaryOperator COPY_IF_NOT_TOTAL = (oldX, newX, i) -> i < UTIL_ALL ? oldX : newX; - ->>>>>>> origin/feature/VDYP-362-compatibility-variables - // YUCV - private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinition bec) - throws ProcessingException { - log.trace( - "computeUtilizationComponentsVeterany for {}, stand total age is {}", vdypLayer.getPolygonIdentifier(), - vdypLayer.getAgeTotal() - ); - - var volumeAdjustMap = Utils.>expectParsedControl( - controlMap, ControlKey.VETERAN_LAYER_VOLUME_ADJUST, 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().getCoe(UTIL_ALL); - { - var baSp = vdypSpecies.getBaseAreaByUtilization().getCoe(UTIL_LARGEST); - var tphSp = vdypSpecies.getTreesPerHectareByUtilization().getCoe(UTIL_LARGEST); - var dqSp = vdypSpecies.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_LARGEST); - - treesPerHectareUtil.setCoe(UTIL_ALL, tphSp); - quadMeanDiameterUtil.setCoe(UTIL_ALL, dqSp); - baseAreaUtil.setCoe(UTIL_ALL, baSp); - wholeStemVolumeUtil.setCoe(UTIL_ALL, 0f); - - treesPerHectareUtil.setCoe(UTIL_LARGEST, tphSp); - quadMeanDiameterUtil.setCoe(UTIL_LARGEST, dqSp); - baseAreaUtil.setCoe(UTIL_LARGEST, baSp); - wholeStemVolumeUtil.setCoe(UTIL_LARGEST, 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 -<<<<<<< HEAD - emp.estimateWholeStemVolume( - utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, -======= - EstimationMethods.estimateWholeStemVolume( - controlMap, utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, ->>>>>>> origin/feature/VDYP-362-compatibility-variables - quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - - adjust.setCoe(4, volumeAdjustCoe.getCoe(2)); - // EMP092 -<<<<<<< HEAD - emp.estimateCloseUtilizationVolume( - utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, -======= - EstimationMethods.estimateCloseUtilizationVolume( - controlMap, utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, ->>>>>>> origin/feature/VDYP-362-compatibility-variables - wholeStemVolumeUtil, closeUtilizationVolumeUtil - ); - - adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); - // EMP093 -<<<<<<< HEAD - emp.estimateNetDecayVolume( - vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, vdypSpecies.getDecayGroup(), - hlSp, vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, -======= - EstimationMethods.estimateNetDecayVolume( - controlMap, vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, - vdypSpecies.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, ->>>>>>> origin/feature/VDYP-362-compatibility-variables - closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil - ); - - adjust.setCoe(4, volumeAdjustCoe.getCoe(4)); - // EMP094 -<<<<<<< HEAD - emp.estimateNetDecayAndWasteVolume( - bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, - vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeUtilizationVolumeUtil, -======= - final var netDecayCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - EstimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, netDecayCoeMap, - wasteModifierMap, quadMeanDiameterUtil, closeUtilizationVolumeUtil, ->>>>>>> origin/feature/VDYP-362-compatibility-variables - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil - ); - - if (getId().isStart()) { - // EMP095 -<<<<<<< HEAD - emp.estimateNetDecayWasteAndBreakageVolume( - utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, -======= - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, ->>>>>>> origin/feature/VDYP-362-compatibility-variables - 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) { - Coefficients utilVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); - - // Set all components other than 4 to 0.0 - for (var i = -1; i < UTIL_LARGEST; i++) { - utilVector.setCoe(i, 0f); - } - - // Set component 0 to equal component 4. - utilVector.setCoe(UTIL_ALL, utilVector.getCoe(UTIL_LARGEST)); - - accessors.getWriteMethod().invoke(vdypSpecies, utilVector); - } - } - - computeLayerUtilizationComponentsFromSpecies(vdypLayer); - - } catch (IllegalAccessException | InvocationTargetException ex) { - throw new IllegalStateException(ex); - } - } - -<<<<<<< HEAD -======= - /** - * Sets the Layer's utilization components based on those of its species. - * - * @param vdypLayer - */ - private void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { - // Layer utilization vectors other than quadratic mean diameter are the pairwise - // sums of those of their species - sumSpeciesUtilizationVectorsToLayer(vdypLayer); - - { - var hlVector = new Coefficients(new float[] { 0f, 0f }, -1); - vdypLayer.getSpecies().values().stream().forEach(spec -> { - var ba = spec.getBaseAreaByUtilization(); - hlVector.pairwiseInPlace(spec.getLoreyHeightByUtilization(), (x, y, i) -> x + y * ba.getCoe(i)); - }); - var ba = vdypLayer.getBaseAreaByUtilization(); - hlVector.scalarInPlace((x, i) -> ba.getCoe(i) > 0 ? x / ba.getCoe(i) : x); - vdypLayer.setLoreyHeightByUtilization(hlVector); - } - // Quadratic mean diameter for the layer is computed from the BA and TPH after - // they have been found from the species - { - var utilVector = vdypLayer.getBaseAreaByUtilization().pairwise( - vdypLayer.getTreesPerHectareByUtilization(), BaseAreaTreeDensityDiameter::quadMeanDiameter - ); - vdypLayer.setQuadraticMeanDiameterByUtilization(utilVector); - } - } - - // TODO De-reflectify this when we want to make it work in GralVM - private void sumSpeciesUtilizationVectorsToLayer(VdypLayer vdypLayer) throws IllegalStateException { - try { - for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { - var utilVector = Utils.utilizationVector(); - for (var vdypSpecies : vdypLayer.getSpecies().values()) { - var speciesVector = (Coefficients) accessors.getReadMethod().invoke(vdypSpecies); - utilVector.pairwiseInPlace(speciesVector, (x, y) -> x + y); - } - accessors.getWriteMethod().invoke(vdypLayer, utilVector); - } - } catch (IllegalAccessException | InvocationTargetException ex) { - throw new IllegalStateException(ex); - } - } - - // TODO De-reflectify this when we want to make it work in GralVM - private void scaleAllSummableUtilization(VdypUtilizationHolder holder, float factor) throws IllegalStateException { - try { - for (var accessors : SUMMABLE_UTILIZATION_VECTOR_ACCESSORS) { - ((Coefficients) accessors.getReadMethod().invoke(holder)).scalarInPlace(x -> x * factor); - } - } catch (IllegalAccessException | InvocationTargetException ex) { - throw new IllegalStateException(ex); - } - } - - private float heightMultiplier(String genus, Region region, float treesPerHectarePrimary) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class - ); - var coe = coeMap.get(genus, region).reindex(0); - return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); - } - - // EMP050 Meth==1 - /** - * Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return - */ - float primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); - } - - // EMP050 Meth==2 - /** - * Return the dominant height of the lead species based on the lorey height of the primary species. - * - * @param primaryHeight lorey height of the primary species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return - */ - float leadHeightFromPrimaryHeight(float primaryHeight, String genus, Region region, float treesPerHectarePrimary) { - return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(genus, region, treesPerHectarePrimary); - } - - // EMP051 - /** - * Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - * @return - */ - private float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class - ); - var coe = coeMap.get(genus, region); - return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); - } - - /** - * Accessor methods for utilization vectors, except for Lorey Height, on Layer and Species objects. - */ - static final Collection UTILIZATION_VECTOR_ACCESSORS; - - /** - * Accessor methods for utilization vectors, except for Lorey Height and Quadratic Mean Diameter, on Layer and - * Species objects. These are properties where the values for the layer are the sum of those for its species. - */ - static final Collection SUMMABLE_UTILIZATION_VECTOR_ACCESSORS; - - /** - * Accessor methods for utilization vectors, except for Lorey Height,and Volume on Layer and Species objects. - */ - static final Collection NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS; - - static { - try { - var bean = Introspector.getBeanInfo(VdypUtilizationHolder.class); - UTILIZATION_VECTOR_ACCESSORS = Arrays.stream(bean.getPropertyDescriptors()) // - .filter(p -> p.getName().endsWith("ByUtilization")) // - .filter(p -> !p.getName().startsWith("loreyHeight")) // - .filter(p -> p.getPropertyType() == Coefficients.class) // - .toList(); - } catch (IntrospectionException e) { - throw new IllegalStateException(e); - } - - SUMMABLE_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() - .filter(x -> !x.getName().startsWith("quadraticMeanDiameter")).toList(); - - NON_VOLUME_UTILIZATION_VECTOR_ACCESSORS = UTILIZATION_VECTOR_ACCESSORS.stream() - .filter(x -> !x.getName().contains("Volume")).toList(); - } - - int getGroup(FipPolygon fipPolygon, MatrixMap2 volumeGroupMap, String genus) { - return volumeGroupMap.get(genus, fipPolygon.getBiogeoclimaticZone()); - } - - MatrixMap2 getGroupMap(ControlKey key) { - return Utils.expectParsedControl(controlMap, key, MatrixMap2.class); - } - ->>>>>>> origin/feature/VDYP-362-compatibility-variables - // FIP_GET - protected FipPolygon getPolygon( - StreamingParser polyStream, StreamingParser> layerStream, - StreamingParser> speciesStream - ) throws ProcessingException, IOException, ResourceParseException { - - log.trace("Getting polygon"); - var polygon = polyStream.next(); - - log.trace("Getting layers for polygon {}", polygon.getPolygonIdentifier()); - Map layers; - try { - layers = layerStream.next(); - } catch (NoSuchElementException ex) { - throw validationError("Layers file has fewer records than polygon file.", ex); - } - - log.trace("Getting species for polygon {}", polygon.getPolygonIdentifier()); - Collection species; - try { - species = speciesStream.next(); - } catch (NoSuchElementException ex) { - throw validationError("Species file has fewer records than polygon file.", ex); - } - - // Validate that layers belong to the correct polygon - for (var layer : layers.values()) { - if (!layer.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { - throw validationError( - "Record in layer file contains layer for polygon %s when expecting one for %s.", - layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() - ); - } - layer.setSpecies(new HashMap<>()); - } - - for (var spec : species) { - var layer = layers.get(spec.getLayerType()); - // Validate that species belong to the correct polygon - if (!spec.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { - throw validationError( - "Record in species file contains species for polygon %s when expecting one for %s.", - layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() - ); - } - if (Objects.isNull(layer)) { - throw validationError( - "Species entry references layer %s of polygon %s but it is not present.", layer, - polygon.getPolygonIdentifier() - ); - } - layer.getSpecies().put(spec.getGenus(), spec); - } - - polygon.setLayers(layers); - - return polygon; - } - - private Optional heightMinimum(LayerType layer) { - var minima = Utils.>expectParsedControl(controlMap, ControlKey.MINIMA.name(), Map.class); - switch (layer) { - case PRIMARY: - return Optional.of(minima.get(BaseControlParser.MINIMUM_HEIGHT)); - case VETERAN: - return Optional.of(minima.get(BaseControlParser.MINIMUM_VETERAN_HEIGHT)); - default: - return Optional.empty(); - } - } - - // FIP_CHK - void checkPolygon(FipPolygon polygon) throws ProcessingException { - - // Fortran did debug logging when a polygon is found to be invalid. Attaching - // messages to exceptions fills that need. - - // TODO finding all the things that are wrong rather than failing on just the - // first would be a good idea. - - var primaryLayer = requireLayer(polygon, LayerType.PRIMARY); - - // FIXME VDYP7 actually tests if total age - YTBH is less than 0.5 but gives an - // error that total age is "less than" YTBH. Replicating that for now but - // consider changing it. - - if (primaryLayer.getAgeTotal().orElse(0f) - primaryLayer.getYearsToBreastHeight().orElse(0f) < 0.5f) { - throw validationError( - "Polygon %s has %s layer where total age is less than YTBH.", polygon.getPolygonIdentifier(), - LayerType.PRIMARY - ); - } - - // TODO This is the only validation step done to non-primary layers, VDYP7 had a - // less well defined idea of a layer being present or not and so it may have - // skipped validating other layers rather than validating them conditionally on - // being present. Consider extending validation of other properties to other - // layers. - - for (FipLayer layer : polygon.getLayers().values()) { - var height = layer.getHeight().orElse(0f); - - throwIfPresent( - heightMinimum(layer.getLayerType()).filter(minimum -> height < minimum).map( - minimum -> validationError( - "Polygon %s has %s layer where height %.1f is less than minimum %.1f.", - polygon.getPolygonIdentifier(), layer.getLayerType(), layer.getHeightSafe(), minimum - ) - ) - ); - } - - if (polygon.getMode().map(x -> x == PolygonMode.YOUNG).orElse(false)) { - throw validationError( - "Polygon %s is using unsupported mode %s.", polygon.getPolygonIdentifier(), PolygonMode.YOUNG - ); - } - - if (primaryLayer.getYearsToBreastHeight().orElse(0f) < 0.5) { - throw validationError( - "Polygon %s has %s layer where years to breast height %.1f is less than minimum %.1f years.", - polygon.getPolygonIdentifier(), LayerType.PRIMARY, primaryLayer.getYearsToBreastHeightSafe(), 0.5f - ); - } - - if (primaryLayer.getSiteIndex().orElse(0f) < 0.5) { - throw validationError( - "Polygon %s has %s layer where site index %s is less than minimum %.1f years.", - polygon.getPolygonIdentifier(), LayerType.PRIMARY, - primaryLayer.getSiteIndex().map(x -> String.format("%.1f", x)).orElse("N/A"), 0.5f - ); - } - - for (FipLayer layer : polygon.getLayers().values()) { - var percentTotal = getPercentTotal(layer); - // VDYP7 performs this step which should be negligible but might have a small - // impact due to the 0.01 percent variation and floating point errors. - if (layer.getLayerType() == LayerType.PRIMARY) { - layer.getSpecies().values() - .forEach(species -> species.setFractionGenus(species.getPercentGenus() / percentTotal)); - } - } - - } - - // EMP098 - float estimateVeteranBaseArea(float height, float crownClosure, String genus, Region region) { - var coefficients = Utils.>expectParsedControl( - controlMap, ControlKey.VETERAN_BQ, MatrixMap2.class - ).getM(genus, region); - - // mismatched index is copied from VDYP7 - float a0 = coefficients.getCoe(1); - float a1 = coefficients.getCoe(2); - float a2 = coefficients.getCoe(3); - - float baseArea = a0 * pow(max(height - a1, 0.0f), a2); - - baseArea *= crownClosure / 4.0f; - - baseArea = max(baseArea, 0.01f); - - return baseArea; - } - - /** - * estimate mean volume per tree For a species, for trees with dbh >= 7.5 CM Using eqn in jf117.doc - * - * @param volumeGroup - * @param loreyHeight - * @param quadMeanDiameter - * @return - */ - public float estimateMeanVolume(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class - ); - - var coe = coeMap.get(volumeGroup); - - if (coe == null) { - throw new IllegalArgumentException("Coefficients not found for volume group " + volumeGroup); - } - - float lvMean = // - coe.getCoe(0) + // - coe.getCoe(1) * log(quadMeanDiameter) + // - coe.getCoe(2) * log(loreyHeight) + // - coe.getCoe(3) * quadMeanDiameter + // - coe.getCoe(4) / quadMeanDiameter + // - coe.getCoe(5) * loreyHeight + // - coe.getCoe(6) * quadMeanDiameter * quadMeanDiameter + // - coe.getCoe(7) * quadMeanDiameter * loreyHeight + // - coe.getCoe(8) * loreyHeight / quadMeanDiameter; - - return exp(lvMean); - } - - double[] rootFinderFunction(double[] point, VdypLayer layer, double[] diameterBase) { - - var percentL1 = new double[point.length]; - double percentSum = 0; - if (point.length > 1) { - for (int i = 0; i < point.length - 1; i++) { - percentL1[i] = point[i]; - percentSum += point[i]; - } - } - percentL1[point.length - 1] = 100d - percentSum; - - double volumeSum = 0d; - double treesPerHectareSum = 0d; - - final var layerBa = layer.getBaseAreaByUtilization().getCoe(UTIL_ALL); - - // Iterate over the fixed order list with an index - { - var it = layer.getSpecies().entrySet().iterator(); - for (int j = 0; it.hasNext(); j++) { - var spec = it.next().getValue(); - - // These side effects are evil but that's how VDYP7 works. - - final float quadMeanDiameter = (float) (7.5 - + (diameterBase[j] - 7.5) * FastMath.exp(point[point.length - 1] / 20d)); - spec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_ALL, quadMeanDiameter); - - final float baseArea = (float) (layerBa * percentL1[j] / 100d); - spec.getBaseAreaByUtilization().setCoe(UTIL_ALL, baseArea); - - final float tph = BaseAreaTreeDensityDiameter.treesPerHectare(baseArea, quadMeanDiameter); - spec.getTreesPerHectareByUtilization().setCoe(UTIL_ALL, tph); - treesPerHectareSum += tph; - - final float loreyHeight = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); - - final float meanVolume = estimateMeanVolume(spec.getVolumeGroup(), loreyHeight, quadMeanDiameter); - final float wholeStemVolume = tph * meanVolume; - - spec.getWholeStemVolumeByUtilization().setCoe(UTIL_ALL, wholeStemVolume); - volumeSum += wholeStemVolume; - } - } - - double dqFinal = BaseAreaTreeDensityDiameter - .quadMeanDiameter(layer.getBaseAreaByUtilization().getCoe(UTIL_ALL), (float) treesPerHectareSum); - - var y = new double[point.length]; - - if (layer.getSpecies().size() > 1) { - var it = layer.getSpecies().values().iterator(); - for (int i = 0; it.hasNext(); i++) { - var spec = it.next(); - - y[i] = 100d * spec.getWholeStemVolumeByUtilization().getCoe(UTIL_ALL) / volumeSum; - } - } - y[y.length - 1] = dqFinal; - return y; - } - -<<<<<<< HEAD -======= - // YSMALL - // TODO move to shared location as it's used elsewhere and implement - // compatibility variables - /** - * Estimate small components for primary layer - * - * @throws ProcessingException - */ - public , SP extends BaseVdypSpecies, SI extends BaseVdypSite> void - estimateSmallComponents(BaseVdypPolygon, SP, SI> polygon, VdypLayer layer) - throws ProcessingException { - float loreyHeightSum = 0f; - float baseAreaSum = 0f; - float treesPerHectareSum = 0f; - float volumeSum = 0f; - - Region region = Utils.getBec(polygon.getBiogeoclimaticZone(), controlMap).getRegion(); - - for (VdypSpecies spec : layer.getSpecies().values()) { - @SuppressWarnings("unused") - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UTIL_ALL); // HLsp - float baseAreaSpec = spec.getBaseAreaByUtilization().getCoe(UTIL_ALL); // BAsp - @SuppressWarnings("unused") - float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL); // DQsp - - // EMP080 - float smallComponentProbability = smallComponentProbability(layer, spec, region); // PROBsp - - // this WHOLE operation on Actual BA's, not 100% occupancy. - float fractionAvailable = polygon.getPercentAvailable().map(p -> p / 100f).orElse(1f); - baseAreaSpec *= fractionAvailable; - // EMP081 - float conditionalExpectedBaseArea = conditionalExpectedBaseArea(spec, baseAreaSpec, region); // BACONDsp - conditionalExpectedBaseArea /= fractionAvailable; - - float baseAreaSpecSmall = smallComponentProbability * conditionalExpectedBaseArea; - - // EMP082 - float quadMeanDiameterSpecSmall = smallComponentQuadMeanDiameter(spec); // DQSMsp - - // EMP085 - float loreyHeightSpecSmall = smallComponentLoreyHeight(spec, quadMeanDiameterSpecSmall); // HLSMsp - - // EMP086 - float meanVolumeSmall = meanVolumeSmall(spec, quadMeanDiameterSpecSmall, loreyHeightSpecSmall); // VMEANSMs - - // TODO Apply Compatibility Variables, not needed for FIPSTART - - spec.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, loreyHeightSpecSmall); - float treesPerHectareSpecSmall = BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaSpecSmall, quadMeanDiameterSpecSmall); // TPHSMsp - spec.getBaseAreaByUtilization().setCoe(UTIL_SMALL, baseAreaSpecSmall); - spec.getTreesPerHectareByUtilization().setCoe(UTIL_SMALL, treesPerHectareSpecSmall); - spec.getQuadraticMeanDiameterByUtilization().setCoe(UTIL_SMALL, quadMeanDiameterSpecSmall); - float wholeStemVolumeSpecSmall = treesPerHectareSpecSmall * meanVolumeSmall; // VOLWS(I,-1) - spec.getWholeStemVolumeByUtilization().setCoe(UTIL_SMALL, wholeStemVolumeSpecSmall); - - loreyHeightSum += baseAreaSpecSmall * loreyHeightSpecSmall; - baseAreaSum += baseAreaSpecSmall; - treesPerHectareSum += treesPerHectareSpecSmall; - volumeSum += wholeStemVolumeSpecSmall; - } - - if (baseAreaSum > 0f) { - layer.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, loreyHeightSum / baseAreaSum); - } else { - layer.getLoreyHeightByUtilization().setCoe(UTIL_SMALL, 0f); - } - layer.getBaseAreaByUtilization().setCoe(UTIL_SMALL, baseAreaSum); - layer.getTreesPerHectareByUtilization().setCoe(UTIL_SMALL, treesPerHectareSum); - layer.getQuadraticMeanDiameterByUtilization() - .setCoe(UTIL_SMALL, BaseAreaTreeDensityDiameter.quadMeanDiameter(baseAreaSum, treesPerHectareSum)); - layer.getWholeStemVolumeByUtilization().setCoe(UTIL_SMALL, volumeSum); - } - - // EMP086 - private float meanVolumeSmall(VdypSpecies spec, float quadMeanDiameterSpecSmall, float loreyHeightSpecSmall) { - Coefficients coe = getCoeForSpecies(spec, ControlKey.SMALL_COMP_WS_VOLUME); - - // EQN 1 in IPSJF119.doc - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - float a2 = coe.getCoe(3); - float a3 = coe.getCoe(4); - - return exp( - a0 + a1 * log(quadMeanDiameterSpecSmall) + a2 * log(loreyHeightSpecSmall) - + a3 * quadMeanDiameterSpecSmall - ); - } - - // EMP085 - private float smallComponentLoreyHeight(VdypSpecies spec, float quadMeanDiameterSpecSmall) { - Coefficients coe = getCoeForSpecies(spec, ControlKey.SMALL_COMP_HL); - - // EQN 1 in IPSJF119.doc - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - - return 1.3f + (spec.getLoreyHeightByUtilization().getCoe(FipStart.UTIL_ALL) - 1.3f) * exp( - a0 * (pow(quadMeanDiameterSpecSmall, a1) - - pow(spec.getQuadraticMeanDiameterByUtilization().getCoe(UTIL_ALL), a1)) - ); - } - - // EMP082 - private float smallComponentQuadMeanDiameter(VdypSpecies spec) { - Coefficients coe = getCoeForSpecies(spec, ControlKey.SMALL_COMP_DQ); - - // EQN 5 in IPSJF118.doc - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - - float logit = // - a0 + a1 * spec.getLoreyHeightByUtilization().getCoe(FipStart.UTIL_ALL); - - return 4.0f + 3.5f * exp(logit) / (1.0f + exp(logit)); - } - - // EMP081 - private float conditionalExpectedBaseArea(VdypSpecies spec, float baseAreaSpec, Region region) { - Coefficients coe = getCoeForSpecies(spec, ControlKey.SMALL_COMP_BA); - - // EQN 3 in IPSJF118.doc - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - float a2 = coe.getCoe(3); - float a3 = coe.getCoe(4); - - float coast = region == Region.COASTAL ? 1.0f : 0.0f; - - // FIXME due to a bug in VDYP7 it always treats this as interior. Replicating - // that for now. - coast = 0f; - - float arg = // - (a0 + // - a1 * coast + // - a2 * spec.getBaseAreaByUtilization().getCoe(FipStart.UTIL_ALL)// - ) * exp(a3 * spec.getLoreyHeightByUtilization().getCoe(FipStart.UTIL_ALL)); - arg = max(arg, 0f); - - return arg; - } - - // EMP080 - private float smallComponentProbability(VdypLayer layer, VdypSpecies spec, Region region) { - Coefficients coe = getCoeForSpecies(spec, ControlKey.SMALL_COMP_PROBABILITY); - - // EQN 1 in IPSJF118.doc - - float a0 = coe.getCoe(1); - float a1 = coe.getCoe(2); - float a2 = coe.getCoe(3); - float a3 = coe.getCoe(4); - - float coast = region == Region.COASTAL ? 1.0f : 0.0f; - - float logit = // - a0 + // - a1 * coast + // - a2 * layer.getBreastHeightAge().orElse(0f) + // - a3 * spec.getLoreyHeightByUtilization().getCoe(FipStart.UTIL_ALL); - - return exp(logit) / (1.0f + exp(logit)); - } - ->>>>>>> origin/feature/VDYP-362-compatibility-variables - @Override - protected ValueOrMarker - isVeteranForEstimatePercentForestLand(FipPolygon polygon, Optional vetLayer) { - if (polygon.getMode().map(mode -> mode == PolygonMode.YOUNG).orElse(false)) { - return FLOAT_OR_BOOL.value(100f); - } - return super.isVeteranForEstimatePercentForestLand(polygon, vetLayer); - } - - /** - * Estimate the Jacobian Matrix of a function using forward difference - * - * @param x - * @param func - * @return - */ - double[][] estimateJacobian(double[] x, MultivariateVectorFunction func) { - return estimateJacobian(x, func.value(x), func); - } - - /** - * Estimate the Jacobian Matrix of a function using forward difference - * - * @param x - * @param y - * @param func - * @return - */ - double[][] estimateJacobian(double[] x, double[] y, MultivariateVectorFunction func) { - // TODO - final double machineEpsilon = 2.22e-16; - final double functionEpsilon = 1.19e-07; - - double epsilon = FastMath.sqrt(FastMath.max(functionEpsilon, machineEpsilon)); - - double[] x2 = Arrays.copyOf(x, x.length); - - double[][] result = new double[x.length][x.length]; - - for (int j = 0; j < x.length; j++) { - double temp = x[j]; - double h = epsilon * FastMath.abs(temp); - if (h == 0) { - h = epsilon; - } - x2[j] = temp + h; - double[] y2 = func.value(x2); - x2[j] = temp; - for (int i = 0; i < x.length; i++) { - result[i][j] = (y2[i] - y[i]) / h; - } - } - return result; - } - - RealMatrix identityMatrix(int n) { - var diag = new double[n]; - Arrays.fill(diag, n); - return new DiagonalMatrix(diag); - - } - - RealVector findRoot(double[] diameterBase, double[] goal, double[] x, VdypLayer layer, double tolerance) { - MultivariateVectorFunction func = point -> rootFinderFunction(point, layer, diameterBase); - - MultivariateMatrixFunction jacFunc = point -> estimateJacobian(point, func); - - LevenbergMarquardtOptimizer optimizer = new LevenbergMarquardtOptimizer(); - - optimizer.withCostRelativeTolerance(tolerance); // Not sure if this is the right tolerance - - LeastSquaresProblem leastSquaresProblem = LeastSquaresFactory.create( - func, // - jacFunc, // - goal, // - x, // - identityMatrix(x.length), // - null, // - 200, // - 1000 // - ); - - var result = optimizer.optimize(leastSquaresProblem); - - return result.getPoint(); - } - - @Override - public VdypApplicationIdentifier getId() { - return VdypApplicationIdentifier.FIP_START; - } - - @Override - protected BaseControlParser getControlFileParser() { - return new FipControlParser(); - } - - @Override - protected FipSpecies copySpecies(FipSpecies toCopy, Consumer> config) { - return FipSpecies.build(builder -> { - builder.copy(toCopy); - }); - } - - @Override - protected Optional getPrimarySite(FipLayer layer) { - return layer.getSite(); - } - - @Override - protected float getYieldFactor(FipPolygon polygon) { - return polygon.getYieldFactor(); - // TODO Make an InputPolygon interface that has this. - } - -} diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java index c393973db..5dd6bcccb 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java @@ -19,7 +19,7 @@ public FipPolygon( Optional percentAvailable, Optional modeFip, Optional nonproductiveDescription, float yieldFactor ) { - super(polygonIdentifier, percentAvailable, fiz, becIdentifier, modeFip); + super(polygonIdentifier, percentAvailable, fiz, becIdentifier, modeFip, Optional.empty()); this.nonproductiveDescription = nonproductiveDescription; this.yieldFactor = yieldFactor; } diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java index 2b8fa3725..1ab1cc259 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java @@ -68,7 +68,7 @@ protected FipSpecies doBuild() { this.genus.get(), // this.genusIndex.get(), // this.percentGenus.get(), // - new Sp64DistributionSet(this.sp64DistributionList), // + this.sp64DistributionSet.get(), // this.site ); } diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java index e655bb798..dfe89e0e7 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java @@ -27,7 +27,6 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -35,6 +34,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 19c337eb5..511c3c61b 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -1,7 +1,6 @@ package ca.bc.gov.nrs.vdyp.forward; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -10,12 +9,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; +import ca.bc.gov.nrs.vdyp.application.ProcessingException; 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 { @@ -58,20 +60,20 @@ class Bank { 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) { + public Bank(VdypLayer layer, BecDefinition becZone, Predicate retainCriteria) throws ProcessingException { this.layer = layer; this.becZone = becZone; List speciesToRetain = layer.getSpecies().values().stream().filter(s -> retainCriteria.test(s)) - .sorted((s1, s2) -> s1.getGenusIndex().compareTo(s2.getGenusIndex())).toList(); + .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 GenusDistributionSet[getNSpecies() + 1]; + sp64Distributions = new Sp64DistributionSet[getNSpecies() + 1]; siteIndices = new float[nSpecies + 1]; dominantHeights = new float[nSpecies + 1]; ageTotals = new float[nSpecies + 1]; @@ -196,14 +198,14 @@ VdypLayer getUpdatedLayer() { return layer; } - private void transferSpeciesIntoBank(int index, VdypSpecies species) { + private void transferSpeciesIntoBank(int index, VdypSpecies species) throws ProcessingException { VdypSite site = species.getSite().orElseThrow(() -> new ProcessingException(MessageFormat.format( "Species {0} of Polygon {1} must contain a Site definition but does not.", species.getGenus(), species.getPolygonIdentifier().toStringCompact()))); speciesNames[index] = species.getGenus(); - sp64Distributions[index] = new GenusDistributionSet(species.getSpeciesPercent()); + sp64Distributions[index] = species.getSp64DistributionSet(); siteIndices[index] = site.getSiteIndex().orElse(VdypEntity.MISSING_FLOAT_VALUE); dominantHeights[index] = site.getHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); ageTotals[index] = site.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE); @@ -282,8 +284,6 @@ private void transferSpeciesFromBank(int index, VdypSpecies species) { transferUtilizationsIntoBank(index, species); } - private Sp64DistributionSet[] copy(Sp64DistributionSet[] a) { - return Arrays.stream(a).map(g -> g == null ? null : g.copy()).toArray(Sp64DistributionSet[]::new); private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { for (UtilizationClass uc: UtilizationClass.values()) { @@ -303,7 +303,6 @@ private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { public Bank copy() { return new Bank(this, CopyMode.CopyAll); - } } @@ -330,4 +329,8 @@ private float[] copy(float[] a) { 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(Sp64DistributionSet::copy).toArray(Sp64DistributionSet[]::new); + } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index bfdc69803..70d19b2e0 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -2,11 +2,9 @@ import java.io.IOException; import java.text.MessageFormat; -import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; @@ -23,7 +21,6 @@ import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; 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.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; @@ -103,54 +100,28 @@ public Optional readNextPolygon() throws ProcessingException { polygon.setTargetYear(polygonDescription.getYear()); } - var speciesCollection = layerSpeciesStream.next(); - var primarySpecies = new HashMap(); - var veteranSpecies = new HashMap(); - for (var species : speciesCollection) { - logger.trace("Saw species {}", species); + var layerSpeciesSet = layerSpeciesStream.next(); + var primarySpecies = new HashMap(); + var veteranSpecies = new HashMap(); + for (var s : layerSpeciesSet) { + logger.trace("Saw species {}", s); - var key = new UtilizationBySpeciesKey(species.getLayerType(), species.getGenusIndex()); + var key = new UtilizationBySpeciesKey(s.getLayerType(), s.getGenusIndex()); var speciesUtilizations = utilizationsBySpeciesMap.get(key); - if (speciesUtilizations != null) { - - UtilizationVector basalAreaUtilizations = new UtilizationVector(); - UtilizationVector liveTreesPerHectareUtilizations = new UtilizationVector(); - UtilizationVector loreyHeightUtilizations = new UtilizationVector(); - UtilizationVector wholeStemVolumeUtilizations = new UtilizationVector(); - UtilizationVector closeUtilizationVolumeUtilizations = new UtilizationVector(); - UtilizationVector cuVolumeMinusDecayUtilizations = new UtilizationVector(); - UtilizationVector cuVolumeMinusDecayWastageUtilizations = new UtilizationVector(); - UtilizationVector cuVolumeMinusDecayWastageBreakageUtilizations = new UtilizationVector(); - UtilizationVector quadraticMeanDiameterAtBHUtilizations = new UtilizationVector(); - - for (var e: speciesUtilizations.entrySet()) { - var uc = e.getKey(); - var ucUtilizations = e.getValue(); - - basalAreaUtilizations.set(uc, ucUtilizations.getBasalArea()); - liveTreesPerHectareUtilizations.set(uc, ucUtilizations.getLiveTreesPerHectare()); - if (uc == UtilizationClass.SMALL || uc == UtilizationClass.ALL) { - loreyHeightUtilizations.set(uc, ucUtilizations.getLoreyHeight()); - } - wholeStemVolumeUtilizations.set(uc, ucUtilizations.getWholeStemVolume()); - closeUtilizationVolumeUtilizations.set(uc, ucUtilizations.getCloseUtilizationVolume()); - cuVolumeMinusDecayUtilizations.set(uc, ucUtilizations.getCuVolumeMinusDecay()); - cuVolumeMinusDecayWastageUtilizations.set(uc, ucUtilizations.getCuVolumeMinusDecayWastage()); - cuVolumeMinusDecayWastageBreakageUtilizations.set(uc, ucUtilizations.getCuVolumeMinusDecayWastageBreakage()); - quadraticMeanDiameterAtBHUtilizations.set(uc, ucUtilizations.getQuadraticMeanDiameterAtBH()); - } + if (speciesUtilizations != null) { + setUtilizations(s, speciesUtilizations); } - - if (LayerType.PRIMARY.equals(species.getLayerType())) { - primarySpecies.put(species.getGenusIndex(), species); - } else if (LayerType.VETERAN.equals(species.getLayerType())) { - veteranSpecies.put(species.getGenusIndex(), species); + + if (LayerType.PRIMARY.equals(s.getLayerType())) { + primarySpecies.put(s.getGenusIndex(), s); + } else if (LayerType.VETERAN.equals(s.getLayerType())) { + veteranSpecies.put(s.getGenusIndex(), s); } else { throw new IllegalStateException( MessageFormat.format( "Unrecognized layer type {} for species {} of polygon {}", - species.getLayerType(), species.getGenusIndex(), polygon.getPolygonIdentifier() + s.getLayerType(), s.getGenusIndex(), polygon.getPolygonIdentifier() ) ); } @@ -165,9 +136,14 @@ public Optional readNextPolygon() throws ProcessingException { Map defaultSpeciesUtilization = utilizationsBySpeciesMap .get(key); - primaryLayer = new VdypLayer( - LayerType.PRIMARY, polygon, primarySpecies, Optional.ofNullable(defaultSpeciesUtilization) - ); + primaryLayer = VdypLayer.build(builder -> { + builder.layerType(LayerType.PRIMARY); + builder.polygonIdentifier(polygon.getPolygonIdentifier()); + builder.inventoryTypeGroup(polygon.getInventoryTypeGroup()); + builder.addSpecies(layerSpeciesSet); + }); + + setUtilizations(primaryLayer, defaultSpeciesUtilization); layerMap.put(LayerType.PRIMARY, primaryLayer); } @@ -179,9 +155,14 @@ public Optional readNextPolygon() throws ProcessingException { Map defaultSpeciesUtilization = utilizationsBySpeciesMap .get(key); - veteranLayer = new VdypLayer( - LayerType.VETERAN, polygon, veteranSpecies, Optional.ofNullable(defaultSpeciesUtilization) - ); + veteranLayer = VdypLayer.build(builder -> { + builder.layerType(LayerType.VETERAN); + builder.polygonIdentifier(polygon.getPolygonIdentifier()); + builder.inventoryTypeGroup(polygon.getInventoryTypeGroup()); + builder.addSpecies(layerSpeciesSet); + }); + + setUtilizations(veteranLayer, defaultSpeciesUtilization); layerMap.put(LayerType.VETERAN, veteranLayer); } @@ -198,6 +179,26 @@ public Optional readNextPolygon() throws ProcessingException { return thePolygon; } + private void setUtilizations(VdypUtilizationHolder u, Map speciesUtilizations) { + + for (var e: speciesUtilizations.entrySet()) { + var uc = e.getKey(); + var ucUtilizations = e.getValue(); + + u.getBaseAreaByUtilization().set(uc, ucUtilizations.getBasalArea()); + u.getTreesPerHectareByUtilization().set(uc, ucUtilizations.getLiveTreesPerHectare()); + if (uc == UtilizationClass.SMALL || uc == UtilizationClass.ALL) { + u.getLoreyHeightByUtilization().set(uc, ucUtilizations.getLoreyHeight()); + } + u.getWholeStemVolumeByUtilization().set(uc, ucUtilizations.getWholeStemVolume()); + u.getCloseUtilizationVolumeByUtilization().set(uc, ucUtilizations.getCloseUtilizationVolume()); + u.getCloseUtilizationVolumeNetOfDecayByUtilization().set(uc, ucUtilizations.getCuVolumeMinusDecay()); + u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set(uc, ucUtilizations.getCuVolumeMinusDecayWastage()); + u.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().set(uc, ucUtilizations.getCuVolumeMinusDecayWastageBreakage()); + u.getQuadraticMeanDiameterByUtilization().set(uc, ucUtilizations.getQuadraticMeanDiameterAtBH()); + } + } + private class UtilizationBySpeciesKey { private final LayerType layerType; private final Integer speciesIndex; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index e3028a1ff..44b8701ac 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -43,7 +43,7 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CommonData; -import ca.bc.gov.nrs.vdyp.model.Sp64Distribution; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; @@ -53,13 +53,13 @@ import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; +import ca.bc.gov.nrs.vdyp.model.Sp64Distribution; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; 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.VolumeVariable; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; @@ -557,7 +557,7 @@ private boolean growUsingPartialSpeciesDynamics( tphNew[0] = tphStart + BaseAreaTreeDensityDiameter.treesPerHectare(baNew[0], dqNew[0]); Map basalAreaPercentagesPerSpecies = new HashMap<>(); - for (String spAlias : fps.fcm.getGenusDefinitionMap().getAliases()) { + for (String spAlias : fps.fcm.getGenusDefinitionMap().getAllGeneraAliases()) { basalAreaPercentagesPerSpecies.put(spAlias, 0.0f); } for (int i : pps.getIndices()) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 649102ade..4b90b97c4 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -51,9 +51,7 @@ public ForwardProcessingState(Map controlMap) { public void setPolygon(VdypPolygon polygon) throws ProcessingException { - BecDefinition becZone = fcm.getBecLookup().get(polygon.getBiogeoclimaticZone()).orElseThrow(() -> - new ProcessingException(MessageFormat.format("{0}: BEC zone {1} is unsupported", polygon.getPolygonIdentifier(), - polygon.getBiogeoclimaticZone()))); + BecDefinition becZone = polygon.getBiogeoclimaticZone(); // Move the primary layer of the given polygon to bank zero. Bank primaryBank = banks[0][LayerType.PRIMARY.getIndex()] = new Bank( diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java new file mode 100644 index 000000000..02ecc1fd9 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/VdypPolygonDescription.java @@ -0,0 +1,45 @@ +package ca.bc.gov.nrs.vdyp.forward.model; + +public class VdypPolygonDescription { + + // See IPSJF155.doc + + private final String description; // POLYDESC + private final String name; // description, with year removed, trimmed + private final Integer year; // derived - last four characters of POLYDESC + + public VdypPolygonDescription(String description, String name, Integer year) { + this.description = description.trim(); + this.year = year; + this.name = name.trim(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(name).append('(').append(year).append(')'); + return sb.toString(); + } + + public String getDescription() { + return description; + } + + public Integer getYear() { + return year; + } + + public String getName() { + return name; + } + + @Override + public boolean equals(Object other) { + return other instanceof VdypPolygonDescription that && this.name.equals(that.name); + } + + @Override + public int hashCode() { + return description.hashCode(); + } +} diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java index f7b186426..4392d2089 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.text.MessageFormat; import java.util.Map; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,7 +21,6 @@ import ca.bc.gov.nrs.vdyp.io.parse.value.ControlledValueParser; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; import ca.bc.gov.nrs.vdyp.model.BecDefinition; -import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.PolygonMode; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; @@ -102,10 +102,16 @@ protected VdypPolygon convert(Map entry) throws ResourceParseExc percentForestLand = DEFAULT_FORESTED_LAND_PERCENTAGE; } - return new VdypPolygon( - description, bec, fizId, percentForestLand, inventoryTypeGroup, basalAreaGroup, - fipMode.flatMap(PolygonMode::getByCode) - ); + final float percentAvailable = percentForestLand; + + return VdypPolygon.build(builder -> { + builder.polygonIdentifier(descriptionText); + builder.biogeoclimaticZone(bec); + builder.forestInventoryZone(fizId.toString()); + fipMode.ifPresentOrElse(m -> builder.mode(PolygonMode.getByCode(m)), () -> Optional.empty()); + builder.percentAvailable(percentAvailable); + builder.inventoryTypeGroup(inventoryTypeGroup); + }); } }; }; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 2ec915a62..289d2d765 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -8,11 +8,8 @@ import java.util.Optional; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; -import ca.bc.gov.nrs.vdyp.forward.model.VdypEntity; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; import ca.bc.gov.nrs.vdyp.io.EndOfRecord; import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; @@ -23,9 +20,12 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.io.parse.value.ControlledValueParser; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.Sp64Distribution; import ca.bc.gov.nrs.vdyp.model.Sp64DistributionSet; +import ca.bc.gov.nrs.vdyp.model.VdypEntity; +import ca.bc.gov.nrs.vdyp.model.VdypSpecies; public class VdypSpeciesParser implements ControlMapValueReplacer { @@ -57,7 +57,7 @@ public ControlKey getControlKey() { } @Override - public StreamingParserFactory> + public StreamingParserFactory> map(String fileName, FileResolver fileResolver, Map control) throws IOException, ResourceParseException { return () -> { @@ -93,12 +93,12 @@ public ControlKey getControlKey() { var genusDefinitionMap = (GenusDefinitionMap) control.get(ControlKey.SP0_DEF.name()); - var delegateStream = new AbstractStreamingParser, EndOfRecord>>( + var delegateStream = new AbstractStreamingParser, EndOfRecord>>( is, lineParser, control ) { @SuppressWarnings("unchecked") @Override - protected ValueOrMarker, EndOfRecord> convert(Map entry) + protected ValueOrMarker, EndOfRecord> convert(Map entry) throws ResourceParseException { var polygonId = VdypPolygonDescriptionParser.parse((String) entry.get(DESCRIPTION)); @@ -126,7 +126,7 @@ protected ValueOrMarker, EndOfRecord> convert(MapoptSafe(entry.get(SITE_CURVE_NUMBER)) .orElse(VdypEntity.MISSING_INTEGER_VALUE); - var builder = new ValueOrMarker.Builder, EndOfRecord>(); + var builder = new ValueOrMarker.Builder, EndOfRecord>(); return layerType.handle(l -> builder.value(l.map(lt -> { List gdList = new ArrayList<>(); @@ -155,30 +155,43 @@ protected ValueOrMarker, EndOfRecord> convert(Map { + speciesBuilder.sp64DistributionSet(speciesDistributionSet); + speciesBuilder.polygonIdentifier(polygonId); + speciesBuilder.layerType(lt); + speciesBuilder.genusIndex(genusIndex); + speciesBuilder.genus(genus); + speciesBuilder.addSite(siteBuilder -> { + siteBuilder.ageTotal(totalAge); + siteBuilder.height(dominantHeight); + siteBuilder.polygonIdentifier(polygonId); + siteBuilder.siteCurveNumber(siteCurveNumber); + siteBuilder.layerType(lt); + siteBuilder.siteGenus(genus); + siteBuilder.siteIndex(siteIndex); + siteBuilder.yearsToBreastHeight(yearsToBreastHeight); + }); + }); })), builder::marker); } }; - return new GroupingStreamingParser, ValueOrMarker, EndOfRecord>>( + return new GroupingStreamingParser, ValueOrMarker, EndOfRecord>>( delegateStream ) { @Override - protected boolean skip(ValueOrMarker, EndOfRecord> nextChild) { + protected boolean skip(ValueOrMarker, EndOfRecord> nextChild) { return nextChild.getValue().map(Optional::isEmpty).orElse(false); } @Override - protected boolean stop(ValueOrMarker, EndOfRecord> nextChild) { + protected boolean stop(ValueOrMarker, EndOfRecord> nextChild) { return nextChild.isMarker(); } @Override - protected Collection - convert(List, EndOfRecord>> children) { + protected Collection + convert(List, EndOfRecord>> children) { // Skip if empty (and unknown layer type) return children.stream().map(ValueOrMarker::getValue).map(Optional::get).flatMap(Optional::stream) .toList(); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java index d9ec86534..a006419d8 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java @@ -37,10 +37,12 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; -import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; import ca.bc.gov.nrs.vdyp.test.TestUtils; @SuppressWarnings({ "unchecked", "rawtypes" }) diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index 1ea96e018..b8a7862e8 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -16,24 +16,22 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; -import ca.bc.gov.nrs.vdyp.forward.model.VdypLayerSpecies; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonDescription; -import ca.bc.gov.nrs.vdyp.forward.model.VdypPolygonLayer; -import ca.bc.gov.nrs.vdyp.forward.model.VdypSpeciesUtilization; +import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; -import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +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.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 PolygonProcessingStateTest { private ForwardControlParser parser; private Map controlMap; - private StreamingParser polygonDescriptionStream; - @SuppressWarnings({ "unchecked", "rawtypes" }) @BeforeEach void before() throws IOException, ResourceParseException { @@ -41,28 +39,21 @@ void before() throws IOException, ResourceParseException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.SP0_DEF, instanceOf(GenusDefinitionMap.class))); - - var polygonDescriptionStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_GROWTO.name()); - polygonDescriptionStream = ((StreamingParserFactory) polygonDescriptionStreamFactory) - .get(); } @Test void testConstruction() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - int nSpecies = pLayer.getGenera().size(); + int nSpecies = pLayer.getSpecies().size(); assertThat(pps, notNullValue()); assertThat(pps.yearsAtBreastHeight.length, is(nSpecies + 1)); @@ -114,14 +105,11 @@ void testConstruction() throws IOException, ResourceParseException, ProcessingEx @Test void testSetCopy() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); - ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); @@ -136,29 +124,25 @@ void testSetCopy() throws IOException, ResourceParseException, ProcessingExcepti @Test void testRemoveSmallLayers() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank bank1 = new Bank( pLayer, polygon.getBiogeoclimaticZone(), - s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= 0.5 : true + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 0.5 ); // the filter should have removed genus B (index 3) since it's ALL basal area is below 0.5 - assertThat(bank1.getNSpecies(), is(pLayer.getGenera().size() - 1)); + assertThat(bank1.getNSpecies(), is(pLayer.getSpecies().size() - 1)); assertThat(bank1.speciesIndices, is(new int[] { 0, 4, 5, 8, 15 })); Bank bank2 = new Bank( pLayer, polygon.getBiogeoclimaticZone(), - s -> s.getUtilizations().isPresent() - ? s.getUtilizations().get().get(UtilizationClass.ALL).getBasalArea() >= 100.0 : true + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 100.0 ); // the filter should have removed all genera. @@ -169,73 +153,68 @@ void testRemoveSmallLayers() throws IOException, ResourceParseException, Process @Test void testCopyConstructor() throws IOException, ResourceParseException, ProcessingException { - assertThat(polygonDescriptionStream.hasNext(), is(true)); - var polygonDescription = polygonDescriptionStream.next(); ForwardDataStreamReader reader = new ForwardDataStreamReader(controlMap); - var polygon = reader.readNextPolygon(polygonDescription); + var polygon = reader.readNextPolygon().orElseThrow(() -> new AssertionError("No polygons defined")); - VdypPolygonLayer pLayer = polygon.getPrimaryLayer(); + VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - Bank ppsCopy = new Bank(pps); + Bank ppsCopy = new Bank(pps, CopyMode.CopyAll); verifyProcessingStateMatchesLayer(ppsCopy, pLayer); } - private void verifyProcessingStateMatchesLayer(Bank pps, VdypPolygonLayer layer) { + private void verifyProcessingStateMatchesLayer(Bank pps, VdypLayer layer) { - List sortedSpIndices = layer.getGenera().keySet().stream().sorted().toList(); + List sortedSpIndices = layer.getSpecies().values().stream().map(s -> s.getGenusIndex()).sorted().toList(); + int arrayIndex = 1; for (int i = 0; i < sortedSpIndices.size(); i++) { - - int arrayIndex = i + 1; - - VdypLayerSpecies genus = layer.getGenera().get(sortedSpIndices.get(i)); + VdypSpecies genus = layer.getSpeciesByIndex(i); + verifyProcessingStateSpeciesMatchesSpecies(pps, arrayIndex, genus); - if (genus.getUtilizations().isPresent()) { - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - pps, arrayIndex, genus.getUtilizations().get() - ); - } + verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( + pps, arrayIndex, genus + ); + + arrayIndex += 1; } - if (layer.getDefaultUtilizationMap().isPresent()) { - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(pps, 0, layer.getDefaultUtilizationMap().get()); - } + verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(pps, 0, layer); } private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - Bank pps, int spIndex, Map map + Bank pps, int spIndex, VdypUtilizationHolder u ) { for (UtilizationClass uc : UtilizationClass.values()) { - VdypSpeciesUtilization u = map.get(uc); - - assertThat(pps.basalAreas[spIndex][uc.index + 1], is(u.getBasalArea())); - assertThat(pps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolume())); - assertThat(pps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCuVolumeMinusDecay())); - assertThat(pps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCuVolumeMinusDecayWastage())); + assertThat(pps.basalAreas[spIndex][uc.index + 1], is(u.getBaseAreaByUtilization().get(uc))); + assertThat(pps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeByUtilization().get(uc))); + assertThat(pps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); + assertThat(pps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc))); if (uc.index <= 0) { - assertThat(pps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeight())); + assertThat(pps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeightByUtilization().get(uc))); } - assertThat(pps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterAtBH())); - assertThat(pps.treesPerHectare[spIndex][uc.index + 1], is(u.getLiveTreesPerHectare())); - assertThat(pps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolume())); + assertThat(pps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc))); + assertThat(pps.treesPerHectare[spIndex][uc.index + 1], is(u.getTreesPerHectareByUtilization().get(uc))); + assertThat(pps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolumeByUtilization().get(uc))); } } - private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, VdypLayerSpecies species) { - assertThat(pps.yearsAtBreastHeight[index], is(species.getAgeAtBreastHeight())); - assertThat(pps.ageTotals[index], is(species.getAgeTotal())); - assertThat(pps.dominantHeights[index], is(species.getDominantHeight())); - assertThat(pps.siteIndices[index], is(species.getSiteIndex())); - assertThat(pps.sp64Distributions[index], is(species.getSpeciesDistributions())); + private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, VdypSpecies species) { + VdypSite site = species.getSite().orElseThrow(); + + assertThat(pps.yearsAtBreastHeight[index], is(site.getYearsAtBreastHeight())); + assertThat(pps.ageTotals[index], is(site.getAgeTotal())); + assertThat(pps.dominantHeights[index], is(site.getHeight())); + assertThat(pps.siteIndices[index], is(site.getSiteIndex())); + assertThat(pps.sp64Distributions[index], is(species.getSp64DistributionSet())); assertThat(pps.speciesIndices[index], is(species.getGenusIndex())); assertThat(pps.speciesNames[index], is(species.getGenus())); - assertThat(pps.yearsToBreastHeight[index], is(species.getYearsToBreastHeight())); + assertThat(pps.yearsToBreastHeight[index], is(site.getYearsToBreastHeight())); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index 534d8a4b0..f72719479 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -1,10 +1,8 @@ package ca.bc.gov.nrs.vdyp.forward; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.lessThanOrEqualTo; import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index c1febe602..b515f3d89 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -33,7 +33,6 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods.Limits; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.SiteIndex2Height; @@ -50,6 +49,7 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; @@ -479,7 +479,7 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws }); float maxHeight = estimationMethods.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) - .maxLoreyHeight(); + .loreyHeightMaximum(); loreyHeight = Math.min(loreyHeight, maxHeight); sBuilder.loreyHeight(loreyHeight); } @@ -585,9 +585,9 @@ void getDqBySpeciesInitial( var limits = getLimitsForSpecies(spec, region); - float min = Math.max(7.6f, limits.minDiameterHeight() * spec.getLoreyHeightByUtilization().getAll()); + float min = Math.max(7.6f, limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll()); float loreyHeightToUse = Math.max(spec.getLoreyHeightByUtilization().getAll(), 7.0f); - float max = Math.min(limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() * loreyHeightToUse); + float max = Math.min(limits.maxQuadMeanDiameterLoreyHeightRatio(), limits.quadMeanDiameterMaximum() * loreyHeightToUse); max = Math.max(7.75f, max); minPerSpecies.put(spec.getGenus(), min); @@ -601,7 +601,7 @@ void getDqBySpeciesInitial( } } - protected Limits getLimitsForSpecies(VdypSpecies spec, Region region) { + protected ComponentSizeLimits getLimitsForSpecies(VdypSpecies spec, Region region) { // TODO for JPROGRAM = 7 implement this differently, see ROOTV01 L91-L99 // EMP061 diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java index 6589bec01..3df0cb08d 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java @@ -20,7 +20,7 @@ public VriPolygon( Optional percentAvailable, Optional modeFip, Optional nonproductiveDescription, float yieldFactor ) { - super(polygonIdentifier, percentAvailable, fiz, becIdentifier, modeFip); + super(polygonIdentifier, percentAvailable, fiz, becIdentifier, modeFip, Optional.empty()); this.nonproductiveDescription = nonproductiveDescription; this.yieldFactor = yieldFactor; } diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java index ff0682e58..82e271285 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java @@ -52,7 +52,7 @@ protected VriSpecies doBuild() { this.genus.get(), // this.genusIndex.get(), // this.percentGenus.get(), // - new Sp64DistributionSet(this.sp64DistributionList), // + this.sp64DistributionSet.get(), // this.site ); } diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java index b6a968d73..4e2901111 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java @@ -29,7 +29,6 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -38,6 +37,7 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; From 9c001b2a023a5115833fed7872896bbbef844cd3 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 16 Aug 2024 14:30:46 -0700 Subject: [PATCH 35/66] Merge out from main; complete refactoring out the now unneeded array of banks --- .../nrs/vdyp/common/EstimationMethods.java | 789 ++++++------------ .../CachingResolvedControlMapImpl.java | 88 +- .../vdyp/controlmap/ResolvedControlMap.java | 30 +- .../controlmap/ResolvedControlMapImpl.java | 49 +- .../vdyp/application/test/TestPolygon.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 13 +- .../bc/gov/nrs/vdyp/fip/model/FipPolygon.java | 2 +- .../vdyp/forward/ForwardProcessingEngine.java | 119 ++- .../vdyp/forward/ForwardProcessingState.java | 49 +- ...ngState.java => LayerProcessingState.java} | 35 +- .../controlmap/ForwardResolvedControlMap.java | 5 +- .../ForwardResolvedControlMapImpl.java | 7 - .../forward/parsers/VdypSpeciesParser.java | 9 +- .../GeneralForwardProcessingEngineTest.java | 73 +- .../vdyp/forward/GrowDominantHeightTest.java | 7 +- ...yVariablesForwardProcessingEngineTest.java | 286 +++---- .../bc/gov/nrs/vdyp/vri/model/VriPolygon.java | 2 +- 17 files changed, 698 insertions(+), 867 deletions(-) rename vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/{PolygonProcessingState.java => LayerProcessingState.java} (94%) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index 2030e7823..c8b77a28f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -19,15 +19,14 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.application.StandProcessingException; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.io.parse.coe.GenusDefinitionParser; -import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMap; +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.Coefficients; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; -import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationVector; @@ -38,6 +37,14 @@ public class EstimationMethods { public static final Logger log = LoggerFactory.getLogger(EstimationMethods.class); + public static final float EMPIRICAL_OCCUPANCY = 0.85f; + + ResolvedControlMap controlMap; + + public EstimationMethods(ResolvedControlMap controlMap) { + this.controlMap = controlMap; + } + /** * Returns the new value if the index is that of a utilization class that represents a size band, otherwise the old * value @@ -53,18 +60,10 @@ public class EstimationMethods { oldX, newX, uc ) -> UtilizationClass.ALL_BUT_SMALL.contains(uc) ? newX : oldX; - Map controlMap; - - public EstimationMethods(Map controlMap) { - this.controlMap = controlMap; - } - - private static float heightMultiplier( - Map controlMap, String genus, Region region, float treesPerHectarePrimary + private float heightMultiplier( + String genus, Region region, float treesPerHectarePrimary ) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class - ); + final var coeMap = controlMap.getHl1Coefficients(); var coe = coeMap.get(genus, region).reindex(0); return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); } @@ -76,27 +75,12 @@ private static float heightMultiplier( * @param genus Primary species * @param region Region of the polygon * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return - */ - public float - primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { - return primaryHeightFromLeadHeight(controlMap, leadHeight, genus, region, treesPerHectarePrimary); - } - - /** - * EMP050 Method 1: Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param controlMap Control map containing coefficients - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - * @return + * @return as described */ - public static float primaryHeightFromLeadHeight( - Map controlMap, float leadHeight, String genus, Region region, float treesPerHectarePrimary + public float primaryHeightFromLeadHeight( + float leadHeight, String genus, Region region, float treesPerHectarePrimary ) { - return 1.3f + (leadHeight - 1.3f) * heightMultiplier(controlMap, genus, region, treesPerHectarePrimary); + return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); } /** @@ -110,62 +94,32 @@ public static float primaryHeightFromLeadHeight( public float leadHeightFromPrimaryHeight( float primaryHeight, String genus, Region region, float treesPerHectarePrimary ) { - return leadHeightFromPrimaryHeight(controlMap, primaryHeight, genus, region, treesPerHectarePrimary); - } - - /** - * EMP050 Method 2: Return the dominant height of the lead species based on the lorey height of the primary species. - * - * @param controlMap Control map containing coefficients - * @param primaryHeight lorey height of the primary species - * @param genus Primary species - * @param region Region of the polygon - * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species - */ - public static float leadHeightFromPrimaryHeight( - Map controlMap, float primaryHeight, String genus, Region region, - float treesPerHectarePrimary - ) { - return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(controlMap, genus, region, treesPerHectarePrimary); - } - - /** - * EMP051 Return the lorey height of the primary species based on the dominant height of the lead species. - * - * @param leadHeight dominant height of the lead species - * @param genus Primary species - * @param region Region of the polygon - */ - public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { - return primaryHeightFromLeadHeightInitial(controlMap, leadHeight, genus, region); + return 1.3f + (primaryHeight - 1.3f) / heightMultiplier(genus, region, treesPerHectarePrimary); } /** - * EMP051 Return the lorey height of the primary species based on the dominant height of the lead species. + * EMP051. Return the lorey height of the primary species based on the dominant height of the lead species. * - * @param controlMap Control map containing coefficients * @param leadHeight dominant height of the lead species * @param genus Primary species * @param region Region of the polygon */ public float primaryHeightFromLeadHeightInitial( - Map controlMap, float leadHeight, String genus, Region region + float leadHeight, String genus, Region region ) { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class - ); + final var coeMap = controlMap.getHl2Coefficients(); var coe = coeMap.get(genus, region); return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); } /** - * EMP053 Estimate the lorey height of a non-primary species of a primary layer. + * EMP053. Estimate the lorey height of a non-primary species of a primary layer. *

    * Using eqns N1 and N2 from ipsjf124.doc * - * * @param vspec The species. * @param vspecPrime The primary species. + * @param bec The BEC zone containing the species. * @param leadHeight lead height of the layer * @param primaryHeight height of the primary species * @throws ProcessingException @@ -178,12 +132,13 @@ public float estimateNonPrimaryLoreyHeight( } /** - * EMP053 Estimate the lorey height of a non-primary species of a primary layer. + * EMP053. Estimate the lorey height of a non-primary species of a primary layer. *

    * Using eqns N1 and N2 from ipsjf124.doc * * @param vspec The species. * @param vspecPrime The primary species. + * @param bec The BEC zone containing the species. * @param leadHeight lead height of the layer * @param primaryHeight height of the primary species * @throws ProcessingException @@ -191,9 +146,7 @@ public float estimateNonPrimaryLoreyHeight( public float estimateNonPrimaryLoreyHeight( String vspec, String vspecPrime, BecDefinition bec, float leadHeight, float primaryHeight ) throws ProcessingException { - var coeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.HL_NONPRIMARY, MatrixMap3.class - ); + var coeMap = controlMap.getHlNonPrimaryCoefficients(); var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( () -> new ProcessingException( @@ -207,9 +160,8 @@ public float estimateNonPrimaryLoreyHeight( return 1.3f + coe.getCoe(1) * pow(heightToUse - 1.3f, coe.getCoe(2)); } - // EMP060 /** - * Estimate DQ for a species (primary or not). Using eqn in jf125.doc. + * EMP060. Estimate DQ for a species (primary or not). Using eqn in jf125.doc. * * Enforces mins and maxes from EMP061. * @@ -220,7 +172,7 @@ public float estimateNonPrimaryLoreyHeight( * @param standBaseArea Base area of the stand * @param standTreesPerHectare Density opf the stand * @param standLoreyHeight Lorey height of the stand - * @return Quadratic mean diameter of the species of interest + * @return quadratic mean diameter of the species of interest * @throws ProcessingException */ public float estimateQuadMeanDiameterForSpecies( @@ -232,71 +184,102 @@ public float estimateQuadMeanDiameterForSpecies( float standTreesPerHectare, // TPH_TOT float standLoreyHeight // HL_TOT ) throws ProcessingException { - String species = spec.getGenus(); + Map basalAreaFractionPerSpecies = new HashMap<>(); + allSpecies.values().stream().forEach(s -> basalAreaFractionPerSpecies.put(s.getGenus(), s.getFractionGenus())); + + return estimateQuadMeanDiameterForSpecies( + spec.getGenus(), spec.getLoreyHeightByUtilization().get( + UtilizationClass.ALL + ), spec.getQuadraticMeanDiameterByUtilization().get( + UtilizationClass.ALL + ), basalAreaFractionPerSpecies, region, standQuadMeanDiameter, standBaseArea, standTreesPerHectare, standLoreyHeight + ); + } + + /** + * EMP060. Estimate DQ for a species (primary or not). Using equations from jf125.doc. + * + * Enforces mins and maxes from EMP061. + * + * @param spAlias The alias of the species + * @param spLoreyHeight The lorey height (all utilizations) of the species + * @param spQuadMeanDiameter The quad-mean-diameter (all utilizations) of the species + * @param basalAreaFractionPerSpecies Basal area fractions of the per species in the stand + * @param region BEC Region of the stand + * @param standQuadMeanDiameter Quadratic mean diameter of the stand + * @param standBaseArea Base area of the stand + * @param standTreesPerHectare Density opf the stand + * @param standLoreyHeight Lorey height of the stand + * @return quadratic mean diameter of the species of interest + * @throws ProcessingException + */ + public float estimateQuadMeanDiameterForSpecies( + String spAlias, + float spLoreyHeight, // HLsp + float spQuadMeanDiameter, // DQsp + Map basalAreaFractionPerSpecies, // FR + Region region, // INDEX_IC + float standQuadMeanDiameter, // DQ_TOT + float standBaseArea, // BA_TOT + float standTreesPerHectare, // TPH_TOT + float standLoreyHeight // HL_TOT + ) throws ProcessingException { float c = 0.00441786467f; float minQuadMeanDiameter = min(7.6f, standQuadMeanDiameter); + Float spFraction = basalAreaFractionPerSpecies.get(spAlias); + // Quick solution - if (spec.getFractionGenus() >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { + if (spFraction >= 1f || standQuadMeanDiameter < minQuadMeanDiameter) { return standQuadMeanDiameter; } - var coeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BY_SPECIES_DQ, Map.class); - var specAliases = GenusDefinitionParser.getSpeciesAliases(controlMap); - - // TODO we can probably remove these as they seem to only be used for debugging - // in VDYP7 - Map adjust = new HashMap<>(coeMap.size()); - Map mult = new HashMap<>(coeMap.size()); + var coeMap = controlMap.getQuadMeanDiameterBySpeciesCoefficients(); + var specAliases = controlMap.getGenusDefinitionMap().getAllGeneraAliases(); var specIt = specAliases.iterator(); - var spec1 = specIt.next(); float a2 = coeMap.get(spec1).getCoe(2); - float fractionOther = 1f - spec.getFractionGenus(); // FR_REST + float fractionOther = 1f - spFraction; // FR_REST - mult.put(spec1, 1f); float a0 = coeMap.get(spec1).getCoe(0); float a1 = coeMap.get(spec1).getCoe(1); while (specIt.hasNext()) { var specIAlias = specIt.next(); - var specI = allSpecies.get(specIAlias); - if (specIAlias.equals(spec.getGenus())) { + if (spAlias.equals(specIAlias)) { float multI = 1f; - mult.put(specIAlias, multI); a0 += multI * coeMap.get(specIAlias).getCoe(0); a1 += multI * coeMap.get(specIAlias).getCoe(1); } else { - if (specI != null && specI.getFractionGenus() > 0f) { - float multI = -specI.getFractionGenus() / fractionOther; - mult.put(specIAlias, multI); + float spIFraction = basalAreaFractionPerSpecies.get(specIAlias); + if (spIFraction > 0f) { + float multI = -spIFraction / fractionOther; a0 += multI * coeMap.get(specIAlias).getCoe(0); a1 -= multI * coeMap.get(specIAlias).getCoe(1); } } } - float loreyHeightSpec = spec.getLoreyHeightByUtilization().getCoe(UtilizationClass.ALL.index); + float loreyHeightSpec = spLoreyHeight; float loreyHeight1 = max(4f, loreyHeightSpec); - float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spec.getFractionGenus()) / fractionOther; + float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spFraction) / fractionOther; float loreyHeightRatio = clamp( (loreyHeight1 - 3f) / (loreyHeight2 - 3f), 0.05f, 20f); float r = exp( - a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) + adjust.getOrDefault(species, 0f) + a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) ); - float baseArea1 = spec.getFractionGenus() * standBaseArea; + float baseArea1 = spFraction * standBaseArea; float baseArea2 = standBaseArea - baseArea1; float treesPerHectare1; if (abs(r - 1f) < 0.0005) { - treesPerHectare1 = spec.getFractionGenus() * standTreesPerHectare; + treesPerHectare1 = spFraction * standTreesPerHectare; } else { float aa = (r - 1f) * c; float bb = c * (1f - r) * standTreesPerHectare + baseArea1 + baseArea2 * r; @@ -305,13 +288,13 @@ public float estimateQuadMeanDiameterForSpecies( if (term <= 0f) { throw new ProcessingException( "Term for trees per hectare calculation when estimating quadratic mean diameter for species " - + species + " was " + term + " but should be positive." + + spAlias + " was " + term + " but should be positive." ); } treesPerHectare1 = (-bb + sqrt(term)) / (2f * aa); if (treesPerHectare1 <= 0f || treesPerHectare1 > standTreesPerHectare) { throw new ProcessingException( - "Trees per hectare 1 for species " + species + " was " + treesPerHectare1 + "Trees per hectare 1 for species " + spAlias + " was " + treesPerHectare1 + " but should be positive and less than or equal to stand trees per hectare " + standTreesPerHectare ); @@ -321,7 +304,7 @@ public float estimateQuadMeanDiameterForSpecies( float quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); float treesPerHectare2 = standTreesPerHectare - treesPerHectare1; float quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); - var limits = getLimitsForHeightAndDiameter(species, region); + var limits = getLimitsForHeightAndDiameter(spAlias, region); quadMeanDiameter1 = estimateQuadMeanDiameterClampResult( limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 @@ -330,7 +313,7 @@ public float estimateQuadMeanDiameterForSpecies( } float estimateQuadMeanDiameterClampResult( - Limits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, + ComponentSizeLimits limits, float standTreesPerHectare, float minQuadMeanDiameter, float loreyHeightSpec, float baseArea1, float baseArea2, float quadMeanDiameter1, float treesPerHectare2, float quadMeanDiameter2 ) { float treesPerHectare1; @@ -342,9 +325,9 @@ float estimateQuadMeanDiameterClampResult( quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); } - final float dqMinSp = max(minQuadMeanDiameter, limits.minDiameterHeight() * loreyHeightSpec); + final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); final float dqMaxSp = max( - 7.6f, min(limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() * loreyHeightSpec) + 7.6f, min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) ); if (quadMeanDiameter1 < dqMinSp) { quadMeanDiameter1 = dqMinSp; @@ -377,74 +360,35 @@ float estimateQuadMeanDiameterClampResult( return quadMeanDiameter1; } - public static record Limits( - float maxLoreyHeight, float maxQuadMeanDiameter, float minDiameterHeight, float maxDiameterHeight - ) { - }; - - // EMP061 - public Limits getLimitsForHeightAndDiameter(String genus, Region region) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class - ); - - var coe = coeMap.get(genus, region); - return new Limits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); - } - /** - * EMP070. Estimate basal area by utilization class from the given parameters, after getting the estimation - * coefficients map from the control map. - * - * @param bec - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException + * EMP061. Return a ComponentSizeLimits instance for the given sp0 and region. + * + * @param sp0 the SP0 species + * @param region the region + * @return as described */ - public void estimateBaseAreaByUtilization( - BecDefinition bec, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus - ) throws ProcessingException { + public ComponentSizeLimits getLimitsForHeightAndDiameter(String sp0, Region region) { + var coeMap = controlMap.getComponentSizeLimitCoefficients(); - estimateBaseAreaByUtilization(controlMap, bec, quadMeanDiameterUtil, baseAreaUtil, genus); + var coe = coeMap.get(sp0, region); + return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); } /** - * EMP070. Estimate basal area by utilization class from the given parameters, after getting the estimation - * coefficients map from the control map. + * EMP070. Estimate basal area by utilization class from the given parameters, after getting + * the estimation coefficients map from the control map. * - * @param controlMap * @param bec * @param quadMeanDiameterUtil * @param baseAreaUtil * @param genus * @throws ProcessingException */ - public static void estimateBaseAreaByUtilization( - Map controlMap, BecDefinition bec, UtilizationVector quadMeanDiameterUtil, - UtilizationVector baseAreaUtil, String genus + public void estimateBaseAreaByUtilization( + BecDefinition bec, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus ) throws ProcessingException { - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_BA, MatrixMap3.class - ); - - estimateBaseAreaByUtilization(bec, coeMap, quadMeanDiameterUtil, baseAreaUtil, genus); - } - /** - * EMP070: estimate basal area by utilization class from the given parameters - * - * @param bec - * @param basalAreaUtilCompCoeMap - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateBaseAreaByUtilization( - BecDefinition bec, MatrixMap3 basalAreaUtilCompCoeMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, String genus - ) throws ProcessingException { + var basalAreaUtilCompCoeMap = controlMap.getBasalAreaDiameterUtilizationComponentMap(); float dq = quadMeanDiameterUtil.getAll(); var b = Utils.utilizationVector(); @@ -478,7 +422,7 @@ public static void estimateBaseAreaByUtilization( } /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. + * EMP071. Estimate DQ by utilization class. See ipsjf120.doc. * * @param bec * @param quadMeanDiameterUtil @@ -488,46 +432,11 @@ public static void estimateBaseAreaByUtilization( public void estimateQuadMeanDiameterByUtilization( BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus ) throws ProcessingException { - - estimateQuadMeanDiameterByUtilization(controlMap, bec, quadMeanDiameterUtil, genus); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param controlMap - * @param bec - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateQuadMeanDiameterByUtilization( - Map controlMap, BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus - ) throws ProcessingException { - - final var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_DQ, MatrixMap3.class - ); - - estimateQuadMeanDiameterByUtilization(bec, coeMap, quadMeanDiameterUtil, genus); - } - - /** - * EMP071. Estimate DQ by utilization class, see ipsjf120.doc. - * - * @param bec - * @param coeMap - * @param quadMeanDiameterUtil - * @param genus - * @throws ProcessingException - */ - public static void estimateQuadMeanDiameterByUtilization( - BecDefinition bec, MatrixMap3 coeMap, - UtilizationVector quadMeanDiameterUtil, String genus - ) throws ProcessingException { log.atTrace().setMessage("Estimate DQ by utilization class for {} in BEC {}. DQ for all >7.5 is {}") .addArgument(genus).addArgument(bec.getName()).addArgument(quadMeanDiameterUtil.getAll()); + var coeMap = controlMap.getQuadMeanDiameterUtilizationComponentMap(); + float quadMeanDiameter07 = quadMeanDiameterUtil.getAll(); for (var uc : UtilizationClass.UTIL_CLASSES) { @@ -591,59 +500,21 @@ public static void estimateQuadMeanDiameterByUtilization( () -> UtilizationClass.UTIL_CLASSES.stream() .map(uc -> String.format("%s: %d", uc.className, quadMeanDiameterUtil.getCoe(uc.index))) ); - - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { - - return estimateWholeStemVolumePerTree(controlMap, volumeGroup, loreyHeight, quadMeanDiameter); - } - - /** - * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad - * mean diameter. - * - * @param controlMap the control map from which the total stand whole stem volume equation coefficients are - * retrieved - * @param volumeGroup the species' volume group - * @param loreyHeight the species' lorey height - * @param quadMeanDiameter the species' quadratic mean diameter - * @return as described - */ - public static float estimateWholeStemVolumePerTree( - Map controlMap, int volumeGroup, float loreyHeight, float quadMeanDiameter - ) { - var coeMap = Utils.>expectParsedControl( - controlMap, ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, Map.class - ); - - return estimateWholeStemVolumePerTree(volumeGroup, loreyHeight, quadMeanDiameter, coeMap); } /** * EMP090. Return an estimate of the volume, per tree, of the whole stem, based on the given lorey height and quad * mean diameter. * - * @param controlMap the control map from which the total stand whole stem volume equation coefficients are - * retrieved * @param volumeGroup the species' volume group * @param loreyHeight the species' lorey height * @param quadMeanDiameter the species' quadratic mean diameter * @return as described */ - public static float estimateWholeStemVolumePerTree( - int volumeGroup, float loreyHeight, float quadMeanDiameter, - Map totalStandWholeStemVolumeCoeMap + public float estimateWholeStemVolumePerTree( + int volumeGroup, float loreyHeight, float quadMeanDiameter ) { + var totalStandWholeStemVolumeCoeMap = controlMap.getTotalStandWholeStepVolumeCoeMap(); var coe = totalStandWholeStemVolumeCoeMap.get(volumeGroup).reindex(0); var logMeanVolume = // @@ -660,59 +531,6 @@ public static float estimateWholeStemVolumePerTree( return exp(logMeanVolume); } - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values, getting wholeStemUtilizationComponentMap from the - * given controlMap. - * - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public void estimateWholeStemVolume( - UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, - UtilizationVector wholeStemVolumeUtil - ) throws ProcessingException { - - estimateWholeStemVolume( - controlMap, utilizationClass, adjustCloseUtil, volumeGroup, hlSp, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - } - - /** - * EMP091. Updates wholeStemVolumeUtil with estimated values, getting wholeStemUtilizationComponentMap from the - * given controlMap. - * - * @param controlMap - * @param utilizationClass - * @param adjustCloseUtil - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param baseAreaUtil - * @param wholeStemVolumeUtil - * @throws ProcessingException - */ - public static void estimateWholeStemVolume( - Map controlMap, UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, - Float hlSp, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, - UtilizationVector wholeStemVolumeUtil - ) throws ProcessingException { - final var wholeStemUtilizationComponentMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.UTIL_COMP_WS_VOLUME, MatrixMap2.class - ); - - estimateWholeStemVolume( - utilizationClass, adjustCloseUtil, volumeGroup, hlSp, wholeStemUtilizationComponentMap, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil - ); - } - /** * EMP091. Updates wholeStemVolumeUtil with estimated values. * @@ -726,12 +544,12 @@ public static void estimateWholeStemVolume( * @param wholeStemVolumeUtil * @throws ProcessingException */ - public static void estimateWholeStemVolume( + public void estimateWholeStemVolume( UtilizationClass utilizationClass, float adjustCloseUtil, int volumeGroup, Float hlSp, - MatrixMap2> wholeStemUtilizationComponentMap, UtilizationVector quadMeanDiameterUtil, UtilizationVector baseAreaUtil, UtilizationVector wholeStemVolumeUtil ) throws ProcessingException { + var wholeStemUtilizationComponentMap = controlMap.getWholeStemUtilizationComponentMap(); var dqSp = quadMeanDiameterUtil.getAll(); estimateUtilization(baseAreaUtil, wholeStemVolumeUtil, utilizationClass, (uc, ba) -> { @@ -782,57 +600,8 @@ public void estimateCloseUtilizationVolume( UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, UtilizationVector closeUtilizationVolumeUtil ) throws ProcessingException { - estimateCloseUtilizationVolume( - controlMap, utilizationClass, aAdjust, volumeGroup, hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil - ); - } - - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param controlMap - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public static void estimateCloseUtilizationVolume( - Map controlMap, UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, - float hlSp, UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, - UtilizationVector closeUtilizationVolumeUtil - ) throws ProcessingException { - final var closeUtilizationCoeMap = Utils - .>>expectParsedControl( - controlMap, ControlKey.CLOSE_UTIL_VOLUME, MatrixMap2.class - ); - estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, hlSp, closeUtilizationCoeMap, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil - ); - } - - /** - * EMP092. Updates closeUtilizationVolumeUtil with estimated values. - * - * @param utilizationClass - * @param aAdjust - * @param volumeGroup - * @param hlSp - * @param closeUtilizationCoeMap - * @param quadMeanDiameterUtil - * @param wholeStemVolumeUtil - * @param closeUtilizationVolumeUtil - * @throws ProcessingException - */ - public static void estimateCloseUtilizationVolume( - UtilizationClass utilizationClass, Coefficients aAdjust, int volumeGroup, float hlSp, - MatrixMap2> closeUtilizationCoeMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector wholeStemVolumeUtil, - UtilizationVector closeUtilizationVolumeUtil - ) throws ProcessingException { + var closeUtilizationCoeMap = controlMap.getCloseUtilizationCoeMap(); + estimateUtilization(wholeStemVolumeUtil, closeUtilizationVolumeUtil, utilizationClass, (uc, ws) -> { Coefficients closeUtilCoe = closeUtilizationCoeMap.get(uc.index, volumeGroup).orElseThrow( () -> new ProcessingException( @@ -871,69 +640,12 @@ public static void estimateCloseUtilizationVolume( */ public void estimateNetDecayVolume( String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayUtil - ) throws ProcessingException { - - estimateNetDecayVolume( - controlMap, genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil - ); - } - - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param controlMap - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @throws ProcessingException - */ - public static void estimateNetDecayVolume( - Map controlMap, String genus, Region region, UtilizationClass utilizationClass, - Coefficients aAdjust, int decayGroup, float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil - ) throws ProcessingException { - final var netDecayCoeMap = Utils.>>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY, MatrixMap2.class - ); - final var decayModifierMap = Utils.>expectParsedControl( - controlMap, ModifierParser.CONTROL_KEY_MOD301_DECAY, MatrixMap2.class - ); - estimateNetDecayVolume( - genus, region, utilizationClass, aAdjust, decayGroup, ageBreastHeight, netDecayCoeMap, decayModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil - ); - } - - /** - * EMP093. Estimate volume NET OF DECAY by (DBH) utilization classes - * - * @param genus - * @param region - * @param utilizationClass - * @param aAdjust - * @param decayGroup - * @param ageBreastHeight - * @param netDecayCoeMap - * @param decayModifierMap - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param lore // EMP053 Using eqns N1 and N2 from ipsjf124.doc yHeight - * @throws ProcessingException - */ - public static void estimateNetDecayVolume( - String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - float ageBreastHeight, MatrixMap2> netDecayCoeMap, - MatrixMap2 decayModifierMap, UtilizationVector quadMeanDiameterUtil, + float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil ) throws ProcessingException { + var netDecayCoeMap = controlMap.getNetDecayCoeMap(); + var decayModifierMap = controlMap.getDecayModifierMap(); + var dqSp = quadMeanDiameterUtil.getAll(); final var ageTr = (float) Math.log(Math.max(20.0, ageBreastHeight)); @@ -964,7 +676,7 @@ public static void estimateNetDecayVolume( storeSumUtilizationComponents(closeUtilizationNetOfDecayUtil); } } - + /** * EMP094. Estimate utilization net of decay and waste * @@ -984,67 +696,9 @@ public void estimateNetDecayAndWasteVolume( UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil ) throws ProcessingException { + final var netDecayWasteCoeMap = controlMap.getNetDecayWasteCoeMap(); + final var wasteModifierMap = controlMap.getWasteModifierMap(); - estimateNetDecayAndWasteVolume( - controlMap, region, utilizationClass, aAdjust, genus, loreyHeight, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil - ); - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param controlMap - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public static void estimateNetDecayAndWasteVolume( - Map controlMap, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, - String genus, float loreyHeight, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil, - UtilizationVector closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { - final var netDecayWasteCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - - estimateNetDecayAndWasteVolume( - region, utilizationClass, aAdjust, genus, loreyHeight, netDecayWasteCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil - ); - } - - /** - * EMP094. Estimate utilization net of decay and waste - * - * @param region - * @param utilizationClass - * @param aAdjust - * @param genus - * @param loreyHeight - * @param netDecayWasteCoeMap - * @param wasteModifierMap - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @throws ProcessingException - */ - public static void estimateNetDecayAndWasteVolume( - Region region, UtilizationClass utilizationClass, Coefficients aAdjust, String genus, float loreyHeight, - Map netDecayWasteCoeMap, MatrixMap2 wasteModifierMap, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil - ) throws ProcessingException { estimateUtilization( closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( i, netDecay @@ -1107,7 +761,6 @@ public static void estimateNetDecayAndWasteVolume( /** * EMP095. Estimate utilization net of decay, waste, and breakage * - * @param controlMap * @param utilizationClass * @param breakageGroup * @param quadMeanDiameterUtil @@ -1117,60 +770,13 @@ public static void estimateNetDecayAndWasteVolume( * @throws ProcessingException */ public void estimateNetDecayWasteAndBreakageVolume( - UtilizationClass utilizationClass, int breakageGroup, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, - UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { - - estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, breakageGroup, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil - ); - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public static void estimateNetDecayWasteAndBreakageVolume( - Map controlMap, UtilizationClass utilizationClass, int breakageGroup, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, - UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil - ) throws ProcessingException { - final var netBreakageCoeMap = Utils - .>expectParsedControl(controlMap, ControlKey.BREAKAGE, Map.class); - - estimateNetDecayWasteAndBreakageVolume( - utilizationClass, breakageGroup, netBreakageCoeMap, quadMeanDiameterUtil, closeUtilizationUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil - ); - } - - /** - * EMP095. Estimate utilization net of decay, waste, and breakage - * - * @param controlMap - * @param utilizationClass - * @param breakageGroup - * @param quadMeanDiameterUtil - * @param closeUtilizationUtil - * @param closeUtilizationNetOfDecayAndWasteUtil - * @param closeUtilizationNetOfDecayWasteAndBreakageUtil - * @throws ProcessingException - */ - public static void estimateNetDecayWasteAndBreakageVolume( - UtilizationClass utilizationClass, int breakageGroup, Map netBreakageCoeMap, + UtilizationClass utilizationClass, int breakageGroup, UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil ) throws ProcessingException { + var netBreakageCoeMap = controlMap.getNetBreakageMap(); + final var coefficients = netBreakageCoeMap.get(breakageGroup); if (coefficients == null) { throw new ProcessingException("Could not find net breakage coefficients for group " + breakageGroup); @@ -1201,6 +807,151 @@ public static 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 dominantHeight dominant height (m) + * @param breastHeightAge breast height age (years) + * @param veteranBaseArea basal area of overstory (>= 0) + * @param fullOccupancy if true, the empirically fitted curve is increased to become + * a full occupancy curve. If false, BAP is for mean conditions. + * @param basalAreaGroup index of the basal area group + * @return as described + * @throws StandProcessingException + */ + public float estimateBaseAreaYield( + Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, + float breastHeightAge, Optional veteranBasalArea, boolean fullOccupancy, int baseAreaGroup + ) throws StandProcessingException { + float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); + + // The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea + // (BATOP98): + + /* + * And one POSSIBLY one last vestige of grouping by ITG. + * + * That limit applies to full occupancy and Empirical occupancy. They were derived as the 98th percentile + * of Empirical stocking, though adjusted PSPs were included. If the ouput of this routine is bumped up + * from empirical to full, MIGHT adjust this limit DOWN here, so that at end, it is correct. Tentatively + * decide NOT to do this: + */ + +// if (fullOccupancy) { +// upperBoundsBaseArea *= EMPOC; +// } + + float ageToUse = breastHeightAge; + + if (controlVariable2Setting > 0) { + ageToUse = Math.min(ageToUse, controlVariable2Setting * 100); + } + + if (ageToUse <= 0f) { + throw new StandProcessingException("Age was not positive"); + } + + float trAge = FloatMath.log(ageToUse); + + float a0 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a1 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a2 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a3 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a4 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a5 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a6 = estimateBasalAreaYieldCoefficients.getCoe(0); + + float a00 = Math.max(a0 + a1 * trAge, 0); + float ap = Math.max(a3 + a4 * trAge, 0); + + float bap; + if (dominantHeight <= a2) { + bap = 0; + } else { + bap = a00 * FloatMath.pow(dominantHeight - a2, ap) + * FloatMath.exp(a5 * dominantHeight + a6 * veteranBasalArea.orElse(0f)); + bap = Math.min(bap, upperBoundBaseArea); + } + + if (fullOccupancy) { + bap /= EMPIRICAL_OCCUPANCY; + } + + return bap; + } + + /** + * EMP107 - estimate DQ yield for the primary layer (from IPSJF161.doc) + * + * @param coefficients coefficients weighted by species and decay bec zone + * @param controlVariable2Setting the value of control variable 2 + * @param dominantHeight dominant height (m) + * @param breastHeightAge breast height age (years) + * @param veteranBaseArea basal area of overstory (>= 0) + * @param basalAreaGroup index of the basal area group + * @return quad-mean-diameter of primary layer (with DBH >= 7.5) + * @throws StandProcessingException in the event of a processing error + */ + public float estimateQuadMeanDiameterYield( + Coefficients coefficients, int controlVariable2Setting, float dominantHeight, + float breastHeightAge, Optional veteranBaseArea, int basalAreaGroup + ) throws StandProcessingException { + + if (dominantHeight <= 5) { + return 7.6f; + } + + final float upperBoundsQuadMeanDiameter = upperBoundsQuadMeanDiameter(basalAreaGroup); + + final float ageUse = breastHeightAge; + + if (ageUse <= 0f) { + throw new StandProcessingException("Primary breast height age must be positive but was " + ageUse); + } + + final float trAge = FloatMath.log(ageUse); + + final float c0 = coefficients.getCoe(0); + final float c1 = Math.max(coefficients.getCoe(1) + coefficients.getCoe(2) * trAge, 0f); + final float c2 = Math.max(coefficients.getCoe(3) + coefficients.getCoe(4) * trAge, 0f); + + float dq = c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2); + + return FloatMath.clamp(dq, 7.6f, upperBoundsQuadMeanDiameter); + } + + /** + * @param basalAreaGroup the basal area group in question + * @return the quad-mean-diameter upper bound for the given basal area group + */ + float upperBoundsQuadMeanDiameter(int basalAreaGroup) { + return upperBounds(basalAreaGroup).getCoe(2); + } + + /** + * @param basalAreaGroup the basal area group in question + * @return the basal area upper bound for the given basal area group + */ + float upperBoundsBaseArea(int basalAreaGroup) { + return upperBounds(basalAreaGroup).getCoe(1); + } + + /** + * UPPERGEN Method 1 - return the upper bounds of basal area and quad-mean-diameter for a given + * basal area group as a list of (two) floats. + * + * @param basalAreaGroup the basal area group in question + * @return as described + */ + Coefficients upperBounds(int basalAreaGroup) { + var upperBoundsMap = controlMap.getUpperBounds(); + return Utils.optSafe(upperBoundsMap.get(basalAreaGroup)).orElseThrow( + () -> new IllegalStateException("Could not find limits for basal area group " + basalAreaGroup) + ); + } + @FunctionalInterface public static interface UtilizationProcessor { float apply(UtilizationClass utilizationClass, float inputValue) throws ProcessingException; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index bbd13edbc..a6d457a06 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -13,10 +13,11 @@ import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; -public class CachingResolvedControlMapImpl extends ResolvedControlMapImpl implements ResolvedControlMap { +public class CachingResolvedControlMapImpl implements ResolvedControlMap { final BecLookup becLookup; final GenusDefinitionMap genusDefinitionMap; @@ -39,12 +40,23 @@ public class CachingResolvedControlMapImpl extends ResolvedControlMapImpl implem final MatrixMap2 defaultEquationGroup; final MatrixMap2> equationModifierGroup; final MatrixMap2 hl1Coefficients; - + final MatrixMap2 hl2Coefficients; + final MatrixMap2 hl3Coefficients; + final MatrixMap3> hlNonPrimaryCoefficients; + final MatrixMap2 componentSizeLimitCoefficients; + final Map breakageMap; + final MatrixMap2 volumeEquationGroups; + final MatrixMap2 decayEquationGroups; + final MatrixMap2 breakageEquationGroups; + final Map quadMeanDiameterBySpeciesCoefficients; + + private final Map controlMap; + public CachingResolvedControlMapImpl(Map controlMap) { - super(controlMap); - - this.becLookup = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class); + this.controlMap = controlMap; + + this.becLookup = this.get(ControlKey.BEC_DEF, BecLookup.class); List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); this.genusDefinitionMap = new GenusDefinitionMap(genusDefinitions); @@ -66,8 +78,21 @@ public CachingResolvedControlMapImpl(Map controlMap) { this.maximumAgeBySiteCurveNumber = this.get(ControlKey.SITE_CURVE_AGE_MAX, Map.class); this.defaultEquationGroup = this.get(ControlKey.DEFAULT_EQ_NUM, MatrixMap2.class); this.hl1Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); + this.hl2Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class); + this.hl3Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P3, MatrixMap2.class); + this.hlNonPrimaryCoefficients = this.get(ControlKey.HL_NONPRIMARY, MatrixMap3.class); this.upperBounds = this.get(ControlKey.BA_DQ_UPPER_BOUNDS, Map.class); this.equationModifierGroup = this.get(ControlKey.EQN_MODIFIERS, MatrixMap2.class); + this.componentSizeLimitCoefficients = this.get(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + this.breakageMap = this.get(ControlKey.BREAKAGE, Map.class); + this.volumeEquationGroups = this.get(ControlKey.VOLUME_EQN_GROUPS, MatrixMap2.class); + this.decayEquationGroups = this.get(ControlKey.DECAY_GROUPS, MatrixMap2.class); + this.breakageEquationGroups = this.get(ControlKey.BREAKAGE_GROUPS, MatrixMap2.class); + this.quadMeanDiameterBySpeciesCoefficients = this.get(ControlKey.BY_SPECIES_DQ, Map.class); + } + + protected U get(ControlKey key, Class clazz) { + return Utils.expectParsedControl(controlMap, key, clazz); } @Override @@ -174,4 +199,57 @@ public MatrixMap2> getEquationModifierGroup( public MatrixMap2 getHl1Coefficients() { return hl1Coefficients; } + + @Override + public MatrixMap2 getHl2Coefficients() { + return hl2Coefficients; + } + + @Override + public MatrixMap2 getHl3Coefficients() { + return hl3Coefficients; + } + + @Override + public MatrixMap3> getHlNonPrimaryCoefficients() { + return hlNonPrimaryCoefficients; + } + + public Map getBreakageMap() { + return breakageMap; + } + + public Map getControlMap() { + return controlMap; + } + + @Override + public MatrixMap2 getComponentSizeLimitCoefficients() { + return componentSizeLimitCoefficients; + } + + @Override + public Map getNetBreakageMap() { + return breakageMap; + } + + @Override + public MatrixMap2 getVolumeEquationGroups() { + return volumeEquationGroups; + } + + @Override + public MatrixMap2 getDecayEquationGroups() { + return decayEquationGroups; + } + + @Override + public MatrixMap2 getBreakageEquationGroups() { + return breakageEquationGroups; + } + + @Override + public Map getQuadMeanDiameterBySpeciesCoefficients() { + return quadMeanDiameterBySpeciesCoefficients; + } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index 175b2249f..03ca26b02 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -3,17 +3,16 @@ import java.util.Map; import java.util.Optional; -import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; public interface ResolvedControlMap { - U get(ControlKey key, Class clazz); /** 9 - BEC_DEF */ BecLookup getBecLookup(); @@ -21,6 +20,15 @@ public interface ResolvedControlMap { /** 10 - SP0_DEF */ GenusDefinitionMap getGenusDefinitionMap(); + /** 20 - VOLUME_EQN_GROUPS */ + MatrixMap2 getVolumeEquationGroups(); + + /** 21 - DECAY_GROUPS */ + MatrixMap2 getDecayEquationGroups(); + + /** 22 - BREAKAGE_GROUPS */ + MatrixMap2 getBreakageEquationGroups(); + /** 26 - SITE_CURVE_AGE_MAX */ Map getMaximumAgeBySiteCurveNumber(); @@ -33,6 +41,21 @@ public interface ResolvedControlMap { /** 50 - HL_PRIMARY_SP_EQN_P1 */ MatrixMap2 getHl1Coefficients(); + /** 51 - HL_PRIMARY_SP_EQN_P2 */ + MatrixMap2 getHl2Coefficients(); + + /** 52 - HL_PRIMARY_SP_EQN_P3 */ + MatrixMap2 getHl3Coefficients(); + + /** 53 - HL_NONPRIMARY */ + MatrixMap3> getHlNonPrimaryCoefficients(); + + /** 60 - BY_SPECIES_DQ */ + Map getQuadMeanDiameterBySpeciesCoefficients(); + + /** 61 - SPECIES_COMPONENT_SIZE_LIMIT */ + MatrixMap2 getComponentSizeLimitCoefficients(); + /** 70 - UTIL_COMP_BA */ MatrixMap3 getBasalAreaDiameterUtilizationComponentMap(); @@ -69,6 +92,9 @@ public interface ResolvedControlMap { /** 94 - VOLUME_NET_DECAY_WASTE */ Map getNetDecayWasteCoeMap(); + /** 95 - BREAKAGE */ + Map getNetBreakageMap(); + /** 108 - BA_DQ_UPPER_BOUNDS */ Map getUpperBounds(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index f4653158e..99d2e0456 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -14,6 +14,7 @@ import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.model.NonprimaryHLCoefficients; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.SiteCurveAgeMaximum; @@ -28,8 +29,7 @@ public ResolvedControlMapImpl(Map controlMap) { } @SuppressWarnings("unchecked") - @Override - public U get(ControlKey key, Class clazz) { + private U get(ControlKey key, Class clazz) { U entity = (U) entityCache.get(key); if (entity == null) { @@ -145,4 +145,49 @@ public MatrixMap2> getEquationModifierGroup( public MatrixMap2 getHl1Coefficients() { return this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); } + + @Override + public MatrixMap2 getHl2Coefficients() { + return this.get(ControlKey.HL_PRIMARY_SP_EQN_P2, MatrixMap2.class); + } + + @Override + public MatrixMap2 getHl3Coefficients() { + return this.get(ControlKey.HL_PRIMARY_SP_EQN_P3, MatrixMap2.class); + } + + @Override + public MatrixMap3> getHlNonPrimaryCoefficients() { + return this.get(ControlKey.HL_NONPRIMARY, MatrixMap3.class); + } + + @Override + public MatrixMap2 getComponentSizeLimitCoefficients() { + return this.get(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + } + + @Override + public Map getNetBreakageMap() { + return this.get(ControlKey.BREAKAGE, Map.class); + } + + @Override + public MatrixMap2 getVolumeEquationGroups() { + return this.get(ControlKey.VOLUME_EQN_GROUPS, MatrixMap2.class); + } + + @Override + public MatrixMap2 getDecayEquationGroups() { + return this.get(ControlKey.DECAY_GROUPS, MatrixMap2.class); + } + + @Override + public MatrixMap2 getBreakageEquationGroups() { + return this.get(ControlKey.BREAKAGE_GROUPS, MatrixMap2.class); + } + + @Override + public Map getQuadMeanDiameterBySpeciesCoefficients() { + return this.get(ControlKey.BY_SPECIES_DQ, Map.class); + } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java index f0e3abfd3..297ea6b95 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java @@ -20,7 +20,7 @@ protected TestPolygon( PolygonIdentifier polygonIdentifier, Optional percentAvailable, String fiz, BecDefinition bec, Optional mode ) { - super(polygonIdentifier, percentAvailable, fiz, becIdentifier, mode, Optional.empty()); + super(polygonIdentifier, percentAvailable, fiz, bec, mode, Optional.empty()); } protected TestPolygon( diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index 84a686c5c..9a14b8cc3 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -46,7 +46,6 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; @@ -469,7 +468,7 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, var dqMin = limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll(); var dqMax = max( - limits.maxQuadMeanDiameter(), limits.maxDiameterHeight() + limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll() ); @@ -752,15 +751,9 @@ private void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefinit adjust.setCoe(4, volumeAdjustCoe.getCoe(4)); // EMP094 - final var netDecayCoeMap = Utils.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, Map.class - ); - final var wasteModifierMap = Utils.>expectParsedControl( - controlMap, ControlKey.WASTE_MODIFIERS, MatrixMap2.class - ); - EstimationMethods.estimateNetDecayAndWasteVolume( + estimationMethods.estimateNetDecayAndWasteVolume( bec.getRegion(), utilizationClass, adjust, vdypSpecies - .getGenus(), hlSp, netDecayCoeMap, wasteModifierMap, quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil + .getGenus(), hlSp, quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil ); if (getId().isStart()) { diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java index 12a3f6c22..aa1b8238c 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java @@ -19,7 +19,7 @@ public FipPolygon( Optional percentAvailable, Optional modeFip, Optional nonproductiveDescription, float yieldFactor ) { - super(polygonIdentifier, percentAvailable, fiz, becIdentifier, modeFip, Optional.empty()); + super(polygonIdentifier, percentAvailable, fiz, bec, modeFip, Optional.empty()); this.nonproductiveDescription = nonproductiveDescription; this.yieldFactor = yieldFactor; } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 44b8701ac..c528a2d12 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -76,15 +76,15 @@ public class ForwardProcessingEngine { private static final int UC_ALL_INDEX = UtilizationClass.ALL.ordinal(); private static final int UC_SMALL_INDEX = UtilizationClass.SMALL.ordinal(); - private static final float MIN_BASAL_AREA = 0.001f; + public static final float MIN_BASAL_AREA = 0.001f; /** π/4/10⁴ */ public static final float PI_40K = (float) (Math.PI / 40_000); /* pp */ final ForwardProcessingState fps; + public ForwardProcessingEngine(Map controlMap) { - this.fps = new ForwardProcessingState(controlMap); } @@ -144,9 +144,9 @@ public void processPolygon(VdypPolygon polygon) throws ProcessingException { */ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) throws ProcessingException { - logger.info("Starting processing of polygon {}", polygon.getPolygonIdentifier()); + logger.info("Starting processing of the primary layer of polygon {}", polygon.getPolygonIdentifier()); - fps.setPolygon(polygon); + fps.setPolygonLayer(polygon, LayerType.PRIMARY); // All of BANKCHK1 that we need validatePolygon(polygon); @@ -180,17 +180,14 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilYear) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); - Bank primaryBank = fps.getBank(0, LayerType.PRIMARY); + LayerProcessingState pps = fps.getLayerProcessingState(); + Bank primaryBank = pps.getStartBank(); Optional veteranLayer; - Optional veteranBank; if (pps.getPolygon().getLayers().containsKey(LayerType.VETERAN)){ veteranLayer = Optional.of(pps.getPolygon().getLayers().get(LayerType.VETERAN)); - veteranBank = Optional.of(fps.getBank(0, LayerType.VETERAN)); } else { veteranLayer = Optional.empty(); - veteranBank = Optional.empty(); } logger.info( @@ -205,7 +202,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // SCINXSET - note these are calculated directly from the Primary bank of instance 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { - calculateMissingSiteCurves(primaryBank, fps.fcm.getSiteCurveMap(), fps.getPolygonProcessingState()); + calculateMissingSiteCurves(primaryBank, fps.fcm.getSiteCurveMap(), fps.getLayerProcessingState()); } // VPRIME1, method == 1 @@ -238,7 +235,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // VGROW1 if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { - int startingYear = fps.getPolygonProcessingState().getPolygon().getPolygonIdentifier().getYear(); + int startingYear = fps.getLayerProcessingState().getPolygon().getPolygonIdentifier().getYear(); VdypPolygon vdypPolygon = pps.getPolygon(); @@ -248,13 +245,12 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY boolean createNewGroups = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 - && fps.getPolygonProcessingState().getNSpecies() > 1; + && fps.getLayerProcessingState().getNSpecies() > 1; - int primaryLayerTargetInstance = 2; int currentYear = startingYear; while (currentYear <= untilYear) { - primaryLayer = grow(primaryBank, currentYear, veteranBank); + primaryLayer = grow(primaryBank, currentYear, veteranLayer); // Store polygon (both primary and veteran layers) to output writeLayers(primaryLayer, veteranLayer, createNewGroups); @@ -277,10 +273,10 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY * * @throws ProcessingException */ - private Bank grow(Bank start, int currentYear, Optional veteranBank) + private VdypLayer grow(Bank start, int currentYear, Optional veteranLayer) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); VdypPolygon polygon = pps.getPolygon(); logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); @@ -311,12 +307,8 @@ private Bank grow(Bank start, int currentYear, Optional veteranBank) // Calculate change in basal area - final Optional veteranLayerBasalArea; - if (veteranBank.isPresent()) - veteranLayerBasalArea = Optional.of(veteranBank.get().basalAreas[0][UC_ALL_INDEX]); - else { - veteranLayerBasalArea = Optional.empty(); - } + final Optional veteranLayerBasalArea = + veteranLayer.flatMap((l) -> Optional.of(l.getBaseAreaByUtilization().get(UtilizationClass.ALL))); float dqStart = start.quadMeanDiameters[0][UC_ALL_INDEX]; float baStart = start.basalAreas[0][UC_ALL_INDEX]; @@ -477,7 +469,7 @@ private Bank grow(Bank start, int currentYear, Optional veteranBank) calculateSmallComponentYields(end); - return end; + return end.getUpdatedLayer(); } /** @@ -490,7 +482,7 @@ private Bank grow(Bank start, int currentYear, Optional veteranBank) */ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphChangeRate) { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); for (int i : pps.getIndices()) { @@ -534,7 +526,7 @@ private boolean growUsingPartialSpeciesDynamics( ) throws ProcessingException { boolean wasSuccessful = true; - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); if (dqDelta == 0 || baDelta == 0 || pps.getNSpecies() == 1) { @@ -597,7 +589,7 @@ private void growUsingFullSpeciesDynamics( float tphStart, float lhStart ) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); Bank end = new Bank(start, CopyMode.CopyStructure); @@ -812,7 +804,7 @@ private void growUsingFullSpeciesDynamics( */ private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region region) { - MatrixMap2 limits = fps.fcm.getComponentSizeCoefficients(); + MatrixMap2 limits = fps.fcm.getComponentSizeLimitCoefficients(); Coefficients coe = limits.get(genusAlias, region); return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); @@ -835,7 +827,7 @@ private float growQuadMeanDiameterForPrimarySpecies( float dqStart, float dqDelta, float pspDqStart, float lhStart, float pspLhStart ) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); ModelCoefficients mc = fps.fcm.getPrimarySpeciesQuadMeanDiameterGrowthCoefficients().get(pspStratumNumber); @@ -857,7 +849,7 @@ private float growQuadMeanDiameterForNonPrimarySpecies( int speciesIndex, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart ) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); String speciesName = pps.getStartBank().speciesNames[speciesIndex]; int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); @@ -925,7 +917,7 @@ private float growBasalAreaForNonPrimarySpecies( float spLhStart ) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); if (spBaStart <= 0.0f || spBaStart >= baStart) { throw new ProcessingException( @@ -991,7 +983,7 @@ private float growBasalAreaForPrimarySpecies( float pspLhStart ) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); float spToAllProportionStart = pspBaStart / baStart; if (spToAllProportionStart <= 0.999f) { @@ -1034,7 +1026,7 @@ private float growBasalAreaForPrimarySpecies( */ private void calculateSmallComponentYields(Bank end) throws ProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); float lhSum = 0.0f; @@ -1148,7 +1140,7 @@ private void growLoreyHeights( Bank end, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart ) { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); float pspLhStartEstimate = estimatePrimarySpeciesLoreyHeight(dhStart, pspTphStart); @@ -1163,7 +1155,7 @@ private void growLoreyHeights( int debugSetting8Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8); - int primarySpeciesIndex = fps.getPolygonProcessingState().getPrimarySpeciesIndex(); + int primarySpeciesIndex = fps.getLayerProcessingState().getPrimarySpeciesIndex(); if (debugSetting8Value != 2 || dhStart != dhEnd) { end.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX] = pspLhEnd; } else if (debugSetting8Value == 2) { @@ -1201,8 +1193,8 @@ private void growLoreyHeights( */ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { - String primarySpeciesAlias = fps.getPolygonProcessingState().getPrimarySpeciesAlias(); - Region polygonRegion = fps.getPolygonProcessingState().getBecZone().getRegion(); + String primarySpeciesAlias = fps.getLayerProcessingState().getPrimarySpeciesAlias(); + Region polygonRegion = fps.getLayerProcessingState().getBecZone().getRegion(); var coefficients = fps.fcm.getLoreyHeightPrimarySpeciesEquationP1Coefficients(); float a0 = coefficients.get(primarySpeciesAlias, polygonRegion).getCoe(1); @@ -1226,7 +1218,7 @@ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { private float estimateNonPrimarySpeciesLoreyHeight( int speciesIndex, float dh, float pspLoreyHeight ) { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); float spLh; @@ -1279,7 +1271,7 @@ float growQuadMeanDiameter( ) throws StandProcessingException { - var pps = fps.getPolygonProcessingState(); + var pps = fps.getLayerProcessingState(); var becZone = pps.getBecZone(); float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); @@ -1297,7 +1289,7 @@ float growQuadMeanDiameter( coefficientsWeightedBySpeciesAndDecayBec.setCoe(i, sum); } - int controlVariable2Value = fps.fcm.get(ControlKey.VTROL, ForwardControlVariables.class) + int controlVariable2Value = fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float dqYieldStart = fps.estimators.estimateQuadMeanDiameterYield( @@ -1404,7 +1396,7 @@ private float calculateQuadMeanDiameterGrowthEmpirical( var dqGrowthEmpiricalCoefficients = fps.fcm.getQuadMeanDiameterGrowthEmpiricalCoefficients(); - Integer stratumNumber = fps.getPolygonProcessingState().getPrimarySpeciesStratumNumber(); + Integer stratumNumber = fps.getLayerProcessingState().getPrimarySpeciesStratumNumber(); var firstSpeciesDqGrowthCoe = dqGrowthEmpiricalCoefficients.get(stratumNumber); float a0 = firstSpeciesDqGrowthCoe.get(0); @@ -1452,7 +1444,7 @@ private float calculateQuadMeanDiameterGrowthEmpirical( private float[] getSpeciesProportionsByBasalArea() { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; @@ -1482,13 +1474,13 @@ float growBasalArea( float baStart, Optional veteranLayerBa, float dhDelta ) throws StandProcessingException { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); - var becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); + var becZoneAlias = fps.getLayerProcessingState().getBecZone().getAlias(); Coefficients estimateBasalAreaYieldCoefficients = Coefficients.empty(7, 0); for (int i = 0; i < 7; i++) { float sum = 0.0f; @@ -1504,9 +1496,8 @@ float growBasalArea( } boolean isFullOccupancy = true; - int pspGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); - int controlVariable2Value = fps.fcm.get(ControlKey.VTROL, ForwardControlVariables.class) - .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); + int pspGroupNumber = fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(); + int controlVariable2Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, pspGroupNumber @@ -1520,7 +1511,7 @@ float growBasalArea( ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() - .get(fps.getPolygonProcessingState().getBecZone().getRegion()); + .get(fps.getLayerProcessingState().getBecZone().getRegion()); var convergenceCoefficient = growthFaitDetails.calculateCoefficient(pspYabhStart); @@ -1604,7 +1595,7 @@ private float calculateBasalAreaGrowthEmpirical( var basalAreaGrowthEmpiricalCoefficients = fps.fcm.getBasalAreaGrowthEmpiricalCoefficients(); - String becZoneAlias = fps.getPolygonProcessingState().getBecZone().getAlias(); + String becZoneAlias = fps.getLayerProcessingState().getBecZone().getAlias(); String firstSpecies = fps.fcm.getGenusDefinitionMap().getByIndex(1).getAlias(); var firstSpeciesBaGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, firstSpecies); @@ -1617,8 +1608,8 @@ private float calculateBasalAreaGrowthEmpirical( float b6 = firstSpeciesBaGrowthCoe.get(6); float b7 = firstSpeciesBaGrowthCoe.get(7); - for (int i = 1; i <= fps.getPolygonProcessingState().getNSpecies(); i++) { - String speciesAlias = fps.getPolygonProcessingState().getStartBank().speciesNames[i]; + for (int i = 1; i <= fps.getLayerProcessingState().getNSpecies(); i++) { + String speciesAlias = fps.getLayerProcessingState().getStartBank().speciesNames[i]; var baGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, speciesAlias); b4 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(4); b5 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(5); @@ -1663,7 +1654,7 @@ private float calculateBasalAreaGrowthEmpirical( */ private float growBasalAreaUpperBound() { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); @@ -1684,7 +1675,7 @@ private float growBasalAreaUpperBound() { */ private float growQuadraticMeanDiameterUpperBound() { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); @@ -1696,7 +1687,7 @@ private float growQuadraticMeanDiameterUpperBound() { return upperBoundsCoefficients .get(region, pps.getStartBank().speciesNames[primarySpeciesIndex], 2); } else { - var primarySpeciesGroupNumber = fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(); + var primarySpeciesGroupNumber = fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); } } @@ -1718,7 +1709,7 @@ float growDominantHeight( ) throws ProcessingException { SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); - Region region = fps.getPolygonProcessingState().getStartBank().getBecZone().getRegion(); + Region region = fps.getLayerProcessingState().getStartBank().getBecZone().getRegion(); if (siteCurveNumber == VdypEntity.MISSING_INTEGER_VALUE) { throw new ProcessingException("No SiteCurveNumber supplied"); @@ -1919,7 +1910,7 @@ void setCompatibilityVariables() throws ProcessingException { Coefficients aAdjust = new Coefficients(new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, 1); var growthDetails = fps.fcm.getForwardControlVariables(); - var pps = fps.getPolygonProcessingState(); + var pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); // Note: L1COM2 (INL1VGRP, INL1DGRP, INL1BGRP) is initialized when @@ -2124,7 +2115,7 @@ void setCompatibilityVariables() throws ProcessingException { calculateSmallCompatibilityVariables(int speciesIndex, ForwardControlVariables forwardControlVariables) throws ProcessingException { - var pps = fps.getPolygonProcessingState(); + var pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); Region region = pps.getBecZone().getRegion(); @@ -2204,7 +2195,7 @@ void setCompatibilityVariables() throws ProcessingException { private float smallComponentProbability( String speciesName, float loreyHeight, Region region ) { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Coefficients coe = fps.fcm.getSmallComponentProbabilityCoefficients().get(speciesName); @@ -2353,7 +2344,7 @@ private static float calculateWholeStemVolume(float actualVolume, float basalAre * @throws ProcessingException */ static void calculateDominantHeightAgeSiteIndex( - PolygonProcessingState pps, MatrixMap2 hl1Coefficients + LayerProcessingState pps, MatrixMap2 hl1Coefficients ) throws ProcessingException { Bank startBank = pps.getStartBank(); @@ -2472,7 +2463,7 @@ static void calculateDominantHeightAgeSiteIndex( * * @param pps the current state of the processing of the polygon */ - static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState pps) { + static void estimateMissingYearsToBreastHeightValues(LayerProcessingState pps) { Bank start = pps.getStartBank(); @@ -2534,7 +2525,7 @@ static void estimateMissingYearsToBreastHeightValues(PolygonProcessingState pps) * @param pps the bank in which the calculations are done. * @throws ProcessingException */ - static void estimateMissingSiteIndices(PolygonProcessingState pps) throws ProcessingException { + static void estimateMissingSiteIndices(LayerProcessingState pps) throws ProcessingException { Bank start = pps.getStartBank(); @@ -2635,7 +2626,7 @@ static void estimateMissingSiteIndices(PolygonProcessingState pps) throws Proces */ void calculateCoverages() { - PolygonProcessingState pps = this.fps.getPolygonProcessingState(); + LayerProcessingState pps = this.fps.getLayerProcessingState(); Bank start = pps.getStartBank(); logger.atDebug().addArgument(pps.getNSpecies()).addArgument(start.basalAreas[0][0]).log( @@ -2664,7 +2655,7 @@ void calculateCoverages() { * @param pps the PolygonProcessingState to where the calculated curves are also to be */ static void calculateMissingSiteCurves( - Bank bank, MatrixMap2 siteCurveMap, PolygonProcessingState pps + Bank bank, MatrixMap2 siteCurveMap, LayerProcessingState pps ) { BecDefinition becZone = bank.getBecZone(); @@ -2726,7 +2717,7 @@ private static void validatePolygon(VdypPolygon polygon) throws ProcessingExcept } } - private static void stopIfNoWork(PolygonProcessingState pps) throws ProcessingException { + private static void stopIfNoWork(LayerProcessingState pps) throws ProcessingException { // The following is extracted from BANKCHK1, simplified for the parameters // METH_CHK = 4, LayerI = 1, and INSTANCE = 1. So IR = 1, which is the first @@ -2764,7 +2755,7 @@ private static void stopIfNoWork(PolygonProcessingState pps) throws ProcessingEx */ void determinePolygonRankings(Collection> speciesToCombine) { - PolygonProcessingState pps = fps.getPolygonProcessingState(); + LayerProcessingState pps = fps.getLayerProcessingState(); Bank start = pps.getStartBank(); if (pps.getNSpecies() == 0) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 4b90b97c4..36c8e8abe 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -1,6 +1,5 @@ package ca.bc.gov.nrs.vdyp.forward; -import java.text.MessageFormat; import java.util.Map; import ca.bc.gov.nrs.vdyp.application.ProcessingException; @@ -9,20 +8,11 @@ import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; -import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; class ForwardProcessingState { - /** An "instance" is the processing state of one polygon */ - private static final int LAYERS_PER_INSTANCE = 2; - - /** An "instance" is the processing state of one polygon */ - @SuppressWarnings("unused") - private static final int MAX_INSTANCES = 3; - /** The control map defining the context of the execution */ final ForwardResolvedControlMap fcm; @@ -32,52 +22,21 @@ class ForwardProcessingState { /** The compuation instance used by this engine */ final ComputationMethods computers; - /** The storage banks */ - private final Bank[/* instances */][/* layers of instance */] banks; - /** The active state */ - private PolygonProcessingState pps; + private LayerProcessingState pps; public ForwardProcessingState(Map controlMap) { - banks = new Bank[][] { new Bank[LAYERS_PER_INSTANCE], new Bank[LAYERS_PER_INSTANCE], - new Bank[LAYERS_PER_INSTANCE] }; - this.fcm = new ForwardResolvedControlMapImpl(controlMap); this.estimators = new EstimationMethods(this.fcm); this.computers = new ComputationMethods(estimators, VdypApplicationIdentifier.VDYP_FORWARD); } - private static final float MIN_BASAL_AREA = 0.001f; - - public void setPolygon(VdypPolygon polygon) throws ProcessingException { - - BecDefinition becZone = polygon.getBiogeoclimaticZone(); - - // Move the primary layer of the given polygon to bank zero. - Bank primaryBank = banks[0][LayerType.PRIMARY.getIndex()] = new Bank( - polygon.getLayers().get(LayerType.PRIMARY), becZone, - s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= MIN_BASAL_AREA); + public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { - banks[0][LayerType.VETERAN.getIndex()] = new Bank( - polygon.getLayers().get(LayerType.VETERAN), becZone, - s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= MIN_BASAL_AREA); - - pps = new PolygonProcessingState(this, polygon, primaryBank); + pps = new LayerProcessingState(this, polygon, subjectLayer); } - public PolygonProcessingState getPolygonProcessingState() { + public LayerProcessingState getLayerProcessingState() { return pps; } - - public void storeActive(Bank end, int instanceNumber, LayerType layerType) { - banks[instanceNumber][layerType.getIndex()] = end.copy(); - } - - public void transfer(int fromInstanceNumber, int toInstanceNumber, LayerType layerType) { - banks[toInstanceNumber][layerType.getIndex()] = banks[fromInstanceNumber][layerType.getIndex()].copy(); - } - - public Bank getBank(int instanceNumber, LayerType layerType) { - return banks[instanceNumber][layerType.getIndex()]; - } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java similarity index 94% rename from vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 2e48d9932..307e7bff8 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -7,7 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; @@ -19,7 +19,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; -class PolygonProcessingState { +class LayerProcessingState { private static final String COMPATIBILITY_VARIABLES_SET_CAN_BE_SET_ONCE_ONLY = "CompatibilityVariablesSet can be set once only"; private static final String PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY = "PrimarySpeciesDetails can be set once only"; @@ -35,19 +35,19 @@ class PolygonProcessingState { private static final String UNSET_SITE_CURVE_NUMBERS = "unset siteCurveNumbers"; private static final String UNSET_INVENTORY_TYPE_GROUP = "unset inventoryTypeGroup"; - private static final Logger logger = LoggerFactory.getLogger(PolygonProcessingState.class); + private static final Logger logger = LoggerFactory.getLogger(LayerProcessingState.class); /** The containing ForwardProcessingState */ private final ForwardProcessingState fps; - /** Polygon on which the processor is operating */ + /** The containing polygon of the layer on which the Processor is operating */ private final VdypPolygon polygon; // L1COM1, L1COM4 and L1COM5 - these common blocks mirror BANK1, BANK2 and BANK3 and are initialized // when copied to "active" in ForwardProcessingEngine. /** - * State of the polygon at the start of processing; read-write during preparation for grow + * State of the layer at the start of processing; read-write during preparation for grow * and read-only after that. */ private Bank start; @@ -111,23 +111,20 @@ class PolygonProcessingState { // MNSP - MSPL1, MSPLV // TODO - public PolygonProcessingState( - ForwardProcessingState fps, VdypPolygon polygon, Bank bank - ) { + public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { this.fps = fps; this.polygon = polygon; - this.start = bank.copy(); - - var volumeEquationGroupMatrix = this.fps.fcm.>get( - ControlKey.VOLUME_EQN_GROUPS, MatrixMap2.class - ); - var decayEquationGroupMatrix = this.fps.fcm.>get( - ControlKey.DECAY_GROUPS, MatrixMap2.class - ); - var breakageEquationGroupMatrix = this.fps.fcm.>get( - ControlKey.BREAKAGE_GROUPS, MatrixMap2.class - ); + + BecDefinition becZone = polygon.getBiogeoclimaticZone(); + + this.start = new Bank( + polygon.getLayers().get(subjectLayer), becZone, + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= ForwardProcessingEngine.MIN_BASAL_AREA); + + var volumeEquationGroupMatrix = this.fps.fcm.getVolumeEquationGroups(); + var decayEquationGroupMatrix = this.fps.fcm.getDecayEquationGroups(); + var breakageEquationGroupMatrix = this.fps.fcm.getBreakageEquationGroups(); this.volumeEquationGroups = new int[this.start.getNSpecies() + 1]; this.decayEquationGroups = new int[this.start.getNSpecies() + 1]; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index 3b59e0611..b1782f3be 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -32,10 +32,7 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 53 - HL_NONPRIMARY */ MatrixMap3> getLoreyHeightNonPrimaryCoefficients(); - - /** 61 - SPECIES_COMPONENT_SIZE_LIMIT */ - MatrixMap2 getComponentSizeCoefficients(); - + /** 101 - VTROL */ ForwardControlVariables getForwardControlVariables(); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index 5af3ea2a8..abe43c41c 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -39,7 +39,6 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl final MatrixMap2> nonPrimarySpeciesBasalAreaGrowthCoefficients; final Map primaryQuadMeanDiameterGrowthCoefficients; final MatrixMap2> nonPrimaryQuadMeanDiameterGrowthCoefficients; - final MatrixMap2 componentSizeCoefficients; public ForwardResolvedControlMapImpl(Map controlMap) { @@ -63,7 +62,6 @@ public ForwardResolvedControlMapImpl(Map controlMap) { this.nonPrimarySpeciesBasalAreaGrowthCoefficients = this.get(ControlKey.NON_PRIMARY_SP_BA_GROWTH, MatrixMap2.class); this.primaryQuadMeanDiameterGrowthCoefficients = this.get(ControlKey.PRIMARY_SP_DQ_GROWTH, Map.class); this.nonPrimaryQuadMeanDiameterGrowthCoefficients = this.get(ControlKey.NON_PRIMARY_SP_DQ_GROWTH, MatrixMap2.class); - this.componentSizeCoefficients = this.get(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); } @Override @@ -155,9 +153,4 @@ public Map getPrimarySpeciesQuadMeanDiameterGrowthCo public MatrixMap2> getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() { return nonPrimaryQuadMeanDiameterGrowthCoefficients; } - - @Override - public MatrixMap2 getComponentSizeCoefficients() { - return this.componentSizeCoefficients; - } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 289d2d765..95b4271dd 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -58,7 +58,7 @@ public ControlKey getControlKey() { @Override public StreamingParserFactory> - map(String fileName, FileResolver fileResolver, Map control) + map(String fileName, FileResolver fileResolver, Map controlMap) throws IOException, ResourceParseException { return () -> { var lineParser = new LineParser().strippedString(25, DESCRIPTION).space(1) @@ -91,10 +91,10 @@ public ControlKey getControlKey() { var is = fileResolver.resolveForInput(fileName); - var genusDefinitionMap = (GenusDefinitionMap) control.get(ControlKey.SP0_DEF.name()); + var genusDefinitionMap = (GenusDefinitionMap) controlMap.get(ControlKey.SP0_DEF.name()); var delegateStream = new AbstractStreamingParser, EndOfRecord>>( - is, lineParser, control + is, lineParser, controlMap ) { @SuppressWarnings("unchecked") @Override @@ -159,8 +159,7 @@ protected ValueOrMarker, EndOfRecord> convert(Map { siteBuilder.ageTotal(totalAge); siteBuilder.height(dominantHeight); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index 73d235ba8..584a0d74b 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -27,6 +27,7 @@ import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.CommonData; +import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2Impl; import ca.bc.gov.nrs.vdyp.model.Region; import ca.bc.gov.nrs.vdyp.model.VdypEntity; @@ -68,9 +69,9 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - fpe.fps.setPolygon(polygon); + fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); - PolygonProcessingState pps = fpe.fps.getPolygonProcessingState(); + LayerProcessingState pps = fpe.fps.getLayerProcessingState(); fpe.calculateCoverages(); fpe.determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); @@ -83,8 +84,8 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces } { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - fpe.fps.setPolygon(polygon); - PolygonProcessingState pps = fpe.fps.getPolygonProcessingState(); + fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); + LayerProcessingState pps = fpe.fps.getLayerProcessingState(); var speciesToCombine = Arrays.asList(Arrays.asList(pps.getStartBank().speciesNames[3], pps.getStartBank().speciesNames[4])); @@ -130,11 +131,11 @@ void testGroupAndStratumNumberSpecialCases() throws IOException, ResourceParseEx ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.DETERMINE_POLYGON_RANKINGS); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesIndex(), is(1)); - assertThrows(IllegalStateException.class, () -> fpe.fps.getPolygonProcessingState().getSecondarySpeciesIndex()); - assertThat(fpe.fps.getPolygonProcessingState().getInventoryTypeGroup(), is(10)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesGroupNumber(), is(35)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesStratumNumber(), is(24)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesIndex(), is(1)); + assertThrows(IllegalStateException.class, () -> fpe.fps.getLayerProcessingState().getSecondarySpeciesIndex()); + assertThat(fpe.fps.getLayerProcessingState().getInventoryTypeGroup(), is(10)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(), is(35)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesStratumNumber(), is(24)); } @Test @@ -302,11 +303,11 @@ void testCalculateMissingSiteCurves() throws IOException, ResourceParseException fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_MISSING_SITE_CURVES); // Cannot check 0 since determinePolygonRankings has not been executed. - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(1), is(12)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(2), is(2)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(3), is(42)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(4), is(10)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(5), is(10)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(1), is(12)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(2), is(2)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(3), is(42)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(4), is(10)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(5), is(10)); } @Test @@ -337,11 +338,11 @@ void testCalculateMissingSiteCurvesNoSiteCurveData() fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_MISSING_SITE_CURVES); // Cannot check 0 since determinePolygonRankings has not been executed. - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(1), is(118)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(2), is(122)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(3), is(13)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(4), is(99)); - assertThat(fpe.fps.getPolygonProcessingState().getSiteCurveNumber(5), is(59)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(1), is(118)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(2), is(122)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(3), is(13)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(4), is(99)); + assertThat(fpe.fps.getLayerProcessingState().getSiteCurveNumber(5), is(59)); } @Test @@ -381,7 +382,7 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getPolygonProcessingState().getStartBank().siteIndices[4], is((float) expectedValue)); + assertThat(fpe.fps.getLayerProcessingState().getStartBank().siteIndices[4], is((float) expectedValue)); } @Test @@ -421,7 +422,7 @@ void testEstimateMissingSiteIndicesStep2() throws ProcessingException, IOExcepti double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getPolygonProcessingState().getStartBank().siteIndices[2], is((float) expectedValue)); + assertThat(fpe.fps.getLayerProcessingState().getStartBank().siteIndices[2], is((float) expectedValue)); } @Test @@ -448,7 +449,7 @@ void testEstimateMissingYearsToBreastHeightValues() ); assertThat( - fpe.fps.getPolygonProcessingState().getStartBank().yearsToBreastHeight, + fpe.fps.getLayerProcessingState().getStartBank().yearsToBreastHeight, is(new float[] { 0.0f, 4.0f, 4.6f, 1.0f, 5.0f, 5.0f }) ); } @@ -476,11 +477,11 @@ void testCalculateDominantHeightAgeSiteIndex() throws ProcessingException, IOExc ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesDominantHeight(), is(35.31195f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesSiteIndex(), is(34.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesTotalAge(), is(15.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesAgeAtBreastHeight(), is(14.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesAgeToBreastHeight(), is(1.0f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesDominantHeight(), is(35.31195f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesSiteIndex(), is(34.0f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesTotalAge(), is(15.0f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesAgeAtBreastHeight(), is(14.0f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesAgeToBreastHeight(), is(1.0f)); } @Test @@ -490,18 +491,18 @@ void testSetEquationGroups() throws ResourceParseException, IOException, Process var polygon = reader.readNextPolygon().get(); ForwardProcessingState fps = new ForwardProcessingState(controlMap); - fps.setPolygon(polygon); + fps.setPolygonLayer(polygon, LayerType.PRIMARY); assertThat( - fps.getPolygonProcessingState().volumeEquationGroups, + fps.getLayerProcessingState().volumeEquationGroups, Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 12, 20, 25, 37, 66 }) ); assertThat( - fps.getPolygonProcessingState().decayEquationGroups, + fps.getLayerProcessingState().decayEquationGroups, Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 7, 14, 19, 31, 54 }) ); assertThat( - fps.getPolygonProcessingState().breakageEquationGroups, + fps.getLayerProcessingState().breakageEquationGroups, Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 5, 6, 12, 17, 28 }) ); } @@ -540,10 +541,10 @@ void testCalculateDominantHeightAgeSiteIndexNoSecondary() ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesDominantHeight(), is(22.950302f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesSiteIndex(), is(34.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesTotalAge(), is(22.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesAgeAtBreastHeight(), is(Float.NaN)); - assertThat(fpe.fps.getPolygonProcessingState().getPrimarySpeciesAgeToBreastHeight(), is(4.7f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesDominantHeight(), is(22.950302f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesSiteIndex(), is(34.0f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesTotalAge(), is(22.0f)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesAgeAtBreastHeight(), is(Float.NaN)); + assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesAgeToBreastHeight(), is(4.7f)); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java index 63ae4e771..cc0aed5e4 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -31,6 +31,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; @@ -65,7 +66,7 @@ void testNormalCurve() throws ProcessingException { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); // Select the first polygon - 01002 S000001 00(1970) - fpe.fps.setPolygon(forwardDataStreamReader.readNextPolygon().orElseThrow()); + fpe.fps.setPolygonLayer(forwardDataStreamReader.readNextPolygon().orElseThrow(), LayerType.PRIMARY); float hd = 35.2999992f; int sc = 13; @@ -88,7 +89,7 @@ void testCurveExtension1() throws ProcessingException { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); } while (! polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); - fpe.fps.setPolygon(polygon); + fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); float hd = 29.5f; int sc = 11; @@ -111,7 +112,7 @@ void testCurveExtension2() throws ProcessingException { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); } while (! polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); - fpe.fps.setPolygon(polygon); + fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); float hd = 26.5f; int sc = 11; diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java index 75b11ae95..af71d3302 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java @@ -40,569 +40,569 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, // platform-specific differences. assertThat( - fpe.fps.getPolygonProcessingState().volumeEquationGroups, + fpe.fps.getLayerProcessingState().volumeEquationGroups, Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 12, 20, 25, 37, 66 }) ); assertThat( - fpe.fps.getPolygonProcessingState().decayEquationGroups, + fpe.fps.getLayerProcessingState().decayEquationGroups, Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 7, 14, 19, 31, 54 }) ); assertThat( - fpe.fps.getPolygonProcessingState().breakageEquationGroups, + fpe.fps.getLayerProcessingState().breakageEquationGroups, Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 5, 6, 12, 17, 28 }) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0063979626f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.00016450882f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.00024962425f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.00011026859f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.000006198883f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.000024557114f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0062299743f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0010375977f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0001244545f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0000038146973f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.00013566017f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.00033128262f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.00021290779f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.0000059604645f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.000882864f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.0002478361f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0008614063f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, OVER225, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(-0.0000052452087f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-0.004629612f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(1.3446808E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.01768279f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.0010006428f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(2.2292137E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-1.9311905E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.010708809f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(7.638931E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-2.4795532E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.011518478f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-0.0010123253f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-9.3603134E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-5.4836273E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(0.010197163f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-0.0014338493f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-2.9087067E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.035768032f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(1, OVER225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(-0.0016698837f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(-0.16244507f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(-0.0045113564f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(-0.0030164719f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(2, OVER225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(3.528595E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(3, OVER225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(4.1484833E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(-0.13775301f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.005630493f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0028266907f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(4, OVER225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(3.7765503E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, U75TO125, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, U125TO175, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, U175TO225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState() + fpe.fps.getLayerProcessingState() .getCVVolume(5, OVER225, CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, LayerType.PRIMARY), is(5.378723E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), is(3.684759E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(0.0027964115f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(1, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-9.393692E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-3.0636787E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), is(4.1246414E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-2.527237E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(2, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(9.536743E-7f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), is(0.001360178f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), is(4.8589706E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(4.4107437E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(3, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-1.1920929E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-5.042553E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), is(5.4240227E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(6.2704086E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(4, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-2.169609E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), is(1.3077259E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-1.21593475E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, U175TO225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(2.3770332E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVVolume(5, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, OVER225, WHOLE_STEM_VOL, LayerType.PRIMARY), is(-1.2636185E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(1, OVER225, LayerType.PRIMARY), is(-2.065301E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(1, OVER225, LayerType.PRIMARY), is(-2.065301E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(1, U125TO175, LayerType.PRIMARY), is(1.0924414E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(1, U125TO175, LayerType.PRIMARY), is(1.0924414E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(1, U175TO225, LayerType.PRIMARY), is(1.0116026E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(1, U175TO225, LayerType.PRIMARY), is(1.0116026E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(1, U75TO125, LayerType.PRIMARY), is(-3.9674342E-7f) + fpe.fps.getLayerProcessingState().getCVBasalArea(1, U75TO125, LayerType.PRIMARY), is(-3.9674342E-7f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(2, OVER225, LayerType.PRIMARY), is(-1.1444092E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(2, OVER225, LayerType.PRIMARY), is(-1.1444092E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(2, U125TO175, LayerType.PRIMARY), is(5.00679E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(2, U125TO175, LayerType.PRIMARY), is(5.00679E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(2, U175TO225, LayerType.PRIMARY), is(9.596348E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(2, U175TO225, LayerType.PRIMARY), is(9.596348E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(2, U75TO125, LayerType.PRIMARY), is(6.660819E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(2, U75TO125, LayerType.PRIMARY), is(6.660819E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(3, OVER225, LayerType.PRIMARY), is(7.6293945E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(3, OVER225, LayerType.PRIMARY), is(7.6293945E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(3, U125TO175, LayerType.PRIMARY), is(-3.7066638E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(3, U125TO175, LayerType.PRIMARY), is(-3.7066638E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(3, U175TO225, LayerType.PRIMARY), is(-1.0579824E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(3, U175TO225, LayerType.PRIMARY), is(-1.0579824E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(3, U75TO125, LayerType.PRIMARY), is(-2.4344772E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(3, U75TO125, LayerType.PRIMARY), is(-2.4344772E-6f) ); - assertThat(fpe.fps.getPolygonProcessingState().getCVBasalArea(4, OVER225, LayerType.PRIMARY), is(3.194809E-5f)); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(4, OVER225, LayerType.PRIMARY), is(3.194809E-5f)); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(4, U125TO175, LayerType.PRIMARY), is(-1.4662743E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(4, U125TO175, LayerType.PRIMARY), is(-1.4662743E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(4, U175TO225, LayerType.PRIMARY), is(-9.059906E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(4, U175TO225, LayerType.PRIMARY), is(-9.059906E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(4, U75TO125, LayerType.PRIMARY), is(-8.106232E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(4, U75TO125, LayerType.PRIMARY), is(-8.106232E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(5, OVER225, LayerType.PRIMARY), is(-4.673004E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(5, OVER225, LayerType.PRIMARY), is(-4.673004E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(5, U125TO175, LayerType.PRIMARY), is(8.821487E-6f) + fpe.fps.getLayerProcessingState().getCVBasalArea(5, U125TO175, LayerType.PRIMARY), is(8.821487E-6f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(5, U175TO225, LayerType.PRIMARY), is(2.8401613E-5f) + fpe.fps.getLayerProcessingState().getCVBasalArea(5, U175TO225, LayerType.PRIMARY), is(2.8401613E-5f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVBasalArea(5, U75TO125, LayerType.PRIMARY), is(-4.954636E-7f) + fpe.fps.getLayerProcessingState().getCVBasalArea(5, U75TO125, LayerType.PRIMARY), is(-4.954636E-7f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(1, OVER225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(1, OVER225, LayerType.PRIMARY), is(-0.0054130554f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(1, U125TO175, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(1, U125TO175, LayerType.PRIMARY), is(-0.011018753f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(1, U175TO225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(1, U175TO225, LayerType.PRIMARY), is(-0.0404377f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(1, U75TO125, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(1, U75TO125, LayerType.PRIMARY), is(-0.018251419f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(2, OVER225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(2, OVER225, LayerType.PRIMARY), is(7.209778E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(2, U125TO175, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(2, U125TO175, LayerType.PRIMARY), is(-2.0122528E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(2, U175TO225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(2, U175TO225, LayerType.PRIMARY), is(6.0272217E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(2, U75TO125, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(2, U75TO125, LayerType.PRIMARY), is(-1.2207031E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(3, OVER225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(3, OVER225, LayerType.PRIMARY), is(-1.7929077E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(3, U125TO175, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(3, U125TO175, LayerType.PRIMARY), is(-0.008193016f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(3, U175TO225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(3, U175TO225, LayerType.PRIMARY), is(-0.0019302368f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(3, U75TO125, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(3, U75TO125, LayerType.PRIMARY), is(-0.008533478f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(4, OVER225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(4, OVER225, LayerType.PRIMARY), is(-0.0016155243f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(4, U125TO175, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(4, U125TO175, LayerType.PRIMARY), is(-7.4863434E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(4, U175TO225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(4, U175TO225, LayerType.PRIMARY), is(-0.0012569427f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(4, U75TO125, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(4, U75TO125, LayerType.PRIMARY), is(1.9168854E-4f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(5, OVER225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(5, OVER225, LayerType.PRIMARY), is(-0.002658844f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(5, U125TO175, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(5, U125TO175, LayerType.PRIMARY), is(0.0011692047f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(5, U175TO225, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(5, U175TO225, LayerType.PRIMARY), is(-0.005224228f) ); assertThat( - fpe.fps.getPolygonProcessingState().getCVQuadraticMeanDiameter(5, U75TO125, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(5, U75TO125, LayerType.PRIMARY), is(-6.6947937E-4f) ); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(1, BASAL_AREA), is(-2.1831444E-7f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(1, QUAD_MEAN_DIAMETER), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(1, LOREY_HEIGHT), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(1, WHOLE_STEM_VOLUME), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(1, BASAL_AREA), is(-2.1831444E-7f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(1, QUAD_MEAN_DIAMETER), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(1, LOREY_HEIGHT), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(1, WHOLE_STEM_VOLUME), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(2, BASAL_AREA), is(-4.4927E-5f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(2, QUAD_MEAN_DIAMETER), is(0.0023670197f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(2, LOREY_HEIGHT), is(3.576278E-7f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(2, WHOLE_STEM_VOLUME), is(0.0010275329f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(2, BASAL_AREA), is(-4.4927E-5f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(2, QUAD_MEAN_DIAMETER), is(0.0023670197f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(2, LOREY_HEIGHT), is(3.576278E-7f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(2, WHOLE_STEM_VOLUME), is(0.0010275329f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(3, BASAL_AREA), is(4.946138E-6f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(3, QUAD_MEAN_DIAMETER), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(3, LOREY_HEIGHT), is(-4.827988E-6f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(3, WHOLE_STEM_VOLUME), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(3, BASAL_AREA), is(4.946138E-6f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(3, QUAD_MEAN_DIAMETER), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(3, LOREY_HEIGHT), is(-4.827988E-6f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(3, WHOLE_STEM_VOLUME), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(4, BASAL_AREA), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(4, QUAD_MEAN_DIAMETER), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(4, LOREY_HEIGHT), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(4, WHOLE_STEM_VOLUME), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(4, BASAL_AREA), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(4, QUAD_MEAN_DIAMETER), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(4, LOREY_HEIGHT), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(4, WHOLE_STEM_VOLUME), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(5, BASAL_AREA), is(3.4186523E-6f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(5, QUAD_MEAN_DIAMETER), is(0.0f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(5, LOREY_HEIGHT), is(1.800044E-5f)); - assertThat(fpe.fps.getPolygonProcessingState().getCVSmall(5, WHOLE_STEM_VOLUME), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(5, BASAL_AREA), is(3.4186523E-6f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(5, QUAD_MEAN_DIAMETER), is(0.0f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(5, LOREY_HEIGHT), is(1.800044E-5f)); + assertThat(fpe.fps.getLayerProcessingState().getCVSmall(5, WHOLE_STEM_VOLUME), is(0.0f)); } } diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java index 5feaa16f8..5a41c9fd1 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java @@ -20,7 +20,7 @@ public VriPolygon( Optional percentAvailable, Optional modeFip, Optional nonproductiveDescription, float yieldFactor ) { - super(polygonIdentifier, percentAvailable, fiz, becIdentifier, modeFip, Optional.empty()); + super(polygonIdentifier, percentAvailable, fiz, bec, modeFip, Optional.empty()); this.nonproductiveDescription = nonproductiveDescription; this.yieldFactor = yieldFactor; } From 1141371fd9cd9bf27210c3b5005d3610393bea8f Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 19 Aug 2024 17:04:47 -0700 Subject: [PATCH 36/66] Get non-Forward unit tests running again --- .../application/VdypStartApplication.java | 4 ++-- .../nrs/vdyp/common/EstimationMethods.java | 7 ++----- .../CachingResolvedControlMapImpl.java | 9 ++++----- .../vdyp/controlmap/ResolvedControlMap.java | 3 ++- .../controlmap/ResolvedControlMapImpl.java | 9 ++++----- .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 13 ++++++------- .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 6 +++--- .../ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 2 +- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 2 +- .../application/VdypStartApplicationTest.java | 4 ++-- .../control/NonFipControlParserTest.java | 19 ++++++++++++++++--- .../bc/gov/nrs/vdyp/fip/model/FipSpecies.java | 2 +- .../nrs/vdyp/fip/FipControlParserTest.java | 19 ++++++++++++++++--- .../vdyp/forward/ForwardProcessingEngine.java | 6 +----- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 2 +- .../bc/gov/nrs/vdyp/vri/model/VriSpecies.java | 2 +- .../nrs/vdyp/vri/VriControlParserTest.java | 19 ++++++++++++++++--- 17 files changed, 79 insertions(+), 49 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 3f0d54fa4..f435820b8 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -41,7 +41,7 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common.ValueOrMarker; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.controlmap.ResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperCoefficientParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -241,7 +241,7 @@ void closeVriWriter() throws IOException { protected void setControlMap(Map controlMap) { this.controlMap = controlMap; - this.estimationMethods = new EstimationMethods(new CachingResolvedControlMapImpl(controlMap)); + this.estimationMethods = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); } protected StreamingParser getStreamingParser(ControlKey key) throws ProcessingException { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index c8b77a28f..31e4c0e73 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -256,7 +256,7 @@ public float estimateQuadMeanDiameterForSpecies( a0 += multI * coeMap.get(specIAlias).getCoe(0); a1 += multI * coeMap.get(specIAlias).getCoe(1); } else { - float spIFraction = basalAreaFractionPerSpecies.get(specIAlias); + float spIFraction = basalAreaFractionPerSpecies.getOrDefault(specIAlias, 0.0f); if (spIFraction > 0f) { float multI = -spIFraction / fractionOther; a0 += multI * coeMap.get(specIAlias).getCoe(0); @@ -368,10 +368,7 @@ float estimateQuadMeanDiameterClampResult( * @return as described */ public ComponentSizeLimits getLimitsForHeightAndDiameter(String sp0, Region region) { - var coeMap = controlMap.getComponentSizeLimitCoefficients(); - - var coe = coeMap.get(sp0, region); - return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); + return controlMap.getComponentSizeLimits().get(sp0, region); } /** diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index a6d457a06..b20a6f4e6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -9,6 +9,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; @@ -43,7 +44,7 @@ public class CachingResolvedControlMapImpl implements ResolvedControlMap { final MatrixMap2 hl2Coefficients; final MatrixMap2 hl3Coefficients; final MatrixMap3> hlNonPrimaryCoefficients; - final MatrixMap2 componentSizeLimitCoefficients; + final MatrixMap2 componentSizeLimitCoefficients; final Map breakageMap; final MatrixMap2 volumeEquationGroups; final MatrixMap2 decayEquationGroups; @@ -58,9 +59,7 @@ public CachingResolvedControlMapImpl(Map controlMap) { this.becLookup = this.get(ControlKey.BEC_DEF, BecLookup.class); - List genusDefinitions = this.get(ControlKey.SP0_DEF, List.class); - this.genusDefinitionMap = new GenusDefinitionMap(genusDefinitions); - + this.genusDefinitionMap = this.get(ControlKey.SP0_DEF, GenusDefinitionMap.class); this.netDecayWasteCoeMap = this.get(ControlKey.VOLUME_NET_DECAY_WASTE, Map.class); this.netDecayCoeMap = this.get(ControlKey.VOLUME_NET_DECAY, MatrixMap2.class); this.wasteModifierMap = this.get(ControlKey.WASTE_MODIFIERS, MatrixMap2.class); @@ -224,7 +223,7 @@ public Map getControlMap() { } @Override - public MatrixMap2 getComponentSizeLimitCoefficients() { + public MatrixMap2 getComponentSizeLimits() { return componentSizeLimitCoefficients; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index 03ca26b02..c01c527b4 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -5,6 +5,7 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; @@ -54,7 +55,7 @@ public interface ResolvedControlMap { Map getQuadMeanDiameterBySpeciesCoefficients(); /** 61 - SPECIES_COMPONENT_SIZE_LIMIT */ - MatrixMap2 getComponentSizeLimitCoefficients(); + MatrixMap2 getComponentSizeLimits(); /** 70 - UTIL_COMP_BA */ MatrixMap3 getBasalAreaDiameterUtilizationComponentMap(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 99d2e0456..004b5c2da 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -1,7 +1,6 @@ package ca.bc.gov.nrs.vdyp.controlmap; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Optional; @@ -10,7 +9,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.coe.ModifierParser; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.GenusDefinition; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; @@ -42,8 +41,8 @@ private U get(ControlKey key, Class clazz) { @Override public GenusDefinitionMap getGenusDefinitionMap() { - List genusDefinitions = this.>get(ControlKey.SP0_DEF, List.class); - return new GenusDefinitionMap(genusDefinitions); + GenusDefinitionMap genusDefinitions = this.get(ControlKey.SP0_DEF, GenusDefinitionMap.class); + return genusDefinitions; } @Override @@ -162,7 +161,7 @@ public MatrixMap3> ge } @Override - public MatrixMap2 getComponentSizeLimitCoefficients() { + public MatrixMap2 getComponentSizeLimits() { return this.get(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 51d185f0b..32ba7acf4 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -139,7 +139,7 @@ public abstract static class Builder, I extends Bas protected Optional genusIndex = Optional.empty(); protected Optional percentGenus = Optional.empty(); protected Optional fractionGenus = Optional.empty(); - protected Optional sp64DistributionSet = Optional.empty(); + protected Sp64DistributionSet sp64DistributionSet = new Sp64DistributionSet(); protected Optional> siteBuilder = Optional.empty(); protected Optional site = Optional.empty(); @@ -202,12 +202,12 @@ protected Builder fractionGenus(float fractionGenus) { } public Builder sp64DistributionList(List sp64DistributionList) { - this.sp64DistributionSet = Optional.of(new Sp64DistributionSet(sp64DistributionList)); + this.sp64DistributionSet = new Sp64DistributionSet(sp64DistributionList); return this; } public Builder sp64DistributionSet(Sp64DistributionSet sp64DistributionSet) { - this.sp64DistributionSet = Optional.of(sp64DistributionSet); + this.sp64DistributionSet = sp64DistributionSet; return this; } @@ -233,9 +233,9 @@ public Builder addSite(Optional site) { } public void addSp64Distribution(String sp64Alias, float f) { - var sp64DistributionList = sp64DistributionSet.map(set -> set.getSp64DistributionList()).orElse(new ArrayList()); - sp64DistributionList.add(new Sp64Distribution(sp64DistributionList.size() + 1, sp64Alias, f)); - sp64DistributionSet = Optional.of(new Sp64DistributionSet(sp64DistributionList)); + var newSp64DistributionList = new ArrayList<>(this.sp64DistributionSet.getSp64DistributionList()); + newSp64DistributionList.add(new Sp64Distribution(newSp64DistributionList.size() + 1, sp64Alias, f)); + sp64DistributionSet = new Sp64DistributionSet(newSp64DistributionList); } @Override @@ -245,7 +245,6 @@ protected void check(Collection errors) { requirePresent(genus, "genus", errors); requirePresent(genusIndex, "genusIndex", errors); requirePresent(percentGenus, "percentGenus", errors); - requirePresent(sp64DistributionSet, "sp64DistributionSet", errors); } @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 9b0eb69a2..eab5ca7de 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -189,10 +189,10 @@ public static VdypLayer build(VdypPolygon polygon, Consumer config) { public static class Builder extends BaseVdypLayer.Builder { - Optional empericalRelationshipParameterIndex = Optional.empty(); + Optional empiricalRelationshipParameterIndex = Optional.empty(); public void empiricalRelationshipParameterIndex(Optional empiricalRelationshipParameterIndex) { - this.empericalRelationshipParameterIndex = empiricalRelationshipParameterIndex; + this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex; } public void empiricalRelationshipParameterIndex(int empiricalRelationshipParameterIndex) { @@ -265,7 +265,7 @@ protected VdypLayer doBuild() { polygonIdentifier.get(), // layerType.get(), // inventoryTypeGroup, // - empericalRelationshipParameterIndex + empiricalRelationshipParameterIndex ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index 50f7a395c..8cbafc8a5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -77,7 +77,7 @@ public static class Builder extends protected VdypPolygon doBuild() { return new VdypPolygon( polygonIdentifier.get(), percentAvailable.get(), forestInventoryZone.get(), - biogeoclimaticZone.get(), mode, targetYear + biogeoclimaticZone.get(), mode, inventoryTypeGroup, targetYear ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index 2ee3e3b0c..0a219f336 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -297,7 +297,7 @@ protected VdypSpecies doBuild() { genus.get(), // genusIndex.get(), // percentGenus.get(), // - sp64DistributionSet.get(), // + sp64DistributionSet, // site, // volumeGroup.get(), // decayGroup.get(), // diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index 575c5f8be..38010d5fa 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -629,7 +629,7 @@ List primarySecondarySpecies(String primary, String secondary) } @Nested - class FindEmpericalRelationshipParameterIndex { + class FindEmpiricalRelationshipParameterIndex { @Test void testModified() throws Exception { @@ -1544,7 +1544,7 @@ void testComputeUtilizationComponentsPrimaryByUtilNoCV() throws ProcessingExcept layer.setSpecies(Arrays.asList(spec1, spec2)); EstimationMethods estimationMethods = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); - ComputationMethods computationMethods = new ComputationMethods(estimationMethods, null); + ComputationMethods computationMethods = new ComputationMethods(estimationMethods, VdypApplicationIdentifier.FIP_START); computationMethods.computeUtilizationComponentsPrimary( bec, layer, VolumeComputeMode.BY_UTIL, CompatibilityVariableMode.NONE ); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java index 27f056fde..1267e38d4 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java @@ -11,6 +11,7 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.isA; @@ -28,12 +29,14 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -295,14 +298,24 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 @Test void testParseE061() throws Exception { BaseControlParser parser = getUnit(); - var result = parse(parser, TestUtils.class, CONTROL_FILE); + var result = (Map)parse(parser, TestUtils.class, CONTROL_FILE); assertThat( result, (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, allOf( - mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL) + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, + mmHasEntry(instanceOf(ComponentSizeLimits.class) + , "AC", Region.COASTAL ) ) ); + + var mm = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + + var csl = mm.get("AC", Region.COASTAL); + + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); } @Test diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java index 0d6b714cd..6065f8808 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java @@ -67,7 +67,7 @@ protected FipSpecies doBuild() { this.genus.get(), // this.genusIndex.get(), // this.percentGenus.get(), // - this.sp64DistributionSet.get(), // + this.sp64DistributionSet, // this.site ); } diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java index 4a9464508..3d44fe298 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java @@ -27,6 +27,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -34,6 +35,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -303,14 +305,25 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 @Test void testParseE061() throws Exception { BaseControlParser parser = new FipControlParser(); - var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); + var result = (Map)parse(parser, TestUtils.class, "FIPSTART.CTR"); + assertThat( result, (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, allOf( - mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL) + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, + mmHasEntry(instanceOf(ComponentSizeLimits.class) + , "AC", Region.COASTAL ) ) ); + + var mm = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + + var csl = mm.get("AC", Region.COASTAL); + + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); } @Test diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index c528a2d12..b087d8763 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -803,11 +803,7 @@ private void growUsingFullSpeciesDynamics( * @return as described */ private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region region) { - - MatrixMap2 limits = fps.fcm.getComponentSizeLimitCoefficients(); - Coefficients coe = limits.get(genusAlias, region); - - return new ComponentSizeLimits(coe.getCoe(1), coe.getCoe(2), coe.getCoe(3), coe.getCoe(4)); + return fps.fcm.getComponentSizeLimits().get(genusAlias, region); } /** diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index a867b372c..3c527d71b 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -587,7 +587,7 @@ void getDqBySpeciesInitial( float min = Math.max(7.6f, limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll()); float loreyHeightToUse = Math.max(spec.getLoreyHeightByUtilization().getAll(), 7.0f); - float max = Math.min(limits.maxQuadMeanDiameterLoreyHeightRatio(), limits.quadMeanDiameterMaximum() * loreyHeightToUse); + float max = Math.min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightToUse); max = Math.max(7.75f, max); minPerSpecies.put(spec.getGenus(), min); diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java index 5f04d92a3..f0823632b 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java @@ -50,7 +50,7 @@ protected VriSpecies doBuild() { this.genus.get(), // this.genusIndex.get(), // this.percentGenus.get(), // - this.sp64DistributionSet.get(), // + this.sp64DistributionSet, // this.site ); } diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java index 9f4df373a..05ff779d2 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -36,6 +37,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; @@ -294,14 +296,25 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 @Test void testParseE061() throws Exception { BaseControlParser parser = new VriControlParser(); - var result = parse(parser, TestUtils.class, CONTROL_FILE); + var result = (Map)parse(parser, TestUtils.class, CONTROL_FILE); + assertThat( result, (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, allOf( - mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL) + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, + mmHasEntry(instanceOf(ComponentSizeLimits.class) + , "AC", Region.COASTAL ) ) ); + + var mm = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + + var csl = mm.get("AC", Region.COASTAL); + + assertThat(csl.loreyHeightMaximum(), is(49.4f)); + assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); + assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); + assertThat(csl.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); } @Test From 97b99e6809ac2f7030ea4928561a7e4ff84faef3 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 23 Aug 2024 15:01:06 -0700 Subject: [PATCH 37/66] Current forward unit tests are all running correctly. --- .../InitializationIncompleteException.java | 10 + .../application/VdypStartApplication.java | 2 +- .../nrs/vdyp/common/ComputationMethods.java | 192 +++++---- .../nrs/vdyp/common/EstimationMethods.java | 61 +-- .../vdyp/common/UtilizationOperations.java | 27 +- .../CachingResolvedControlMapImpl.java | 15 +- .../vdyp/controlmap/ResolvedControlMap.java | 2 + .../controlmap/ResolvedControlMapImpl.java | 9 + .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 39 +- .../vdyp/model/CompatibilityVariableMode.java | 6 +- .../nrs/vdyp/model/Sp64DistributionSet.java | 11 + .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 10 +- .../ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 5 + .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 101 ++++- .../application/VdypStartApplicationTest.java | 4 - .../vdyp/application/test/TestSpecies.java | 2 +- .../gov/nrs/vdyp/model/VdypSpeciesTest.java | 4 +- .../bc/gov/nrs/vdyp/fip/model/FipSpecies.java | 2 +- .../bc/gov/nrs/vdyp/fip/RootFinderTest.java | 15 - .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 154 ++++--- .../vdyp/forward/ForwardDataStreamReader.java | 101 ++++- .../vdyp/forward/ForwardProcessingEngine.java | 395 +++++++++--------- .../vdyp/forward/ForwardProcessingState.java | 8 +- .../nrs/vdyp/forward/ForwardProcessor.java | 51 +-- .../vdyp/forward/LayerProcessingState.java | 16 + .../forward/parsers/VdypSpeciesParser.java | 23 +- .../AbstractForwardProcessingEngineTest.java | 3 +- .../forward/ForwardControlParserTest.java | 19 +- .../GeneralForwardProcessingEngineTest.java | 28 +- .../nrs/vdyp/forward/GrowBasalAreaTest.java | 10 +- .../vdyp/forward/GrowDominantHeightTest.java | 2 +- .../forward/GrowQuadMeanDiameterTest.java | 2 +- .../forward/PolygonProcessingStateTest.java | 114 ++--- .../forward/VdypForwardPolygonParserTest.java | 123 +++--- .../forward/VdypForwardReadPolygonTest.java | 62 +-- .../forward/VdypForwardSpeciesParserTest.java | 117 ++++-- .../bc/gov/nrs/vdyp/vri/model/VriSpecies.java | 5 +- 37 files changed, 970 insertions(+), 780 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/InitializationIncompleteException.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/InitializationIncompleteException.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/InitializationIncompleteException.java new file mode 100644 index 000000000..664be61cb --- /dev/null +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/InitializationIncompleteException.java @@ -0,0 +1,10 @@ +package ca.bc.gov.nrs.vdyp.application; + +public class InitializationIncompleteException extends RuntimeException { + + private static final long serialVersionUID = -4549468703592060502L; + + public InitializationIncompleteException(String reason) { + super(reason); + } +} diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index f435820b8..b75971f77 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -324,7 +324,7 @@ protected List findPrimarySpecies(Collection allSpecies) { continue; } var groupPrimary = copySpecies( - // groupSpecies.size() is at least 2 so findFirest will not be empty + // groupSpecies.size() is at least 2 so findFirst will not be empty groupSpecies.stream().sorted(PERCENT_GENUS_DESCENDING).findFirst().orElseThrow(), builder -> { var total = (float) groupSpecies.stream().mapToDouble(BaseVdypSpecies::getPercentGenus).sum(); builder.percentGenus(total); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java index 0326ec454..ca60a1a1b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java @@ -15,6 +15,7 @@ import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; import ca.bc.gov.nrs.vdyp.application.VdypStartApplication; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; +import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; @@ -24,9 +25,10 @@ import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; import ca.bc.gov.nrs.vdyp.model.VolumeComputeMode; +import ca.bc.gov.nrs.vdyp.model.VolumeVariable; public class ComputationMethods { - + public static final Logger log = LoggerFactory.getLogger(VdypStartApplication.class); /** @@ -64,10 +66,18 @@ public class ComputationMethods { .filter(x -> !x.getName().contains("Volume")).toList(); } + private final static UtilizationVector quadMeanDiameterLowerBounds = new UtilizationVector( + 0f, 0f, 7.5f, 12.5f, 17.5f, 22.5f + ); + + private final static UtilizationVector quadMeanDiameterUpperBounds = new UtilizationVector( + 0f, 0f, 12.5f, 17.5f, 22.5f, 10000f + ); + private final EstimationMethods estimationMethods; private final VdypApplicationIdentifier context; - + public ComputationMethods(EstimationMethods estimationMethods, VdypApplicationIdentifier context) { this.estimationMethods = estimationMethods; this.context = context; @@ -80,36 +90,36 @@ public void computeUtilizationComponentsPrimary( ) throws ProcessingException { log.atTrace().setMessage("computeUtilizationComponentsPrimary for {}, stand total age is {}") .addArgument(vdypLayer.getPolygonIdentifier()).addArgument(vdypLayer.getAgeTotal()).log(); - + log.atDebug().setMessage("Primary layer for {} has {} species/genera: {}") .addArgument(vdypLayer::getPolygonIdentifier) // .addArgument(() -> vdypLayer.getSpecies().size()) // .addArgument(() -> vdypLayer.getSpecies().keySet().stream().collect(Collectors.joining(", "))) // .log(); - + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { float loreyHeightSpec = spec.getLoreyHeightByUtilization().getAll(); float baseAreaSpec = spec.getBaseAreaByUtilization().getAll(); float quadMeanDiameterSpec = spec.getQuadraticMeanDiameterByUtilization().getAll(); float treesPerHectareSpec = spec.getTreesPerHectareByUtilization().getAll(); - + log.atDebug().setMessage("Working with species {} LH: {} DQ: {} BA: {} TPH: {}") .addArgument(spec.getClass()).addArgument(loreyHeightSpec).addArgument(quadMeanDiameterSpec) .addArgument(baseAreaSpec).addArgument(treesPerHectareSpec); - + if (volumeComputeMode == VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC) { log.atDebug().log("Estimating tree volume"); - + var volumeGroup = spec.getVolumeGroup(); var meanVolume = this.estimationMethods .estimateWholeStemVolumePerTree(volumeGroup, loreyHeightSpec, quadMeanDiameterSpec); var specWholeStemVolume = treesPerHectareSpec * meanVolume; - + spec.getWholeStemVolumeByUtilization().setAll(specWholeStemVolume); } float wholeStemVolumeSpec = spec.getWholeStemVolumeByUtilization().getAll(); - - var baseAreaUtil = Utils.utilizationVector(); + + var basalAreaUtil = Utils.utilizationVector(); var quadMeanDiameterUtil = Utils.utilizationVector(); var treesPerHectareUtil = Utils.utilizationVector(); var wholeStemVolumeUtil = Utils.utilizationVector(); @@ -117,111 +127,140 @@ public void computeUtilizationComponentsPrimary( var closeVolumeNetDecayUtil = Utils.utilizationVector(); var closeVolumeNetDecayWasteUtil = Utils.utilizationVector(); var closeVolumeNetDecayWasteBreakUtil = Utils.utilizationVector(); - - baseAreaUtil.setAll(baseAreaSpec); // BAU + + basalAreaUtil.setAll(baseAreaSpec); // BAU quadMeanDiameterUtil.setAll(quadMeanDiameterSpec); // DQU treesPerHectareUtil.setAll(treesPerHectareSpec); // TPHU wholeStemVolumeUtil.setAll(wholeStemVolumeSpec); // WSU - + var adjustCloseUtil = Utils.utilizationVector(); // ADJVCU - @SuppressWarnings("unused") var adjustDecayUtil = Utils.utilizationVector(); // ADJVD - @SuppressWarnings("unused") var adjustDecayWasteUtil = Utils.utilizationVector(); // ADJVDW - + // EMP071 estimationMethods.estimateQuadMeanDiameterByUtilization(bec, quadMeanDiameterUtil, spec.getGenus()); - + // EMP070 - estimationMethods.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, baseAreaUtil, spec.getGenus()); - + estimationMethods.estimateBaseAreaByUtilization(bec, quadMeanDiameterUtil, basalAreaUtil, spec.getGenus()); + // Calculate tree density components for (var uc : VdypStartApplication.UTIL_CLASSES) { treesPerHectareUtil.set( - uc, - BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) + uc, BaseAreaTreeDensityDiameter + .treesPerHectare(basalAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) ); } - + // reconcile components with totals - + // YUC1R - ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - + ReconcilationMethods.reconcileComponents(basalAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); + if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { - throw new UnsupportedOperationException("TODO"); + + float basalAreaSumForSpecies = 0.0f; + for (var uc : VdypStartApplication.UTIL_CLASSES) { + + float currentUcBasalArea = basalAreaUtil.get(uc); + basalAreaUtil.set(uc, currentUcBasalArea + spec.getCvBasalArea(uc, spec.getLayerType())); + if (basalAreaUtil.get(uc) < 0.0f) { + basalAreaUtil.set(uc, 0.0f); + } + + basalAreaSumForSpecies += basalAreaUtil.get(uc); + + float newDqValue = quadMeanDiameterUtil.get(uc) + spec.getCvQuadraticMeanDiameter(uc, spec.getLayerType()); + quadMeanDiameterUtil + .set(uc, FloatMath.clamp( + newDqValue, quadMeanDiameterLowerBounds.get(uc), quadMeanDiameterUpperBounds.get(uc))); + } + + float baMult = basalAreaUtil.get(UtilizationClass.ALL) / basalAreaSumForSpecies; + + for (UtilizationClass uc: UtilizationClass.ALL_CLASSES) { + basalAreaUtil.set(uc, basalAreaUtil.get(uc) * baMult); + } } - + // Recalculate TPH's - + for (var uc : VdypStartApplication.UTIL_CLASSES) { treesPerHectareUtil.setCoe( - uc.index, - BaseAreaTreeDensityDiameter - .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) + uc.index, BaseAreaTreeDensityDiameter + .treesPerHectare(basalAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) ); } - + // Since DQ's may have changed, MUST RECONCILE AGAIN // Seems this might only be needed when compatibilityVariableMode is not NONE? - + // YUC1R - ReconcilationMethods.reconcileComponents(baseAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); - + ReconcilationMethods.reconcileComponents(basalAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); + if (volumeComputeMode == VolumeComputeMode.ZERO) { throw new UnsupportedOperationException("TODO"); } else { - + // EMP091 estimationMethods.estimateWholeStemVolume( - UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, - quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + UtilizationClass.ALL, adjustCloseUtil.getCoe(4), + spec.getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, basalAreaUtil, wholeStemVolumeUtil ); - + if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { - // apply compatibity variables to WS volume - + // apply compatibility variables to WS volume + + float wholeStemVolumeSum = 0.0f; + for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + wholeStemVolumeUtil.set(uc, wholeStemVolumeUtil.get(uc) + * FloatMath.exp(spec.getCvVolume(uc, VolumeVariable.WHOLE_STEM_VOL, spec.getLayerType()))); + wholeStemVolumeSum += wholeStemVolumeUtil.get(uc); + } + wholeStemVolumeUtil.set(UtilizationClass.ALL, wholeStemVolumeSum); + // Set the adjustment factors for next three volume types - - throw new UnsupportedOperationException("TODO"); + for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { + adjustCloseUtil.set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL, spec.getLayerType())); + adjustDecayUtil.set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY, spec.getLayerType())); + adjustDecayWasteUtil.set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, spec.getLayerType())); + } } else { // Do nothing as the adjustment vectors are already set to 0 } - + // EMP092 estimationMethods.estimateCloseUtilizationVolume( - UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, - quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil + UtilizationClass.ALL, adjustCloseUtil, spec + .getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil ); - + // EMP093 estimationMethods.estimateNetDecayVolume( - spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), - vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, - closeVolumeNetDecayUtil + spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec + .getDecayGroup(), vdypLayer.getBreastHeightAge() + .orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil ); - + // EMP094 estimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, - quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil + bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec + .getGenus(), loreyHeightSpec, quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil ); - + if (context.isStart()) { // EMP095 estimationMethods.estimateNetDecayWasteAndBreakageVolume( - UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, - closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil + UtilizationClass.ALL, spec + .getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil ); } } - - spec.getBaseAreaByUtilization().pairwiseInPlace(baseAreaUtil, EstimationMethods.COPY_IF_BAND); + + spec.getBaseAreaByUtilization().pairwiseInPlace(basalAreaUtil, EstimationMethods.COPY_IF_BAND); spec.getTreesPerHectareByUtilization().pairwiseInPlace(treesPerHectareUtil, EstimationMethods.COPY_IF_BAND); spec.getQuadraticMeanDiameterByUtilization() .pairwiseInPlace(quadMeanDiameterUtil, EstimationMethods.COPY_IF_BAND); - + spec.getWholeStemVolumeByUtilization() .pairwiseInPlace(wholeStemVolumeUtil, EstimationMethods.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeByUtilization() @@ -232,10 +271,11 @@ public void computeUtilizationComponentsPrimary( .pairwiseInPlace(closeVolumeNetDecayWasteUtil, EstimationMethods.COPY_IF_NOT_SMALL); spec.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); - + } + computeLayerUtilizationComponentsFromSpecies(vdypLayer); - + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { if (vdypLayer.getBaseAreaByUtilization().getAll() > 0f) { spec.setFractionGenus( @@ -245,12 +285,12 @@ public void computeUtilizationComponentsPrimary( log.atDebug().addArgument(spec.getGenus()).addArgument(spec.getFractionGenus()) .setMessage("Species {} base area {}%").log(); } - + log.atDebug().setMessage("Calculating Stand Lorey Height").log(); - + vdypLayer.getLoreyHeightByUtilization().setSmall(0f); vdypLayer.getLoreyHeightByUtilization().setAll(0f); - + for (VdypSpecies spec : vdypLayer.getSpecies().values()) { log.atDebug() // .addArgument(spec.getGenus()) // @@ -263,27 +303,27 @@ public void computeUtilizationComponentsPrimary( "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" ).log(); vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.SMALL, - x -> x + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() + UtilizationClass.SMALL, x -> x + + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() ); vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.ALL, - x -> x + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + UtilizationClass.ALL, x -> x + + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() ); } { float baSmall = vdypLayer.getBaseAreaByUtilization().getSmall(); float baAll = vdypLayer.getBaseAreaByUtilization().getAll(); - + if (baSmall > 0) { vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.SMALL, x -> x / baSmall); } if (baAll > 0) { vdypLayer.getLoreyHeightByUtilization().scalarInPlace(UtilizationClass.ALL, x -> x / baAll); } - + } - + } /** @@ -292,23 +332,25 @@ public void computeUtilizationComponentsPrimary( * @param vdypLayer */ protected static void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { + // Layer utilization vectors other than quadratic mean diameter are the pairwise // sums of those of their species sumSpeciesUtilizationVectorsToLayer(vdypLayer); - + { var hlVector = Utils.heightVector(); vdypLayer.getSpecies().values().stream().forEach(spec -> { var ba = spec.getBaseAreaByUtilization(); hlVector.pairwiseInPlace( - spec.getLoreyHeightByUtilization(), - (float x, float y, UtilizationClass uc) -> x + y * ba.get(uc) + spec.getLoreyHeightByUtilization(), (float x, float y, UtilizationClass uc) -> x + + y * ba.get(uc) ); }); var ba = vdypLayer.getBaseAreaByUtilization(); hlVector.scalarInPlace((float x, UtilizationClass uc) -> ba.get(uc) > 0 ? x / ba.get(uc) : x); vdypLayer.setLoreyHeightByUtilization(hlVector); } + // Quadratic mean diameter for the layer is computed from the BA and TPH after // they have been found from the species { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index 31e4c0e73..87b1cc64f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -813,17 +813,16 @@ public void estimateNetDecayWasteAndBreakageVolume( * @param breastHeightAge breast height age (years) * @param veteranBaseArea basal area of overstory (>= 0) * @param fullOccupancy if true, the empirically fitted curve is increased to become - * a full occupancy curve. If false, BAP is for mean conditions. - * @param basalAreaGroup index of the basal area group + * a full occupancy curve. If false, BAP is for mean conditions + * @param upperBoundBasalArea limit on the resulting basal area * @return as described * @throws StandProcessingException */ public float estimateBaseAreaYield( Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, - float breastHeightAge, Optional veteranBasalArea, boolean fullOccupancy, int baseAreaGroup + float breastHeightAge, Optional veteranBasalArea, boolean fullOccupancy, float upperBoundBasalArea ) throws StandProcessingException { - float upperBoundBaseArea = upperBoundsBaseArea(baseAreaGroup); - + // The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea // (BATOP98): @@ -853,12 +852,12 @@ public float estimateBaseAreaYield( float trAge = FloatMath.log(ageToUse); float a0 = estimateBasalAreaYieldCoefficients.getCoe(0); - float a1 = estimateBasalAreaYieldCoefficients.getCoe(0); - float a2 = estimateBasalAreaYieldCoefficients.getCoe(0); - float a3 = estimateBasalAreaYieldCoefficients.getCoe(0); - float a4 = estimateBasalAreaYieldCoefficients.getCoe(0); - float a5 = estimateBasalAreaYieldCoefficients.getCoe(0); - float a6 = estimateBasalAreaYieldCoefficients.getCoe(0); + float a1 = estimateBasalAreaYieldCoefficients.getCoe(1); + float a2 = estimateBasalAreaYieldCoefficients.getCoe(2); + float a3 = estimateBasalAreaYieldCoefficients.getCoe(3); + float a4 = estimateBasalAreaYieldCoefficients.getCoe(4); + float a5 = estimateBasalAreaYieldCoefficients.getCoe(5); + float a6 = estimateBasalAreaYieldCoefficients.getCoe(6); float a00 = Math.max(a0 + a1 * trAge, 0); float ap = Math.max(a3 + a4 * trAge, 0); @@ -869,7 +868,7 @@ public float estimateBaseAreaYield( } else { bap = a00 * FloatMath.pow(dominantHeight - a2, ap) * FloatMath.exp(a5 * dominantHeight + a6 * veteranBasalArea.orElse(0f)); - bap = Math.min(bap, upperBoundBaseArea); + bap = Math.min(bap, upperBoundBasalArea); } if (fullOccupancy) { @@ -887,21 +886,19 @@ public float estimateBaseAreaYield( * @param dominantHeight dominant height (m) * @param breastHeightAge breast height age (years) * @param veteranBaseArea basal area of overstory (>= 0) - * @param basalAreaGroup index of the basal area group + * @param upperBoundQuadMeanDiameter upper bound on the result of this call * @return quad-mean-diameter of primary layer (with DBH >= 7.5) * @throws StandProcessingException in the event of a processing error */ public float estimateQuadMeanDiameterYield( Coefficients coefficients, int controlVariable2Setting, float dominantHeight, - float breastHeightAge, Optional veteranBaseArea, int basalAreaGroup + float breastHeightAge, Optional veteranBaseArea, float upperBoundQuadMeanDiameter ) throws StandProcessingException { if (dominantHeight <= 5) { return 7.6f; } - final float upperBoundsQuadMeanDiameter = upperBoundsQuadMeanDiameter(basalAreaGroup); - final float ageUse = breastHeightAge; if (ageUse <= 0f) { @@ -916,37 +913,7 @@ public float estimateQuadMeanDiameterYield( float dq = c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2); - return FloatMath.clamp(dq, 7.6f, upperBoundsQuadMeanDiameter); - } - - /** - * @param basalAreaGroup the basal area group in question - * @return the quad-mean-diameter upper bound for the given basal area group - */ - float upperBoundsQuadMeanDiameter(int basalAreaGroup) { - return upperBounds(basalAreaGroup).getCoe(2); - } - - /** - * @param basalAreaGroup the basal area group in question - * @return the basal area upper bound for the given basal area group - */ - float upperBoundsBaseArea(int basalAreaGroup) { - return upperBounds(basalAreaGroup).getCoe(1); - } - - /** - * UPPERGEN Method 1 - return the upper bounds of basal area and quad-mean-diameter for a given - * basal area group as a list of (two) floats. - * - * @param basalAreaGroup the basal area group in question - * @return as described - */ - Coefficients upperBounds(int basalAreaGroup) { - var upperBoundsMap = controlMap.getUpperBounds(); - return Utils.optSafe(upperBoundsMap.get(basalAreaGroup)).orElseThrow( - () -> new IllegalStateException("Could not find limits for basal area group " + basalAreaGroup) - ); + return FloatMath.clamp(dq, 7.6f, upperBoundQuadMeanDiameter); } @FunctionalInterface diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java index 3915d517f..bb098e642 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java @@ -8,6 +8,7 @@ import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; import ca.bc.gov.nrs.vdyp.math.FloatMath; 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.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; @@ -103,8 +104,8 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { } private static final float MAX_ACCEPTABLE_BASAL_AREA_ERROR = 0.1f; - private static final float[] CLASS_LOWER_BOUNDS = { 4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f }; - private static final float[] CLASS_UPPER_BOUNDS = { 7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f }; + private static final UtilizationVector CLASS_LOWER_BOUNDS = new UtilizationVector(4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f); + private static final UtilizationVector CLASS_UPPER_BOUNDS = new UtilizationVector(7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f); private static final float DQ_EPS = 0.005f; /** @@ -113,7 +114,7 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { private static void resetOnMissingValues(VdypUtilizationHolder uh) { for (UtilizationClass uc: UtilizationClass.values()) { - if (uh.getBaseAreaByUtilization().get(uc) <= 0.0f || uh.getLoreyHeightByUtilization().get(uc) <= 0.0f) { + if (uh.getBaseAreaByUtilization().get(uc) <= 0.0f || uh.getTreesPerHectareByUtilization().get(uc) <= 0.0f) { uh.getBaseAreaByUtilization().set(uc, 0.0f); uh.getTreesPerHectareByUtilization().set(uc, 0.0f); // DO NOT zero-out the lorey height value. @@ -134,18 +135,18 @@ private static void resetOnMissingValues(VdypUtilizationHolder uh) { private static void adjustBasalAreaToMatchTreesPerHectare(VdypUtilizationHolder uh) throws ProcessingException { for (UtilizationClass uc: UtilizationClass.values()) { - float tph = uh.getTreesPerHectareByUtilization().get(0); + float tph = uh.getTreesPerHectareByUtilization().get(uc); if (tph > 0.0f) { float basalAreaLowerBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_LOWER_BOUNDS[uc.ordinal()] + DQ_EPS, tph); + .basalArea(CLASS_LOWER_BOUNDS.get(uc) + DQ_EPS, tph); float basalAreaUpperBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_UPPER_BOUNDS[uc.ordinal()] - DQ_EPS, tph); + .basalArea(CLASS_UPPER_BOUNDS.get(uc) - DQ_EPS, tph); float basalAreaError; float newBasalArea; String message = null; - float basalArea = uh.getBaseAreaByUtilization().get(0); + float basalArea = uh.getBaseAreaByUtilization().get(uc); if (basalArea < basalAreaLowerBound) { basalAreaError = FloatMath.abs(basalArea - basalAreaLowerBound); newBasalArea = basalAreaLowerBound; @@ -189,23 +190,23 @@ private static void doCalculateQuadMeanDiameter(VdypUtilizationHolder uh) throws float tph = uh.getTreesPerHectareByUtilization().get(uc); float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, tph); - if (qmd < CLASS_LOWER_BOUNDS[uc.ordinal()]) { + if (qmd < CLASS_LOWER_BOUNDS.get(uc)) { qmd = qmd + DQ_EPS; - if (qmd /* is still */ < CLASS_LOWER_BOUNDS[uc.ordinal()]) { + if (qmd /* is still */ < CLASS_LOWER_BOUNDS.get(uc)) { throw new ProcessingException( MessageFormat.format( "{0}: Error 6: calculated quad-mean-diameter value {1} is below lower limit {2}", - uh, qmd, CLASS_LOWER_BOUNDS[uc.ordinal()] + uh, qmd, CLASS_LOWER_BOUNDS.get(uc) ) ); } - } else if (qmd > CLASS_UPPER_BOUNDS[uc.ordinal()]) { + } else if (qmd > CLASS_UPPER_BOUNDS.get(uc)) { qmd = qmd - DQ_EPS; - if (qmd /* is still */ > CLASS_UPPER_BOUNDS[uc.ordinal()]) { + if (qmd /* is still */ > CLASS_UPPER_BOUNDS.get(uc)) { throw new ProcessingException( MessageFormat.format( "{0}: Error 6: calculated quad-mean-diameter value {1} is above upper limit {2}", - uh, qmd, CLASS_UPPER_BOUNDS[uc.ordinal()] + uh, qmd, CLASS_UPPER_BOUNDS.get(uc) ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index b20a6f4e6..4bbce7825 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -1,6 +1,6 @@ package ca.bc.gov.nrs.vdyp.controlmap; -import java.util.List; +import java.util.Collections; import java.util.Map; import java.util.Optional; @@ -10,7 +10,6 @@ import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; -import ca.bc.gov.nrs.vdyp.model.GenusDefinition; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; @@ -90,6 +89,14 @@ public CachingResolvedControlMapImpl(Map controlMap) { this.quadMeanDiameterBySpeciesCoefficients = this.get(ControlKey.BY_SPECIES_DQ, Map.class); } + /** + * @return the underlying control map + */ + @Override + public Map getControlMap() { + return Collections.unmodifiableMap(controlMap); + } + protected U get(ControlKey key, Class clazz) { return Utils.expectParsedControl(controlMap, key, clazz); } @@ -218,10 +225,6 @@ public Map getBreakageMap() { return breakageMap; } - public Map getControlMap() { - return controlMap; - } - @Override public MatrixMap2 getComponentSizeLimits() { return componentSizeLimitCoefficients; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index c01c527b4..188708cc5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -15,6 +15,8 @@ public interface ResolvedControlMap { + Map getControlMap(); + /** 9 - BEC_DEF */ BecLookup getBecLookup(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 004b5c2da..2d2765995 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -1,5 +1,6 @@ package ca.bc.gov.nrs.vdyp.controlmap; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -27,6 +28,14 @@ public ResolvedControlMapImpl(Map controlMap) { this.controlMap = controlMap; } + /** + * @return the underlying control map + */ + @Override + public Map getControlMap() { + return Collections.unmodifiableMap(controlMap); + } + @SuppressWarnings("unchecked") private U get(ControlKey key, Class clazz) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 32ba7acf4..d3eb2885f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -9,6 +9,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; +import ca.bc.gov.nrs.vdyp.application.InitializationIncompleteException; import ca.bc.gov.nrs.vdyp.common.Computed; import ca.bc.gov.nrs.vdyp.io.parse.coe.GenusDefinitionParser; @@ -26,25 +27,25 @@ public abstract class BaseVdypSpecies { /** the species index within species definition file (e.g. SPODEF_v0.dat) */ private final int genusIndex; // BANK1/ISPB, L1COM1/ISPL1, etc. - private float percentGenus; // FIPS/PCTVOLV L1COM1/PCTL1 + private Optional percentGenus = Optional.empty(); // FIPS/PCTVOLV L1COM1/PCTL1 // This is computed from percentGenus, but VDYP7 computes it in a way that might // lead to a slight difference so it's stored separately and can be modified. @Computed - private float fractionGenus; // FRBASP0/FR + private Optional fractionGenus = Optional.empty(); // FRBASP0/FR private Sp64DistributionSet sp64DistributionSet; private Optional site; protected BaseVdypSpecies( - PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, int genusIndex, float percentGenus, + PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, int genusIndex, Optional percentGenus, Sp64DistributionSet sp64DistributionSet, Optional site ) { this.polygonIdentifier = polygonIdentifier; this.layerType = layerType; this.genus = genus; - this.setPercentGenus(percentGenus); + percentGenus.ifPresent(p -> this.setPercentGenus(p)); this.site = site; this.genusIndex = genusIndex; this.sp64DistributionSet = sp64DistributionSet; @@ -59,30 +60,33 @@ public LayerType getLayerType() { } public float getPercentGenus() { - return percentGenus; + return percentGenus.orElseThrow(() -> new InitializationIncompleteException(MessageFormat.format("Species {0}, percentGenus", this))); } - @Computed - public float getFractionGenus() { - return fractionGenus; + public void setPercentGenus(float value) { + // Note - it is permitted to set percentGenus more than once. + this.percentGenus = Optional.of(value); + setFractionGenus(percentGenus.get() / 100f); } - public void setPercentGenus(float percentGenus) { - this.percentGenus = percentGenus; - this.fractionGenus = percentGenus / 100f; + @Computed + public float getFractionGenus() { + return fractionGenus.orElseThrow(() -> new InitializationIncompleteException(MessageFormat.format("Species {0}, fractionGenus", this))); } @Computed - public void setFractionGenus(float fractionGenus) { - this.fractionGenus = fractionGenus; + public void setFractionGenus(float value) { + // Note - it is permitted to set fractionGenus more than once. + this.fractionGenus = Optional.of(value); } public Sp64DistributionSet getSp64DistributionSet() { return sp64DistributionSet; } - public void setSp64DistributionSet(Sp64DistributionSet sp64DistributionSet) { - this.sp64DistributionSet = sp64DistributionSet; + @Override + public String toString() { + return MessageFormat.format("{0} {1} {2}", polygonIdentifier, layerType, genus); } /** @@ -244,7 +248,10 @@ protected void check(Collection errors) { requirePresent(layerType, "layerType", errors); requirePresent(genus, "genus", errors); requirePresent(genusIndex, "genusIndex", errors); - requirePresent(percentGenus, "percentGenus", errors); + + // percentGenus is not required on build because the Forward + // input data format does not include it in the species data files. + // requirePresent(percentGenus, "percentGenus", errors); } @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java index 42d8749c8..6bdbc69bd 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java @@ -12,5 +12,9 @@ public enum CompatibilityVariableMode { /** * Apply compatibility variables to all components */ - ALL // 2 + ALL; // 2 + + public static CompatibilityVariableMode getByInteger(int v) { + return values()[v]; + } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java index 3d08724fc..cb1a89295 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java @@ -95,6 +95,12 @@ public int getSize() { return sp64DistributionList.size(); } + /** + * Returns the Sp64Distribution at index withIndex. THIS INDEX is + * one-based - that is, the first entry has index one. + * @param withIndex index, one-based, in list. + * @return as described + */ public Optional getSpeciesDistribution(int withIndex) { if (withIndex > maxIndex) { throw new IllegalArgumentException( @@ -204,4 +210,9 @@ public int compareTo(Sp64DistributionSet that) { return 1; } } + + @Override + public String toString() { + return this.sp64DistributionList.toString(); + } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index eab5ca7de..4d57177ec 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -28,14 +28,14 @@ public class VdypLayer extends SingleSiteLayer implements private UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = // VdypUtilizationHolder.emptyUtilization(); // LVCOM/VOL_DWB species 0 - private Optional empericalRelationshipParameterIndex = Optional.empty(); // INXL1/GRPBA1 + private Optional empiricalRelationshipParameterIndex = Optional.empty(); // INXL1/GRPBA1 public VdypLayer( PolygonIdentifier polygonIdentifier, LayerType layer, Optional inventoryTypeGroup, - Optional empericalRelationshipParameterIndex + Optional empiricalRelationshipParameterIndex ) { super(polygonIdentifier, layer, inventoryTypeGroup); - this.empericalRelationshipParameterIndex = empericalRelationshipParameterIndex; + this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex; } @Computed @@ -140,11 +140,11 @@ public void setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( } public Optional getEmpiricalRelationshipParameterIndex() { - return empericalRelationshipParameterIndex; + return empiricalRelationshipParameterIndex; } public void setEmpericalRelationshipParameterIndex(Optional empericalRelationshipParameterIndex) { - this.empericalRelationshipParameterIndex = empericalRelationshipParameterIndex; + this.empiricalRelationshipParameterIndex = empericalRelationshipParameterIndex; } /** diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index 8cbafc8a5..229033ca1 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -44,6 +44,11 @@ public VdypPolygon( } } + @Override + public String toString() { + return super.getPolygonIdentifier().toString(); + } + public Optional getTargetYear() { return targetYear; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index 0a219f336..3e6b20158 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -1,9 +1,13 @@ package ca.bc.gov.nrs.vdyp.model; +import java.text.MessageFormat; import java.util.Collection; +import java.util.Map; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Consumer; +import ca.bc.gov.nrs.vdyp.application.InitializationIncompleteException; import ca.bc.gov.nrs.vdyp.common.Utils; public class VdypSpecies extends BaseVdypSpecies implements VdypUtilizationHolder { @@ -19,14 +23,21 @@ public class VdypSpecies extends BaseVdypSpecies implements VdypUtiliz private UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(); // LVCOM/VOL_DW private UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(); // LVCOM/VOL_DWB - int volumeGroup; - int decayGroup; - int breakageGroup; + private Optional volumeGroup; + private Optional decayGroup; + private Optional breakageGroup; + + // Compatibility Variables + + private Optional> cvVolume = Optional.empty(); + private Optional> cvBasalArea = Optional.empty(); + private Optional> cvQuadraticMeanDiameter = Optional.empty(); + private Optional> cvPrimaryLayerSmall = Optional.empty(); public VdypSpecies( - PolygonIdentifier polygonIdentifier, LayerType layer, String genus, int genusIndex, float percentGenus, - Sp64DistributionSet sp64DistributionSet, Optional site, int volumeGroup, int decayGroup, - int breakageGroup + PolygonIdentifier polygonIdentifier, LayerType layer, String genus, int genusIndex, Optional percentGenus, + Sp64DistributionSet sp64DistributionSet, Optional site, Optional volumeGroup, + Optional decayGroup, Optional breakageGroup ) { super(polygonIdentifier, layer, genus, genusIndex, percentGenus, sp64DistributionSet, site); this.volumeGroup = volumeGroup; @@ -67,27 +78,42 @@ public void setLoreyHeightByUtilization(UtilizationVector loreyHeightByUtilizati } public int getVolumeGroup() { - return volumeGroup; + return volumeGroup.orElseThrow(() -> new NoSuchElementException(MessageFormat.format("Species {0} volumeGroup", + toString()))); } public void setVolumeGroup(int volumeGroup) { - this.volumeGroup = volumeGroup; + if (this.volumeGroup.isPresent()) { + throw new IllegalStateException(MessageFormat.format("Species {0} volumeGroup is already set", toString())); + } + + this.volumeGroup = Optional.of(volumeGroup); } public int getDecayGroup() { - return decayGroup; + return decayGroup.orElseThrow(() -> new NoSuchElementException(MessageFormat.format("Species {0} decayGroup", + toString()))); } public void setDecayGroup(int decayGroup) { - this.decayGroup = decayGroup; + if (this.decayGroup.isPresent()) { + throw new IllegalStateException(MessageFormat.format("Species {0} decayGroup is already set", toString())); + } + + this.decayGroup = Optional.of(decayGroup); } public int getBreakageGroup() { - return breakageGroup; + return breakageGroup.orElseThrow(() -> new NoSuchElementException(MessageFormat.format("Species {0} breakageGroup", + toString()))); } public void setBreakageGroup(int breakageGroup) { - this.breakageGroup = breakageGroup; + if (this.breakageGroup.isPresent()) { + throw new IllegalStateException(MessageFormat.format("Species {0} breakageGroup is already set", toString())); + } + + this.breakageGroup = Optional.of(breakageGroup); } @Override @@ -166,6 +192,46 @@ public void setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization; } + public void setCompatibilityVariables( + MatrixMap3 cvVolume, + MatrixMap2 cvBasalArea, + MatrixMap2 cvQuadraticMeanDiameter, + Map cvPrimaryLayerSmall) { + + this.cvVolume = Optional.of(cvVolume); + this.cvBasalArea = Optional.of(cvBasalArea); + this.cvQuadraticMeanDiameter = Optional.of(cvQuadraticMeanDiameter); + this.cvPrimaryLayerSmall = Optional.of(cvPrimaryLayerSmall); + } + + public float getCvVolume(UtilizationClass uc, VolumeVariable vv, LayerType lt) { + if (cvVolume.isEmpty()) { + throw new InitializationIncompleteException(MessageFormat.format("Species {0}: cvVolume", this)); + } + return cvVolume.get().get(uc, vv, lt); + } + + public float getCvBasalArea(UtilizationClass uc, LayerType lt) { + if (cvBasalArea.isEmpty()) { + throw new InitializationIncompleteException(MessageFormat.format("Species {0}: cvBasalArea", this)); + } + return cvBasalArea.get().get(uc, lt); + } + + public float getCvQuadraticMeanDiameter(UtilizationClass uc, LayerType lt) { + if (cvQuadraticMeanDiameter.isEmpty()) { + throw new InitializationIncompleteException(MessageFormat.format("Species {0}: cvQuadraticMeanDiameter", this)); + } + return cvQuadraticMeanDiameter.get().get(uc, lt); + } + + public float getCvPrimaryLayerSmall(UtilizationClassVariable ucv) { + if (cvPrimaryLayerSmall.isEmpty()) { + throw new InitializationIncompleteException(MessageFormat.format("Species {0}: cvPrimaryLayerSmall", this)); + } + return cvPrimaryLayerSmall.get().get(ucv); + } + /** * Accepts a configuration function that accepts a builder to configure. * @@ -264,9 +330,6 @@ public void wholeStemVolume(float volume) { @Override protected void check(Collection errors) { super.check(errors); - requirePresent(volumeGroup, "volumeGroup", errors); - requirePresent(decayGroup, "decayGroup", errors); - requirePresent(breakageGroup, "breakageGroup", errors); } @Override @@ -296,12 +359,12 @@ protected VdypSpecies doBuild() { layerType.get(), // genus.get(), // genusIndex.get(), // - percentGenus.get(), // + percentGenus, // sp64DistributionSet, // site, // - volumeGroup.get(), // - decayGroup.get(), // - breakageGroup.get() // + volumeGroup, // + decayGroup, // + breakageGroup // ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index 38010d5fa..0b18964db 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -1369,10 +1369,6 @@ void testApplyToObject() throws Exception { lb.addSpecies(sb -> { sb.genus("B", controlMap); sb.percentGenus(100); - - sb.volumeGroup(0); - sb.decayGroup(0); - sb.breakageGroup(0); }); }); }); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java index bdd366e00..bcc16ce40 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java @@ -14,7 +14,7 @@ protected TestSpecies( PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, int genusIndex, float percentGenus, Optional site ) { - super(polygonIdentifier, layerType, genus, genusIndex, percentGenus, new Sp64DistributionSet(), site); + super(polygonIdentifier, layerType, genus, genusIndex, Optional.of(percentGenus), new Sp64DistributionSet(), site); } public static TestSpecies build(Consumer config) { diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java index afcd7d339..461e93ba1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java @@ -45,9 +45,7 @@ ex, hasProperty( "message", allOf( containsString("polygonIdentifier"), containsString("layer"), containsString( "genus" - ), containsString( - "percentGenus" - ), containsString("volumeGroup"), containsString("decayGroup") + ) ) ) ); diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java index 6065f8808..78e2e4582 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipSpecies.java @@ -14,7 +14,7 @@ public FipSpecies( PolygonIdentifier polygonIdentifier, LayerType layer, String genus, int genusIndex, float percentGenus, Sp64DistributionSet sp64DistributionSet, Optional site ) { - super(polygonIdentifier, layer, genus, genusIndex, percentGenus, sp64DistributionSet, site); + super(polygonIdentifier, layer, genus, genusIndex, Optional.of(percentGenus), sp64DistributionSet, site); } /** diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java index b4a742374..c7f3820f5 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java @@ -117,45 +117,30 @@ VdypLayer mockLayer1(Map control) { var spec3 = VdypSpecies.build(layer, builder -> { builder.genus(GenusDefinitionParser.getSpeciesByIndex(3, control).getAlias(), control); // B builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); }); spec3.getLoreyHeightByUtilization().setAll(38.7456512f); var spec4 = VdypSpecies.build(layer, builder -> { builder.genus(GenusDefinitionParser.getSpeciesByIndex(4, control).getAlias(), control); // C builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); }); spec4.getLoreyHeightByUtilization().setAll(22.8001652f); var spec5 = VdypSpecies.build(layer, builder -> { builder.genus(GenusDefinitionParser.getSpeciesByIndex(5, control).getAlias(), control); // D builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); }); spec5.getLoreyHeightByUtilization().setAll(33.6889763f); var spec8 = VdypSpecies.build(layer, builder -> { builder.genus(GenusDefinitionParser.getSpeciesByIndex(8, control).getAlias(), control); // 8 builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); }); spec8.getLoreyHeightByUtilization().setAll(24.3451157f); var spec15 = VdypSpecies.build(layer, builder -> { builder.genus(GenusDefinitionParser.getSpeciesByIndex(15, control).getAlias(), control); // S builder.percentGenus(20f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); }); spec15.getLoreyHeightByUtilization().setAll(34.6888771f); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 511c3c61b..7dd8be325 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -60,11 +60,12 @@ class Bank { 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) throws ProcessingException { + public Bank(VdypLayer layer, BecDefinition becZone, Predicate retainCriteria) + throws ProcessingException { 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(); @@ -103,37 +104,39 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai } } - enum CopyMode { CopyAll, CopyStructure }; - - public Bank(Bank s, CopyMode copyMode) { + enum CopyMode { + CopyAll, CopyStructure + }; - this.becZone = s.becZone; - this.layer = s.layer; + public Bank(Bank source, CopyMode copyMode) { - this.nSpecies = s.nSpecies; - this.indices = copy(s.indices); - this.speciesNames = copy(s.speciesNames); - this.speciesIndices = copy(s.speciesIndices); + this.becZone = source.becZone; + this.layer = source.layer; - this.siteCurveNumbers = copy(s.siteCurveNumbers); - this.sp64Distributions = copy(s.sp64Distributions); + 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); if (copyMode == CopyMode.CopyAll) { - this.ageTotals = copy(s.ageTotals); - this.dominantHeights = copy(s.dominantHeights); - this.percentagesOfForestedLand = copy(s.percentagesOfForestedLand); - this.siteIndices = copy(s.siteIndices); - this.yearsAtBreastHeight = copy(s.yearsAtBreastHeight); - this.yearsToBreastHeight = copy(s.yearsToBreastHeight); - - this.basalAreas = copy(s.basalAreas); - this.closeUtilizationVolumes = copy(s.closeUtilizationVolumes); - this.cuVolumesMinusDecay = copy(s.cuVolumesMinusDecay); - this.cuVolumesMinusDecayAndWastage = copy(s.cuVolumesMinusDecayAndWastage); - this.loreyHeights = copy(s.loreyHeights); - this.quadMeanDiameters = copy(s.quadMeanDiameters); - this.treesPerHectare = copy(s.treesPerHectare); - this.wholeStemVolumes = copy(s.wholeStemVolumes); + 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); } else { this.ageTotals = buildShell(nSpecies); this.dominantHeights = buildShell(nSpecies); @@ -141,7 +144,7 @@ public Bank(Bank s, CopyMode copyMode) { this.siteIndices = buildShell(nSpecies); this.yearsAtBreastHeight = buildShell(nSpecies); this.yearsToBreastHeight = buildShell(nSpecies); - + int nUtilizationClasses = UtilizationClass.values().length; this.basalAreas = buildShell(nSpecies, nUtilizationClasses); this.closeUtilizationVolumes = buildShell(nSpecies, nUtilizationClasses); @@ -153,24 +156,24 @@ public Bank(Bank s, CopyMode copyMode) { this.wholeStemVolumes = buildShell(nSpecies, nUtilizationClasses); } } - + private float[] buildShell(int n) { - + float[] result = new float[nSpecies + 1]; Arrays.fill(result, Float.NaN); return result; } private float[][] buildShell(int n, int m) { - + float[][] result = new float[nSpecies + 1][]; - - for (int i = 0; i < n; i++) { + + for (int i = 0; i <= n; i++) { float[] row = new float[m]; Arrays.fill(row, Float.NaN); result[i] = row; } - + return result; } @@ -185,32 +188,39 @@ int[] getIndices() { BecDefinition getBecZone() { return becZone; } - + /** - * 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. + * 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 getUpdatedLayer() { + transferLayerFromBank(); + return layer; } private void transferSpeciesIntoBank(int index, VdypSpecies species) throws ProcessingException { - VdypSite site = species.getSite().orElseThrow(() -> new ProcessingException(MessageFormat.format( - "Species {0} of Polygon {1} must contain a Site definition but does not.", - species.getGenus(), species.getPolygonIdentifier().toStringCompact()))); - + VdypSite site = species.getSite().orElseThrow( + () -> new ProcessingException( + MessageFormat.format( + "Species {0} of Polygon {1} must contain a Site definition but does not.", + species.getGenus(), species.getPolygonIdentifier().toStringCompact() + ) + ) + ); + speciesNames[index] = species.getGenus(); sp64Distributions[index] = species.getSp64DistributionSet(); siteIndices[index] = site.getSiteIndex().orElse(VdypEntity.MISSING_FLOAT_VALUE); dominantHeights[index] = site.getHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); ageTotals[index] = site.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE); yearsToBreastHeight[index] = site.getYearsToBreastHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); - if (ageTotals[index] != VdypEntity.MISSING_FLOAT_VALUE && yearsToBreastHeight[index] != 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; @@ -224,12 +234,13 @@ private void transferSpeciesIntoBank(int index, VdypSpecies species) throws Proc private void transferUtilizationsIntoBank(int index, VdypUtilizationHolder uh) { - for (UtilizationClass uc: UtilizationClass.values()) { + 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); + 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); } @@ -239,59 +250,37 @@ private void transferUtilizationsIntoBank(int index, VdypUtilizationHolder uh) { } } - private void transferDefaultUtilizationsIntoBank(int index) { - - for (var uc : UtilizationClass.values()) { - int ucIndex = uc.ordinal(); - basalAreas[index][ucIndex] = Float.NaN; - closeUtilizationVolumes[index][ucIndex] = Float.NaN; - cuVolumesMinusDecay[index][ucIndex] = Float.NaN; - cuVolumesMinusDecayAndWastage[index][ucIndex] = Float.NaN; - if (ucIndex < 2 /* only uc 0 and 1 have a lorey height */) { - loreyHeights[index][ucIndex] = Float.NaN; - } - quadMeanDiameters[index][ucIndex] = Float.NaN; - treesPerHectare[index][ucIndex] = Float.NaN; - wholeStemVolumes[index][ucIndex] = Float.NaN; - } - } - private void transferLayerFromBank() { transferUtilizationsFromBank(0, layer); - - for (int i: indices) { - transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i])); + + for (int i : indices) { + transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i])); } } private void transferSpeciesFromBank(int index, VdypSpecies species) { VdypSite site = species.getSite().get(); - - VdypSite updatedSite = new VdypSite.Builder() - .adapt(site) - .siteIndex(siteIndices[index]) - .ageTotal(ageTotals[index]) - .height(dominantHeights[index]) - .yearsToBreastHeight(yearsToBreastHeight[index]) - .build(); - - VdypSpecies speciesBuilder = new VdypSpecies.Builder() - .addSite(updatedSite) - .adapt(species).build(); + VdypSite updatedSite = new VdypSite.Builder().adapt(site).siteIndex(siteIndices[index]) + .ageTotal(ageTotals[index]).height(dominantHeights[index]) + .yearsToBreastHeight(yearsToBreastHeight[index]).build(); + + species = new VdypSpecies.Builder().addSite(updatedSite).adapt(species).build(); + transferUtilizationsIntoBank(index, species); } private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { - for (UtilizationClass uc: UtilizationClass.values()) { + 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]); + 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]); } @@ -303,7 +292,7 @@ private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { public Bank copy() { return new Bank(this, CopyMode.CopyAll); - + } private String[] copy(String[] a) { @@ -331,6 +320,7 @@ private float[][] copy(float[][] a) { } private Sp64DistributionSet[] copy(Sp64DistributionSet[] sp64Distributions) { - return Arrays.stream(sp64Distributions).map(Sp64DistributionSet::copy).toArray(Sp64DistributionSet[]::new); + return Arrays.stream(sp64Distributions).map(s -> s == null ? null : s.copy()) + .toArray(Sp64DistributionSet[]::new); } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 70d19b2e0..53f39b8fb 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -15,9 +15,12 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.UtilizationOperations; import ca.bc.gov.nrs.vdyp.common.Utils; +import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; +import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +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.UtilizationClass; @@ -31,35 +34,56 @@ public class ForwardDataStreamReader { private static final Logger logger = LoggerFactory.getLogger(ForwardDataStreamReader.class); + private final ForwardResolvedControlMap resolvedControlMap; + private final StreamingParser polygonStream; private final StreamingParser> layerSpeciesStream; private final StreamingParser> speciesUtilizationStream; Optional> polygonDescriptionStream; @SuppressWarnings("unchecked") - public ForwardDataStreamReader(Map controlMap) throws IOException { - - var polygonStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_POLY.name()); - polygonStream = ((StreamingParserFactory) polygonStreamFactory).get(); - - var layerSpeciesStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SPECIES.name()); - layerSpeciesStream = ((StreamingParserFactory>) layerSpeciesStreamFactory).get(); - - var speciesUtilizationStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()); - speciesUtilizationStream = ((StreamingParserFactory>) speciesUtilizationStreamFactory) - .get(); + public ForwardDataStreamReader(ForwardResolvedControlMap resolvedControlMap) throws ProcessingException { - polygonDescriptionStream = Optional.empty(); - if (controlMap.containsKey(ControlKey.FORWARD_INPUT_GROWTO.name())) { - var polygonDescriptionStreamFactory = Utils.> - expectParsedControl(controlMap, ControlKey.FORWARD_INPUT_GROWTO, StreamingParserFactory.class); + try { + this.resolvedControlMap = resolvedControlMap; + Map controlMap = resolvedControlMap.getControlMap(); + + var polygonStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_POLY.name()); + polygonStream = ((StreamingParserFactory) polygonStreamFactory).get(); + + var layerSpeciesStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SPECIES.name()); + layerSpeciesStream = ((StreamingParserFactory>) layerSpeciesStreamFactory).get(); + + var speciesUtilizationStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()); + speciesUtilizationStream = ((StreamingParserFactory>) speciesUtilizationStreamFactory) + .get(); - polygonDescriptionStream = Optional.of(polygonDescriptionStreamFactory.get()); - } else { polygonDescriptionStream = Optional.empty(); + if (controlMap.containsKey(ControlKey.FORWARD_INPUT_GROWTO.name())) { + var polygonDescriptionStreamFactory = Utils.> + expectParsedControl(controlMap, ControlKey.FORWARD_INPUT_GROWTO, StreamingParserFactory.class); + + polygonDescriptionStream = Optional.of(polygonDescriptionStreamFactory.get()); + } else { + polygonDescriptionStream = Optional.empty(); + } + } catch (IOException e) { + throw new ProcessingException(e); } } + /** + * Constructor that takes a raw control map. This should only be used from unit tests. + * + * @param controlMap + * @throws IOException in the event of an error + * @throws ProcessingException + */ + ForwardDataStreamReader(Map controlMap) throws ProcessingException { + + this(new ForwardResolvedControlMapImpl(controlMap)); + } + public Optional readNextPolygon() throws ProcessingException { // Advance all the streams until the definition for the polygon is found. @@ -106,11 +130,19 @@ public Optional readNextPolygon() throws ProcessingException { for (var s : layerSpeciesSet) { logger.trace("Saw species {}", s); - var key = new UtilizationBySpeciesKey(s.getLayerType(), s.getGenusIndex()); - var speciesUtilizations = utilizationsBySpeciesMap.get(key); + applyGroups(polygon.getBiogeoclimaticZone(), s.getGenus(), s); + + var perSpeciesKey = new UtilizationBySpeciesKey(s.getLayerType(), s.getGenusIndex()); + var speciesUtilizations = utilizationsBySpeciesMap.get(perSpeciesKey); if (speciesUtilizations != null) { setUtilizations(s, speciesUtilizations); + + var defaultKey = new UtilizationBySpeciesKey(LayerType.PRIMARY, 0); + Map defaultUtilization = utilizationsBySpeciesMap + .get(defaultKey); + + calculateSpeciesCoverage(s, defaultUtilization); } if (LayerType.PRIMARY.equals(s.getLayerType())) { @@ -152,7 +184,7 @@ public Optional readNextPolygon() throws ProcessingException { if (veteranSpecies.size() > 0) { var key = new UtilizationBySpeciesKey(LayerType.VETERAN, 0); - Map defaultSpeciesUtilization = utilizationsBySpeciesMap + Map defaultUtilization = utilizationsBySpeciesMap .get(key); veteranLayer = VdypLayer.build(builder -> { @@ -162,7 +194,7 @@ public Optional readNextPolygon() throws ProcessingException { builder.addSpecies(layerSpeciesSet); }); - setUtilizations(veteranLayer, defaultSpeciesUtilization); + setUtilizations(veteranLayer, defaultUtilization); layerMap.put(LayerType.VETERAN, veteranLayer); } @@ -179,6 +211,33 @@ public Optional readNextPolygon() throws ProcessingException { return thePolygon; } + private void calculateSpeciesCoverage(VdypSpecies s, Map defaultUtilization) { + + float speciesCoverage = s.getBaseAreaByUtilization().get(UtilizationClass.ALL) + / defaultUtilization.get(UtilizationClass.ALL).getBasalArea(); + + s.setPercentGenus(speciesCoverage); + } + + protected void applyGroups(BecDefinition bec, String genus, VdypSpecies species) { + // Look up Volume group, Decay Group, and Breakage group for each species. + + var volumeGroupMap = resolvedControlMap.getVolumeEquationGroups(); + var decayGroupMap = resolvedControlMap.getDecayEquationGroups(); + var breakageGroupMap = resolvedControlMap.getBreakageEquationGroups(); + + // VGRPFIND + var volumeGroup = volumeGroupMap.get(genus, bec.getVolumeBec().getAlias()); + // DGRPFIND + var decayGroup = decayGroupMap.get(genus, bec.getDecayBec().getAlias()); + // BGRPFIND (Breakage uses decay BEC) + var breakageGroup = breakageGroupMap.get(genus, bec.getDecayBec().getAlias()); + + species.setVolumeGroup(volumeGroup); + species.setDecayGroup(decayGroup); + species.setBreakageGroup(breakageGroup); + } + private void setUtilizations(VdypUtilizationHolder u, Map speciesUtilizations) { for (var e: speciesUtilizations.entrySet()) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index b087d8763..f941a9049 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -43,6 +43,7 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CommonData; +import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; @@ -60,6 +61,7 @@ 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.VolumeComputeMode; import ca.bc.gov.nrs.vdyp.model.VolumeVariable; import ca.bc.gov.nrs.vdyp.si32.site.SiteTool; @@ -180,24 +182,24 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilYear) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank primaryBank = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank primaryBank = lps.getStartBank(); Optional veteranLayer; - if (pps.getPolygon().getLayers().containsKey(LayerType.VETERAN)){ - veteranLayer = Optional.of(pps.getPolygon().getLayers().get(LayerType.VETERAN)); + if (lps.getPolygon().getLayers().containsKey(LayerType.VETERAN)){ + veteranLayer = Optional.of(lps.getPolygon().getLayers().get(LayerType.VETERAN)); } else { veteranLayer = Optional.empty(); } logger.info( - "Beginning processing of polygon {} Primary layer {}", pps.getPolygon().getPolygonIdentifier() + "Beginning processing of polygon {} Primary layer {}", lps.getPolygon().getPolygonIdentifier() .toStringCompact() ); // BANKCHK1, simplified for the parameters METH_CHK = 4, LayerI = 1, and INSTANCE = 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CHECK_FOR_WORK.ordinal()) { - stopIfNoWork(pps); + stopIfNoWork(lps); } // SCINXSET - note these are calculated directly from the Primary bank of instance 1 @@ -216,16 +218,16 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // SITEADD (TODO: SITEADDU when NDEBUG 11 > 0) if (lastStepInclusive.ordinal() >= ExecutionStep.ESTIMATE_MISSING_SITE_INDICES.ordinal()) { - estimateMissingSiteIndices(pps); + estimateMissingSiteIndices(lps); } if (lastStepInclusive.ordinal() >= ExecutionStep.ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES.ordinal()) { - estimateMissingYearsToBreastHeightValues(pps); + estimateMissingYearsToBreastHeightValues(lps); } // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX.ordinal()) { - calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); + calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } // CVSET1 @@ -237,7 +239,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { int startingYear = fps.getLayerProcessingState().getPolygon().getPolygonIdentifier().getYear(); - VdypPolygon vdypPolygon = pps.getPolygon(); + VdypPolygon vdypPolygon = lps.getPolygon(); VdypLayer primaryLayer = vdypPolygon.getLayers().get(LayerType.PRIMARY); @@ -276,8 +278,8 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY private VdypLayer grow(Bank start, int currentYear, Optional veteranLayer) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); - VdypPolygon polygon = pps.getPolygon(); + LayerProcessingState lps = fps.getLayerProcessingState(); + VdypPolygon polygon = lps.getPolygon(); logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); @@ -292,14 +294,14 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL calculateCoverages(); // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 - calculateDominantHeightAgeSiteIndex(pps, fps.fcm.getHl1Coefficients()); + calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } - float dhStart = pps.getPrimarySpeciesDominantHeight(); - int pspSiteCurveNumber = pps.getSiteCurveNumber(pps.getPrimarySpeciesIndex()); - float pspSiteIndex = pps.getPrimarySpeciesSiteIndex(); - float pspYtbhStart = pps.getPrimarySpeciesAgeToBreastHeight(); - float pspYabhStart = pps.getPrimarySpeciesAgeAtBreastHeight(); + float dhStart = lps.getPrimarySpeciesDominantHeight(); + int pspSiteCurveNumber = lps.getSiteCurveNumber(lps.getPrimarySpeciesIndex()); + float pspSiteIndex = lps.getPrimarySpeciesSiteIndex(); + float pspYtbhStart = lps.getPrimarySpeciesAgeToBreastHeight(); + float pspYabhStart = lps.getPrimarySpeciesAgeAtBreastHeight(); // Calculate change in dominant height @@ -335,8 +337,8 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL float baChangeRate = baDelta / baStart; - float pspLhStart = start.loreyHeights[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; - float pspTphStart = start.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspLhStart = start.loreyHeights[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspTphStart = start.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; float dhEnd = dhStart + dhDelta; float dqEnd = dqStart + dqDelta; @@ -422,7 +424,7 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL // Calculate Lorey heights over all species, uc UC_ALL_INDEX - float pspTphEnd = end.treesPerHectare[pps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspTphEnd = end.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; growLoreyHeights(end, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); // We now have site level predications for basal area, quad-mean-diameter, trees-per-hectare @@ -435,14 +437,14 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL } // Update the running values. TODO: why isn't siteIndex being updated? - pps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); + lps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); for (int i = 1; i < start.getNSpecies(); i++) { - if (i == pps.getPrimarySpeciesIndex()) { - end.ageTotals[i] = pps.getPrimarySpeciesTotalAge(); + if (i == lps.getPrimarySpeciesIndex()) { + end.ageTotals[i] = lps.getPrimarySpeciesTotalAge(); end.dominantHeights[i] = dhEnd; - end.siteIndices[i] = pps.getPrimarySpeciesSiteIndex(); - end.yearsAtBreastHeight[i] = pps.getPrimarySpeciesAgeAtBreastHeight(); + end.siteIndices[i] = lps.getPrimarySpeciesSiteIndex(); + end.yearsAtBreastHeight[i] = lps.getPrimarySpeciesAgeAtBreastHeight(); } else { float spSiStart = start.siteIndices[i]; float spDhStart = start.dominantHeights[i]; @@ -462,10 +464,14 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL } } - pps.updateCompatibilityVariablesAfterGrowth(); + lps.updateCompatibilityVariablesAfterGrowth(); - VdypLayer primaryLayer = pps.getStartBank().getUpdatedLayer(); - pps.getFps().computers.computeUtilizationComponentsPrimary(pps.getBecZone(), primaryLayer, null, null); + VdypLayer primaryLayer = lps.getLayerFromBank(end); + + VolumeComputeMode volumeComputationMode = VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC; + int controlVariable3Value = lps.getFps().fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); + CompatibilityVariableMode compatibilityVariableMode = CompatibilityVariableMode.getByInteger(controlVariable3Value); + lps.getFps().computers.computeUtilizationComponentsPrimary(lps.getBecZone(), primaryLayer, volumeComputationMode, compatibilityVariableMode); calculateSmallComponentYields(end); @@ -482,10 +488,10 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL */ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphChangeRate) { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { float spBaStart = start.basalAreas[i][UC_ALL_INDEX]; if (spBaStart > 0.0f) { @@ -526,44 +532,44 @@ private boolean growUsingPartialSpeciesDynamics( ) throws ProcessingException { boolean wasSuccessful = true; - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); - if (dqDelta == 0 || baDelta == 0 || pps.getNSpecies() == 1) { + if (dqDelta == 0 || baDelta == 0 || lps.getNSpecies() == 1) { return false /* no solution available */; } - float[] dqs1 = new float[pps.getNSpecies() + 1]; - float[] dqs2 = new float[pps.getNSpecies() + 1]; + float[] dqs1 = new float[lps.getNSpecies() + 1]; + float[] dqs2 = new float[lps.getNSpecies() + 1]; - float[] baNew = new float[pps.getNSpecies() + 1]; + float[] baNew = new float[lps.getNSpecies() + 1]; baNew[0] = baStart + baDelta; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { baNew[i] = start.basalAreas[i][0] * baNew[0] / start.basalAreas[0][0]; } - float[] dqNew = new float[pps.getNSpecies() + 1]; + float[] dqNew = new float[lps.getNSpecies() + 1]; dqNew[0] = dqStart + dqDelta; - float[] tphNew = new float[pps.getNSpecies() + 1]; + float[] tphNew = new float[lps.getNSpecies() + 1]; tphNew[0] = tphStart + BaseAreaTreeDensityDiameter.treesPerHectare(baNew[0], dqNew[0]); Map basalAreaPercentagesPerSpecies = new HashMap<>(); for (String spAlias : fps.fcm.getGenusDefinitionMap().getAllGeneraAliases()) { basalAreaPercentagesPerSpecies.put(spAlias, 0.0f); } - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { basalAreaPercentagesPerSpecies.put(start.speciesNames[i], start.percentagesOfForestedLand[i]); } - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { dqs1[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( start.speciesNames[i], start.basalAreas[i][0], start.quadMeanDiameters[i][0], basalAreaPercentagesPerSpecies, - pps.getBecZone().getRegion(), + lps.getBecZone().getRegion(), dqStart, baStart, tphStart, @@ -574,7 +580,7 @@ private boolean growUsingPartialSpeciesDynamics( baNew[0], dqNew[0], basalAreaPercentagesPerSpecies, - pps.getBecZone().getRegion(), + lps.getBecZone().getRegion(), dqStart, baStart, tphStart, @@ -589,16 +595,16 @@ private void growUsingFullSpeciesDynamics( float tphStart, float lhStart ) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); Bank end = new Bank(start, CopyMode.CopyStructure); - float spBaEnd[] = new float[pps.getNSpecies() + 1]; - float spTphNew[] = new float[pps.getNSpecies() + 1]; - float spDqNew[] = new float[pps.getNSpecies() + 1]; - boolean doSkip[] = new boolean[pps.getNSpecies() + 1]; + float spBaEnd[] = new float[lps.getNSpecies() + 1]; + float spTphNew[] = new float[lps.getNSpecies() + 1]; + float spDqNew[] = new float[lps.getNSpecies() + 1]; + boolean doSkip[] = new boolean[lps.getNSpecies() + 1]; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { spBaEnd[i] = start.basalAreas[i][UC_ALL_INDEX]; spTphNew[i] = start.treesPerHectare[i][UC_ALL_INDEX]; spDqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; @@ -607,13 +613,13 @@ private void growUsingFullSpeciesDynamics( } float sumSpBaDelta = 0.0f; - float spBaDelta[] = new float[pps.getNSpecies()]; + float spBaDelta[] = new float[lps.getNSpecies() + 1]; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { float pspLhStart = start.loreyHeights[i][UC_ALL_INDEX]; - if (i == pps.getPrimarySpeciesIndex()) { + if (i == lps.getPrimarySpeciesIndex()) { float pspBaStart = start.basalAreas[i][UC_ALL_INDEX]; - float pspYabhStart = pps.getPrimarySpeciesAgeAtBreastHeight(); + float pspYabhStart = lps.getPrimarySpeciesAgeAtBreastHeight(); // Note: the FORTRAN passes Lorey height into parameter "HD" ("Dominant Height") - are these // equivalent? @@ -652,9 +658,9 @@ private void growUsingFullSpeciesDynamics( int nSkipped = 0; sumSpBaDelta = 0.0f; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (!doSkip[i]) { - var spBaStart = pps.getStartBank().basalAreas[i][UC_ALL_INDEX]; + var spBaStart = lps.getStartBank().basalAreas[i][UC_ALL_INDEX]; spBaEnd[i] = spBaStart + spBaDelta[i] + f * spBaStart; if (spBaEnd[i] < 0.0f) { spBaEnd[i] = 0.0f; @@ -686,23 +692,23 @@ private void growUsingFullSpeciesDynamics( { // Estimate of quad-mean-diameter growth by species + + var passNumber = 0; + var bestScore = 1000.0; + var bestF = Float.NaN; while (true) { - var bestScore = 1000.0; - var bestF = Float.NaN; - var f = 0.0f; - var passNumber = 0; var nSkipped = 0; var totalBasalAreaSkipped = 0.0f; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; float spLhStart = start.loreyHeights[i][UC_ALL_INDEX]; float spDqDelta; - if (i == pps.getPrimarySpeciesIndex()) { + if (i == lps.getPrimarySpeciesIndex()) { spDqDelta = growQuadMeanDiameterForPrimarySpecies( dqStart, dqDelta, spDqStart, lhStart, spLhStart @@ -716,7 +722,7 @@ private void growUsingFullSpeciesDynamics( spDqDelta += f; ComponentSizeLimits csl = getComponentSizeLimits( - start.speciesNames[i], pps.getBecZone().getRegion() + start.speciesNames[i], lps.getBecZone().getRegion() ); var spLhAllStart = start.loreyHeights[i][UC_ALL_INDEX]; @@ -743,7 +749,7 @@ private void growUsingFullSpeciesDynamics( } float tph = 0.0f; - for (int i : start.speciesIndices) { + for (int i : start.getIndices()) { if (spBaEnd[i] > 0.0f) { spTphNew[i] = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd[i], spDqNew[i]); } else { @@ -752,7 +758,7 @@ private void growUsingFullSpeciesDynamics( tph += spTphNew[i]; } - if (passNumber == 15 || (nSkipped == pps.getNSpecies() && passNumber > 2)) { + if (passNumber == 15 || (nSkipped == lps.getNSpecies() && passNumber > 2)) { break; } @@ -783,7 +789,7 @@ private void growUsingFullSpeciesDynamics( } } - for (int i : start.speciesIndices) { + for (int i : start.getIndices()) { end.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; end.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; if (spBaEnd[i] > 0.0f) { @@ -823,8 +829,8 @@ private float growQuadMeanDiameterForPrimarySpecies( float dqStart, float dqDelta, float pspDqStart, float lhStart, float pspLhStart ) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); - int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); + LayerProcessingState lps = fps.getLayerProcessingState(); + int pspStratumNumber = lps.getPrimarySpeciesStratumNumber(); ModelCoefficients mc = fps.fcm.getPrimarySpeciesQuadMeanDiameterGrowthCoefficients().get(pspStratumNumber); @@ -845,10 +851,10 @@ private float growQuadMeanDiameterForNonPrimarySpecies( int speciesIndex, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart ) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); + LayerProcessingState lps = fps.getLayerProcessingState(); - String speciesName = pps.getStartBank().speciesNames[speciesIndex]; - int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); + String speciesName = lps.getStartBank().speciesNames[speciesIndex]; + int pspStratumNumber = lps.getPrimarySpeciesStratumNumber(); var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() .get(speciesName, pspStratumNumber); @@ -913,7 +919,7 @@ private float growBasalAreaForNonPrimarySpecies( float spLhStart ) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); + LayerProcessingState lps = fps.getLayerProcessingState(); if (spBaStart <= 0.0f || spBaStart >= baStart) { throw new ProcessingException( @@ -924,7 +930,7 @@ private float growBasalAreaForNonPrimarySpecies( ); } - int pspStratumNumber = pps.getPrimarySpeciesStratumNumber(); + int pspStratumNumber = lps.getPrimarySpeciesStratumNumber(); var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients() .get(speciesName, pspStratumNumber); @@ -979,11 +985,11 @@ private float growBasalAreaForPrimarySpecies( float pspLhStart ) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); + LayerProcessingState lps = fps.getLayerProcessingState(); float spToAllProportionStart = pspBaStart / baStart; if (spToAllProportionStart <= 0.999f) { - var psStratumNumber = pps.getPrimarySpeciesStratumNumber(); + var psStratumNumber = lps.getPrimarySpeciesStratumNumber(); ModelCoefficients mc = fps.fcm.getPrimarySpeciesBasalAreaGrowthCoefficients().get(psStratumNumber); int model = mc.getModel(); @@ -1022,28 +1028,28 @@ private float growBasalAreaForPrimarySpecies( */ private void calculateSmallComponentYields(Bank end) throws ProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); float lhSum = 0.0f; float baSum = 0.0f; float tphSum = 0.0f; float wsVolumeSum = 0.0f; - for (int speciesIndex : pps.getIndices()) { + for (int speciesIndex : lps.getIndices()) { float spLhAll = end.loreyHeights[speciesIndex][UC_ALL_INDEX]; float spBaAll = end.basalAreas[speciesIndex][UC_ALL_INDEX]; float spDqAll = end.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; - Region region = pps.getBecZone().getRegion(); + Region region = lps.getBecZone().getRegion(); String speciesName = start.speciesNames[speciesIndex]; // EMP080 float smallProbability = smallComponentProbability(speciesName, spLhAll, region); // This whole operation is on Actual BA's, not 100% occupancy. - float fractionAvailable = pps.getPolygon().getPercentAvailable() / 100.0f; + float fractionAvailable = lps.getPolygon().getPercentAvailable() / 100.0f; if (fractionAvailable > 0.0f) { spBaAll *= fractionAvailable; @@ -1071,22 +1077,22 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException .getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); if (controlVar3Value >= 1 /* apply compatibility variables */) { - spBaSmall += pps.getCVSmall(speciesIndex, UtilizationClassVariable.BASAL_AREA); + spBaSmall += lps.getCVSmall(speciesIndex, UtilizationClassVariable.BASAL_AREA); if (spBaSmall < 0.0f) { spBaSmall = 0.0f; } - spDqSmall += pps.getCVSmall(speciesIndex, UtilizationClassVariable.QUAD_MEAN_DIAMETER); + spDqSmall += lps.getCVSmall(speciesIndex, UtilizationClassVariable.QUAD_MEAN_DIAMETER); if (spDqSmall < 4.01f) { spDqSmall = 4.01f; } else if (spDqSmall > 7.49) { spDqSmall = 7.49f; } spLhSmall = 1.3f * (spLhSmall - 1.3f) - * FloatMath.exp(pps.getCVSmall(speciesIndex, UtilizationClassVariable.LOREY_HEIGHT)); + * FloatMath.exp(lps.getCVSmall(speciesIndex, UtilizationClassVariable.LOREY_HEIGHT)); if (controlVar3Value >= 2 && meanVolumeSmall > 0.0f) { meanVolumeSmall *= FloatMath - .exp(pps.getCVSmall(speciesIndex, UtilizationClassVariable.WHOLE_STEM_VOLUME)); + .exp(lps.getCVSmall(speciesIndex, UtilizationClassVariable.WHOLE_STEM_VOLUME)); } } @@ -1136,8 +1142,8 @@ private void growLoreyHeights( Bank end, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart ) { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); float pspLhStartEstimate = estimatePrimarySpeciesLoreyHeight(dhStart, pspTphStart); float pspLhEndEstimate = estimatePrimarySpeciesLoreyHeight(dhEnd, pspTphEnd); @@ -1160,7 +1166,7 @@ private void growLoreyHeights( float nonPrimaryLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightOther(); - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (start.basalAreas[i][UC_ALL_INDEX] > 0.0f && i != primarySpeciesIndex) { if (! (dhEnd == dhStart && debugSetting8Value >= 1)) { float spLhEstimate1 = estimateNonPrimarySpeciesLoreyHeight( @@ -1214,15 +1220,15 @@ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { private float estimateNonPrimarySpeciesLoreyHeight( int speciesIndex, float dh, float pspLoreyHeight ) { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); float spLh; - int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); String primarySpeciesAlias = start.speciesNames[primarySpeciesIndex]; String speciesAlias = start.speciesNames[speciesIndex]; - Region region = pps.getBecZone().getRegion(); + Region region = lps.getBecZone().getRegion(); var coefficients = fps.fcm.getLoreyHeightNonPrimaryCoefficients(); @@ -1267,8 +1273,8 @@ float growQuadMeanDiameter( ) throws StandProcessingException { - var pps = fps.getLayerProcessingState(); - var becZone = pps.getBecZone(); + var lps = fps.getLayerProcessingState(); + var becZone = lps.getBecZone(); float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); @@ -1277,28 +1283,29 @@ float growQuadMeanDiameter( Coefficients coefficientsWeightedBySpeciesAndDecayBec = Coefficients.empty(6, 0); for (int i = 0; i < 6; i++) { float sum = 0.0f; - for (int speciesIndex : pps.getIndices()) { - String speciesAlias = pps.getStartBank().speciesNames[speciesIndex]; + for (int speciesIndex : lps.getIndices()) { + String speciesAlias = lps.getStartBank().speciesNames[speciesIndex]; sum += dqYieldCoefficients.get(decayBecZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; } coefficientsWeightedBySpeciesAndDecayBec.setCoe(i, sum); } + float dqUpperBound = growQuadraticMeanDiameterUpperBound(); + float dqLimit = Math.max(dqUpperBound, dqStart); + int controlVariable2Value = fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float dqYieldStart = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhStart, pspYabhStart, veteranBaStart, pps - .getPrimarySpeciesGroupNumber() + coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhStart, pspYabhStart, veteranBaStart, dqLimit ); float dhEnd = dhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float dqYieldEnd = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhEnd, pspYabhEnd, veteranBaEnd, pps - .getPrimarySpeciesGroupNumber() + coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhEnd, pspYabhEnd, veteranBaEnd, dqLimit ); float dqYieldGrowth = dqYieldEnd - dqYieldStart; @@ -1354,9 +1361,6 @@ float growQuadMeanDiameter( throw new IllegalStateException("debugSetting6Value of " + debugSetting6Value + " is not supported"); } - float dqUpperBound = growQuadraticMeanDiameterUpperBound(); - float dqLimit = Math.max(dqUpperBound, dqStart); - if (dqStart + dqGrowth < 7.6f) { dqGrowth = 7.6f - dqStart; } @@ -1440,12 +1444,12 @@ private float calculateQuadMeanDiameterGrowthEmpirical( private float[] getSpeciesProportionsByBasalArea() { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); - float[] speciesProportionsByBasalArea = new float[pps.getNSpecies() + 1]; + float[] speciesProportionsByBasalArea = new float[lps.getNSpecies() + 1]; - for (int i = 1; i <= pps.getNSpecies(); i++) { + for (int i = 1; i <= lps.getNSpecies(); i++) { speciesProportionsByBasalArea[i] = start.basalAreas[i][UC_ALL_INDEX] / start.basalAreas[0][UC_ALL_INDEX]; } @@ -1470,17 +1474,17 @@ float growBasalArea( float baStart, Optional veteranLayerBa, float dhDelta ) throws StandProcessingException { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); var becZoneAlias = fps.getLayerProcessingState().getBecZone().getAlias(); Coefficients estimateBasalAreaYieldCoefficients = Coefficients.empty(7, 0); - for (int i = 0; i < 7; i++) { + for (int i = 0; i <= 6; i++) { float sum = 0.0f; - for (int speciesIndex : pps.getIndices()) { + for (int speciesIndex : lps.getIndices()) { String speciesAlias = start.speciesNames[speciesIndex]; sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; @@ -1491,19 +1495,21 @@ float growBasalArea( estimateBasalAreaYieldCoefficients.setCoe(5, 0.0f); } + // UPPERGEN( 1, BATOP98, DQTOP98) + var baUpperBound = growBasalAreaUpperBound(); + boolean isFullOccupancy = true; - int pspGroupNumber = fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(); int controlVariable2Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, pspGroupNumber + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, baUpperBound ); float pspDhEnd = pspDhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float baYieldEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, isFullOccupancy, pspGroupNumber + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, isFullOccupancy, baUpperBound ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() @@ -1547,9 +1553,6 @@ float growBasalArea( } } - // UPPERGEN( 1, BATOP98, DQTOP98) - var baUpperBound = growBasalAreaUpperBound(); - baUpperBound = baUpperBound / EstimationMethods.EMPIRICAL_OCCUPANCY; var baLimit = Math.max(baUpperBound, baStart); @@ -1650,18 +1653,18 @@ private float calculateBasalAreaGrowthEmpirical( */ private float growBasalAreaUpperBound() { - LayerProcessingState pps = fps.getLayerProcessingState(); + LayerProcessingState lps = fps.getLayerProcessingState(); int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); - Region region = pps.getBecZone().getRegion(); - int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + Region region = lps.getBecZone().getRegion(); + int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); return upperBoundsCoefficients - .get(region, pps.getStartBank().speciesNames[primarySpeciesIndex], 1); + .get(region, lps.getStartBank().speciesNames[primarySpeciesIndex], 1); } else { - var primarySpeciesGroupNumber = pps.getPrimarySpeciesGroupNumber(); + var primarySpeciesGroupNumber = lps.getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); } } @@ -1671,17 +1674,17 @@ private float growBasalAreaUpperBound() { */ private float growQuadraticMeanDiameterUpperBound() { - LayerProcessingState pps = fps.getLayerProcessingState(); + LayerProcessingState lps = fps.getLayerProcessingState(); int debugSetting4Value = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4); if (debugSetting4Value > 0) { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); - Region region = pps.getBecZone().getRegion(); - int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + Region region = lps.getBecZone().getRegion(); + int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); return upperBoundsCoefficients - .get(region, pps.getStartBank().speciesNames[primarySpeciesIndex], 2); + .get(region, lps.getStartBank().speciesNames[primarySpeciesIndex], 2); } else { var primarySpeciesGroupNumber = fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); @@ -1906,8 +1909,8 @@ void setCompatibilityVariables() throws ProcessingException { Coefficients aAdjust = new Coefficients(new float[] { 0.0f, 0.0f, 0.0f, 0.0f }, 1); var growthDetails = fps.fcm.getForwardControlVariables(); - var pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + var lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); // Note: L1COM2 (INL1VGRP, INL1DGRP, INL1BGRP) is initialized when // PolygonProcessingState (volumeEquationGroups, decayEquationGroups @@ -1918,12 +1921,12 @@ void setCompatibilityVariables() throws ProcessingException { // INL1VGRP is built, rather than when LCOM1 VGRPL is built in the // original code.) - var cvVolume = new MatrixMap3[pps.getNSpecies() + 1]; - var cvBasalArea = new MatrixMap2[pps.getNSpecies() + 1]; - var cvQuadraticMeanDiameter = new MatrixMap2[pps.getNSpecies() + 1]; - var cvSmall = new HashMap[pps.getNSpecies() + 1]; + var cvVolume = new MatrixMap3[lps.getNSpecies() + 1]; + var cvBasalArea = new MatrixMap2[lps.getNSpecies() + 1]; + var cvQuadraticMeanDiameter = new MatrixMap2[lps.getNSpecies() + 1]; + var cvSmall = new HashMap[lps.getNSpecies() + 1]; - for (int s = 1; s <= pps.getNSpecies(); s++) { + for (int s = 1; s <= lps.getNSpecies(); s++) { String genusName = start.speciesNames[s]; @@ -1975,7 +1978,7 @@ void setCompatibilityVariables() throws ProcessingException { // EMP094 fps.estimators.estimateNetDecayAndWasteVolume( - pps.getBecZone() + lps.getBecZone() .getRegion(), uc, aAdjust, start.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste ); @@ -1994,9 +1997,9 @@ void setCompatibilityVariables() throws ProcessingException { if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP093 - int decayGroup = pps.decayEquationGroups[s]; + int decayGroup = lps.decayEquationGroups[s]; fps.estimators.estimateNetDecayVolume( - start.speciesNames[s], pps.getBecZone().getRegion(), uc, aAdjust, decayGroup, pps + start.speciesNames[s], lps.getBecZone().getRegion(), uc, aAdjust, decayGroup, lps .getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay ); @@ -2014,7 +2017,7 @@ void setCompatibilityVariables() throws ProcessingException { if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP092 - int volumeGroup = pps.volumeEquationGroups[s]; + int volumeGroup = lps.volumeEquationGroups[s]; fps.estimators.estimateCloseUtilizationVolume( uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes ); @@ -2027,7 +2030,7 @@ void setCompatibilityVariables() throws ProcessingException { cvVolume[s].put(uc, VolumeVariable.CLOSE_UTIL_VOL, LayerType.PRIMARY, adjustment); } - int primarySpeciesVolumeGroup = pps.volumeEquationGroups[s]; + int primarySpeciesVolumeGroup = lps.volumeEquationGroups[s]; float primarySpeciesQMDAll = start.quadMeanDiameters[s][UC_ALL_INDEX]; var wholeStemVolume = start.treesPerHectare[s][UC_ALL_INDEX] * fps.estimators.estimateWholeStemVolumePerTree( @@ -2053,11 +2056,11 @@ void setCompatibilityVariables() throws ProcessingException { } fps.estimators.estimateQuadMeanDiameterByUtilization( - pps.getBecZone(), quadMeanDiameters, genusName + lps.getBecZone(), quadMeanDiameters, genusName ); fps.estimators.estimateBaseAreaByUtilization( - pps.getBecZone(), quadMeanDiameters, basalAreas, genusName + lps.getBecZone(), quadMeanDiameters, basalAreas, genusName ); // Calculate trees-per-hectare per utilization @@ -2096,7 +2099,7 @@ void setCompatibilityVariables() throws ProcessingException { cvSmall[s] = calculateSmallCompatibilityVariables(s, growthDetails); } - pps.setCompatibilityVariableDetails(cvVolume, cvBasalArea, cvQuadraticMeanDiameter, cvSmall); + lps.setCompatibilityVariableDetails(cvVolume, cvBasalArea, cvQuadraticMeanDiameter, cvSmall); } /** @@ -2111,10 +2114,10 @@ void setCompatibilityVariables() throws ProcessingException { calculateSmallCompatibilityVariables(int speciesIndex, ForwardControlVariables forwardControlVariables) throws ProcessingException { - var pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + var lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); - Region region = pps.getBecZone().getRegion(); + Region region = lps.getBecZone().getRegion(); String speciesName = start.speciesNames[speciesIndex]; float spLoreyHeight_All = start.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp @@ -2191,7 +2194,7 @@ void setCompatibilityVariables() throws ProcessingException { private float smallComponentProbability( String speciesName, float loreyHeight, Region region ) { - LayerProcessingState pps = fps.getLayerProcessingState(); + LayerProcessingState lps = fps.getLayerProcessingState(); Coefficients coe = fps.fcm.getSmallComponentProbabilityCoefficients().get(speciesName); @@ -2206,7 +2209,7 @@ private float smallComponentProbability( float logit = a0 + // a1 + // - a2 * pps.getStartBank().yearsAtBreastHeight[pps.getPrimarySpeciesIndex()] + // + a2 * lps.getStartBank().yearsAtBreastHeight[lps.getPrimarySpeciesIndex()] + // a3 * loreyHeight; return exp(logit) / (1.0f + exp(logit)); @@ -2335,18 +2338,18 @@ private static float calculateWholeStemVolume(float actualVolume, float basalAre /** * VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 * - * @param pps + * @param lps * @param hl1Coefficients * @throws ProcessingException */ static void calculateDominantHeightAgeSiteIndex( - LayerProcessingState pps, MatrixMap2 hl1Coefficients + LayerProcessingState lps, MatrixMap2 hl1Coefficients ) throws ProcessingException { - Bank startBank = pps.getStartBank(); + Bank startBank = lps.getStartBank(); // Calculate primary species values - int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); // (1) Dominant Height float primarySpeciesDominantHeight = startBank.dominantHeights[primarySpeciesIndex]; @@ -2362,7 +2365,7 @@ static void calculateDominantHeightAgeSiteIndex( // Estimate dominant height from the lorey height String primarySpeciesAlias = startBank.speciesNames[primarySpeciesIndex]; - Region primarySpeciesRegion = pps.getBecZone().getRegion(); + Region primarySpeciesRegion = lps.getBecZone().getRegion(); var coefficients = hl1Coefficients.get(primarySpeciesAlias, primarySpeciesRegion); float a0 = coefficients.getCoe(1); @@ -2384,11 +2387,11 @@ static void calculateDominantHeightAgeSiteIndex( if (Float.isNaN(primarySpeciesTotalAge)) { - if (pps.hasSecondarySpeciesIndex() - && !Float.isNaN(startBank.ageTotals[pps.getSecondarySpeciesIndex()])) { - activeIndex = Optional.of(pps.getSecondarySpeciesIndex()); + if (lps.hasSecondarySpeciesIndex() + && !Float.isNaN(startBank.ageTotals[lps.getSecondarySpeciesIndex()])) { + activeIndex = Optional.of(lps.getSecondarySpeciesIndex()); } else { - for (int i = 1; i <= pps.getNSpecies(); i++) { + for (int i = 1; i <= lps.getNSpecies(); i++) { if (!Float.isNaN(startBank.ageTotals[i])) { activeIndex = Optional.of(i); break; @@ -2413,12 +2416,12 @@ static void calculateDominantHeightAgeSiteIndex( float primarySpeciesSiteIndex = startBank.siteIndices[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesSiteIndex)) { - if (pps.hasSecondarySpeciesIndex() - && !Float.isNaN(startBank.siteIndices[pps.getSecondarySpeciesIndex()])) { - activeIndex = Optional.of(pps.getSecondarySpeciesIndex()); + if (lps.hasSecondarySpeciesIndex() + && !Float.isNaN(startBank.siteIndices[lps.getSecondarySpeciesIndex()])) { + activeIndex = Optional.of(lps.getSecondarySpeciesIndex()); } else { if (activeIndex.isEmpty() || Float.isNaN(startBank.siteIndices[activeIndex.get()])) { - for (int i = 1; i <= pps.getNSpecies(); i++) { + for (int i = 1; i <= lps.getNSpecies(); i++) { if (!Float.isNaN(startBank.siteIndices[i])) { activeIndex = Optional.of(i); break; @@ -2432,8 +2435,8 @@ static void calculateDominantHeightAgeSiteIndex( activeIndex = Optional.of(primarySpeciesIndex); } - SiteIndexEquation siteCurve1 = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(activeIndex.get())); - SiteIndexEquation siteCurve2 = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(0)); + SiteIndexEquation siteCurve1 = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(activeIndex.get())); + SiteIndexEquation siteCurve2 = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(0)); try { double newSI = SiteTool.convertSiteIndexBetweenCurves(siteCurve1, primarySpeciesSiteIndex, siteCurve2); @@ -2444,7 +2447,7 @@ static void calculateDominantHeightAgeSiteIndex( // do nothing. primarySpeciesSiteIndex will not be modified. } - pps.setPrimarySpeciesDetails( + lps.setPrimarySpeciesDetails( new PrimarySpeciesDetails( primarySpeciesDominantHeight, primarySpeciesSiteIndex, primarySpeciesTotalAge, primarySpeciesYearsAtBreastHeight, primarySpeciesYearsToBreastHeight @@ -2457,13 +2460,13 @@ static void calculateDominantHeightAgeSiteIndex( * years-at-breast-height and age-total values if given or otherwise estimate it from the site curve and site index * values for the species. * - * @param pps the current state of the processing of the polygon + * @param lps the current state of the processing of the polygon */ - static void estimateMissingYearsToBreastHeightValues(LayerProcessingState pps) { + static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { - Bank start = pps.getStartBank(); + Bank start = lps.getStartBank(); - int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); + int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; // Determine the default site index by using the site index of the primary species unless @@ -2474,7 +2477,7 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState pps) { float defaultSiteIndex = primarySpeciesSiteIndex; if (Float.isNaN(defaultSiteIndex)) { - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (!Float.isNaN(start.siteIndices[i])) { defaultSiteIndex = start.siteIndices[i]; break; @@ -2482,7 +2485,7 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState pps) { } } - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (!Float.isNaN(start.yearsToBreastHeight[i])) { // was supplied continue; @@ -2500,7 +2503,7 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState pps) { float siteIndex = !Float.isNaN(start.siteIndices[i]) ? start.siteIndices[i] : defaultSiteIndex; try { - SiteIndexEquation curve = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(i)); + SiteIndexEquation curve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); double yearsToBreastHeight = SiteTool.yearsToBreastHeight(curve, siteIndex); start.yearsToBreastHeight[i] = (float) yearsToBreastHeight; } catch (CommonCalculatorException e) { @@ -2518,15 +2521,15 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState pps) { * index has not been set from the primary site index after converting it between the site curve of the other * species and that of the primary species. * - * @param pps the bank in which the calculations are done. + * @param lps the bank in which the calculations are done. * @throws ProcessingException */ - static void estimateMissingSiteIndices(LayerProcessingState pps) throws ProcessingException { + static void estimateMissingSiteIndices(LayerProcessingState lps) throws ProcessingException { - Bank start = pps.getStartBank(); + Bank start = lps.getStartBank(); - int primarySpeciesIndex = pps.getPrimarySpeciesIndex(); - SiteIndexEquation primarySiteCurve = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(primarySpeciesIndex)); + int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); + SiteIndexEquation primarySiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(primarySpeciesIndex)); // (1) @@ -2535,7 +2538,7 @@ static void estimateMissingSiteIndices(LayerProcessingState pps) throws Processi double otherSiteIndicesSum = 0.0f; int nOtherSiteIndices = 0; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (i == primarySpeciesIndex) { continue; @@ -2544,7 +2547,7 @@ static void estimateMissingSiteIndices(LayerProcessingState pps) throws Processi float siteIndexI = start.siteIndices[i]; if (!Float.isNaN(siteIndexI)) { - SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(i)); + SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); try { double mappedSiteIndex = SiteTool @@ -2579,7 +2582,7 @@ static void estimateMissingSiteIndices(LayerProcessingState pps) throws Processi float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; if (!Float.isNaN(primarySpeciesSiteIndex)) { - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (i == primarySpeciesIndex) { continue; @@ -2587,7 +2590,7 @@ static void estimateMissingSiteIndices(LayerProcessingState pps) throws Processi float siteIndexI = start.siteIndices[i]; if (Float.isNaN(siteIndexI)) { - SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(pps.getSiteCurveNumber(i)); + SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); try { double mappedSiteIndex = SiteTool @@ -2622,14 +2625,14 @@ static void estimateMissingSiteIndices(LayerProcessingState pps) throws Processi */ void calculateCoverages() { - LayerProcessingState pps = this.fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = this.fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); - logger.atDebug().addArgument(pps.getNSpecies()).addArgument(start.basalAreas[0][0]).log( + logger.atDebug().addArgument(lps.getNSpecies()).addArgument(start.basalAreas[0][0]).log( "Calculating coverages as a ratio of Species BA over Total BA. # species: {}; Layer total 7.5cm+ basal area: {}" ); - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { start.percentagesOfForestedLand[i] = start.basalAreas[i][UC_ALL_INDEX] / start.basalAreas[0][UC_ALL_INDEX] * 100.0f; @@ -2648,10 +2651,10 @@ void calculateCoverages() { * * @param bank the bank in which the calculations are done. * @param siteCurveMap the Site Curve definitions. - * @param pps the PolygonProcessingState to where the calculated curves are also to be + * @param lps the PolygonProcessingState to where the calculated curves are also to be */ static void calculateMissingSiteCurves( - Bank bank, MatrixMap2 siteCurveMap, LayerProcessingState pps + Bank bank, MatrixMap2 siteCurveMap, LayerProcessingState lps ) { BecDefinition becZone = bank.getBecZone(); @@ -2661,7 +2664,7 @@ static void calculateMissingSiteCurves( Optional scIndex = Optional.empty(); - Optional sp0Dist = bank.sp64Distributions[i].getSpeciesDistribution(0); + Optional sp0Dist = bank.sp64Distributions[i].getSpeciesDistribution(1); // First alternative is to use the name of the first of the species' sp64Distributions if (sp0Dist.isPresent()) { @@ -2690,7 +2693,7 @@ static void calculateMissingSiteCurves( } } - pps.setSiteCurveNumbers(bank.siteCurveNumbers); + lps.setSiteCurveNumbers(bank.siteCurveNumbers); } /** @@ -2713,7 +2716,7 @@ private static void validatePolygon(VdypPolygon polygon) throws ProcessingExcept } } - private static void stopIfNoWork(LayerProcessingState pps) throws ProcessingException { + private static void stopIfNoWork(LayerProcessingState lps) throws ProcessingException { // The following is extracted from BANKCHK1, simplified for the parameters // METH_CHK = 4, LayerI = 1, and INSTANCE = 1. So IR = 1, which is the first @@ -2722,10 +2725,10 @@ private static void stopIfNoWork(LayerProcessingState pps) throws ProcessingExce // => all that is done is that an exception is thrown if there are no species to // process. - if (pps.getNSpecies() == 0) { + if (lps.getNSpecies() == 0) { throw new ProcessingException( MessageFormat.format( - "Polygon {0} layer 0 has no species with basal area above {1}", pps.getPolygon() + "Polygon {0} layer 0 has no species with basal area above {1}", lps.getPolygon() .getPolygonIdentifier().toStringCompact(), MIN_BASAL_AREA ) ); @@ -2746,15 +2749,15 @@ private static void stopIfNoWork(LayerProcessingState pps) throws ProcessingExce *

  • the percentage of forested land occupied by the primary species * * - * @param pps the bank on which to operate + * @param lps the bank on which to operate * @return as described */ void determinePolygonRankings(Collection> speciesToCombine) { - LayerProcessingState pps = fps.getLayerProcessingState(); - Bank start = pps.getStartBank(); + LayerProcessingState lps = fps.getLayerProcessingState(); + Bank start = lps.getStartBank(); - if (pps.getNSpecies() == 0) { + if (lps.getNSpecies() == 0) { throw new IllegalArgumentException("Can not find primary species as there are no species"); } @@ -2769,7 +2772,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { int highestPercentageIndex = -1; float secondHighestPercentage = 0.0f; int secondHighestPercentageIndex = -1; - for (int i : pps.getIndices()) { + for (int i : lps.getIndices()) { if (percentages[i] > highestPercentage) { @@ -2820,7 +2823,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { basalAreaGroup3 += 20; } - pps.setSpeciesRankingDetails( + lps.setSpeciesRankingDetails( new SpeciesRankingDetails( highestPercentageIndex, secondHighestPercentageIndex != -1 ? Optional.of(secondHighestPercentageIndex) diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 36c8e8abe..03aac111d 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -19,11 +19,11 @@ class ForwardProcessingState { /** The estimators instance used by this engine */ final EstimationMethods estimators; - /** The compuation instance used by this engine */ + /** The computation instance used by this engine */ final ComputationMethods computers; /** The active state */ - private LayerProcessingState pps; + private LayerProcessingState lps; public ForwardProcessingState(Map controlMap) { this.fcm = new ForwardResolvedControlMapImpl(controlMap); @@ -33,10 +33,10 @@ public ForwardProcessingState(Map controlMap) { public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { - pps = new LayerProcessingState(this, polygon, subjectLayer); + lps = new LayerProcessingState(this, polygon, subjectLayer); } public LayerProcessingState getLayerProcessingState() { - return pps; + return lps; } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index 4cbbec657..a19f73e34 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -115,36 +115,31 @@ public void process(Set vdypPassSet, Map controlMap if (vdypPassSet.contains(ForwardPass.PASS_3)) { - try { - var fpe = new ForwardProcessingEngine(controlMap); - - var forwardDataStreamReader = new ForwardDataStreamReader(controlMap); - - // Fetch the next polygon to process. - int nPolygonsProcessed = 0; - while (true) { - - if (nPolygonsProcessed == maxPoly) { - logger.info( - "Prematurely terminating polygon processing since MAX_POLY ({}) polygons have been processed", - maxPoly - ); - } - - var polygonHolder = forwardDataStreamReader.readNextPolygon(); - if (polygonHolder.isEmpty()) { - break; - } - - var polygon = polygonHolder.get(); - - fpe.processPolygon(polygon); - - nPolygonsProcessed += 1; + var fpe = new ForwardProcessingEngine(controlMap); + + var forwardDataStreamReader = new ForwardDataStreamReader(fpe.fps.fcm); + + // Fetch the next polygon to process. + int nPolygonsProcessed = 0; + while (true) { + + if (nPolygonsProcessed == maxPoly) { + logger.info( + "Prematurely terminating polygon processing since MAX_POLY ({}) polygons have been processed", + maxPoly + ); } + + var polygonHolder = forwardDataStreamReader.readNextPolygon(); + if (polygonHolder.isEmpty()) { + break; + } + + var polygon = polygonHolder.get(); - } catch (IOException e) { - throw new ProcessingException(e); + fpe.processPolygon(polygon); + + nPolygonsProcessed += 1; } } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 307e7bff8..9754a76dc 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -16,7 +16,9 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.UtilizationClassVariable; 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.VolumeVariable; class LayerProcessingState { @@ -279,6 +281,7 @@ public int getPrimarySpeciesStratumNumber() { public int[] getSiteCurveNumbers() { return siteCurveNumbers; } + public MatrixMap3[] getCvVolume() { return cvVolume; } @@ -491,4 +494,17 @@ public float getCVSmall(int speciesIndex, UtilizationClassVariable variable) { return cvPrimaryLayerSmall[speciesIndex].get(variable); } + + public VdypLayer getLayerFromBank(Bank bank) { + + VdypLayer updatedLayer = bank.getUpdatedLayer(); + + for (int i = 1; i < getNSpecies() + 1; i++) { + VdypSpecies species = updatedLayer.getSpeciesBySp0(bank.speciesNames[i]); + species.setCompatibilityVariables( + cvVolume[i], cvBasalArea[i], cvQuadraticMeanDiameter[i], cvPrimaryLayerSmall[i]); + } + + return updatedLayer; + } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 95b4271dd..2af63ca73 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -120,12 +120,12 @@ protected ValueOrMarker, EndOfRecord> convert(MapoptSafe(entry.get(IS_PRIMARY_SPECIES)); var siteCurveNumber = Utils.optSafe(entry.get(SITE_CURVE_NUMBER)) .orElse(VdypEntity.MISSING_INTEGER_VALUE); - + var builder = new ValueOrMarker.Builder, EndOfRecord>(); return layerType.handle(l -> builder.value(l.map(lt -> { @@ -155,20 +155,35 @@ protected ValueOrMarker, EndOfRecord> convert(Map 0.0 && yearsToBreastHeight > 0.0) + iTotalAge = yearsAtBreastHeight + yearsToBreastHeight; + } else if (Float.isNaN(yearsToBreastHeight)) { + if (yearsAtBreastHeight > 0.0 && totalAge > yearsAtBreastHeight) + iYearsToBreastHeight = totalAge - yearsAtBreastHeight; + } + + var inferredTotalAge = iTotalAge; + var inferredYearsToBreastHeight = iYearsToBreastHeight; + return VdypSpecies.build(speciesBuilder -> { speciesBuilder.sp64DistributionSet(speciesDistributionSet); speciesBuilder.polygonIdentifier(polygonId); speciesBuilder.layerType(lt); speciesBuilder.genus(genus, controlMap); speciesBuilder.addSite(siteBuilder -> { - siteBuilder.ageTotal(totalAge); + siteBuilder.ageTotal(inferredTotalAge); siteBuilder.height(dominantHeight); siteBuilder.polygonIdentifier(polygonId); siteBuilder.siteCurveNumber(siteCurveNumber); siteBuilder.layerType(lt); siteBuilder.siteGenus(genus); siteBuilder.siteIndex(siteIndex); - siteBuilder.yearsToBreastHeight(yearsToBreastHeight); + siteBuilder.yearsToBreastHeight(inferredYearsToBreastHeight); }); }); })), builder::marker); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java index a96b079f4..4c7cea74c 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java @@ -7,6 +7,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypPolygonParser; import ca.bc.gov.nrs.vdyp.forward.parsers.VdypSpeciesParser; @@ -33,7 +34,7 @@ abstract class AbstractForwardProcessingEngineTest { @SuppressWarnings("unchecked") @BeforeEach - void beforeTest() throws IOException, ResourceParseException { + void beforeTest() throws ProcessingException, ResourceParseException, IOException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java index b71a728cb..280ab199f 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java @@ -29,6 +29,7 @@ import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.coe.SiteCurveAgeMaximumParserTest; @@ -37,6 +38,7 @@ import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.Region; @@ -285,11 +287,18 @@ void testParseE061() throws Exception { var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); assertThat( result, - (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - allOf(mmHasEntry(coe(1, contains(49.4f, 153.3f, 0.726f, 3.647f)), "AC", Region.COASTAL)) - ) - ); + (Matcher) controlMapHasEntry(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, Matchers.anything()) + ); + + MatrixMap2 coastalSpeciesComponentSizeMap = Utils.expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + var acCoastalSpeciesComponentSizeLimits = coastalSpeciesComponentSizeMap.get("AC", Region.COASTAL); + assertThat( + acCoastalSpeciesComponentSizeLimits, + Matchers.instanceOf(ComponentSizeLimits.class)); + assertThat(acCoastalSpeciesComponentSizeLimits.loreyHeightMaximum(), is(49.4f)); + assertThat(acCoastalSpeciesComponentSizeLimits.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); + assertThat(acCoastalSpeciesComponentSizeLimits.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); + assertThat(acCoastalSpeciesComponentSizeLimits.quadMeanDiameterMaximum(), is(153.3f)); } @Test diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index 584a0d74b..cf701c1fd 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -71,34 +71,34 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); - LayerProcessingState pps = fpe.fps.getLayerProcessingState(); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); fpe.calculateCoverages(); fpe.determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); - assertThat(pps.getPrimarySpeciesIndex(), is(3)); - assertThat(pps.getSecondarySpeciesIndex(), is(4)); - assertThat(pps.getInventoryTypeGroup(), is(37)); - assertThat(pps.getPrimarySpeciesGroupNumber(), is(1)); - assertThat(pps.getPrimarySpeciesStratumNumber(), is(1)); + assertThat(lps.getPrimarySpeciesIndex(), is(3)); + assertThat(lps.getSecondarySpeciesIndex(), is(4)); + assertThat(lps.getInventoryTypeGroup(), is(37)); + assertThat(lps.getPrimarySpeciesGroupNumber(), is(1)); + assertThat(lps.getPrimarySpeciesStratumNumber(), is(1)); } { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); - LayerProcessingState pps = fpe.fps.getLayerProcessingState(); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); - var speciesToCombine = Arrays.asList(Arrays.asList(pps.getStartBank().speciesNames[3], pps.getStartBank().speciesNames[4])); + var speciesToCombine = Arrays.asList(Arrays.asList(lps.getStartBank().speciesNames[3], lps.getStartBank().speciesNames[4])); fpe.calculateCoverages(); fpe.determinePolygonRankings(speciesToCombine); // The test-specific speciesToCombine will combine 3 & 4 into 3 (leaving 4 at 0.0), promoting 2 to // secondary. - assertThat(pps.getPrimarySpeciesIndex(), is(3)); - assertThat(pps.getSecondarySpeciesIndex(), is(2)); - assertThat(pps.getInventoryTypeGroup(), is(37)); - assertThat(pps.getPrimarySpeciesGroupNumber(), is(1)); - assertThat(pps.getPrimarySpeciesStratumNumber(), is(1)); + assertThat(lps.getPrimarySpeciesIndex(), is(3)); + assertThat(lps.getSecondarySpeciesIndex(), is(2)); + assertThat(lps.getInventoryTypeGroup(), is(37)); + assertThat(lps.getPrimarySpeciesGroupNumber(), is(1)); + assertThat(lps.getPrimarySpeciesStratumNumber(), is(1)); } } @@ -108,7 +108,7 @@ void testGroupAndStratumNumberSpecialCases() throws IOException, ResourceParseEx // We want the // "equationModifierGroup.isPresent()" // and the - // " Region.INTERIOR.equals(pps.wallet.getBecZone().getRegion()) + // " Region.INTERIOR.equals(lps.wallet.getBecZone().getRegion()) // && exceptedSpeciesIndicies.contains(primarySpeciesIndex)" // cases in determinePolygonRankings. diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java index 119480746..d7b8b4ce1 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java @@ -38,7 +38,7 @@ class GrowBasalAreaTest { @SuppressWarnings("unchecked") @BeforeEach - void beforeTest() throws IOException, ResourceParseException { + void beforeTest() throws IOException, ResourceParseException, ProcessingException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); @@ -90,7 +90,7 @@ void testYoungPath() throws ProcessingException { } @Test - void testDebugSettings2EqualsZeroPath() throws ProcessingException { + void testDebugSettings3EqualsZeroPath() throws ProcessingException { ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); @@ -102,13 +102,13 @@ void testDebugSettings2EqualsZeroPath() throws ProcessingException { float yabh = 54.0f; float hd = 35.2999992f; float ba = 45.3864441f; - float growthInHd = 0.173380271f; + float hdDelta = 0.173380271f; ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.BASAL_AREA_GROWTH_MODEL_3, 0); - float gba = fpe.growBasalArea(yabh, debugSettings, hd, ba, Optional.empty(), growthInHd); + float gba = fpe.growBasalArea(yabh, debugSettings, hd, ba, Optional.empty(), hdDelta); - assertThat(gba, is(3.7865982f)); + assertThat(gba, is(-0.10392746f)); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java index cc0aed5e4..4595f0b17 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java @@ -49,7 +49,7 @@ class GrowDominantHeightTest { @SuppressWarnings("unchecked") @BeforeEach - void beforeTest() throws IOException, ResourceParseException { + void beforeTest() throws IOException, ResourceParseException, ProcessingException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java index f9f4cc5a2..1cff43563 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java @@ -40,7 +40,7 @@ class GrowQuadMeanDiameterTest { @SuppressWarnings("unchecked") @BeforeEach - void beforeTest() throws IOException, ResourceParseException { + void beforeTest() throws IOException, ResourceParseException, ProcessingException { parser = new ForwardControlParser(); controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index b8a7862e8..dfcfd5d20 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -51,54 +51,54 @@ void testConstruction() throws IOException, ResourceParseException, ProcessingEx VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); - Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + Bank lps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); int nSpecies = pLayer.getSpecies().size(); - assertThat(pps, notNullValue()); - assertThat(pps.yearsAtBreastHeight.length, is(nSpecies + 1)); - assertThat(pps.ageTotals.length, is(nSpecies + 1)); - assertThat(pps.dominantHeights.length, is(nSpecies + 1)); - assertThat(pps.percentagesOfForestedLand.length, is(nSpecies + 1)); - assertThat(pps.siteIndices.length, is(nSpecies + 1)); - assertThat(pps.sp64Distributions.length, is(nSpecies + 1)); - assertThat(pps.speciesIndices.length, is(nSpecies + 1)); - assertThat(pps.speciesNames.length, is(nSpecies + 1)); - assertThat(pps.yearsToBreastHeight.length, is(nSpecies + 1)); - assertThat(pps.getNSpecies(), is(nSpecies)); - - assertThat(pps.basalAreas.length, is(nSpecies + 1)); + assertThat(lps, notNullValue()); + assertThat(lps.yearsAtBreastHeight.length, is(nSpecies + 1)); + assertThat(lps.ageTotals.length, is(nSpecies + 1)); + assertThat(lps.dominantHeights.length, is(nSpecies + 1)); + assertThat(lps.percentagesOfForestedLand.length, is(nSpecies + 1)); + assertThat(lps.siteIndices.length, is(nSpecies + 1)); + assertThat(lps.sp64Distributions.length, is(nSpecies + 1)); + assertThat(lps.speciesIndices.length, is(nSpecies + 1)); + assertThat(lps.speciesNames.length, is(nSpecies + 1)); + assertThat(lps.yearsToBreastHeight.length, is(nSpecies + 1)); + assertThat(lps.getNSpecies(), is(nSpecies)); + + assertThat(lps.basalAreas.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.basalAreas[i].length, is(UtilizationClass.values().length)); + assertThat(lps.basalAreas[i].length, is(UtilizationClass.values().length)); } - assertThat(pps.closeUtilizationVolumes.length, is(nSpecies + 1)); + assertThat(lps.closeUtilizationVolumes.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.closeUtilizationVolumes[i].length, is(UtilizationClass.values().length)); + assertThat(lps.closeUtilizationVolumes[i].length, is(UtilizationClass.values().length)); } - assertThat(pps.cuVolumesMinusDecay.length, is(nSpecies + 1)); + assertThat(lps.cuVolumesMinusDecay.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.cuVolumesMinusDecay[i].length, is(UtilizationClass.values().length)); + assertThat(lps.cuVolumesMinusDecay[i].length, is(UtilizationClass.values().length)); } - assertThat(pps.cuVolumesMinusDecayAndWastage.length, is(nSpecies + 1)); + assertThat(lps.cuVolumesMinusDecayAndWastage.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.cuVolumesMinusDecayAndWastage[i].length, is(UtilizationClass.values().length)); + assertThat(lps.cuVolumesMinusDecayAndWastage[i].length, is(UtilizationClass.values().length)); } - assertThat(pps.loreyHeights.length, is(nSpecies + 1)); + assertThat(lps.loreyHeights.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.loreyHeights[i].length, is(2)); + assertThat(lps.loreyHeights[i].length, is(2)); } - assertThat(pps.quadMeanDiameters.length, is(nSpecies + 1)); + assertThat(lps.quadMeanDiameters.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.quadMeanDiameters[i].length, is(UtilizationClass.values().length)); + assertThat(lps.quadMeanDiameters[i].length, is(UtilizationClass.values().length)); } - assertThat(pps.treesPerHectare.length, is(nSpecies + 1)); + assertThat(lps.treesPerHectare.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.treesPerHectare[i].length, is(UtilizationClass.values().length)); + assertThat(lps.treesPerHectare[i].length, is(UtilizationClass.values().length)); } - assertThat(pps.wholeStemVolumes.length, is(nSpecies + 1)); + assertThat(lps.wholeStemVolumes.length, is(nSpecies + 1)); for (int i = 0; i < nSpecies + 1; i++) { - assertThat(pps.wholeStemVolumes[i].length, is(UtilizationClass.values().length)); + assertThat(lps.wholeStemVolumes[i].length, is(UtilizationClass.values().length)); } } @@ -112,11 +112,11 @@ void testSetCopy() throws IOException, ResourceParseException, ProcessingExcepti VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); - Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + Bank lps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - verifyProcessingStateMatchesLayer(pps, pLayer); + verifyProcessingStateMatchesLayer(lps, pLayer); - Bank ppsCopy = pps.copy(); + Bank ppsCopy = lps.copy(); verifyProcessingStateMatchesLayer(ppsCopy, pLayer); } @@ -160,61 +160,61 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin VdypLayer pLayer = polygon.getLayers().get(LayerType.PRIMARY); assertThat(pLayer, notNullValue()); - Bank pps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + Bank lps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - Bank ppsCopy = new Bank(pps, CopyMode.CopyAll); + Bank ppsCopy = new Bank(lps, CopyMode.CopyAll); verifyProcessingStateMatchesLayer(ppsCopy, pLayer); } - private void verifyProcessingStateMatchesLayer(Bank pps, VdypLayer layer) { + private void verifyProcessingStateMatchesLayer(Bank lps, VdypLayer layer) { List sortedSpIndices = layer.getSpecies().values().stream().map(s -> s.getGenusIndex()).sorted().toList(); int arrayIndex = 1; for (int i = 0; i < sortedSpIndices.size(); i++) { - VdypSpecies genus = layer.getSpeciesByIndex(i); + VdypSpecies genus = layer.getSpeciesByIndex(sortedSpIndices.get(i)); - verifyProcessingStateSpeciesMatchesSpecies(pps, arrayIndex, genus); + verifyProcessingStateSpeciesMatchesSpecies(lps, arrayIndex, genus); verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - pps, arrayIndex, genus + lps, arrayIndex, genus ); arrayIndex += 1; } - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(pps, 0, layer); + verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(lps, 0, layer); } private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - Bank pps, int spIndex, VdypUtilizationHolder u + Bank lps, int spIndex, VdypUtilizationHolder u ) { for (UtilizationClass uc : UtilizationClass.values()) { - assertThat(pps.basalAreas[spIndex][uc.index + 1], is(u.getBaseAreaByUtilization().get(uc))); - assertThat(pps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeByUtilization().get(uc))); - assertThat(pps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); - assertThat(pps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc))); + assertThat(lps.basalAreas[spIndex][uc.index + 1], is(u.getBaseAreaByUtilization().get(uc))); + assertThat(lps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeByUtilization().get(uc))); + assertThat(lps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); + assertThat(lps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc))); if (uc.index <= 0) { - assertThat(pps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeightByUtilization().get(uc))); + assertThat(lps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeightByUtilization().get(uc))); } - assertThat(pps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc))); - assertThat(pps.treesPerHectare[spIndex][uc.index + 1], is(u.getTreesPerHectareByUtilization().get(uc))); - assertThat(pps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolumeByUtilization().get(uc))); + assertThat(lps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc))); + assertThat(lps.treesPerHectare[spIndex][uc.index + 1], is(u.getTreesPerHectareByUtilization().get(uc))); + assertThat(lps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolumeByUtilization().get(uc))); } } - private void verifyProcessingStateSpeciesMatchesSpecies(Bank pps, int index, VdypSpecies species) { + private void verifyProcessingStateSpeciesMatchesSpecies(Bank bank, int index, VdypSpecies species) { VdypSite site = species.getSite().orElseThrow(); - assertThat(pps.yearsAtBreastHeight[index], is(site.getYearsAtBreastHeight())); - assertThat(pps.ageTotals[index], is(site.getAgeTotal())); - assertThat(pps.dominantHeights[index], is(site.getHeight())); - assertThat(pps.siteIndices[index], is(site.getSiteIndex())); - assertThat(pps.sp64Distributions[index], is(species.getSp64DistributionSet())); - assertThat(pps.speciesIndices[index], is(species.getGenusIndex())); - assertThat(pps.speciesNames[index], is(species.getGenus())); - assertThat(pps.yearsToBreastHeight[index], is(site.getYearsToBreastHeight())); + assertThat(bank.yearsAtBreastHeight[index], is(site.getYearsAtBreastHeight().get())); + assertThat(bank.ageTotals[index], is(site.getAgeTotal().get())); + assertThat(bank.dominantHeights[index], is(site.getHeight().get())); + assertThat(bank.siteIndices[index], is(site.getSiteIndex().get())); + assertThat(bank.sp64Distributions[index], is(species.getSp64DistributionSet())); + assertThat(bank.speciesIndices[index], is(species.getGenusIndex())); + assertThat(bank.speciesNames[index], is(species.getGenus())); + assertThat(bank.yearsToBreastHeight[index], is(site.getYearsToBreastHeight().get())); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java index 910b2536f..43388f9be 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java @@ -78,13 +78,12 @@ void testParsePolygon() throws Exception { var poly = assertNext(stream); assertThat(poly.toString(), is("01002 S000001 00 1970")); - assertThat(poly, hasProperty("year", is(1970))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1970)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('A'))); - assertThat(poly, hasProperty("percentForestLand", is(99.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("A"))); + assertThat(poly, hasProperty("percentAvailable", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(37)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(1)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); VdypMatchers.assertEmpty(stream); } @@ -116,13 +115,12 @@ void testParsePolygonWithBlanks() throws Exception { var poly = assertNext(stream); assertThat(poly.toString(), is("01002 S000001 00 1970")); - assertThat(poly, hasProperty("year", is(1970))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1970)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('A'))); - assertThat(poly, hasProperty("percentForestLand", is(99.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("A"))); + assertThat(poly, hasProperty("percentAvailable", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", notPresent())); - assertThat(poly, hasProperty("basalAreaGroup", notPresent())); - assertThat(poly, hasProperty("polygonMode", notPresent())); + assertThat(poly, hasProperty("mode", notPresent())); VdypMatchers.assertEmpty(stream); } @@ -167,115 +165,102 @@ void testParseMultiple() throws Exception { var poly = assertNext(stream); // 1 assertThat(poly.toString(), is("01002 S000001 00 1970")); - assertThat(poly, hasProperty("year", is(1970))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1970)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('A'))); - assertThat(poly, hasProperty("percentForestLand", is(99.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("A"))); + assertThat(poly, hasProperty("percentAvailable", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(37)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(1)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 2 assertThat(poly.toString(), is("01002 S000002 00 1970")); - assertThat(poly, hasProperty("year", is(1970))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1970)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('A'))); - assertThat(poly, hasProperty("percentForestLand", is(98.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("A"))); + assertThat(poly, hasProperty("percentAvailable", is(98.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(15)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(75)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 3 assertThat(poly.toString(), is("01002 S000003 00 1970")); - assertThat(poly, hasProperty("year", is(1970))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1970)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('A'))); - assertThat(poly, hasProperty("percentForestLand", is(99.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("A"))); + assertThat(poly, hasProperty("percentAvailable", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(15)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(75)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 4 assertThat(poly.toString(), is("01002 S000004 00 1970")); - assertThat(poly, hasProperty("year", is(1970))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1970)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("MH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('A'))); - assertThat(poly, hasProperty("percentForestLand", is(99.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("A"))); + assertThat(poly, hasProperty("percentAvailable", is(99.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(15)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(75)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 5 assertThat(poly.toString(), is("01003AS000001 00 1953")); - assertThat(poly, hasProperty("year", is(1953))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1953)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('B'))); - assertThat(poly, hasProperty("percentForestLand", is(91.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("B"))); + assertThat(poly, hasProperty("percentAvailable", is(91.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.YOUNG)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.YOUNG)))); poly = assertNext(stream); // 6 assertThat(poly.toString(), is("01003AS000003 00 1953")); - assertThat(poly, hasProperty("year", is(1953))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1953)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("SBS")))); - assertThat(poly, hasProperty("forestInventoryZone", is('B'))); - assertThat(poly, hasProperty("percentForestLand", is(92.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("B"))); + assertThat(poly, hasProperty("percentAvailable", is(92.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 7 - assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000002 00")))); - assertThat(poly, hasProperty("year", is(1953))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("name", is("01004 S000002 00")))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1953)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('B'))); - assertThat(poly, hasProperty("percentForestLand", is(96.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("B"))); + assertThat(poly, hasProperty("percentAvailable", is(96.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("polygonMode", present(is(PolygonMode.START)))); + assertThat(poly, hasProperty("mode", present(is(PolygonMode.START)))); poly = assertNext(stream); // 8 - assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000036 00")))); - assertThat(poly, hasProperty("description", hasProperty("year", is(1957)))); - assertThat(poly, hasProperty("year", is(1957))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("name", is("01004 S000036 00")))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1957)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("MH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('B'))); - assertThat(poly, hasProperty("percentForestLand", is(97.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("B"))); + assertThat(poly, hasProperty("percentAvailable", is(97.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); - assertThat(poly, hasProperty("basalAreaGroup", present(is(31)))); - assertThat(poly, hasProperty("polygonMode", notPresent())); + assertThat(poly, hasProperty("mode", notPresent())); poly = assertNext(stream); // 9 - assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000037 00")))); - assertThat(poly, hasProperty("description", hasProperty("year", is(1957)))); - assertThat(poly, hasProperty("year", is(1957))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("name", is("01004 S000037 00")))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1957)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("SBS")))); - assertThat(poly, hasProperty("forestInventoryZone", is('B'))); - assertThat(poly, hasProperty("percentForestLand", is(94.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("B"))); + assertThat(poly, hasProperty("percentAvailable", is(94.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", present(is(11)))); - assertThat(poly, hasProperty("basalAreaGroup", notPresent())); - assertThat(poly, hasProperty("polygonMode", notPresent())); + assertThat(poly, hasProperty("mode", notPresent())); poly = assertNext(stream); // 10 - assertThat(poly, hasProperty("description", hasProperty("name", is("01004 S000038 00")))); - assertThat(poly, hasProperty("description", hasProperty("year", is(1957)))); - assertThat(poly, hasProperty("year", is(1957))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("name", is("01004 S000038 00")))); + assertThat(poly, hasProperty("polygonIdentifier", hasProperty("year", is(1957)))); assertThat(poly, hasProperty("biogeoclimaticZone", hasProperty("alias", is("CWH")))); - assertThat(poly, hasProperty("forestInventoryZone", is('B'))); - assertThat(poly, hasProperty("percentForestLand", is(90.0f))); + assertThat(poly, hasProperty("forestInventoryZone", is("B"))); + assertThat(poly, hasProperty("percentAvailable", is(90.0f))); assertThat(poly, hasProperty("inventoryTypeGroup", notPresent())); - assertThat(poly, hasProperty("basalAreaGroup", notPresent())); - assertThat(poly, hasProperty("polygonMode", notPresent())); + assertThat(poly, hasProperty("mode", notPresent())); VdypMatchers.assertEmpty(stream); } @@ -310,11 +295,11 @@ void testParsePolygonPercentForestLandDefaulting() throws Exception { var poly = assertNext(stream); - assertThat(poly, hasProperty("percentForestLand", is(90.0f))); + assertThat(poly, hasProperty("percentAvailable", is(90.0f))); poly = assertNext(stream); - assertThat(poly, hasProperty("percentForestLand", is(90.0f))); + assertThat(poly, hasProperty("percentAvailable", is(90.0f))); VdypMatchers.assertEmpty(stream); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index f72719479..3b0419ee9 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -1,6 +1,8 @@ package ca.bc.gov.nrs.vdyp.forward; +import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; @@ -21,10 +23,12 @@ import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; -import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; 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.test.TestUtils; @SuppressWarnings({ "unchecked" }) @@ -62,46 +66,26 @@ void testReadPolygons() throws Exception { assertThat(polygon.getPolygonIdentifier().toStringCompact(), is("01002 S000001 00(1970)")); - var primaryLayer = polygon.getLayers().get(LayerType.PRIMARY); + for (VdypLayer layer: polygon.getLayers().values()) { - assertThat(primaryLayer, hasProperty("layerType", is(LayerType.PRIMARY))); - assertThat(primaryLayer, hasProperty("defaultUtilizationMap")); - assertThat(primaryLayer.getPolygonIdentifier().getName(), is(polygon.getPolygonIdentifier().getName())); - assertThat(primaryLayer.getPolygonIdentifier().getYear(), is(polygon.getPolygonIdentifier().getYear())); - - assertThat(UtilizationClass.values().length, is(primaryLayer.getBaseAreaByUtilization().size())); - - var speciesMap = primaryLayer.getSpecies(); - assertThat(speciesMap.size(), is(5)); - - var species = speciesMap.values().iterator().next(); - - assertThat(species, hasProperty("layerType", is(primaryLayer.getLayerType()))); - assertThat(species, hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier()))); - assertThat(species, hasProperty("utilizations")); - - for (var u : UtilizationClass.values()) { - assertThat(u, hasProperty("genusIndex", is(species.getGenusIndex()))); - assertThat(u, hasProperty("polygonIdentifier", is("01002 S000001 00 (1970)"))); - } - } - - var veteranLayer = polygon.getLayers().get(LayerType.VETERAN); - if (veteranLayer != null) { - - assertThat(primaryLayer.getBaseAreaByUtilization().size(), is(UtilizationClass.values().length)); - assertThat(primaryLayer.getLoreyHeightByUtilization().size(), is(2)); - for (UtilizationClass uc : UtilizationClass.values()) { - assertThat(primaryLayer.getBaseAreaByUtilization(), hasProperty("genusIndex", is(0))); + assertThat(layer.getPolygonIdentifier().getName(), is(polygon.getPolygonIdentifier().getName())); + assertThat(layer.getPolygonIdentifier().getYear(), is(polygon.getPolygonIdentifier().getYear())); + + assertThat(UtilizationClass.values().length, is(layer.getBaseAreaByUtilization().size())); + + var speciesMap = layer.getSpecies(); + for (VdypSpecies species: speciesMap.values()) { + assertThat(species, hasProperty("layerType", is(layer.getLayerType()))); + assertThat(species, hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier()))); + + assertThat(species.getSite(), present(Matchers.anything())); + + VdypSite site = species.getSite().get(); + assertThat(site, allOf( + hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier())), + hasProperty("layerType", is(layer.getLayerType())) + )); } - - var speciesMap = veteranLayer.getSpecies(); - assertThat(speciesMap.size(), is(5)); - - var genus = speciesMap.values().iterator().next(); - - assertThat(genus, hasProperty("parent", is(veteranLayer))); - assertThat(genus, hasProperty("utilizations")); } } catch (ResourceParseException | IOException e) { throw new ProcessingException(e); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java index 352cfec45..4104228fa 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java @@ -2,6 +2,7 @@ import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.assertEmpty; import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.assertNext; +import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasEntry; @@ -15,8 +16,8 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Optional; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; @@ -91,12 +92,13 @@ void testParseOneGenus() throws Exception { genera, hasItem( allOf( - hasProperty("polygonId", hasProperty("name", is("01002 S000001 00"))), - hasProperty("polygonId", hasProperty("year", is(1970))), - hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genusIndex", is(15)), + hasProperty("polygonIdentifier", hasProperty("base", is("01002 S000001 00"))), + hasProperty("polygonIdentifier", hasProperty("year", is(1970))), + hasProperty("layerType", is(LayerType.PRIMARY)), + hasProperty("genusIndex", is(15)), hasProperty("genus", is("S")), hasProperty( - "speciesDistributions", + "sp64DistributionSet", hasProperty( "sp64DistributionMap", hasEntry( @@ -108,12 +110,16 @@ void testParseOneGenus() throws Exception { ) ) ) - ), hasProperty("siteIndex", is(Float.NaN)), - hasProperty("dominantHeight", is(Float.NaN)), hasProperty("ageTotal", is(Float.NaN)), - hasProperty("ageAtBreastHeight", is(Float.NaN)), - hasProperty("yearsToBreastHeight", is(Float.NaN)), - hasProperty("isPrimary", is(Optional.of(false))), - hasProperty("siteCurveNumber", is(VdypEntity.MISSING_INTEGER_VALUE)) + ), + hasProperty("site", present(allOf( + hasProperty("siteIndex", present(is(Float.NaN))), + hasProperty("siteGenus", is("S")), + hasProperty("height", present(is(Float.NaN))), + hasProperty("ageTotal", present(is(Float.NaN))), + hasProperty("yearsToBreastHeight", present(is(Float.NaN))), + hasProperty("layerType", is(LayerType.PRIMARY)), + hasProperty("siteCurveNumber", present(is(VdypEntity.MISSING_INTEGER_VALUE))) + ))) ) ) ); @@ -201,13 +207,15 @@ void testParseComputesAgesWhenMissing() throws Exception { genera, hasItems( allOf( - hasProperty("ageTotal", is(20.0f)), hasProperty("ageAtBreastHeight", is(12.0f)), - hasProperty("yearsToBreastHeight", is(8.0f)), - hasProperty("isPrimary", is(Optional.of(false))) - ), + hasProperty("layerType", is(LayerType.PRIMARY)), + hasProperty("site", present(allOf( + hasProperty("ageTotal", present(is(20.0f))), + // hasProperty("yearsAtBreastHeight", present(is(12.0f))), + hasProperty("yearsToBreastHeight", present(is(8.0f))) + )))), allOf( hasProperty( - "speciesDistributions", + "sp64DistributionSet", hasProperty( "sp64DistributionMap", allOf( @@ -227,13 +235,16 @@ void testParseComputesAgesWhenMissing() throws Exception { ) ) ) - ), hasProperty("ageTotal", is(12.0f)), hasProperty("ageAtBreastHeight", is(8.0f)), - hasProperty("yearsToBreastHeight", is(4.0f)), - hasProperty("isPrimary", is(Optional.empty())) - ), + ), + hasProperty("layerType", is(LayerType.VETERAN)), + hasProperty("site", present(allOf( + hasProperty("ageTotal", present(is(12.0f))), + // hasProperty("yearsAtBreastHeight", present(is(8.0f))), + hasProperty("yearsToBreastHeight", present(is(4.0f)))) + ))), allOf( hasProperty( - "speciesDistributions", + "sp64DistributionSet", hasProperty( "sp64DistributionMap", allOf( @@ -267,13 +278,21 @@ void testParseComputesAgesWhenMissing() throws Exception { ) ) ) - ), hasProperty("ageTotal", is(14.0f)), hasProperty("ageAtBreastHeight", is(8.0f)), - hasProperty("yearsToBreastHeight", is(6.0f)), - hasProperty("isPrimary", is(Optional.of(true))) + ), + hasProperty("layerType", is(LayerType.VETERAN)), + hasProperty("site", present(allOf( + hasProperty("ageTotal", present(is(14.0f))), + // hasProperty("yearsAtBreastHeight", present(is(8.0f))), + hasProperty("yearsToBreastHeight", present(is(6.0f))) + )) + ) ) ) ); + assertThat(genera.stream().map(s -> s.getSite().get().getYearsAtBreastHeight()).toList(), + hasItems(present(is(12.0f)), present(is(8.0f)), present(is(8.0f)))); + assertEmpty(stream); } @@ -313,12 +332,13 @@ void testParseTwoGenera() throws Exception { genera, hasItems( allOf( - hasProperty("polygonId", hasProperty("name", is("01002 S000002 00"))), - hasProperty("polygonId", hasProperty("year", is(1970))), - hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genusIndex", is(15)), + hasProperty("polygonIdentifier", hasProperty("base", is("01002 S000002 00"))), + hasProperty("polygonIdentifier", hasProperty("year", is(1970))), + hasProperty("layerType", is(LayerType.PRIMARY)), + hasProperty("genusIndex", is(15)), hasProperty("genus", is("S")), hasProperty( - "speciesDistributions", + "sp64DistributionSet", hasProperty( "sp64DistributionMap", hasEntry( @@ -330,20 +350,25 @@ void testParseTwoGenera() throws Exception { ) ) ) - ), hasProperty("siteIndex", is(Float.NaN)), - hasProperty("dominantHeight", is(Float.NaN)), hasProperty("ageTotal", is(Float.NaN)), - hasProperty("ageAtBreastHeight", is(Float.NaN)), - hasProperty("yearsToBreastHeight", is(Float.NaN)), - hasProperty("isPrimary", is(Optional.of(false))), - hasProperty("siteCurveNumber", is(VdypEntity.MISSING_INTEGER_VALUE)) + ), + hasProperty("site", present(allOf( + hasProperty("siteIndex", present(is(Float.NaN))), + hasProperty("siteGenus", is("S")), + hasProperty("height", present(is(Float.NaN))), + hasProperty("ageTotal", present(is(Float.NaN))), + hasProperty("yearsToBreastHeight", present(is(Float.NaN))), + hasProperty("layerType", is(LayerType.PRIMARY)), + hasProperty("siteCurveNumber", present(is(VdypEntity.MISSING_INTEGER_VALUE))) + ))) ), allOf( - hasProperty("polygonId", hasProperty("name", is("01002 S000002 00"))), - hasProperty("polygonId", hasProperty("year", is(1970))), - hasProperty("layerType", is(LayerType.VETERAN)), hasProperty("genusIndex", is(3)), + hasProperty("polygonIdentifier", hasProperty("base", is("01002 S000002 00"))), + hasProperty("polygonIdentifier", hasProperty("year", is(1970))), + hasProperty("layerType", is(LayerType.VETERAN)), + hasProperty("genusIndex", is(3)), hasProperty("genus", is("B")), hasProperty( - "speciesDistributions", + "sp64DistributionSet", hasProperty( "sp64DistributionMap", allOf( @@ -365,12 +390,16 @@ void testParseTwoGenera() throws Exception { ) ) ) - ), hasProperty("siteIndex", is(Float.NaN)), - hasProperty("dominantHeight", is(Float.NaN)), hasProperty("ageTotal", is(Float.NaN)), - hasProperty("ageAtBreastHeight", is(Float.NaN)), - hasProperty("yearsToBreastHeight", is(Float.NaN)), - hasProperty("isPrimary", is(Optional.empty())), - hasProperty("siteCurveNumber", is(VdypEntity.MISSING_INTEGER_VALUE)) + ), + hasProperty("site", present(allOf( + hasProperty("siteIndex", present(is(Float.NaN))), + hasProperty("siteGenus", is("B")), + hasProperty("height", present(is(Float.NaN))), + hasProperty("ageTotal", present(is(Float.NaN))), + hasProperty("yearsAtBreastHeight", present(is(Float.NaN))), + hasProperty("layerType", is(LayerType.VETERAN)), + hasProperty("siteCurveNumber", present(is(VdypEntity.MISSING_INTEGER_VALUE))) + ))) ) ) ); diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java index f0823632b..9f54ed621 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriSpecies.java @@ -15,7 +15,7 @@ public VriSpecies( PolygonIdentifier polygonIdentifier, LayerType layer, String genus, int genusIndex, float percentGenus, Sp64DistributionSet sp64DistributionSet, Optional site ) { - super(polygonIdentifier, layer, genus, genusIndex, percentGenus, sp64DistributionSet, site); + super(polygonIdentifier, layer, genus, genusIndex, Optional.of(percentGenus), sp64DistributionSet, site); } /** @@ -73,7 +73,8 @@ public String toString() { this.getPolygonIdentifier(), // this.getLayerType(), // this.getGenus(), // - this.getPercentGenus(), this.getSp64DistributionSet().getSp64DistributionList().stream() + this.getPercentGenus(), // + this.getSp64DistributionSet().getSp64DistributionList().stream() .map(e -> String.format("%s: %s%%", e.getGenusAlias(), e.getPercentage())) .collect(Collectors.joining(", ")) ); From 99f65d60184c8964af6618d930042d788e4311c6 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 27 Aug 2024 15:07:51 -0700 Subject: [PATCH 38/66] Begin adaptation of VDYP output code to Forward --- .../ca/bc/gov/nrs/vdyp/math/FloatMath.java | 25 + .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 16 + .../gov/nrs/vdyp/model/BaseVdypPolygon.java | 15 + .../bc/gov/nrs/vdyp/model/BaseVdypSite.java | 17 + .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 12 + .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 26 + .../vdyp/forward/ForwardProcessingEngine.java | 493 +++++++++++++++--- .../vdyp/forward/LayerProcessingState.java | 67 ++- 8 files changed, 566 insertions(+), 105 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java index 56318d663..94223fcaa 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java @@ -93,4 +93,29 @@ public static float safeExponent(float logit) throws ProcessingException { } return exp(logit); } + + /** + * Compute the maximum of three float values, using Math.max to do pairwise + * comparisons. + * @param f1 + * @param f2 + * @param f3 + * @return as described + */ + public static float max(float f1, float f2, float f3) { + return Math.max(f1, Math.max(f2, f3)); + } + + /** + * Compute the maximum of four float values, using Math.max to do pairwise + * comparisons. + * @param f1 + * @param f2 + * @param f3 + * @param f4 + * @return as described + */ + public static float max(float f1, float f2, float f3, float f4) { + return Math.max(Math.max(f1, f2), Math.max(f3, f4)); + } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index 1a94193f3..ace759c84 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -79,6 +79,22 @@ public Optional getInventoryTypeGroup() { public void setInventoryTypeGroup(Optional inventoryTypeGroup) { this.inventoryTypeGroup = inventoryTypeGroup; } + + @Override + public String toString() { + return polygonIdentifier.toStringCompact() + "-" + layerType; + } + + @Override + public boolean equals(Object other) { + if (other instanceof BaseVdypLayer that) { + // This is the "business key" of a layer. + return this.polygonIdentifier.equals(that.polygonIdentifier) + && this.layerType.equals(that.layerType); + } else { + return false; + } + } public abstract static class Builder, S extends BaseVdypSpecies, I extends BaseVdypSite, SB extends BaseVdypSpecies.Builder, IB extends BaseVdypSite.Builder> extends ModelClassBuilder { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java index 6f7f6e95a..30e84065a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java @@ -114,6 +114,21 @@ public Optional getMode() { public void setMode(Optional mode) { this.mode = mode; } + + @Override + public String toString() { + return polygonIdentifier.toStringCompact(); + } + + @Override + public boolean equals(Object other) { + if (other instanceof BaseVdypPolygon that) { + // This is the "business key" of a polygon. + return this.polygonIdentifier.equals(that.polygonIdentifier); + } else { + return false; + } + } protected abstract static class Builder< // T extends BaseVdypPolygon, // diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java index 25210297a..cd60faf01 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java @@ -71,6 +71,23 @@ public Optional getYearsToBreastHeight() { public Optional getYearsAtBreastHeight() { return Utils.mapBoth(ageTotal, yearsToBreastHeight, (age, ytbh) -> age - ytbh); } + + @Override + public String toString() { + return polygonIdentifier.toStringCompact() + "-" + layerType + "-" + siteGenus; + } + + @Override + public boolean equals(Object other) { + if (other instanceof BaseVdypSite that) { + // This is the "business key" of a site. + return this.polygonIdentifier.equals(that.polygonIdentifier) + && this.layerType.equals(that.layerType) + && this.siteGenus.equals(that.siteGenus); + } else { + return false; + } + } public abstract static class Builder extends ModelClassBuilder { protected Optional polygonIdentifier = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index d3eb2885f..3523784dd 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -88,6 +88,18 @@ public Sp64DistributionSet getSp64DistributionSet() { public String toString() { return MessageFormat.format("{0} {1} {2}", polygonIdentifier, layerType, genus); } + + @Override + public boolean equals(Object other) { + if (other instanceof BaseVdypSpecies that) { + // This is the "business key" of a species. + return this.polygonIdentifier.equals(that.polygonIdentifier) + && this.layerType.equals(that.layerType) + && this.genus.equals(that.genus); + } else { + return false; + } + } /** * Construct the species sp64DistributionSet from the given list of species percentages. The maxIndex of the Set is diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 7dd8be325..e9a31b80b 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -189,6 +189,32 @@ 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(); + + transferUtilizationsIntoBank(0, layer); + + int nextSlot = 1; + for (VdypSpecies s : species) { + transferSpeciesIntoBank(nextSlot++, s); + } + } + /** * 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. diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index f941a9049..416cccbc2 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -183,7 +183,6 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilYear) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank primaryBank = lps.getStartBank(); Optional veteranLayer; if (lps.getPolygon().getLayers().containsKey(LayerType.VETERAN)){ @@ -204,12 +203,12 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // SCINXSET - note these are calculated directly from the Primary bank of instance 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { - calculateMissingSiteCurves(primaryBank, fps.fcm.getSiteCurveMap(), fps.getLayerProcessingState()); + calculateMissingSiteCurves(lps, fps.fcm.getSiteCurveMap()); } // VPRIME1, method == 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_COVERAGES.ordinal()) { - calculateCoverages(); + calculateCoverages(lps); } if (lastStepInclusive.ordinal() >= ExecutionStep.DETERMINE_POLYGON_RANKINGS.ordinal()) { @@ -237,25 +236,43 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY // VGROW1 if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { - int startingYear = fps.getLayerProcessingState().getPolygon().getPolygonIdentifier().getYear(); + int startingYear = lps.getPolygon().getPolygonIdentifier().getYear(); VdypPolygon vdypPolygon = lps.getPolygon(); VdypLayer primaryLayer = vdypPolygon.getLayers().get(LayerType.PRIMARY); - writeLayers(primaryLayer, veteranLayer, false); + writeLayers(primaryLayer, veteranLayer, startingYear, startingYear, untilYear); - boolean createNewGroups = fps.fcm.getDebugSettings() + boolean doRecalculateGroupsPriorToOutput = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 - && fps.getLayerProcessingState().getNSpecies() > 1; + && lps.getNSpecies() > 1; + boolean doRecalculateGroups = fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1; + int currentYear = startingYear; while (currentYear <= untilYear) { - primaryLayer = grow(primaryBank, currentYear, veteranLayer); + Bank endBank = grow(lps, currentYear, veteranLayer); + + lps.swapBank(endBank); + + // If update-during-growth is set, update the context prior to output + if (doRecalculateGroupsPriorToOutput) { + calculateCoverages(lps); + calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); + } // Store polygon (both primary and veteran layers) to output - writeLayers(primaryLayer, veteranLayer, createNewGroups); + writeLayers(primaryLayer, veteranLayer, startingYear, currentYear, untilYear); + + // If update-during-growth is set, and not already recalculated, recalculate + // context now. + if (! doRecalculateGroupsPriorToOutput && doRecalculateGroups) { + calculateCoverages(lps); + calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); + } currentYear += 1; } @@ -263,40 +280,27 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY } /** - * VGROW1 - "grow" the primary layer, located in primaryLayerSourceInstance, starting at the - * given year, and write the results to primaryLayerTargetInstance. The veteran layer instance - * is supplied but at this point is ignored. + * VGROW1 - "grow" the primary layer, located in lps.startBank, starting at the + * given year, and return the resulting bank. The veteran layer instance is supplied but at + * this point is ignored. * - * @param primaryLayerSourceInstance - * @param currentYear - * @param primaryLayerTargetInstance - * @param veteranLayerInstance - * @return + * @param lps the layer processing state + * @param currentYear the current growth period + * @param veteranLayer the polygon's veteran layer + * @return as described * * @throws ProcessingException */ - private VdypLayer grow(Bank start, int currentYear, Optional veteranLayer) + private Bank grow(LayerProcessingState lps, int currentYear, Optional veteranLayer) throws ProcessingException { - LayerProcessingState lps = fps.getLayerProcessingState(); VdypPolygon polygon = lps.getPolygon(); + Bank start = lps.getStartBank(); logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); Bank end = new Bank(start, CopyMode.CopyStructure); - // If update-during-growth is set, and this is not the starting year, update the context - int startingYear = polygon.getPolygonIdentifier().getYear(); - if (currentYear > startingYear - && fps.fcm.getForwardControlVariables() - .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1) { - // VPRIME1, method == 1 - calculateCoverages(); - - // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 - calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); - } - float dhStart = lps.getPrimarySpeciesDominantHeight(); int pspSiteCurveNumber = lps.getSiteCurveNumber(lps.getPrimarySpeciesIndex()); float pspSiteIndex = lps.getPrimarySpeciesSiteIndex(); @@ -361,10 +365,10 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL // This is the PARTIAL SPECIES DYNAMICS section. // Begin by updating HL for all species (save the ungrown HLs). - float[] currentLoreyHeights = new float[start.getNSpecies() + 1]; - currentLoreyHeights[0] = start.loreyHeights[0][UC_ALL_INDEX]; + float[] startingLoreyHeights = new float[start.getNSpecies() + 1]; + startingLoreyHeights[0] = start.loreyHeights[0][UC_ALL_INDEX]; for (int i : start.getIndices()) { - currentLoreyHeights[i] = start.loreyHeights[i][UC_ALL_INDEX]; + startingLoreyHeights[i] = start.loreyHeights[i][UC_ALL_INDEX]; } float pspTphEndEstimate = pspTphStart * (tphEnd / tphStart); @@ -383,13 +387,13 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL // Now do the actual updates of DQ by species wasSolutionFound = growUsingPartialSpeciesDynamics( - end, dqDelta, baDelta, baStart, dqStart, tphStart, currentLoreyHeights + end, dqDelta, baDelta, baStart, dqStart, tphStart, startingLoreyHeights ); // Restore the Lorey Heights back to the values at the beginning of the period. // They will be updated below using the new estimate of TPH-primary species. for (int i = 1; i < start.getNSpecies(); i++) { - start.loreyHeights[i][UC_ALL_INDEX] = currentLoreyHeights[i]; + start.loreyHeights[i][UC_ALL_INDEX] = startingLoreyHeights[i]; } } @@ -402,19 +406,19 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL } else { // This is the FULL SPECIES DYNAMICS section - growUsingFullSpeciesDynamics(dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); + growUsingFullSpeciesDynamics(end, dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); } } // Calculate trees-per-hectare over all species, all ucs - float totalTphEnd = 0.0f; + float tphEndSum = 0.0f; for (int i = 1; i < end.getNSpecies(); i++) { if (end.basalAreas[i][UC_ALL_INDEX] > 0.0f) { - totalTphEnd += end.treesPerHectare[i][UC_ALL_INDEX]; + tphEndSum += end.treesPerHectare[i][UC_ALL_INDEX]; } } - end.treesPerHectare[0][UC_ALL_INDEX] = totalTphEnd; + end.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; // Calculate quad-mean-diameter over all species, uc UC_ALL_INDEX @@ -469,22 +473,28 @@ private VdypLayer grow(Bank start, int currentYear, Optional veteranL VdypLayer primaryLayer = lps.getLayerFromBank(end); VolumeComputeMode volumeComputationMode = VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC; - int controlVariable3Value = lps.getFps().fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); + int controlVariable3Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); CompatibilityVariableMode compatibilityVariableMode = CompatibilityVariableMode.getByInteger(controlVariable3Value); lps.getFps().computers.computeUtilizationComponentsPrimary(lps.getBecZone(), primaryLayer, volumeComputationMode, compatibilityVariableMode); + end.refreshBank(primaryLayer); + calculateSmallComponentYields(end); - return end.getUpdatedLayer(); + return end; } /** - * Calculate basal area, trees-per-hectare and quad-mean-diameter for all species - * in the polygon, given the per-layer basal area growth rate and tree-per-hectare - * muliplier + * Calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare + * and quad-mean-diameter at the end of the growth period for all species in the polygon, given + * the per-layer basal area and trees-per-hectare rate of change. * - * @param baChangeRate - * @param tphChangeRate + * @param end the target of the computation + * @param baChangeRate the rate of change of the basal area during the growth period, + * expressed as a percentage / 100. So a rate of 10% (i.e., 1.1 times the starting + * value) would be expressed at 0.1f. + * @param tphChangeRate the rate of change of trees-per-hectare during the growth period, + * expressed the same way. */ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphChangeRate) { @@ -511,6 +521,33 @@ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphC } } + private static final int NSTAGES = 10; + + private record AdjustmentParameters( + /** normal maximum change towards zero */ + float cjMax, + /** true iff allowed to cross the zero boundary */ + boolean canCrossZero, + /** allowable wrong-way change for species closest to zero */ + float cjWrongWayChange1, + /** allowable wrong-way change for other species */ + float cjWrongWayChangeX) {} + + private static AdjustmentParameters[] adjustmentParametersByStage = new AdjustmentParameters[NSTAGES]; + + static { + adjustmentParametersByStage[0] = new AdjustmentParameters(0.01f, false, 0.0f, 0.0f); + adjustmentParametersByStage[1] = new AdjustmentParameters(0.015f, true, 0.005f, 0.0f); + adjustmentParametersByStage[2] = new AdjustmentParameters(0.03f, true, 0.02f, 0.01f); + adjustmentParametersByStage[3] = new AdjustmentParameters(0.045f, true, 0.03f, 0.02f); + adjustmentParametersByStage[4] = new AdjustmentParameters(0.06f, true, 0.045f, 0.035f); + adjustmentParametersByStage[5] = adjustmentParametersByStage[0]; + adjustmentParametersByStage[6] = adjustmentParametersByStage[1]; + adjustmentParametersByStage[7] = adjustmentParametersByStage[2]; + adjustmentParametersByStage[8] = adjustmentParametersByStage[3]; + adjustmentParametersByStage[9] = adjustmentParametersByStage[4]; + } + /** * GRSPpart - update quad-mean-diameter (dq) by species. * @@ -530,15 +567,20 @@ private boolean growUsingPartialSpeciesDynamics( Bank end, float dqDelta, float baDelta, float baStart, float dqStart, float tphStart, float[] currentLoreyHeights ) throws ProcessingException { - boolean wasSuccessful = true; LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank start = lps.getStartBank(); + VdypPolygon polygon = lps.getPolygon(); + Region polygonRegion = polygon.getBiogeoclimaticZone().getRegion(); if (dqDelta == 0 || baDelta == 0 || lps.getNSpecies() == 1) { return false /* no solution available */; } - + + float[] tryDq = new float[lps.getNSpecies() + 1]; + float[] tryTph = new float[lps.getNSpecies() + 1]; + float[] rs1 = new float[lps.getNSpecies() + 1]; + float[] dqs1 = new float[lps.getNSpecies() + 1]; float[] dqs2 = new float[lps.getNSpecies() + 1]; @@ -587,17 +629,268 @@ private boolean growUsingPartialSpeciesDynamics( start.loreyHeights[i][0]); } - return wasSuccessful; + float[] dqLowerBoundBySpecies = new float[lps.getNSpecies() + 1]; + float[] dqUpperBoundBySpecies = new float[lps.getNSpecies() + 1]; + float[] tphLowerBoundBySpecies = new float[lps.getNSpecies() + 1]; + float[] tphUpperBoundBySpecies = new float[lps.getNSpecies() + 1]; + boolean exactMatchFound = false; + boolean biggerD; + int incorrectlySignedSpeciesIndex = 0; + + float tphLow = 0.0f; + float tphHigh = 0.0f; + + int stage; + for (stage = 0; stage < NSTAGES; stage++) { + + if (stage == 1 || stage == 6) { + // Set bounds + + for (int i : lps.getIndices()) { + + dqLowerBoundBySpecies[i] = 7.51f; + dqUpperBoundBySpecies[i] = 100.0f; + + if (start.treesPerHectare[i][UC_ALL_INDEX] <= 0) { + continue; + } + + var sizeLimits = fps.estimators.getLimitsForHeightAndDiameter(start.speciesNames[i], polygonRegion); + var spDqMax = sizeLimits.quadMeanDiameterMaximum(); + + float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; + + // Non-negotiable bounds + dqUpperBoundBySpecies[i] = FloatMath.max(dqNew[i], dqStart, spDqMax, spDqStart); + + // Non-decline constraint imposed unless net change in ba/tree < 1% + float dqNetChange = dqNew[0] / spDqStart; + float rateDq2 = dqNetChange * dqNetChange - 1.0f; + if (rateDq2 > 0.01) { + dqLowerBoundBySpecies[i] = spDqStart; + } else { + float dq2Min = spDqStart * spDqStart * (1.0f + rateDq2 - 0.01f); + if (dq2Min > 0.0f) { + dqLowerBoundBySpecies[i] = Math.max(dqLowerBoundBySpecies[i], + Math.min(FloatMath.sqrt(dq2Min), spDqStart)); + } + } + + if (stage > 5) { + continue; + } + + // More restrictive bounds, stages 1 - 5 only. + + float spHlStart = start.loreyHeights[i][UC_ALL_INDEX]; + + float trialMax = Math.max(spDqStart, spDqMax); + if (spDqStart < 1.001 * sizeLimits.maxQuadMeanDiameterLoreyHeightRatio() * spHlStart) { + trialMax = Math.min(trialMax, sizeLimits.maxQuadMeanDiameterLoreyHeightRatio() * spHlStart); + } + + dqUpperBoundBySpecies[i] = Math.min(dqUpperBoundBySpecies[i], trialMax); + + float spDqMin = sizeLimits.minQuadMeanDiameterLoreyHeightRatio() * spHlStart; + if (spDqStart > 0.999 * spDqMin) { + dqLowerBoundBySpecies[i] = Math.max(dqLowerBoundBySpecies[i], spDqMin); + } + } + } + + // Bounds now set + + // With CJ = 0, subject to constraints, find the resultant trees-per-hectare. + + float tphSum = 0.0f; + for (int i : lps.getIndices()) { + if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + continue; + } + + float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; + tryDq[i] = 7.5f + (dqs2[i] - 7.5f) * ((spDqStart - 7.5f)/(dqs1[i] - 7.5f)); + if (tryDq[i] < dqLowerBoundBySpecies[i]) { + tryDq[i] = dqLowerBoundBySpecies[i]; + } + if (tryDq[i] > dqUpperBoundBySpecies[i]) { + tryDq[i] = dqUpperBoundBySpecies[i]; + } + rs1[i] = FloatMath.log(spDqStart - 7.5f / dqs1[i] - 7.5f); + tryTph[i] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[i], tryDq[i]); + tphSum += tryTph[i]; + } + + if (tphSum == tphNew[0]) { + exactMatchFound = true; + break; + } + + biggerD = tphSum > tphNew[0]; + incorrectlySignedSpeciesIndex = 0; + float amountWrong = 50000.0f; + + for (int i : lps.getIndices()) { + if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + continue; + } + + if (biggerD && rs1[i] > 0.0f) { + if (rs1[i] < amountWrong) { + incorrectlySignedSpeciesIndex = i; + amountWrong = rs1[i]; + } + } else if (!biggerD && rs1[i] < 0.0f) { + if (-1.0f * rs1[i] < amountWrong) { + incorrectlySignedSpeciesIndex = i; + amountWrong = -rs1[i]; + } + } + } + + // Calculate the low and high quad-mean-diameters + + float cjLow; + float cjHigh; + float cjOther; + + for (int i : lps.getIndices()) { + if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + continue; + } + + if (i == incorrectlySignedSpeciesIndex) { + cjOther = adjustmentParametersByStage[stage].cjWrongWayChange1; + } else { + cjOther = adjustmentParametersByStage[stage].cjWrongWayChangeX; + } + + if (biggerD) { + if (rs1[i] <= 0.0f) { + cjLow = -cjOther; + cjHigh = adjustmentParametersByStage[stage].cjMax; + if (! adjustmentParametersByStage[stage].canCrossZero) { + cjHigh = Math.min(cjHigh, -rs1[i]); + } + } else { + cjLow = 0.0f; + cjHigh = cjOther; + } + } else { + if (rs1[i] <= 0.0f) { + cjLow = -cjOther; + cjHigh = 0.0f; + } else { + cjLow = -adjustmentParametersByStage[stage].cjMax; + if (! adjustmentParametersByStage[stage].canCrossZero) { + cjLow = Math.max(-adjustmentParametersByStage[stage].cjMax, -rs1[i]); + } + cjHigh = 0.0f; + } + } + + float trialDqLow = 7.5f + (dqs2[i] - 7.5f) * FloatMath.exp(rs1[i] + cjLow); + float trialDqHigh = 7.5f + (dqs2[i] - 7.5f) * FloatMath.exp(rs1[i] + cjHigh); + + if (trialDqLow < dqLowerBoundBySpecies[i]) { + trialDqLow = dqLowerBoundBySpecies[i]; + } + if (trialDqLow > dqUpperBoundBySpecies[i]) { + trialDqLow = dqUpperBoundBySpecies[i]; + } + + if (trialDqHigh < dqLowerBoundBySpecies[i]) { + trialDqHigh = dqLowerBoundBySpecies[i]; + } + if (trialDqHigh > dqUpperBoundBySpecies[i]) { + trialDqHigh = dqUpperBoundBySpecies[i]; + } + + tphUpperBoundBySpecies[i] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[i], trialDqLow); + tphLowerBoundBySpecies[i] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[i], trialDqHigh); + + tphLow += tphLowerBoundBySpecies[i]; + tphHigh += tphUpperBoundBySpecies[i]; + } + + if (tphNew[0] >= tphLow && tphNew[0] <= tphHigh) { + break; + } + } + + if (stage == NSTAGES) { + // Finished all stages and no viable solution found. + return false; + } + + if (!exactMatchFound) { + // A viable solution was found, but not an exact one. Find the solution for trees. + + if (tphLow > tphHigh) { + throw new ProcessingException(MessageFormat.format("Polygon {0}, layer {1}: while computing growth" + + " using partial species dynamics, trees-per-hectare lower bound ({2}) was found to be" + + " greater than the upper bound ({3})" + , polygon.getPolygonIdentifier().toStringCompact(), lps.getLayerType(), tphLow, tphHigh)); + } + + float k; + if (tphLow == tphHigh) { + k = 0.0f; + } else { + k = (tphNew[0] - tphLow)/(tphHigh - tphLow); + } + + for (int i : lps.getIndices()) { + if (start.basalAreas[i][UC_ALL_INDEX] >= 0.0f) { + tphNew[i] = tphLowerBoundBySpecies[i] + k * (tphUpperBoundBySpecies[i] - tphLowerBoundBySpecies[i]); + dqNew[i] = BaseAreaTreeDensityDiameter.quadMeanDiameter(baNew[i], tphNew[i]); + } else { + baNew[i] = 0.0f; + tphNew[i] = 0.0f; + dqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; + } + } + } else { + // An exact solution was found. + for (int i : lps.getIndices()) { + if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + tphNew[i] = 0.0f; + dqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; + } else { + tphNew[i] = tryTph[i]; + dqNew[i] = tryDq[i]; + } + } + } + + for (int i : lps.getIndices()) { + end.basalAreas[i][UC_ALL_INDEX] = baNew[i]; + end.quadMeanDiameters[i][UC_ALL_INDEX] = dqNew[i]; + end.treesPerHectare[i][UC_ALL_INDEX] = tphNew[i]; + } + + return true /* was successful */; } + /** + * Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth + * during the growth period. The result is stored in end, Utilization Class ALL. + * @param end the target of the computation + * @param dqDelta per-layer change in quad-mean-diameter during growth period + * @param baDelta per-layer change in basal area during growth period + * @param baStart per-layer basal area at start of growth period + * @param dqStart per-layer quad-mean-diameter at the start of growth period + * @param tphStart per-layer trees-per-breast-height at that of growth period + * @param lhStart per-layer Lorey height at the start of the growth period + * @throws ProcessingException + */ private void growUsingFullSpeciesDynamics( - float dqDelta, float baDelta, float baStart, float dqStart, + Bank end, float dqDelta, float baDelta, float baStart, float dqStart, float tphStart, float lhStart ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); Bank start = lps.getStartBank(); - Bank end = new Bank(start, CopyMode.CopyStructure); float spBaEnd[] = new float[lps.getNSpecies() + 1]; float spTphNew[] = new float[lps.getNSpecies() + 1]; @@ -1022,7 +1315,7 @@ private float growBasalAreaForPrimarySpecies( } /** - * Record small component utilization values for primary layer. + * YSMALL - record small component utilization values for primary layer. * * @throws ProcessingException */ @@ -1276,7 +1569,7 @@ float growQuadMeanDiameter( var lps = fps.getLayerProcessingState(); var becZone = lps.getBecZone(); - float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalAreaAtStartOfYear(); var dqYieldCoefficients = fps.fcm.getQuadMeanDiameterYieldCoefficients(); var decayBecZoneAlias = becZone.getDecayBec().getAlias(); @@ -1442,7 +1735,10 @@ private float calculateQuadMeanDiameterGrowthEmpirical( return FloatMath.clamp(dqDelta, dqGrowthMin, dqGrowthMax); } - private float[] getSpeciesProportionsByBasalArea() { + /** + * @return the species proportions at the start of the year for the current layer. + */ + private float[] getSpeciesProportionsByBasalAreaAtStartOfYear() { LayerProcessingState lps = fps.getLayerProcessingState(); Bank start = lps.getStartBank(); @@ -1460,24 +1756,24 @@ private float[] getSpeciesProportionsByBasalArea() { /** * EMP111A - Basal area growth for the primary layer. * - * @param pspYabhStart at the start of the year + * @param pspYabhStart primary species years-at-breast-height at the start of the year * @param pspDhStart primary species dominant height at start of year - * @param baStart at the start of the year - * @param veteranLayerBa at the start of the year - * @param dhDelta during the year + * @param baStart primary layer basal area at the start of the year + * @param veteranLayerBaStart veteran layer basal area at the start of the year + * @param dhDelta primary layer during the year * - * @return the growth in the basal area for the year + * @return the growth in the basal area of the primary layer for the year * @throws StandProcessingException in the event of an error */ float growBasalArea( float pspYabhStart, ForwardDebugSettings debugSettings, float pspDhStart, - float baStart, Optional veteranLayerBa, float dhDelta + float baStart, Optional veteranLayerBaStart, float dhDelta ) throws StandProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); Bank start = lps.getStartBank(); - float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalArea(); + float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalAreaAtStartOfYear(); var baYieldCoefficients = fps.fcm.getBasalAreaYieldCoefficients(); var becZoneAlias = fps.getLayerProcessingState().getBecZone().getAlias(); @@ -1502,14 +1798,14 @@ float growBasalArea( int controlVariable2Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBa, isFullOccupancy, baUpperBound + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBaStart, isFullOccupancy, baUpperBound ); float pspDhEnd = pspDhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float baYieldEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBa, isFullOccupancy, baUpperBound + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBaStart, isFullOccupancy, baUpperBound ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() @@ -1891,12 +2187,45 @@ private static double ageAndSiteIndexToHeight( } } - private void writeLayers(VdypLayer primaryLayer, Optional veteranLayer, boolean doCreateNewGroups) { + private void writeLayers(VdypLayer primaryLayer, Optional veteranLayer, int startYear, int currentYear, int endYear) + throws ProcessingException { logger.info( "Writing primary layer {}{}", primaryLayer.getPolygonIdentifier(), veteranLayer.isPresent() ? veteranLayer.get().getPolygonIdentifier() : "" ); + + int controlVariable4Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.OUTPUT_FILES_4); + + switch (controlVariable4Value) { + case 0: { + /* never write output */ + return; + } + case 1: { + /* write only first growth period */ + if (currentYear != startYear) { + return; + } + } + case 2: { + /* write only first and last growth periods */ + if (currentYear != startYear && currentYear != endYear) { + return; + } + } + case 4: { + /* write only the first, every tenth subsequent, and the last periods */ + if ((currentYear - startYear) % 10 != 0 && currentYear != endYear) { + return; + } + } + case 3: { + break; + } + default: + throw new ProcessingException(MessageFormat.format("Invalid value for control variable 4: {0}", controlVariable4Value)); + } } private static final float[] DEFAULT_QUAD_MEAN_DIAMETERS = new float[] { Float.NaN, 10.0f, 15.0f, 20.0f, 25.0f }; @@ -2336,10 +2665,11 @@ private static float calculateWholeStemVolume(float actualVolume, float basalAre } /** - * VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 + * VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2. + * + * @param lps layer processing state + * @param hl1Coefficients the configured dominant height recalculation coefficients * - * @param lps - * @param hl1Coefficients * @throws ProcessingException */ static void calculateDominantHeightAgeSiteIndex( @@ -2618,27 +2948,26 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } /** - * Calculate the percentage of forested land covered by each species by dividing the basal area of each given - * species with the basal area of the polygon covered by forest. + * VPRIME1, method == 1: calculate the percentage of forested land covered by each species + * by dividing the basal area of each given species with the basal area of the polygon covered by forest. * * @param state the bank in which the calculations are performed */ - void calculateCoverages() { + static void calculateCoverages(LayerProcessingState lps) { - LayerProcessingState lps = this.fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getStartBank(); - logger.atDebug().addArgument(lps.getNSpecies()).addArgument(start.basalAreas[0][0]).log( + logger.atDebug().addArgument(lps.getNSpecies()).addArgument(bank.basalAreas[0][0]).log( "Calculating coverages as a ratio of Species BA over Total BA. # species: {}; Layer total 7.5cm+ basal area: {}" ); for (int i : lps.getIndices()) { - start.percentagesOfForestedLand[i] = start.basalAreas[i][UC_ALL_INDEX] - / start.basalAreas[0][UC_ALL_INDEX] * 100.0f; + bank.percentagesOfForestedLand[i] = bank.basalAreas[i][UC_ALL_INDEX] + / bank.basalAreas[0][UC_ALL_INDEX] * 100.0f; - logger.atDebug().addArgument(i).addArgument(start.speciesIndices[i]) - .addArgument(start.speciesNames[i]).addArgument(start.basalAreas[i][0]) - .addArgument(start.percentagesOfForestedLand[i]) + logger.atDebug().addArgument(i).addArgument(bank.speciesIndices[i]) + .addArgument(bank.speciesNames[i]).addArgument(bank.basalAreas[i][0]) + .addArgument(bank.percentagesOfForestedLand[i]) .log("Species {}: SP0 {}, Name {}, Species 7.5cm+ BA {}, Calculated Percent {}"); } } @@ -2654,8 +2983,10 @@ void calculateCoverages() { * @param lps the PolygonProcessingState to where the calculated curves are also to be */ static void calculateMissingSiteCurves( - Bank bank, MatrixMap2 siteCurveMap, LayerProcessingState lps + LayerProcessingState lps, MatrixMap2 siteCurveMap ) { + Bank bank = lps.getStartBank(); + BecDefinition becZone = bank.getBecZone(); for (int i : bank.getIndices()) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 9754a76dc..985521cc4 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -44,6 +44,9 @@ class LayerProcessingState { /** The containing polygon of the layer on which the Processor is operating */ private final VdypPolygon polygon; + + /** The type of Layer being processed */ + private final LayerType layerType; // L1COM1, L1COM4 and L1COM5 - these common blocks mirror BANK1, BANK2 and BANK3 and are initialized // when copied to "active" in ForwardProcessingEngine. @@ -52,7 +55,7 @@ class LayerProcessingState { * State of the layer at the start of processing; read-write during preparation for grow * and read-only after that. */ - private Bank start; + private Bank startBank; // L1COM2 - equation groups. From the configuration, narrowed to the // polygon's BEC zone. @@ -113,32 +116,33 @@ class LayerProcessingState { // MNSP - MSPL1, MSPLV // TODO - public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { + public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, LayerType subjectLayerType) throws ProcessingException { this.fps = fps; this.polygon = polygon; + this.layerType = subjectLayerType; BecDefinition becZone = polygon.getBiogeoclimaticZone(); - this.start = new Bank( - polygon.getLayers().get(subjectLayer), becZone, + this.startBank = new Bank( + polygon.getLayers().get(subjectLayerType), becZone, s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= ForwardProcessingEngine.MIN_BASAL_AREA); var volumeEquationGroupMatrix = this.fps.fcm.getVolumeEquationGroups(); var decayEquationGroupMatrix = this.fps.fcm.getDecayEquationGroups(); var breakageEquationGroupMatrix = this.fps.fcm.getBreakageEquationGroups(); - this.volumeEquationGroups = new int[this.start.getNSpecies() + 1]; - this.decayEquationGroups = new int[this.start.getNSpecies() + 1]; - this.breakageEquationGroups = new int[this.start.getNSpecies() + 1]; + this.volumeEquationGroups = new int[this.startBank.getNSpecies() + 1]; + this.decayEquationGroups = new int[this.startBank.getNSpecies() + 1]; + this.breakageEquationGroups = new int[this.startBank.getNSpecies() + 1]; this.volumeEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; this.decayEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; this.breakageEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; String becZoneAlias = this.getBecZone().getAlias(); - for (int i = 1; i < this.start.getNSpecies() + 1; i++) { - String speciesName = this.start.speciesNames[i]; + for (int i = 1; i < this.startBank.getNSpecies() + 1; i++) { + String speciesName = this.startBank.speciesNames[i]; this.volumeEquationGroups[i] = volumeEquationGroupMatrix.get(speciesName, becZoneAlias); // From VGRPFIND, volumeEquationGroup 10 is mapped to 11. if (this.volumeEquationGroups[i] == 10) { @@ -148,21 +152,36 @@ public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, Lay this.breakageEquationGroups[i] = breakageEquationGroupMatrix.get(speciesName, becZoneAlias); } } + + /** + * Set the layer processing state to the given Bank. This is normally done at the conclusion of + * the growth of a layer for one growth period; the Bank resulting from that calculation is + * assigned as the start bank for the next growth period. + * + * @param newStartBank + */ + public void swapBank(Bank newStartBank) { + this.startBank = newStartBank; + } public VdypPolygon getPolygon() { return polygon; } + + public LayerType getLayerType() { + return layerType; + } public int getNSpecies() { - return start.getNSpecies(); + return startBank.getNSpecies(); } public int[] getIndices() { - return start.getIndices(); + return startBank.getIndices(); } public BecDefinition getBecZone() { - return start.getBecZone(); + return startBank.getBecZone(); } public int getPrimarySpeciesIndex() { @@ -176,7 +195,7 @@ public String getPrimarySpeciesAlias() { if (!areRankingDetailsSet) { throw new IllegalStateException("unset primarySpeciesIndex"); } - return start.speciesNames[primarySpeciesIndex]; + return startBank.speciesNames[primarySpeciesIndex]; } public boolean hasSecondarySpeciesIndex() { @@ -251,7 +270,7 @@ public ForwardProcessingState getFps() { } public Bank getStartBank() { - return start; + return startBank; } public int[] getVolumeEquationGroups() { @@ -390,20 +409,20 @@ public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { this.primarySpeciesAgeToBreastHeight = details.primarySpeciesAgeToBreastHeight(); // Store these values into start - VHDOM1 lines 182 - 186 - if (start.dominantHeights[primarySpeciesIndex] <= 0.0) { - start.dominantHeights[primarySpeciesIndex] = this.primarySpeciesDominantHeight; + if (startBank.dominantHeights[primarySpeciesIndex] <= 0.0) { + startBank.dominantHeights[primarySpeciesIndex] = this.primarySpeciesDominantHeight; } - if (start.siteIndices[primarySpeciesIndex] <= 0.0) { - start.siteIndices[primarySpeciesIndex] = this.primarySpeciesSiteIndex; + if (startBank.siteIndices[primarySpeciesIndex] <= 0.0) { + startBank.siteIndices[primarySpeciesIndex] = this.primarySpeciesSiteIndex; } - if (start.ageTotals[primarySpeciesIndex] <= 0.0) { - start.ageTotals[primarySpeciesIndex] = this.primarySpeciesTotalAge; + if (startBank.ageTotals[primarySpeciesIndex] <= 0.0) { + startBank.ageTotals[primarySpeciesIndex] = this.primarySpeciesTotalAge; } - if (start.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { - start.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeAtBreastHeight; + if (startBank.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { + startBank.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeAtBreastHeight; } - if (start.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { - start.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeToBreastHeight; + if (startBank.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { + startBank.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeToBreastHeight; } this.arePrimarySpeciesDetailsSet = true; From 394a2f0f1da435511e06bf8754bba604340b079f Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 28 Aug 2024 13:09:09 -0700 Subject: [PATCH 39/66] Implement output --- .../ca/bc/gov/nrs/vdyp/common/ControlKey.java | 3 + .../nrs/vdyp/io/write/VdypOutputWriter.java | 296 ++++++++++++++++++ .../vdyp/io/write/VriAdjustInputWriter.java | 238 +------------- .../ITFipStart.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 8 +- .../vdyp/forward/ForwardProcessingEngine.java | 172 ++++++---- .../vdyp/forward/ForwardProcessingState.java | 27 +- .../nrs/vdyp/forward/ForwardProcessor.java | 14 +- .../vdyp/forward/LayerProcessingState.java | 32 +- .../GeneralForwardProcessingEngineTest.java | 4 +- .../forward/VdypForwardSpeciesParserTest.java | 1 - 11 files changed, 473 insertions(+), 324 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java rename vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/{integeration => integration}/ITFipStart.java (99%) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java index d919c94b0..7985c11e7 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java @@ -22,6 +22,9 @@ public enum ControlKey { // FIP/VRI Outputs VRI_OUTPUT_VDYP_POLYGON(15), VRI_OUTPUT_VDYP_LAYER_BY_SPECIES(16), VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL(18), + // VDYP Forward Outputs + VDYP_OUTPUT_VDYP_POLYGON(15), VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES(16), VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL(18), + VOLUME_EQN_GROUPS(20), DECAY_GROUPS(21), BREAKAGE_GROUPS(22), SITE_CURVE_NUMBERS(25), SITE_CURVE_AGE_MAX(26), diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java new file mode 100644 index 000000000..76f6dee78 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java @@ -0,0 +1,296 @@ +package ca.bc.gov.nrs.vdyp.io.write; + +import java.io.Closeable; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +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.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.PolygonIdentifier; +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.VdypSpecies; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; + +/** + * Write files to be input into VRI Adjust. + */ +public class VdypOutputWriter implements Closeable { + + private OutputStream polygonFile; + private OutputStream speciesFile; + private OutputStream utilizationFile; + + private Optional currentYear = Optional.empty(); + + static final String POLY_IDENTIFIER_FORMAT = "%-25s"; + static final String LAYER_TYPE_FORMAT = "%-1s"; + static final String SPEC_IDENTIFIER_FORMAT = "%-2s"; + static final String SPEC_INDEX_FORMAT = "%2d"; + static final String SPEC_DIST_FORMAT = "%-3s%5.1f"; + static final String DISTANCE_FORMAT = "%6.2f"; + static final String AGE_FORMAT = "%6.1f"; + + static final float EMPTY_FLOAT = -9f; + static final int EMPTY_INT = -9; + + // FORMAT(A25, 1x,A4,1x,A1,I6, I3, I3 , I3 ) + static final String POLY_FORMAT = POLY_IDENTIFIER_FORMAT + " %-4s %1s%6d%3d%3d%3d\n"; + + // FORMAT(A25,1x,A1,1x,I2,1x,A2,1x,A32,2f6.2,3f6.1,I2,I3) + static final String SPEC_FORMAT = POLY_IDENTIFIER_FORMAT + " " + LAYER_TYPE_FORMAT + " " + SPEC_INDEX_FORMAT + " " + + SPEC_IDENTIFIER_FORMAT + " " + SPEC_DIST_FORMAT.repeat(4) + DISTANCE_FORMAT.repeat(2) + + AGE_FORMAT.repeat(3) + "%2d%3d\n"; + + // 082E004 615 1988 P 0 0 19.97867 1485.82 13.0660 117.9938 67.7539 67.0665 + // 66.8413 65.4214 13.1 + // FORMAT (A25, 1x, A1, 1x, I2, 1x, A2, I3, + // 1 F9.5, F9.2, F9.4, 5F9.4, F6.1) + static final String UTIL_FORMAT = POLY_IDENTIFIER_FORMAT + " " + LAYER_TYPE_FORMAT + " " + SPEC_INDEX_FORMAT + " " + + SPEC_IDENTIFIER_FORMAT + "%3d%9.5f%9.2f%9.4f%9.4f%9.4f%9.4f%9.4f%9.4f%6.1f\n"; + + static final String END_RECORD_FORMAT = POLY_IDENTIFIER_FORMAT + " \n"; + + /** + * Create a writer for Vdyp output files using provided OutputStreams. The Streams will be + * closed when the writer is closed. + * + * @param polygonFile + * @param speciesFile + * @param utilizationFile + * @param controlMap + */ + public VdypOutputWriter( + OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile + ) { + this.polygonFile = polygonFile; + this.speciesFile = speciesFile; + this.utilizationFile = utilizationFile; + } + + /** + * Create a writer for Vdyp output files configured using the given control map. + * + * @param polygonFile + * @param speciesFile + * @param utilizationFile + * @param controlMap + */ + public VdypOutputWriter(Map controlMap, FileResolver resolver) throws IOException { + this( + getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_POLYGON.name()), + getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name()), + getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()) + ); + } + + static OutputStream getOutputStream(Map controlMap, FileResolver resolver, String key) + throws IOException { + String fileName = Utils.expectParsedControl(controlMap, key, String.class); + return resolver.resolveForOutput(fileName); + } + + private void setPolygonYear(Optional polygonYear) { + this.currentYear = polygonYear; + } + + private PolygonIdentifier getCurrentPolygonDescriptor(PolygonIdentifier originalIdentifier) { + if (currentYear.isPresent()) { + return new PolygonIdentifier(originalIdentifier.getBase(), currentYear.get()); + } else { + return originalIdentifier; + } + } + + // V7W_AIP + /** + * Write a polygon record to the polygon file + * + * @param polygon + * @throws IOException + */ + void writePolygon(VdypPolygon polygon) throws IOException { + setPolygonYear(polygon.getTargetYear()); + + writeFormat( + polygonFile, // + POLY_FORMAT, // + + getCurrentPolygonDescriptor(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 + boolean isSiteSpec = layer.getSiteGenus().map(spec.getGenus()::equals).orElse(false); + writeFormat( + speciesFile, // + SPEC_FORMAT, // + + getCurrentPolygonDescriptor(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(), // + + layer.getSiteIndex().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // + layer.getHeight().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // + layer.getAgeTotal().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // + layer.getBreastHeightAge().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // + layer.getYearsToBreastHeight().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // + layer.getSiteGenus().filter(x -> isSiteSpec).map(id -> id.equals(spec.getGenus())).orElse(false) ? 1 + : 0, // + layer.getSiteCurveNumber().filter(x -> isSiteSpec).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 specId = Optional.empty(); + Optional specIndex = Optional.empty(); + if (utils instanceof VdypSpecies spec) { + specId = Optional.of(spec.getGenus()); + specIndex = Optional.of(spec.getGenusIndex()); + } + + for (var uc : UtilizationClass.values()) { + Optional height = Optional.empty(); + if (uc.index < 1) { + height = Optional.of(utils.getLoreyHeightByUtilization().getCoe(uc.index)).filter(x -> x > 0f); + } + Optional 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, // + + getCurrentPolygonDescriptor(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 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, getCurrentPolygonDescriptor(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(); + } +} diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java index 5849a46cf..90205129c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java @@ -1,64 +1,16 @@ package ca.bc.gov.nrs.vdyp.io.write; -import java.io.Closeable; import java.io.IOException; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; 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.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.VdypSpecies; -import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; /** * Write files to be input into VRI Adjust. */ -public class VriAdjustInputWriter implements Closeable { - - private OutputStream polygonFile; - private OutputStream speciesFile; - private OutputStream utilizationFile; - - static final String POLY_IDENTIFIER_FORMAT = "%-25s"; - static final String LAYER_TYPE_FORMAT = "%-1s"; - static final String SPEC_IDENTIFIER_FORMAT = "%-2s"; - static final String SPEC_INDEX_FORMAT = "%2d"; - static final String SPEC_DIST_FORMAT = "%-3s%5.1f"; - static final String DISTANCE_FORMAT = "%6.2f"; - static final String AGE_FORMAT = "%6.1f"; - - static final float EMPTY_FLOAT = -9f; - static final int EMPTY_INT = -9; - - // FORMAT(A25, 1x,A4,1x,A1,I6, I3, I3 , I3 ) - static final String POLY_FORMAT = POLY_IDENTIFIER_FORMAT + " %-4s %1s%6d%3d%3d%3d\n"; - - // FORMAT(A25,1x,A1,1x,I2,1x,A2,1x,A32,2f6.2,3f6.1,I2,I3) - static final String SPEC_FORMAT = POLY_IDENTIFIER_FORMAT + " " + LAYER_TYPE_FORMAT + " " + SPEC_INDEX_FORMAT + " " - + SPEC_IDENTIFIER_FORMAT + " " + SPEC_DIST_FORMAT.repeat(4) + DISTANCE_FORMAT.repeat(2) - + AGE_FORMAT.repeat(3) + "%2d%3d\n"; - - // 082E004 615 1988 P 0 0 19.97867 1485.82 13.0660 117.9938 67.7539 67.0665 - // 66.8413 65.4214 13.1 - // FORMAT (A25, 1x, A1, 1x, I2, 1x, A2, I3, - // 1 F9.5, F9.2, F9.4, 5F9.4, F6.1) - static final String UTIL_FORMAT = POLY_IDENTIFIER_FORMAT + " " + LAYER_TYPE_FORMAT + " " + SPEC_INDEX_FORMAT + " " - + SPEC_IDENTIFIER_FORMAT + "%3d%9.5f%9.2f%9.4f%9.4f%9.4f%9.4f%9.4f%9.4f%6.1f\n"; - - static final String END_RECORD_FORMAT = POLY_IDENTIFIER_FORMAT + " \n"; +public class VriAdjustInputWriter extends VdypOutputWriter { /** * Create a writer for VRI Adjust input files using provided OutputStreams. The Streams will be closed when the @@ -73,9 +25,7 @@ public VriAdjustInputWriter( OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile, Map controlMap ) { - this.polygonFile = polygonFile; - this.speciesFile = speciesFile; - this.utilizationFile = utilizationFile; + super(polygonFile, speciesFile, utilizationFile); } /** @@ -94,188 +44,4 @@ public VriAdjustInputWriter(Map controlMap, FileResolver resolve controlMap ); } - - static OutputStream getOutputStream(Map 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 - boolean isSiteSpec = layer.getSiteGenus().map(spec.getGenus()::equals).orElse(false); - 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(), // - - layer.getSiteIndex().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getHeight().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getAgeTotal().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getBreastHeightAge().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getYearsToBreastHeight().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getSiteGenus().filter(x -> isSiteSpec).map(id -> id.equals(spec.getGenus())).orElse(false) ? 1 - : 0, // - layer.getSiteCurveNumber().filter(x -> isSiteSpec).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 specId = Optional.empty(); - Optional specIndex = Optional.empty(); - if (utils instanceof VdypSpecies spec) { - specId = Optional.of(spec.getGenus()); - specIndex = Optional.of(spec.getGenusIndex()); - } - - for (var uc : UtilizationClass.values()) { - Optional height = Optional.empty(); - if (uc.index < 1) { - height = Optional.of(utils.getLoreyHeightByUtilization().getCoe(uc.index)).filter(x -> x > 0f); - } - Optional 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 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(); - } } diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integration/ITFipStart.java similarity index 99% rename from vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java rename to vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integration/ITFipStart.java index 7dd456977..594004a83 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integeration/ITFipStart.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/integration/ITFipStart.java @@ -1,4 +1,4 @@ -package ca.bc.gov.nrs.vdyp.fip.integeration; +package ca.bc.gov.nrs.vdyp.fip.integration; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index e9a31b80b..8f91c9150 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -21,6 +21,10 @@ class Bank { + enum CopyMode { + CopyAll, CopyStructure + }; + @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(Bank.class); @@ -104,10 +108,6 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai } } - enum CopyMode { - CopyAll, CopyStructure - }; - public Bank(Bank source, CopyMode copyMode) { this.becZone = source.becZone; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 416cccbc2..f6fe20c8d 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -6,6 +6,7 @@ import static ca.bc.gov.nrs.vdyp.math.FloatMath.pow; import static java.lang.Math.max; +import java.io.IOException; import java.text.MessageFormat; import java.util.Arrays; import java.util.Collection; @@ -34,10 +35,11 @@ import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.SpeciesErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexAgeType; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; +import ca.bc.gov.nrs.vdyp.forward.LayerProcessingState.BankType; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperBoundsParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; @@ -84,10 +86,15 @@ public class ForwardProcessingEngine { public static final float PI_40K = (float) (Math.PI / 40_000); /* pp */ final ForwardProcessingState fps; - - public ForwardProcessingEngine(Map controlMap) { - this.fps = new ForwardProcessingState(controlMap); + public ForwardProcessingEngine(Map controlMap, Optional outputFileResolver) + throws ProcessingException { + this.fps = new ForwardProcessingState(controlMap, outputFileResolver); + } + + public ForwardProcessingEngine(Map controlMap) + throws ProcessingException { + this.fps = new ForwardProcessingState(controlMap, Optional.empty()); } public enum ExecutionStep { @@ -240,10 +247,10 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY VdypPolygon vdypPolygon = lps.getPolygon(); - VdypLayer primaryLayer = vdypPolygon.getLayers().get(LayerType.PRIMARY); - - writeLayers(primaryLayer, veteranLayer, startingYear, startingYear, untilYear); + writePolygon(vdypPolygon, startingYear, startingYear, untilYear); + Map polygonLayers = vdypPolygon.getLayers(); + boolean doRecalculateGroupsPriorToOutput = fps.fcm.getDebugSettings() .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 && lps.getNSpecies() > 1; @@ -254,18 +261,23 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY int currentYear = startingYear; while (currentYear <= untilYear) { - Bank endBank = grow(lps, currentYear, veteranLayer); + grow(lps, currentYear, veteranLayer); - lps.swapBank(endBank); + // Set startBank to endBank and clear out endBank, in preparation for the + // next iteration. + + lps.swapBanks(); // If update-during-growth is set, update the context prior to output if (doRecalculateGroupsPriorToOutput) { calculateCoverages(lps); calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } - + + polygonLayers.put(LayerType.PRIMARY, lps.getLayerFromBank(BankType.Start)); + // Store polygon (both primary and veteran layers) to output - writeLayers(primaryLayer, veteranLayer, startingYear, currentYear, untilYear); + writePolygon(vdypPolygon, startingYear, currentYear, untilYear); // If update-during-growth is set, and not already recalculated, recalculate // context now. @@ -291,27 +303,26 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY * * @throws ProcessingException */ - private Bank grow(LayerProcessingState lps, int currentYear, Optional veteranLayer) + private void grow(LayerProcessingState lps, int currentYear, Optional veteranLayer) throws ProcessingException { VdypPolygon polygon = lps.getPolygon(); Bank start = lps.getStartBank(); + Bank end = lps.getEndBank(); logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); - Bank end = new Bank(start, CopyMode.CopyStructure); - float dhStart = lps.getPrimarySpeciesDominantHeight(); int pspSiteCurveNumber = lps.getSiteCurveNumber(lps.getPrimarySpeciesIndex()); float pspSiteIndex = lps.getPrimarySpeciesSiteIndex(); float pspYtbhStart = lps.getPrimarySpeciesAgeToBreastHeight(); float pspYabhStart = lps.getPrimarySpeciesAgeAtBreastHeight(); - // Calculate change in dominant height + // (1) Calculate change in dominant height (layer) float dhDelta = growDominantHeight(dhStart, pspSiteCurveNumber, pspSiteIndex, pspYtbhStart); - // Calculate change in basal area + // (2) Calculate change in basal area (layer) final Optional veteranLayerBasalArea = veteranLayer.flatMap((l) -> Optional.of(l.getBaseAreaByUtilization().get(UtilizationClass.ALL))); @@ -325,6 +336,8 @@ private Bank grow(LayerProcessingState lps, int currentYear, Optional pspYabhStart, fps.fcm.getDebugSettings(), dhStart, baStart, veteranLayerBasalArea, dhDelta ); + // (3) Calculate change in quad-mean-diameter (layer) + Reference wasDqGrowthLimitApplied = new Reference<>(); float dqDelta = growQuadMeanDiameter( pspYtbhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied @@ -350,21 +363,23 @@ private Bank grow(LayerProcessingState lps, int currentYear, Optional float tphEnd = BaseAreaTreeDensityDiameter.treesPerHectare(baEnd, dqEnd); float tphMultiplier = tphEnd / tphStart; - // Begin storing computed results - dq, ba and tph for the layer + // (4) Begin storing computed results - dq, ba and tph for the layer end.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; end.basalAreas[0][UC_ALL_INDEX] = baEnd; end.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; - // Now do DQ growth by species, using one of several options: "full species", "dynamic", "partial dynamics" - // or "no dynamics." + // (5) Now do DQ growth by species, using one of several options: "full species", "dynamic", + // "partial dynamics" or "no dynamics." int debugSetting1Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1); boolean wasSolutionFound = false; if (debugSetting1Value == 2) { - // This is the PARTIAL SPECIES DYNAMICS section. + // (5a) This is the PARTIAL SPECIES DYNAMICS section. - // Begin by updating HL for all species (save the ungrown HLs). + // (5a1) Begin by updating HL for all species + + // First save the ungrown HLs float[] startingLoreyHeights = new float[start.getNSpecies() + 1]; startingLoreyHeights[0] = start.loreyHeights[0][UC_ALL_INDEX]; for (int i : start.getIndices()) { @@ -373,7 +388,7 @@ private Bank grow(LayerProcessingState lps, int currentYear, Optional float pspTphEndEstimate = pspTphStart * (tphEnd / tphStart); - growLoreyHeights(end, dhStart, dhEnd, pspTphStart, pspTphEndEstimate, pspLhStart); + growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEndEstimate, pspLhStart); float sum1 = 0.0f; float sum2 = 0.0f; @@ -429,7 +444,7 @@ private Bank grow(LayerProcessingState lps, int currentYear, Optional // Calculate Lorey heights over all species, uc UC_ALL_INDEX float pspTphEnd = end.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; - growLoreyHeights(end, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); + growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); // We now have site level predications for basal area, quad-mean-diameter, trees-per-hectare // and Lorey height. Proceed to per-species estimates. @@ -470,7 +485,7 @@ private Bank grow(LayerProcessingState lps, int currentYear, Optional lps.updateCompatibilityVariablesAfterGrowth(); - VdypLayer primaryLayer = lps.getLayerFromBank(end); + VdypLayer primaryLayer = lps.getLayerFromBank(BankType.End); VolumeComputeMode volumeComputationMode = VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC; int controlVariable3Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); @@ -479,9 +494,9 @@ private Bank grow(LayerProcessingState lps, int currentYear, Optional end.refreshBank(primaryLayer); - calculateSmallComponentYields(end); - - return end; + // ( + + calculateSmallComponentYields(lps); } /** @@ -1217,8 +1232,8 @@ private float growBasalAreaForNonPrimarySpecies( if (spBaStart <= 0.0f || spBaStart >= baStart) { throw new ProcessingException( MessageFormat.format( - "Species basal area {} is out of range; it must be" - + " positive and less that overall basal area", spBaStart, baStart + "Species basal area {0} is out of range; it must be" + + " positive and less that overall basal area {1}", spBaStart, baStart ) ); } @@ -1315,14 +1330,15 @@ private float growBasalAreaForPrimarySpecies( } /** - * YSMALL - record small component utilization values for primary layer. + * YSMALL - records in end the small component utilization values for + * current layer. * * @throws ProcessingException */ - private void calculateSmallComponentYields(Bank end) throws ProcessingException { + private void calculateSmallComponentYields(LayerProcessingState lps) throws ProcessingException { - LayerProcessingState lps = fps.getLayerProcessingState(); Bank start = lps.getStartBank(); + Bank end = lps.getEndBank(); float lhSum = 0.0f; float baSum = 0.0f; @@ -1423,8 +1439,9 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException /** * GRSPHL - estimate the Lorey Heights of all species at end of growth period. The results of - * the calculations are persisted in {@code start}. + * the calculations are persisted in {@code lps.endBank}. * + * @param lps processing state context * @param dhStart (primary species) dominant height at start * @param dhEnd (primary species) dominant height at end * @param pspTphStart primary species trees-per-hectare at start @@ -1432,11 +1449,11 @@ private void calculateSmallComponentYields(Bank end) throws ProcessingException * @param pspLhStart primary species Lorey height at end */ private void growLoreyHeights( - Bank end, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart + LayerProcessingState lps, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart ) { - LayerProcessingState lps = fps.getLayerProcessingState(); Bank start = lps.getStartBank(); + Bank end = lps.getEndBank(); float pspLhStartEstimate = estimatePrimarySpeciesLoreyHeight(dhStart, pspTphStart); float pspLhEndEstimate = estimatePrimarySpeciesLoreyHeight(dhEnd, pspTphEnd); @@ -1504,6 +1521,8 @@ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { /** * EMP053 - estimate the Lorey height of a non-primary species of the polygon. * + * Does not modify either startBank or endBank. + * * @param speciesIndex (non-primary) species index * @param dh (primary species) dominant height * @param pspLoreyHeight primary species Lorey height @@ -1669,7 +1688,8 @@ float growQuadMeanDiameter( } /** - * EMP122. Calculate quad mean diameter growth using the empirical model. + * EMP122. Function that returns the quad mean diameter growth quad-mean-diameter value + * computed using the empirical model. * * @param pspYabhStart primary species years at breast height at start of growth period * @param dhStart primary species dominant height at start of growth period @@ -1867,7 +1887,7 @@ float growBasalArea( } /** - * EMP121. Calculate basal area growth using the empirical model. + * EMP121. Function that returns the basal area growth calculated using the empirical model. * * @param speciesBasalAreaProportions the proportion by basal area of each of the polygon's species * @param baStart basal area of primary layer @@ -2187,13 +2207,10 @@ private static double ageAndSiteIndexToHeight( } } - private void writeLayers(VdypLayer primaryLayer, Optional veteranLayer, int startYear, int currentYear, int endYear) + private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, int endYear) throws ProcessingException { - logger.info( - "Writing primary layer {}{}", primaryLayer.getPolygonIdentifier(), - veteranLayer.isPresent() ? veteranLayer.get().getPolygonIdentifier() : "" - ); + logger.info("Writing polygon {} for year {}", polygon, currentYear); int controlVariable4Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.OUTPUT_FILES_4); @@ -2226,12 +2243,26 @@ private void writeLayers(VdypLayer primaryLayer, Optional veteranLaye default: throw new ProcessingException(MessageFormat.format("Invalid value for control variable 4: {0}", controlVariable4Value)); } + + if (fps.getOutputWriter().isPresent()) { + try { + fps.getOutputWriter().get().writePolygonWithSpeciesAndUtilization(polygon); + } catch (IOException e) { + throw new ProcessingException(e); + } + } } private static final float[] DEFAULT_QUAD_MEAN_DIAMETERS = new float[] { Float.NaN, 10.0f, 15.0f, 20.0f, 25.0f }; private static final float V_BASE_MIN = 0.1f; private static final float B_BASE_MIN = 0.01f; + /** + * CVSET1 - computes cvVolume, cvBasalArea, cvQuadraticMeanDiameter and cvSmall and assigns + * them to the current LayerProcessingState. + * + * @throws ProcessingException + */ @SuppressWarnings("unchecked") void setCompatibilityVariables() throws ProcessingException { @@ -2255,7 +2286,7 @@ void setCompatibilityVariables() throws ProcessingException { var cvQuadraticMeanDiameter = new MatrixMap2[lps.getNSpecies() + 1]; var cvSmall = new HashMap[lps.getNSpecies() + 1]; - for (int s = 1; s <= lps.getNSpecies(); s++) { + for (int s : lps.getIndices()) { String genusName = start.speciesNames[s]; @@ -2432,7 +2463,8 @@ void setCompatibilityVariables() throws ProcessingException { } /** - * Calculate the small component compatibility variables. + * Function that calculates values for the small component compatibility variables and returns + * the result. * * @param speciesIndex the index of the species for which this operation is to be performed * @param forwardControlVariables the control variables for this run @@ -2843,8 +2875,10 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { } /** + * SITEADD + *

    * (1) If the site index of the primary species has not been set, calculate it as the average of the site indices of - * the other species that -do- have one, after converting it between the site curve of the other species and that of + * the other species that -do- have one, after converting each between the site curve of the other species and that of * the primary species. *

    * (2) If the site index of the primary species has (now) been set, calculate that of the other species whose site @@ -2858,30 +2892,30 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi Bank start = lps.getStartBank(); - int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); - SiteIndexEquation primarySiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(primarySpeciesIndex)); + int pspIndex = lps.getPrimarySpeciesIndex(); + SiteIndexEquation pspSiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(pspIndex)); // (1) - if (Float.isNaN(start.siteIndices[primarySpeciesIndex])) { + if (Float.isNaN(start.siteIndices[pspIndex])) { double otherSiteIndicesSum = 0.0f; int nOtherSiteIndices = 0; - for (int i : lps.getIndices()) { + for (int spIndex : lps.getIndices()) { - if (i == primarySpeciesIndex) { + if (spIndex == pspIndex) { continue; } - float siteIndexI = start.siteIndices[i]; + float spSiteIndex = start.siteIndices[spIndex]; - if (!Float.isNaN(siteIndexI)) { - SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); + if (!Float.isNaN(spSiteIndex)) { + SiteIndexEquation spSiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(spIndex)); try { double mappedSiteIndex = SiteTool - .convertSiteIndexBetweenCurves(siteCurveI, siteIndexI, primarySiteCurve); + .convertSiteIndexBetweenCurves(spSiteCurve, spSiteIndex, pspSiteCurve); if (mappedSiteIndex > 1.3) { otherSiteIndicesSum += mappedSiteIndex; nOtherSiteIndices += 1; @@ -2889,13 +2923,13 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion from curves {0} to {1}. Skipping species {3}", siteCurveI, primarySiteCurve, i + "there is no conversion from curves {0} to {1}. Skipping species {3}", spSiteCurve, pspSiteCurve, spIndex ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", siteCurveI, siteIndexI, primarySiteCurve + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", spSiteCurve, spSiteIndex, pspSiteCurve ), e ); } @@ -2903,39 +2937,39 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } if (nOtherSiteIndices > 0) { - start.siteIndices[primarySpeciesIndex] = (float) (otherSiteIndicesSum / nOtherSiteIndices); + start.siteIndices[pspIndex] = (float) (otherSiteIndicesSum / nOtherSiteIndices); } } // (2) - float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; - if (!Float.isNaN(primarySpeciesSiteIndex)) { + float pspSiteIndex = start.siteIndices[pspIndex]; + if (!Float.isNaN(start.siteIndices[pspIndex])) { - for (int i : lps.getIndices()) { + for (int spIndex : lps.getIndices()) { - if (i == primarySpeciesIndex) { + if (spIndex == pspIndex) { continue; } - float siteIndexI = start.siteIndices[i]; - if (Float.isNaN(siteIndexI)) { - SiteIndexEquation siteCurveI = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); + float spSiteIndex = start.siteIndices[spIndex]; + if (Float.isNaN(spSiteIndex)) { + SiteIndexEquation spSiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(spIndex)); try { double mappedSiteIndex = SiteTool - .convertSiteIndexBetweenCurves(primarySiteCurve, primarySpeciesSiteIndex, siteCurveI); - start.siteIndices[i] = (float) mappedSiteIndex; + .convertSiteIndexBetweenCurves(pspSiteCurve, pspSiteIndex, spSiteCurve); + start.siteIndices[spIndex] = (float) mappedSiteIndex; } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion between curves {0} and {1}. Skipping species {2}", primarySiteCurve, siteCurveI, i + "there is no conversion between curves {0} and {1}. Skipping species {2}", pspSiteCurve, spSiteCurve, spIndex ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed. Skipping species {3}", primarySiteCurve, primarySpeciesSiteIndex, siteCurveI, i + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed. Skipping species {3}", pspSiteCurve, pspSiteIndex, spSiteCurve, spIndex ), e ); } @@ -2944,7 +2978,7 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } // Finally, set bank.siteIndices[0] to that of the primary species. - start.siteIndices[0] = primarySpeciesSiteIndex; + start.siteIndices[0] = pspSiteIndex; } /** diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 03aac111d..5893697e5 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -1,6 +1,8 @@ package ca.bc.gov.nrs.vdyp.forward; +import java.io.IOException; import java.util.Map; +import java.util.Optional; import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; @@ -8,6 +10,8 @@ import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; +import ca.bc.gov.nrs.vdyp.io.write.VdypOutputWriter; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; @@ -24,11 +28,28 @@ class ForwardProcessingState { /** The active state */ private LayerProcessingState lps; + + /** The entity to which result information is written */ + private Optional outputWriter = Optional.empty(); - public ForwardProcessingState(Map controlMap) { + public ForwardProcessingState(Map controlMap) + throws ProcessingException { + this(controlMap, Optional.empty()); + } + + public ForwardProcessingState(Map controlMap, Optional outputFileResolver) + throws ProcessingException { this.fcm = new ForwardResolvedControlMapImpl(controlMap); this.estimators = new EstimationMethods(this.fcm); this.computers = new ComputationMethods(estimators, VdypApplicationIdentifier.VDYP_FORWARD); + + if (outputFileResolver.isPresent()) { + try { + outputWriter = Optional.of(new VdypOutputWriter(controlMap, outputFileResolver.get())); + } catch (IOException e) { + throw new ProcessingException(e); + } + } } public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { @@ -39,4 +60,8 @@ public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws public LayerProcessingState getLayerProcessingState() { return lps; } + + public Optional getOutputWriter() { + return outputWriter; + } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index a19f73e34..a1da74d2e 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.slf4j.Logger; @@ -75,6 +76,8 @@ void run(FileResolver resolver, List controlFileNames, Set var parser = new ForwardControlParser(); + Optional outputFileResolver = Optional.empty(); + for (var controlFileName : controlFileNames) { logger.info("Resolving and parsing {}", controlFileName); @@ -83,18 +86,23 @@ void run(FileResolver resolver, List controlFileNames, Set FileSystemFileResolver relativeResolver = new FileSystemFileResolver(controlFilePath); parser.parse(is, relativeResolver, controlMap); + + if (controlMap.containsKey(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name())) { + outputFileResolver = Optional.of(relativeResolver); + } } } - process(vdypPassSet, controlMap); + process(vdypPassSet, controlMap, outputFileResolver); } /** * Implements VDYP_SUB + * @param outputFileResolver * * @throws ProcessingException */ - public void process(Set vdypPassSet, Map controlMap) throws ProcessingException { + public void process(Set vdypPassSet, Map controlMap, Optional outputFileResolver) throws ProcessingException { logger.info("Beginning processing with given configuration"); @@ -115,7 +123,7 @@ public void process(Set vdypPassSet, Map controlMap if (vdypPassSet.contains(ForwardPass.PASS_3)) { - var fpe = new ForwardProcessingEngine(controlMap); + var fpe = new ForwardProcessingEngine(controlMap, outputFileResolver); var forwardDataStreamReader = new ForwardDataStreamReader(fpe.fps.fcm); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 985521cc4..3c38ace99 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; @@ -23,6 +24,10 @@ class LayerProcessingState { + enum BankType { + Start, End + }; + private static final String COMPATIBILITY_VARIABLES_SET_CAN_BE_SET_ONCE_ONLY = "CompatibilityVariablesSet can be set once only"; private static final String PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY = "PrimarySpeciesDetails can be set once only"; private static final String SITE_CURVE_NUMBERS_CAN_BE_SET_ONCE_ONLY = "SiteCurveNumbers can be set once only"; @@ -57,6 +62,12 @@ class LayerProcessingState { */ private Bank startBank; + /** + * State of the layer at the end of processing. The information comprising this is calculated + * during the execution of grow(). + */ + private Bank endBank; + // L1COM2 - equation groups. From the configuration, narrowed to the // polygon's BEC zone. @@ -128,6 +139,8 @@ public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, Lay polygon.getLayers().get(subjectLayerType), becZone, s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= ForwardProcessingEngine.MIN_BASAL_AREA); + this.endBank = new Bank(this.startBank, CopyMode.CopyStructure); + var volumeEquationGroupMatrix = this.fps.fcm.getVolumeEquationGroups(); var decayEquationGroupMatrix = this.fps.fcm.getDecayEquationGroups(); var breakageEquationGroupMatrix = this.fps.fcm.getBreakageEquationGroups(); @@ -157,11 +170,10 @@ public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, Lay * Set the layer processing state to the given Bank. This is normally done at the conclusion of * the growth of a layer for one growth period; the Bank resulting from that calculation is * assigned as the start bank for the next growth period. - * - * @param newStartBank */ - public void swapBank(Bank newStartBank) { - this.startBank = newStartBank; + public void swapBanks() { + this.startBank = endBank; + this.endBank = new Bank(this.startBank, CopyMode.CopyStructure); } public VdypPolygon getPolygon() { @@ -273,6 +285,10 @@ public Bank getStartBank() { return startBank; } + public Bank getEndBank() { + return endBank; + } + public int[] getVolumeEquationGroups() { return volumeEquationGroups; } @@ -514,12 +530,14 @@ public float getCVSmall(int speciesIndex, UtilizationClassVariable variable) { return cvPrimaryLayerSmall[speciesIndex].get(variable); } - public VdypLayer getLayerFromBank(Bank bank) { + public VdypLayer getLayerFromBank(BankType bankType) { + + Bank sourceBank = bankType == BankType.Start ? startBank : endBank; - VdypLayer updatedLayer = bank.getUpdatedLayer(); + VdypLayer updatedLayer = sourceBank.getUpdatedLayer(); for (int i = 1; i < getNSpecies() + 1; i++) { - VdypSpecies species = updatedLayer.getSpeciesBySp0(bank.speciesNames[i]); + VdypSpecies species = updatedLayer.getSpeciesBySp0(sourceBank.speciesNames[i]); species.setCompatibilityVariables( cvVolume[i], cvBasalArea[i], cvQuadraticMeanDiameter[i], cvPrimaryLayerSmall[i]); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index cf701c1fd..8f4ad9368 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -73,7 +73,7 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces LayerProcessingState lps = fpe.fps.getLayerProcessingState(); - fpe.calculateCoverages(); + ForwardProcessingEngine.calculateCoverages(lps); fpe.determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); assertThat(lps.getPrimarySpeciesIndex(), is(3)); @@ -89,7 +89,7 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces var speciesToCombine = Arrays.asList(Arrays.asList(lps.getStartBank().speciesNames[3], lps.getStartBank().speciesNames[4])); - fpe.calculateCoverages(); + ForwardProcessingEngine.calculateCoverages(lps); fpe.determinePolygonRankings(speciesToCombine); // The test-specific speciesToCombine will combine 3 & 4 into 3 (leaving 4 at 0.0), promoting 2 to diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java index 4104228fa..30c0f16be 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java @@ -17,7 +17,6 @@ import java.util.HashMap; import java.util.Map; -import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; From cf529a51eecfec65071b8db0c79453564cf1863b Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 28 Aug 2024 18:33:50 -0700 Subject: [PATCH 40/66] First end-to-end run with output --- .../ca/bc/gov/nrs/vdyp/common/ControlKey.java | 1 + .../nrs/vdyp/io/write/VdypOutputWriter.java | 14 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 11 +- .../vdyp/forward/ForwardControlParser.java | 5 +- .../vdyp/forward/ForwardProcessingEngine.java | 563 +++++++++--------- .../vdyp/forward/ForwardProcessingState.java | 24 - .../nrs/vdyp/forward/ForwardProcessor.java | 21 +- .../vdyp/forward/LayerProcessingState.java | 94 ++- .../GeneralForwardProcessingEngineTest.java | 8 +- 9 files changed, 370 insertions(+), 371 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java index 7985c11e7..48ac00125 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java @@ -24,6 +24,7 @@ public enum ControlKey { // VDYP Forward Outputs VDYP_OUTPUT_VDYP_POLYGON(15), VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES(16), VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL(18), + VDYP_OUTPUT_COMPATIBILITY_VARIABLES(19), VOLUME_EQN_GROUPS(20), DECAY_GROUPS(21), BREAKAGE_GROUPS(22), diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java index 76f6dee78..fa5d74e14 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java @@ -32,6 +32,8 @@ public class VdypOutputWriter implements Closeable { private OutputStream polygonFile; private OutputStream speciesFile; private OutputStream utilizationFile; + @SuppressWarnings("unused") + private OutputStream compatibilityVariablesFile; private Optional currentYear = Optional.empty(); @@ -70,14 +72,17 @@ public class VdypOutputWriter implements Closeable { * @param polygonFile * @param speciesFile * @param utilizationFile + * @param compatibilityVariablesFile * @param controlMap */ public VdypOutputWriter( - OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile + OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile, + OutputStream compatibilityVariablesFile ) { this.polygonFile = polygonFile; this.speciesFile = speciesFile; this.utilizationFile = utilizationFile; + this.compatibilityVariablesFile = compatibilityVariablesFile; } /** @@ -90,9 +95,10 @@ public VdypOutputWriter( */ public VdypOutputWriter(Map controlMap, FileResolver resolver) throws IOException { this( - getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_POLYGON.name()), - getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name()), - getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()) + 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()), + getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name()) ); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 8f91c9150..73f8dc3e7 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -289,13 +289,16 @@ private void transferSpeciesFromBank(int index, VdypSpecies species) { VdypSite site = species.getSite().get(); - VdypSite updatedSite = new VdypSite.Builder().adapt(site).siteIndex(siteIndices[index]) - .ageTotal(ageTotals[index]).height(dominantHeights[index]) - .yearsToBreastHeight(yearsToBreastHeight[index]).build(); + VdypSite updatedSite = new VdypSite.Builder().adapt(site) // + .siteIndex(siteIndices[index]) // + .ageTotal(ageTotals[index]) // + .height(dominantHeights[index]) // + .yearsToBreastHeight(yearsToBreastHeight[index]) // + .build(); species = new VdypSpecies.Builder().addSite(updatedSite).adapt(species).build(); - transferUtilizationsIntoBank(index, species); + transferUtilizationsFromBank(index, species); } private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java index 457104afa..e38df0d84 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParser.java @@ -98,7 +98,10 @@ protected List> inputFileParsers() { @Override protected List outputFileParsers() { - return Collections.emptyList(); + return List.of( + ControlKey.VDYP_OUTPUT_VDYP_POLYGON, ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES, + ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES + ); } @Override diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index f6fe20c8d..7f1e40d87 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -35,12 +35,12 @@ import ca.bc.gov.nrs.vdyp.common_calculators.custom_exceptions.SpeciesErrorException; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexAgeType; import ca.bc.gov.nrs.vdyp.common_calculators.enumerations.SiteIndexEquation; -import ca.bc.gov.nrs.vdyp.forward.LayerProcessingState.BankType; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperBoundsParser; +import ca.bc.gov.nrs.vdyp.io.write.VdypOutputWriter; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.Coefficients; @@ -87,14 +87,18 @@ public class ForwardProcessingEngine { /* pp */ final ForwardProcessingState fps; - public ForwardProcessingEngine(Map controlMap, Optional outputFileResolver) + /** The entity to which result information is written */ + private Optional outputWriter; + + public ForwardProcessingEngine(Map controlMap, Optional outputWriter) throws ProcessingException { - this.fps = new ForwardProcessingState(controlMap, outputFileResolver); + this.fps = new ForwardProcessingState(controlMap); + this.outputWriter = outputWriter; } public ForwardProcessingEngine(Map controlMap) throws ProcessingException { - this.fps = new ForwardProcessingState(controlMap, Optional.empty()); + this.fps = new ForwardProcessingState(controlMap); } public enum ExecutionStep { @@ -263,18 +267,13 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY grow(lps, currentYear, veteranLayer); - // Set startBank to endBank and clear out endBank, in preparation for the - // next iteration. - - lps.swapBanks(); - // If update-during-growth is set, update the context prior to output if (doRecalculateGroupsPriorToOutput) { calculateCoverages(lps); calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } - polygonLayers.put(LayerType.PRIMARY, lps.getLayerFromBank(BankType.Start)); + polygonLayers.put(LayerType.PRIMARY, lps.getLayer()); // Store polygon (both primary and veteran layers) to output writePolygon(vdypPolygon, startingYear, currentYear, untilYear); @@ -292,7 +291,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY } /** - * VGROW1 - "grow" the primary layer, located in lps.startBank, starting at the + * VGROW1 - "grow" the primary layer, located in lps.bank, starting at the * given year, and return the resulting bank. The veteran layer instance is supplied but at * this point is ignored. * @@ -307,8 +306,7 @@ private void grow(LayerProcessingState lps, int currentYear, Optional throws ProcessingException { VdypPolygon polygon = lps.getPolygon(); - Bank start = lps.getStartBank(); - Bank end = lps.getEndBank(); + Bank bank = lps.getBank(); logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); @@ -327,10 +325,10 @@ private void grow(LayerProcessingState lps, int currentYear, Optional final Optional veteranLayerBasalArea = veteranLayer.flatMap((l) -> Optional.of(l.getBaseAreaByUtilization().get(UtilizationClass.ALL))); - float dqStart = start.quadMeanDiameters[0][UC_ALL_INDEX]; - float baStart = start.basalAreas[0][UC_ALL_INDEX]; - float tphStart = start.treesPerHectare[0][UC_ALL_INDEX]; - float lhStart = start.loreyHeights[0][UC_ALL_INDEX]; + float dqStart = bank.quadMeanDiameters[0][UC_ALL_INDEX]; + float baStart = bank.basalAreas[0][UC_ALL_INDEX]; + float tphStart = bank.treesPerHectare[0][UC_ALL_INDEX]; + float lhStart = bank.loreyHeights[0][UC_ALL_INDEX]; float baDelta = growBasalArea( pspYabhStart, fps.fcm.getDebugSettings(), dhStart, baStart, veteranLayerBasalArea, dhDelta @@ -354,8 +352,8 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float baChangeRate = baDelta / baStart; - float pspLhStart = start.loreyHeights[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; - float pspTphStart = start.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspLhStart = bank.loreyHeights[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspTphStart = bank.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; float dhEnd = dhStart + dhDelta; float dqEnd = dqStart + dqDelta; @@ -365,9 +363,9 @@ private void grow(LayerProcessingState lps, int currentYear, Optional // (4) Begin storing computed results - dq, ba and tph for the layer - end.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; - end.basalAreas[0][UC_ALL_INDEX] = baEnd; - end.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; + bank.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; + bank.basalAreas[0][UC_ALL_INDEX] = baEnd; + bank.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; // (5) Now do DQ growth by species, using one of several options: "full species", "dynamic", // "partial dynamics" or "no dynamics." @@ -380,10 +378,10 @@ private void grow(LayerProcessingState lps, int currentYear, Optional // (5a1) Begin by updating HL for all species // First save the ungrown HLs - float[] startingLoreyHeights = new float[start.getNSpecies() + 1]; - startingLoreyHeights[0] = start.loreyHeights[0][UC_ALL_INDEX]; - for (int i : start.getIndices()) { - startingLoreyHeights[i] = start.loreyHeights[i][UC_ALL_INDEX]; + float[] startingLoreyHeights = new float[bank.getNSpecies() + 1]; + startingLoreyHeights[0] = bank.loreyHeights[0][UC_ALL_INDEX]; + for (int i : bank.getIndices()) { + startingLoreyHeights[i] = bank.loreyHeights[i][UC_ALL_INDEX]; } float pspTphEndEstimate = pspTphStart * (tphEnd / tphStart); @@ -393,82 +391,84 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float sum1 = 0.0f; float sum2 = 0.0f; - for (int i : start.getIndices()) { - sum1 += start.basalAreas[i][UC_ALL_INDEX] * start.loreyHeights[i][UC_ALL_INDEX]; - sum2 += start.basalAreas[i][UC_ALL_INDEX]; + for (int i : bank.getIndices()) { + sum1 += bank.basalAreas[i][UC_ALL_INDEX] * bank.loreyHeights[i][UC_ALL_INDEX]; + sum2 += bank.basalAreas[i][UC_ALL_INDEX]; } - start.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; + bank.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; // Now do the actual updates of DQ by species wasSolutionFound = growUsingPartialSpeciesDynamics( - end, dqDelta, baDelta, baStart, dqStart, tphStart, startingLoreyHeights + dqDelta, baDelta, baStart, dqStart, tphStart, startingLoreyHeights ); // Restore the Lorey Heights back to the values at the beginning of the period. // They will be updated below using the new estimate of TPH-primary species. - for (int i = 1; i < start.getNSpecies(); i++) { - start.loreyHeights[i][UC_ALL_INDEX] = startingLoreyHeights[i]; + for (int i = 1; i < bank.getNSpecies(); i++) { + bank.loreyHeights[i][UC_ALL_INDEX] = startingLoreyHeights[i]; } } + // (6) Calculate the basal area, trees-per-hectare and quad-mean-diameter for all + // species in the polygon (UC All) + if (!wasSolutionFound) { - - if (debugSetting1Value == 1 || start.getNSpecies() == 1) { + if (debugSetting1Value == 1 || bank.getNSpecies() == 1) { // This is the NO SPECIES DYNAMICS section - growUsingNoSpeciesDynamics(end, baChangeRate, tphMultiplier); + growUsingNoSpeciesDynamics(baChangeRate, tphMultiplier); } else { // This is the FULL SPECIES DYNAMICS section - growUsingFullSpeciesDynamics(end, dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); + growUsingFullSpeciesDynamics(dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); } } - // Calculate trees-per-hectare over all species, all ucs + // (7) Calculate layer trees-per-hectare, uc All float tphEndSum = 0.0f; - for (int i = 1; i < end.getNSpecies(); i++) { - if (end.basalAreas[i][UC_ALL_INDEX] > 0.0f) { - tphEndSum += end.treesPerHectare[i][UC_ALL_INDEX]; + for (int i : bank.getIndices()) { + if (bank.basalAreas[i][UC_ALL_INDEX] > 0.0f) { + tphEndSum += bank.treesPerHectare[i][UC_ALL_INDEX]; } } - end.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; + bank.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; - // Calculate quad-mean-diameter over all species, uc UC_ALL_INDEX + // (8) Calculate layer quad-mean-diameter, uc All - end.quadMeanDiameters[0][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter( - end.basalAreas[0][UC_ALL_INDEX], end.treesPerHectare[0][UC_ALL_INDEX] + bank.quadMeanDiameters[0][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter( + bank.basalAreas[0][UC_ALL_INDEX], bank.treesPerHectare[0][UC_ALL_INDEX] ); - // Calculate Lorey heights over all species, uc UC_ALL_INDEX + // (9) Calculate layer Lorey heights over all species, uc UC_ALL_INDEX - float pspTphEnd = end.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; + float pspTphEnd = bank.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); - // We now have site level predications for basal area, quad-mean-diameter, trees-per-hectare - // and Lorey height. Proceed to per-species estimates. + // We now have site (layer) level predications for basal area, quad-mean-diameter, + // trees-per-hectare and Lorey height. Proceed to per-species estimates. - // Calculate basal area percentages per species, uc UC_ALL_INDEX - for (int i : start.getIndices()) { - end.percentagesOfForestedLand[i] = 100.0f * end.basalAreas[i][UC_ALL_INDEX] - / end.basalAreas[0][UC_ALL_INDEX]; + // (10) Calculate basal area percentages per species, uc UC_ALL_INDEX + for (int i : bank.getIndices()) { + bank.percentagesOfForestedLand[i] = 100.0f * bank.basalAreas[i][UC_ALL_INDEX] + / bank.basalAreas[0][UC_ALL_INDEX]; } - // Update the running values. TODO: why isn't siteIndex being updated? + // (11) Update the running values. TODO: why isn't siteIndex being updated? lps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); - for (int i = 1; i < start.getNSpecies(); i++) { + for (int i = 1; i < bank.getNSpecies(); i++) { if (i == lps.getPrimarySpeciesIndex()) { - end.ageTotals[i] = lps.getPrimarySpeciesTotalAge(); - end.dominantHeights[i] = dhEnd; - end.siteIndices[i] = lps.getPrimarySpeciesSiteIndex(); - end.yearsAtBreastHeight[i] = lps.getPrimarySpeciesAgeAtBreastHeight(); + bank.ageTotals[i] = lps.getPrimarySpeciesTotalAge(); + bank.dominantHeights[i] = dhEnd; + bank.siteIndices[i] = lps.getPrimarySpeciesSiteIndex(); + bank.yearsAtBreastHeight[i] = lps.getPrimarySpeciesAgeAtBreastHeight(); } else { - float spSiStart = start.siteIndices[i]; - float spDhStart = start.dominantHeights[i]; - float spYtbhStart = start.yearsToBreastHeight[i]; - float spYabhStart = start.yearsAtBreastHeight[i]; + float spSiStart = bank.siteIndices[i]; + float spDhStart = bank.dominantHeights[i]; + float spYtbhStart = bank.yearsToBreastHeight[i]; + float spYabhStart = bank.yearsAtBreastHeight[i]; if (!Float.isNaN(spSiStart) && !Float.isNaN(spDhStart) && !Float.isNaN(spYtbhStart) && !Float.isNaN(spYabhStart)) { @@ -476,25 +476,28 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float dhGrowth = growDominantHeight( spDhStart, pspSiteCurveNumber, spSiStart, spYtbhStart ); - end.dominantHeights[i] += dhGrowth; + bank.dominantHeights[i] += dhGrowth; } else { - end.dominantHeights[i] = Float.NaN; + bank.dominantHeights[i] = Float.NaN; } } } + // (12) update the compatibility variables to reflect the changes during the growth period lps.updateCompatibilityVariablesAfterGrowth(); - VdypLayer primaryLayer = lps.getLayerFromBank(BankType.End); + // (13) calculate All and the large component volumes to reflect the changes in growth + + VdypLayer primaryLayer = lps.getLayer(); VolumeComputeMode volumeComputationMode = VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC; int controlVariable3Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); CompatibilityVariableMode compatibilityVariableMode = CompatibilityVariableMode.getByInteger(controlVariable3Value); lps.getFps().computers.computeUtilizationComponentsPrimary(lps.getBecZone(), primaryLayer, volumeComputationMode, compatibilityVariableMode); - end.refreshBank(primaryLayer); + bank.refreshBank(primaryLayer); - // ( + // (14) calculate the small component volumes to reflect the changes in growth calculateSmallComponentYields(lps); } @@ -503,25 +506,23 @@ private void grow(LayerProcessingState lps, int currentYear, Optional * Calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare * and quad-mean-diameter at the end of the growth period for all species in the polygon, given * the per-layer basal area and trees-per-hectare rate of change. - * - * @param end the target of the computation * @param baChangeRate the rate of change of the basal area during the growth period, * expressed as a percentage / 100. So a rate of 10% (i.e., 1.1 times the starting * value) would be expressed at 0.1f. * @param tphChangeRate the rate of change of trees-per-hectare during the growth period, * expressed the same way. */ - private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphChangeRate) { + private void growUsingNoSpeciesDynamics(float baChangeRate, float tphChangeRate) { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); for (int i : lps.getIndices()) { - float spBaStart = start.basalAreas[i][UC_ALL_INDEX]; + float spBaStart = bank.basalAreas[i][UC_ALL_INDEX]; if (spBaStart > 0.0f) { float spBaEnd = spBaStart * (1.0f + baChangeRate); - float spTphStart = start.treesPerHectare[i][UC_ALL_INDEX]; + float spTphStart = bank.treesPerHectare[i][UC_ALL_INDEX]; float spTphEnd = spTphStart * tphChangeRate; float spDqEnd = BaseAreaTreeDensityDiameter.quadMeanDiameter(spBaEnd, spTphEnd); if (spDqEnd < 7.51f) { @@ -529,9 +530,9 @@ private void growUsingNoSpeciesDynamics(Bank end, float baChangeRate, float tphC spTphEnd = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd, spDqEnd); } - end.basalAreas[i][UC_ALL_INDEX] = spBaEnd; - end.treesPerHectare[i][UC_ALL_INDEX] = spTphEnd; - end.quadMeanDiameters[i][UC_ALL_INDEX] = spDqEnd; + bank.basalAreas[i][UC_ALL_INDEX] = spBaEnd; + bank.treesPerHectare[i][UC_ALL_INDEX] = spTphEnd; + bank.quadMeanDiameters[i][UC_ALL_INDEX] = spDqEnd; } } } @@ -564,9 +565,9 @@ private record AdjustmentParameters( } /** - * GRSPpart - update quad-mean-diameter (dq) by species. + * GRSPpart - calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare + * and quad-mean-diameter at the end of the growth period for all species in the polygon. * - * @param end the target of the computation * @param dqDelta change in overall quad-mean-diameter during the growth period * @param baDelta change in overall basal area during the growth period * @param baStart overall basal area at start of growth period @@ -579,12 +580,12 @@ private record AdjustmentParameters( * @throws ProcessingException */ private boolean growUsingPartialSpeciesDynamics( - Bank end, float dqDelta, float baDelta, float baStart, - float dqStart, float tphStart, float[] currentLoreyHeights + float dqDelta, float baDelta, float baStart, float dqStart, + float tphStart, float[] currentLoreyHeights ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); VdypPolygon polygon = lps.getPolygon(); Region polygonRegion = polygon.getBiogeoclimaticZone().getRegion(); @@ -602,7 +603,7 @@ private boolean growUsingPartialSpeciesDynamics( float[] baNew = new float[lps.getNSpecies() + 1]; baNew[0] = baStart + baDelta; for (int i : lps.getIndices()) { - baNew[i] = start.basalAreas[i][0] * baNew[0] / start.basalAreas[0][0]; + baNew[i] = bank.basalAreas[i][0] * baNew[0] / bank.basalAreas[0][0]; } float[] dqNew = new float[lps.getNSpecies() + 1]; @@ -616,15 +617,15 @@ private boolean growUsingPartialSpeciesDynamics( basalAreaPercentagesPerSpecies.put(spAlias, 0.0f); } for (int i : lps.getIndices()) { - basalAreaPercentagesPerSpecies.put(start.speciesNames[i], start.percentagesOfForestedLand[i]); + basalAreaPercentagesPerSpecies.put(bank.speciesNames[i], bank.percentagesOfForestedLand[i]); } for (int i : lps.getIndices()) { dqs1[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( - start.speciesNames[i], - start.basalAreas[i][0], - start.quadMeanDiameters[i][0], + bank.speciesNames[i], + bank.basalAreas[i][0], + bank.quadMeanDiameters[i][0], basalAreaPercentagesPerSpecies, lps.getBecZone().getRegion(), dqStart, @@ -633,7 +634,7 @@ private boolean growUsingPartialSpeciesDynamics( currentLoreyHeights[0]); dqs2[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( - start.speciesNames[i], + bank.speciesNames[i], baNew[0], dqNew[0], basalAreaPercentagesPerSpecies, @@ -641,7 +642,7 @@ private boolean growUsingPartialSpeciesDynamics( dqStart, baStart, tphStart, - start.loreyHeights[i][0]); + bank.loreyHeights[i][0]); } float[] dqLowerBoundBySpecies = new float[lps.getNSpecies() + 1]; @@ -666,14 +667,14 @@ private boolean growUsingPartialSpeciesDynamics( dqLowerBoundBySpecies[i] = 7.51f; dqUpperBoundBySpecies[i] = 100.0f; - if (start.treesPerHectare[i][UC_ALL_INDEX] <= 0) { + if (bank.treesPerHectare[i][UC_ALL_INDEX] <= 0) { continue; } - var sizeLimits = fps.estimators.getLimitsForHeightAndDiameter(start.speciesNames[i], polygonRegion); + var sizeLimits = fps.estimators.getLimitsForHeightAndDiameter(bank.speciesNames[i], polygonRegion); var spDqMax = sizeLimits.quadMeanDiameterMaximum(); - float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; + float spDqStart = bank.quadMeanDiameters[i][UC_ALL_INDEX]; // Non-negotiable bounds dqUpperBoundBySpecies[i] = FloatMath.max(dqNew[i], dqStart, spDqMax, spDqStart); @@ -697,7 +698,7 @@ private boolean growUsingPartialSpeciesDynamics( // More restrictive bounds, stages 1 - 5 only. - float spHlStart = start.loreyHeights[i][UC_ALL_INDEX]; + float spHlStart = bank.loreyHeights[i][UC_ALL_INDEX]; float trialMax = Math.max(spDqStart, spDqMax); if (spDqStart < 1.001 * sizeLimits.maxQuadMeanDiameterLoreyHeightRatio() * spHlStart) { @@ -719,11 +720,11 @@ private boolean growUsingPartialSpeciesDynamics( float tphSum = 0.0f; for (int i : lps.getIndices()) { - if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { continue; } - float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; + float spDqStart = bank.quadMeanDiameters[i][UC_ALL_INDEX]; tryDq[i] = 7.5f + (dqs2[i] - 7.5f) * ((spDqStart - 7.5f)/(dqs1[i] - 7.5f)); if (tryDq[i] < dqLowerBoundBySpecies[i]) { tryDq[i] = dqLowerBoundBySpecies[i]; @@ -746,7 +747,7 @@ private boolean growUsingPartialSpeciesDynamics( float amountWrong = 50000.0f; for (int i : lps.getIndices()) { - if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { continue; } @@ -770,7 +771,7 @@ private boolean growUsingPartialSpeciesDynamics( float cjOther; for (int i : lps.getIndices()) { - if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { continue; } @@ -856,21 +857,21 @@ private boolean growUsingPartialSpeciesDynamics( } for (int i : lps.getIndices()) { - if (start.basalAreas[i][UC_ALL_INDEX] >= 0.0f) { + if (bank.basalAreas[i][UC_ALL_INDEX] >= 0.0f) { tphNew[i] = tphLowerBoundBySpecies[i] + k * (tphUpperBoundBySpecies[i] - tphLowerBoundBySpecies[i]); dqNew[i] = BaseAreaTreeDensityDiameter.quadMeanDiameter(baNew[i], tphNew[i]); } else { baNew[i] = 0.0f; tphNew[i] = 0.0f; - dqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; + dqNew[i] = bank.quadMeanDiameters[i][UC_ALL_INDEX]; } } } else { // An exact solution was found. for (int i : lps.getIndices()) { - if (start.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { + if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { tphNew[i] = 0.0f; - dqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; + dqNew[i] = bank.quadMeanDiameters[i][UC_ALL_INDEX]; } else { tphNew[i] = tryTph[i]; dqNew[i] = tryDq[i]; @@ -879,9 +880,9 @@ private boolean growUsingPartialSpeciesDynamics( } for (int i : lps.getIndices()) { - end.basalAreas[i][UC_ALL_INDEX] = baNew[i]; - end.quadMeanDiameters[i][UC_ALL_INDEX] = dqNew[i]; - end.treesPerHectare[i][UC_ALL_INDEX] = tphNew[i]; + bank.basalAreas[i][UC_ALL_INDEX] = baNew[i]; + bank.quadMeanDiameters[i][UC_ALL_INDEX] = dqNew[i]; + bank.treesPerHectare[i][UC_ALL_INDEX] = tphNew[i]; } return true /* was successful */; @@ -890,7 +891,6 @@ private boolean growUsingPartialSpeciesDynamics( /** * Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth * during the growth period. The result is stored in end, Utilization Class ALL. - * @param end the target of the computation * @param dqDelta per-layer change in quad-mean-diameter during growth period * @param baDelta per-layer change in basal area during growth period * @param baStart per-layer basal area at start of growth period @@ -900,12 +900,12 @@ private boolean growUsingPartialSpeciesDynamics( * @throws ProcessingException */ private void growUsingFullSpeciesDynamics( - Bank end, float dqDelta, float baDelta, float baStart, float dqStart, - float tphStart, float lhStart + float dqDelta, float baDelta, float baStart, float dqStart, float tphStart, + float lhStart ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); float spBaEnd[] = new float[lps.getNSpecies() + 1]; float spTphNew[] = new float[lps.getNSpecies() + 1]; @@ -913,9 +913,9 @@ private void growUsingFullSpeciesDynamics( boolean doSkip[] = new boolean[lps.getNSpecies() + 1]; for (int i : lps.getIndices()) { - spBaEnd[i] = start.basalAreas[i][UC_ALL_INDEX]; - spTphNew[i] = start.treesPerHectare[i][UC_ALL_INDEX]; - spDqNew[i] = start.quadMeanDiameters[i][UC_ALL_INDEX]; + spBaEnd[i] = bank.basalAreas[i][UC_ALL_INDEX]; + spTphNew[i] = bank.treesPerHectare[i][UC_ALL_INDEX]; + spDqNew[i] = bank.quadMeanDiameters[i][UC_ALL_INDEX]; doSkip[i] = false; } @@ -924,9 +924,9 @@ private void growUsingFullSpeciesDynamics( float spBaDelta[] = new float[lps.getNSpecies() + 1]; for (int i : lps.getIndices()) { - float pspLhStart = start.loreyHeights[i][UC_ALL_INDEX]; + float pspLhStart = bank.loreyHeights[i][UC_ALL_INDEX]; if (i == lps.getPrimarySpeciesIndex()) { - float pspBaStart = start.basalAreas[i][UC_ALL_INDEX]; + float pspBaStart = bank.basalAreas[i][UC_ALL_INDEX]; float pspYabhStart = lps.getPrimarySpeciesAgeAtBreastHeight(); // Note: the FORTRAN passes Lorey height into parameter "HD" ("Dominant Height") - are these @@ -935,11 +935,11 @@ private void growUsingFullSpeciesDynamics( baStart, baDelta, pspBaStart, lhStart, pspYabhStart, pspLhStart ); } else { - float spBaStart = start.basalAreas[i][UC_ALL_INDEX]; - float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; - float spLhStart = start.loreyHeights[i][UC_ALL_INDEX]; + float spBaStart = bank.basalAreas[i][UC_ALL_INDEX]; + float spDqStart = bank.quadMeanDiameters[i][UC_ALL_INDEX]; + float spLhStart = bank.loreyHeights[i][UC_ALL_INDEX]; spBaDelta[i] = growBasalAreaForNonPrimarySpecies( - start.speciesNames[i], baStart, baDelta, pspLhStart, spBaStart, spDqStart, spLhStart + bank.speciesNames[i], baStart, baDelta, pspLhStart, spBaStart, spDqStart, spLhStart ); } @@ -968,7 +968,7 @@ private void growUsingFullSpeciesDynamics( for (int i : lps.getIndices()) { if (!doSkip[i]) { - var spBaStart = lps.getStartBank().basalAreas[i][UC_ALL_INDEX]; + var spBaStart = lps.getBank().basalAreas[i][UC_ALL_INDEX]; spBaEnd[i] = spBaStart + spBaDelta[i] + f * spBaStart; if (spBaEnd[i] < 0.0f) { spBaEnd[i] = 0.0f; @@ -1012,8 +1012,8 @@ private void growUsingFullSpeciesDynamics( var totalBasalAreaSkipped = 0.0f; for (int i : lps.getIndices()) { - float spDqStart = start.quadMeanDiameters[i][UC_ALL_INDEX]; - float spLhStart = start.loreyHeights[i][UC_ALL_INDEX]; + float spDqStart = bank.quadMeanDiameters[i][UC_ALL_INDEX]; + float spLhStart = bank.loreyHeights[i][UC_ALL_INDEX]; float spDqDelta; if (i == lps.getPrimarySpeciesIndex()) { @@ -1030,10 +1030,10 @@ private void growUsingFullSpeciesDynamics( spDqDelta += f; ComponentSizeLimits csl = getComponentSizeLimits( - start.speciesNames[i], lps.getBecZone().getRegion() + bank.speciesNames[i], lps.getBecZone().getRegion() ); - var spLhAllStart = start.loreyHeights[i][UC_ALL_INDEX]; + var spLhAllStart = bank.loreyHeights[i][UC_ALL_INDEX]; float spDqMaximum = Math.min( csl.quadMeanDiameterMaximum(), csl.maxQuadMeanDiameterLoreyHeightRatio() * spLhAllStart @@ -1042,7 +1042,7 @@ private void growUsingFullSpeciesDynamics( if (spDqStart + spDqDelta > spDqMaximum) { spDqDelta = Math.min(0.0f, spDqMaximum - spDqStart); nSkipped += 1; - totalBasalAreaSkipped += start.basalAreas[i][UC_ALL_INDEX]; + totalBasalAreaSkipped += bank.basalAreas[i][UC_ALL_INDEX]; } float spDqMinimum = Math.max(7.6f, csl.minQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); @@ -1050,14 +1050,14 @@ private void growUsingFullSpeciesDynamics( if (spDqStart + spDqDelta < spDqMinimum) { spDqDelta = spDqMinimum - spDqStart; nSkipped += 1; - totalBasalAreaSkipped += start.basalAreas[i][UC_ALL_INDEX]; + totalBasalAreaSkipped += bank.basalAreas[i][UC_ALL_INDEX]; } spDqNew[i] = spDqStart + spDqDelta; } float tph = 0.0f; - for (int i : start.getIndices()) { + for (int i : bank.getIndices()) { if (spBaEnd[i] > 0.0f) { spTphNew[i] = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd[i], spDqNew[i]); } else { @@ -1097,11 +1097,11 @@ private void growUsingFullSpeciesDynamics( } } - for (int i : start.getIndices()) { - end.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; - end.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; + for (int i : bank.getIndices()) { + bank.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; + bank.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; if (spBaEnd[i] > 0.0f) { - end.quadMeanDiameters[i][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter + bank.quadMeanDiameters[i][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter .quadMeanDiameter(spBaEnd[i], spTphNew[i]); } } @@ -1161,7 +1161,7 @@ private float growQuadMeanDiameterForNonPrimarySpecies( LayerProcessingState lps = fps.getLayerProcessingState(); - String speciesName = lps.getStartBank().speciesNames[speciesIndex]; + String speciesName = lps.getBank().speciesNames[speciesIndex]; int pspStratumNumber = lps.getPrimarySpeciesStratumNumber(); var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() @@ -1337,8 +1337,7 @@ private float growBasalAreaForPrimarySpecies( */ private void calculateSmallComponentYields(LayerProcessingState lps) throws ProcessingException { - Bank start = lps.getStartBank(); - Bank end = lps.getEndBank(); + Bank bank = lps.getBank(); float lhSum = 0.0f; float baSum = 0.0f; @@ -1347,12 +1346,12 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc for (int speciesIndex : lps.getIndices()) { - float spLhAll = end.loreyHeights[speciesIndex][UC_ALL_INDEX]; - float spBaAll = end.basalAreas[speciesIndex][UC_ALL_INDEX]; - float spDqAll = end.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; + float spLhAll = bank.loreyHeights[speciesIndex][UC_ALL_INDEX]; + float spBaAll = bank.basalAreas[speciesIndex][UC_ALL_INDEX]; + float spDqAll = bank.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; Region region = lps.getBecZone().getRegion(); - String speciesName = start.speciesNames[speciesIndex]; + String speciesName = bank.speciesNames[speciesIndex]; // EMP080 float smallProbability = smallComponentProbability(speciesName, spLhAll, region); @@ -1365,7 +1364,7 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc } // EMP081 - float conditionalExpectedBasalArea = conditionalExpectedBaseArea(speciesName, spBaAll, spLhAll, region); + float conditionalExpectedBasalArea = calculateConditionalExpectedBasalArea(speciesName, spBaAll, spLhAll, region); if (fractionAvailable > 0.0f) { conditionalExpectedBasalArea /= fractionAvailable; @@ -1408,14 +1407,14 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc float spTphSmall = BaseAreaTreeDensityDiameter.treesPerHectare(spBaSmall, spDqSmall); float spWsVolumeSmall = spTphSmall * meanVolumeSmall; - end.loreyHeights[speciesIndex][UC_SMALL_INDEX] = spLhSmall; - end.basalAreas[speciesIndex][UC_SMALL_INDEX] = spBaSmall; - end.treesPerHectare[speciesIndex][UC_SMALL_INDEX] = spTphSmall; - end.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX] = spDqSmall; - end.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX] = spWsVolumeSmall; - end.closeUtilizationVolumes[speciesIndex][UC_SMALL_INDEX] = 0.0f; - end.cuVolumesMinusDecay[speciesIndex][UC_SMALL_INDEX] = 0.0f; - end.cuVolumesMinusDecayAndWastage[speciesIndex][UC_SMALL_INDEX] = 0.0f; + bank.loreyHeights[speciesIndex][UC_SMALL_INDEX] = spLhSmall; + bank.basalAreas[speciesIndex][UC_SMALL_INDEX] = spBaSmall; + bank.treesPerHectare[speciesIndex][UC_SMALL_INDEX] = spTphSmall; + bank.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX] = spDqSmall; + bank.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX] = spWsVolumeSmall; + bank.closeUtilizationVolumes[speciesIndex][UC_SMALL_INDEX] = 0.0f; + bank.cuVolumesMinusDecay[speciesIndex][UC_SMALL_INDEX] = 0.0f; + bank.cuVolumesMinusDecayAndWastage[speciesIndex][UC_SMALL_INDEX] = 0.0f; lhSum += spBaSmall * spDqSmall; baSum += spBaSmall; @@ -1424,22 +1423,22 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc } if (baSum > 0.0) { - end.loreyHeights[0][UC_SMALL_INDEX] = lhSum / baSum; + bank.loreyHeights[0][UC_SMALL_INDEX] = lhSum / baSum; } else { - end.loreyHeights[0][UC_SMALL_INDEX] = 0.0f; - } - end.basalAreas[0][UC_SMALL_INDEX] = baSum; - end.treesPerHectare[0][UC_SMALL_INDEX] = tphSum; - end.quadMeanDiameters[0][UC_SMALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter(baSum, tphSum); - end.wholeStemVolumes[0][UC_SMALL_INDEX] = wsVolumeSum; - end.closeUtilizationVolumes[0][UC_SMALL_INDEX] = 0.0f; - end.cuVolumesMinusDecay[0][UC_SMALL_INDEX] = 0.0f; - end.cuVolumesMinusDecayAndWastage[0][UC_SMALL_INDEX] = 0.0f; + bank.loreyHeights[0][UC_SMALL_INDEX] = 0.0f; + } + bank.basalAreas[0][UC_SMALL_INDEX] = baSum; + bank.treesPerHectare[0][UC_SMALL_INDEX] = tphSum; + bank.quadMeanDiameters[0][UC_SMALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter(baSum, tphSum); + bank.wholeStemVolumes[0][UC_SMALL_INDEX] = wsVolumeSum; + bank.closeUtilizationVolumes[0][UC_SMALL_INDEX] = 0.0f; + bank.cuVolumesMinusDecay[0][UC_SMALL_INDEX] = 0.0f; + bank.cuVolumesMinusDecayAndWastage[0][UC_SMALL_INDEX] = 0.0f; } /** * GRSPHL - estimate the Lorey Heights of all species at end of growth period. The results of - * the calculations are persisted in {@code lps.endBank}. + * the calculations are persisted in {@code lps.bank}. * * @param lps processing state context * @param dhStart (primary species) dominant height at start @@ -1451,9 +1450,7 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc private void growLoreyHeights( LayerProcessingState lps, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart ) { - - Bank start = lps.getStartBank(); - Bank end = lps.getEndBank(); + Bank bank = lps.getBank(); float pspLhStartEstimate = estimatePrimarySpeciesLoreyHeight(dhStart, pspTphStart); float pspLhEndEstimate = estimatePrimarySpeciesLoreyHeight(dhEnd, pspTphEnd); @@ -1469,15 +1466,15 @@ private void growLoreyHeights( int primarySpeciesIndex = fps.getLayerProcessingState().getPrimarySpeciesIndex(); if (debugSetting8Value != 2 || dhStart != dhEnd) { - end.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX] = pspLhEnd; + bank.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX] = pspLhEnd; } else if (debugSetting8Value == 2) { - pspLhEnd = start.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; + pspLhEnd = bank.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; } float nonPrimaryLhAdjustment = fps.fcm.getCompVarAdjustments().getLoreyHeightOther(); for (int i : lps.getIndices()) { - if (start.basalAreas[i][UC_ALL_INDEX] > 0.0f && i != primarySpeciesIndex) { + if (i != primarySpeciesIndex && bank.basalAreas[i][UC_ALL_INDEX] > 0.0f) { if (! (dhEnd == dhStart && debugSetting8Value >= 1)) { float spLhEstimate1 = estimateNonPrimarySpeciesLoreyHeight( i, dhStart, pspLhStart @@ -1486,9 +1483,9 @@ private void growLoreyHeights( i, dhEnd, pspLhEnd ); - float otherF = (start.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (spLhEstimate1 - 1.3f); + float otherF = (bank.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (spLhEstimate1 - 1.3f); otherF = 1.0f - (otherF - 1.0f) * nonPrimaryLhAdjustment; - end.loreyHeights[i][UC_ALL_INDEX] = 1.3f + (spLhEstimate2 - 1.3f) * otherF; + bank.loreyHeights[i][UC_ALL_INDEX] = 1.3f + (spLhEstimate2 - 1.3f) * otherF; } } } @@ -1519,9 +1516,8 @@ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { } /** - * EMP053 - estimate the Lorey height of a non-primary species of the polygon. - * - * Does not modify either startBank or endBank. + * EMP053 - function that returns an estimate of the Lorey height of a non-primary + * species of the polygon. * * @param speciesIndex (non-primary) species index * @param dh (primary species) dominant height @@ -1533,13 +1529,13 @@ private float estimateNonPrimarySpeciesLoreyHeight( int speciesIndex, float dh, float pspLoreyHeight ) { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); float spLh; int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); - String primarySpeciesAlias = start.speciesNames[primarySpeciesIndex]; - String speciesAlias = start.speciesNames[speciesIndex]; + String primarySpeciesAlias = bank.speciesNames[primarySpeciesIndex]; + String speciesAlias = bank.speciesNames[speciesIndex]; Region region = lps.getBecZone().getRegion(); var coefficients = fps.fcm.getLoreyHeightNonPrimaryCoefficients(); @@ -1596,7 +1592,7 @@ float growQuadMeanDiameter( for (int i = 0; i < 6; i++) { float sum = 0.0f; for (int speciesIndex : lps.getIndices()) { - String speciesAlias = lps.getStartBank().speciesNames[speciesIndex]; + String speciesAlias = lps.getBank().speciesNames[speciesIndex]; sum += dqYieldCoefficients.get(decayBecZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; } @@ -1761,13 +1757,13 @@ private float calculateQuadMeanDiameterGrowthEmpirical( private float[] getSpeciesProportionsByBasalAreaAtStartOfYear() { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); float[] speciesProportionsByBasalArea = new float[lps.getNSpecies() + 1]; for (int i = 1; i <= lps.getNSpecies(); i++) { - speciesProportionsByBasalArea[i] = start.basalAreas[i][UC_ALL_INDEX] - / start.basalAreas[0][UC_ALL_INDEX]; + speciesProportionsByBasalArea[i] = bank.basalAreas[i][UC_ALL_INDEX] + / bank.basalAreas[0][UC_ALL_INDEX]; } return speciesProportionsByBasalArea; @@ -1791,7 +1787,7 @@ float growBasalArea( ) throws StandProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); float[] speciesProportionsByBasalArea = getSpeciesProportionsByBasalAreaAtStartOfYear(); @@ -1801,7 +1797,7 @@ float growBasalArea( for (int i = 0; i <= 6; i++) { float sum = 0.0f; for (int speciesIndex : lps.getIndices()) { - String speciesAlias = start.speciesNames[speciesIndex]; + String speciesAlias = bank.speciesNames[speciesIndex]; sum += baYieldCoefficients.get(becZoneAlias, speciesAlias).getCoe(i) * speciesProportionsByBasalArea[speciesIndex]; } @@ -1924,7 +1920,7 @@ private float calculateBasalAreaGrowthEmpirical( float b7 = firstSpeciesBaGrowthCoe.get(7); for (int i = 1; i <= fps.getLayerProcessingState().getNSpecies(); i++) { - String speciesAlias = fps.getLayerProcessingState().getStartBank().speciesNames[i]; + String speciesAlias = fps.getLayerProcessingState().getBank().speciesNames[i]; var baGrowthCoe = basalAreaGrowthEmpiricalCoefficients.get(becZoneAlias, speciesAlias); b4 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(4); b5 += speciesBasalAreaProportions[i] * baGrowthCoe.getCoe(5); @@ -1978,7 +1974,7 @@ private float growBasalAreaUpperBound() { Region region = lps.getBecZone().getRegion(); int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); return upperBoundsCoefficients - .get(region, lps.getStartBank().speciesNames[primarySpeciesIndex], 1); + .get(region, lps.getBank().speciesNames[primarySpeciesIndex], 1); } else { var primarySpeciesGroupNumber = lps.getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); @@ -2000,7 +1996,7 @@ private float growQuadraticMeanDiameterUpperBound() { Region region = lps.getBecZone().getRegion(); int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); return upperBoundsCoefficients - .get(region, lps.getStartBank().speciesNames[primarySpeciesIndex], 2); + .get(region, lps.getBank().speciesNames[primarySpeciesIndex], 2); } else { var primarySpeciesGroupNumber = fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); @@ -2024,7 +2020,7 @@ float growDominantHeight( ) throws ProcessingException { SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); - Region region = fps.getLayerProcessingState().getStartBank().getBecZone().getRegion(); + Region region = fps.getLayerProcessingState().getBank().getBecZone().getRegion(); if (siteCurveNumber == VdypEntity.MISSING_INTEGER_VALUE) { throw new ProcessingException("No SiteCurveNumber supplied"); @@ -2244,9 +2240,9 @@ private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, i throw new ProcessingException(MessageFormat.format("Invalid value for control variable 4: {0}", controlVariable4Value)); } - if (fps.getOutputWriter().isPresent()) { + if (outputWriter.isPresent()) { try { - fps.getOutputWriter().get().writePolygonWithSpeciesAndUtilization(polygon); + outputWriter.get().writePolygonWithSpeciesAndUtilization(polygon); } catch (IOException e) { throw new ProcessingException(e); } @@ -2270,7 +2266,7 @@ void setCompatibilityVariables() throws ProcessingException { var growthDetails = fps.fcm.getForwardControlVariables(); var lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); // Note: L1COM2 (INL1VGRP, INL1DGRP, INL1BGRP) is initialized when // PolygonProcessingState (volumeEquationGroups, decayEquationGroups @@ -2288,9 +2284,9 @@ void setCompatibilityVariables() throws ProcessingException { for (int s : lps.getIndices()) { - String genusName = start.speciesNames[s]; + String genusName = bank.speciesNames[s]; - float spLoreyHeight_All = start.loreyHeights[s][UtilizationClass.ALL.ordinal()]; + float spLoreyHeight_All = bank.loreyHeights[s][UtilizationClass.ALL.ordinal()]; UtilizationVector basalAreas = Utils.utilizationVector(); UtilizationVector wholeStemVolumes = Utils.utilizationVector(); @@ -2312,14 +2308,14 @@ void setCompatibilityVariables() throws ProcessingException { for (UtilizationClass uc : UtilizationClass.ALL_BUT_SMALL) { - basalAreas.setCoe(uc.index, start.basalAreas[s][uc.ordinal()]); - wholeStemVolumes.setCoe(uc.index, start.wholeStemVolumes[s][uc.ordinal()]); - closeUtilizationVolumes.setCoe(uc.index, start.closeUtilizationVolumes[s][uc.ordinal()]); - closeUtilizationVolumesNetOfDecay.setCoe(uc.index, start.cuVolumesMinusDecay[s][uc.ordinal()]); + basalAreas.setCoe(uc.index, bank.basalAreas[s][uc.ordinal()]); + wholeStemVolumes.setCoe(uc.index, bank.wholeStemVolumes[s][uc.ordinal()]); + closeUtilizationVolumes.setCoe(uc.index, bank.closeUtilizationVolumes[s][uc.ordinal()]); + closeUtilizationVolumesNetOfDecay.setCoe(uc.index, bank.cuVolumesMinusDecay[s][uc.ordinal()]); closeUtilizationVolumesNetOfDecayAndWaste - .setCoe(uc.index, start.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]); + .setCoe(uc.index, bank.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]); - quadMeanDiameters.setCoe(uc.index, start.quadMeanDiameters[s][uc.ordinal()]); + quadMeanDiameters.setCoe(uc.index, bank.quadMeanDiameters[s][uc.ordinal()]); if (uc != UtilizationClass.ALL && quadMeanDiameters.getCoe(uc.index) <= 0.0f) { quadMeanDiameters.setCoe(uc.index, DEFAULT_QUAD_MEAN_DIAMETERS[uc.ordinal()]); } @@ -2332,17 +2328,17 @@ void setCompatibilityVariables() throws ProcessingException { // Volume less decay and waste adjustment = 0.0f; - baseVolume = start.cuVolumesMinusDecay[s][uc.ordinal()]; + baseVolume = bank.cuVolumesMinusDecay[s][uc.ordinal()]; if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP094 fps.estimators.estimateNetDecayAndWasteVolume( lps.getBecZone() - .getRegion(), uc, aAdjust, start.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste + .getRegion(), uc, aAdjust, bank.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste ); - float actualVolume = start.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; + float actualVolume = bank.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; float staticVolume = closeUtilizationVolumesNetOfDecayAndWaste.getCoe(uc.index); adjustment = calculateCompatibilityVariable(actualVolume, baseVolume, staticVolume); } @@ -2352,18 +2348,18 @@ void setCompatibilityVariables() throws ProcessingException { // Volume less decay adjustment = 0.0f; - baseVolume = start.closeUtilizationVolumes[s][uc.ordinal()]; + baseVolume = bank.closeUtilizationVolumes[s][uc.ordinal()]; if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP093 int decayGroup = lps.decayEquationGroups[s]; fps.estimators.estimateNetDecayVolume( - start.speciesNames[s], lps.getBecZone().getRegion(), uc, aAdjust, decayGroup, lps + bank.speciesNames[s], lps.getBecZone().getRegion(), uc, aAdjust, decayGroup, lps .getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay ); - float actualVolume = start.cuVolumesMinusDecay[s][uc.ordinal()]; + float actualVolume = bank.cuVolumesMinusDecay[s][uc.ordinal()]; float staticVolume = closeUtilizationVolumesNetOfDecay.getCoe(uc.index); adjustment = calculateCompatibilityVariable(actualVolume, baseVolume, staticVolume); } @@ -2372,7 +2368,7 @@ void setCompatibilityVariables() throws ProcessingException { // Volume adjustment = 0.0f; - baseVolume = start.wholeStemVolumes[s][uc.ordinal()]; + baseVolume = bank.wholeStemVolumes[s][uc.ordinal()]; if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { @@ -2382,7 +2378,7 @@ void setCompatibilityVariables() throws ProcessingException { uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes ); - float actualVolume = start.closeUtilizationVolumes[s][uc.ordinal()]; + float actualVolume = bank.closeUtilizationVolumes[s][uc.ordinal()]; float staticVolume = closeUtilizationVolumes.getCoe(uc.index); adjustment = calculateCompatibilityVariable(actualVolume, baseVolume, staticVolume); } @@ -2391,8 +2387,8 @@ void setCompatibilityVariables() throws ProcessingException { } int primarySpeciesVolumeGroup = lps.volumeEquationGroups[s]; - float primarySpeciesQMDAll = start.quadMeanDiameters[s][UC_ALL_INDEX]; - var wholeStemVolume = start.treesPerHectare[s][UC_ALL_INDEX] + float primarySpeciesQMDAll = bank.quadMeanDiameters[s][UC_ALL_INDEX]; + var wholeStemVolume = bank.treesPerHectare[s][UC_ALL_INDEX] * fps.estimators.estimateWholeStemVolumePerTree( primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll ); @@ -2408,7 +2404,7 @@ void setCompatibilityVariables() throws ProcessingException { float basalArea = basalAreas.getCoe(uc.index); if (growthDetails.allowCalculation(basalArea, B_BASE_MIN, (l, r) -> l > r)) { adjustment = calculateWholeStemVolume( - start.wholeStemVolumes[s][uc.ordinal()], basalArea, wholeStemVolumes.getCoe(uc.index) + bank.wholeStemVolumes[s][uc.ordinal()], basalArea, wholeStemVolumes.getCoe(uc.index) ); } @@ -2424,7 +2420,7 @@ void setCompatibilityVariables() throws ProcessingException { ); // Calculate trees-per-hectare per utilization - treesPerHectare.setCoe(UtilizationClass.ALL.index, start.treesPerHectare[s][UC_ALL_INDEX]); + treesPerHectare.setCoe(UtilizationClass.ALL.index, bank.treesPerHectare[s][UC_ALL_INDEX]); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { treesPerHectare.setCoe( uc.index, BaseAreaTreeDensityDiameter.treesPerHectare( @@ -2436,10 +2432,10 @@ void setCompatibilityVariables() throws ProcessingException { ReconcilationMethods.reconcileComponents(basalAreas, treesPerHectare, quadMeanDiameters); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { - float baCvValue = start.basalAreas[s][uc.ordinal()] - basalAreas.getCoe(uc.index); + float baCvValue = bank.basalAreas[s][uc.ordinal()] - basalAreas.getCoe(uc.index); cvBasalArea[s].put(uc, LayerType.PRIMARY, baCvValue); - float originalQmd = start.quadMeanDiameters[s][uc.ordinal()]; + float originalQmd = bank.quadMeanDiameters[s][uc.ordinal()]; float adjustedQmd = quadMeanDiameters.getCoe(uc.index); float qmdCvValue; @@ -2476,23 +2472,23 @@ void setCompatibilityVariables() throws ProcessingException { throws ProcessingException { var lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); Region region = lps.getBecZone().getRegion(); - String speciesName = start.speciesNames[speciesIndex]; + String speciesName = bank.speciesNames[speciesIndex]; - float spLoreyHeight_All = start.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp - float spQuadMeanDiameter_All = start.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp + float spLoreyHeight_All = bank.loreyHeights[speciesIndex][UC_ALL_INDEX]; // HLsp + float spQuadMeanDiameter_All = bank.quadMeanDiameters[speciesIndex][UC_ALL_INDEX]; // DQsp // this WHOLE operation on Actual BA's, not 100% occupancy. // TODO: verify this: float fractionAvailable = polygon.getPercentForestLand(); - float spBaseArea_All = start.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp + float spBaseArea_All = bank.basalAreas[speciesIndex][UC_ALL_INDEX] /* * fractionAvailable */; // BAsp // EMP080 float smallProbability = smallComponentProbability(speciesName, spLoreyHeight_All, region); // PROBsp // EMP081 - float conditionalExpectedBaseArea = conditionalExpectedBaseArea( + float conditionalExpectedBaseArea = calculateConditionalExpectedBasalArea( speciesName, spBaseArea_All, spLoreyHeight_All, region ); // BACONDsp @@ -2513,11 +2509,11 @@ void setCompatibilityVariables() throws ProcessingException { var cvSmall = new HashMap(); - float spInputBasalArea_Small = start.basalAreas[speciesIndex][UC_SMALL_INDEX]; + float spInputBasalArea_Small = bank.basalAreas[speciesIndex][UC_SMALL_INDEX]; cvSmall.put(UtilizationClassVariable.BASAL_AREA, spInputBasalArea_Small - baSmall); if (forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { - float spInputQuadMeanDiameter_Small = start.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; + float spInputQuadMeanDiameter_Small = bank.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; cvSmall.put( UtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - qmdSmall @@ -2526,7 +2522,7 @@ void setCompatibilityVariables() throws ProcessingException { cvSmall.put(UtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); } - float spInputLoreyHeight_Small = start.loreyHeights[speciesIndex][UC_SMALL_INDEX]; + float spInputLoreyHeight_Small = bank.loreyHeights[speciesIndex][UC_SMALL_INDEX]; if (spInputLoreyHeight_Small > 1.3f && lhSmall > 1.3f && spInputBasalArea_Small > 0.0f) { float cvLoreyHeight = FloatMath.log( (spInputLoreyHeight_Small - 1.3f) / (lhSmall - 1.3f)); cvSmall.put(UtilizationClassVariable.LOREY_HEIGHT, cvLoreyHeight); @@ -2534,11 +2530,11 @@ void setCompatibilityVariables() throws ProcessingException { cvSmall.put(UtilizationClassVariable.LOREY_HEIGHT, 0.0f); } - float spInputWholeStemVolume_Small = start.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; + float spInputWholeStemVolume_Small = bank.wholeStemVolumes[speciesIndex][UC_SMALL_INDEX]; if (spInputWholeStemVolume_Small > 0.0f && meanVolumeSmall > 0.0f && forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l >= r)) { - float spInputTreePerHectare_Small = start.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; + float spInputTreePerHectare_Small = bank.treesPerHectare[speciesIndex][UC_SMALL_INDEX]; var wsVolumeSmall = FloatMath .log(spInputWholeStemVolume_Small / spInputTreePerHectare_Small / meanVolumeSmall); @@ -2551,13 +2547,22 @@ void setCompatibilityVariables() throws ProcessingException { return cvSmall; } - // EMP080 + /** + * EMP080 - calculate the small component probability of the species with + * speciesAlias, the given Lorey height and in the given + * region. + * + * @param speciesAlias the species' alias + * @param loreyHeight current Lorey height of the stand + * @param region the stand's region + * @return as described + */ private float smallComponentProbability( - String speciesName, float loreyHeight, Region region + String speciesAlias, float loreyHeight, Region region ) { LayerProcessingState lps = fps.getLayerProcessingState(); - Coefficients coe = fps.fcm.getSmallComponentProbabilityCoefficients().get(speciesName); + Coefficients coe = fps.fcm.getSmallComponentProbabilityCoefficients().get(speciesAlias); // EQN 1 in IPSJF118.doc @@ -2570,14 +2575,22 @@ private float smallComponentProbability( float logit = a0 + // a1 + // - a2 * lps.getStartBank().yearsAtBreastHeight[lps.getPrimarySpeciesIndex()] + // + a2 * lps.getBank().yearsAtBreastHeight[lps.getPrimarySpeciesIndex()] + // a3 * loreyHeight; return exp(logit) / (1.0f + exp(logit)); } // EMP081 - private float conditionalExpectedBaseArea( + /** + * + * @param speciesName + * @param basalArea + * @param loreyHeight + * @param region + * @return + */ + private float calculateConditionalExpectedBasalArea( String speciesName, float basalArea, float loreyHeight, Region region ) { Coefficients coe = fps.fcm.getSmallComponentBasalAreaCoefficients().get(speciesName); @@ -2589,16 +2602,16 @@ private float conditionalExpectedBaseArea( float a2 = coe.getCoe(3); float a3 = coe.getCoe(4); - float coast = region == Region.COASTAL ? 1.0f : 0.0f; + float regionMultiplier = region == Region.COASTAL ? 1.0f : 0.0f; // FIXME due to a bug in VDYP7 it always treats this as interior. Replicating // that for now. - coast = 0f; + regionMultiplier = 0f; - float arg = (a0 + a1 * coast + a2 * basalArea) * exp(a3 * loreyHeight); - arg = max(arg, 0f); + float result = (a0 + a1 * regionMultiplier + a2 * basalArea) * exp(a3 * loreyHeight); + result = max(result, 0f); - return arg; + return result; } // EMP082 @@ -2708,25 +2721,25 @@ static void calculateDominantHeightAgeSiteIndex( LayerProcessingState lps, MatrixMap2 hl1Coefficients ) throws ProcessingException { - Bank startBank = lps.getStartBank(); + Bank bank = lps.getBank(); // Calculate primary species values int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); // (1) Dominant Height - float primarySpeciesDominantHeight = startBank.dominantHeights[primarySpeciesIndex]; + float primarySpeciesDominantHeight = bank.dominantHeights[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesDominantHeight)) { - float loreyHeight = startBank.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; + float loreyHeight = bank.loreyHeights[primarySpeciesIndex][UC_ALL_INDEX]; if (Float.isNaN(loreyHeight)) { throw new ProcessingException( MessageFormat.format( - "Neither dominant nor lorey height[All] is available for primary species {}", startBank.speciesNames[primarySpeciesIndex] + "Neither dominant nor lorey height[All] is available for primary species {}", bank.speciesNames[primarySpeciesIndex] ), 2 ); } // Estimate dominant height from the lorey height - String primarySpeciesAlias = startBank.speciesNames[primarySpeciesIndex]; + String primarySpeciesAlias = bank.speciesNames[primarySpeciesIndex]; Region primarySpeciesRegion = lps.getBecZone().getRegion(); var coefficients = hl1Coefficients.get(primarySpeciesAlias, primarySpeciesRegion); @@ -2734,27 +2747,27 @@ static void calculateDominantHeightAgeSiteIndex( float a1 = coefficients.getCoe(2); float a2 = coefficients.getCoe(3); - float treesPerHectare = startBank.treesPerHectare[primarySpeciesIndex][UC_ALL_INDEX]; + float treesPerHectare = bank.treesPerHectare[primarySpeciesIndex][UC_ALL_INDEX]; float hMult = a0 - a1 + a1 * FloatMath.exp(a2 * (treesPerHectare - 100.0f)); primarySpeciesDominantHeight = 1.3f + (loreyHeight - 1.3f) / hMult; } // (2) Age (total, years at breast height, years to breast height - float primarySpeciesTotalAge = startBank.ageTotals[primarySpeciesIndex]; - float primarySpeciesYearsAtBreastHeight = startBank.yearsAtBreastHeight[primarySpeciesIndex]; - float primarySpeciesYearsToBreastHeight = startBank.yearsToBreastHeight[primarySpeciesIndex]; + float primarySpeciesTotalAge = bank.ageTotals[primarySpeciesIndex]; + float primarySpeciesYearsAtBreastHeight = bank.yearsAtBreastHeight[primarySpeciesIndex]; + float primarySpeciesYearsToBreastHeight = bank.yearsToBreastHeight[primarySpeciesIndex]; Optional activeIndex = Optional.empty(); if (Float.isNaN(primarySpeciesTotalAge)) { if (lps.hasSecondarySpeciesIndex() - && !Float.isNaN(startBank.ageTotals[lps.getSecondarySpeciesIndex()])) { + && !Float.isNaN(bank.ageTotals[lps.getSecondarySpeciesIndex()])) { activeIndex = Optional.of(lps.getSecondarySpeciesIndex()); } else { for (int i = 1; i <= lps.getNSpecies(); i++) { - if (!Float.isNaN(startBank.ageTotals[i])) { + if (!Float.isNaN(bank.ageTotals[i])) { activeIndex = Optional.of(i); break; } @@ -2763,35 +2776,35 @@ static void calculateDominantHeightAgeSiteIndex( activeIndex.orElseThrow(() -> new ProcessingException("Age data unavailable for ALL species", 5)); - primarySpeciesTotalAge = startBank.ageTotals[activeIndex.get()]; + primarySpeciesTotalAge = bank.ageTotals[activeIndex.get()]; if (!Float.isNaN(primarySpeciesYearsToBreastHeight)) { primarySpeciesYearsAtBreastHeight = primarySpeciesTotalAge - primarySpeciesYearsToBreastHeight; } else if (!Float.isNaN(primarySpeciesYearsAtBreastHeight)) { primarySpeciesYearsToBreastHeight = primarySpeciesTotalAge - primarySpeciesYearsAtBreastHeight; } else { - primarySpeciesYearsAtBreastHeight = startBank.yearsAtBreastHeight[activeIndex.get()]; - primarySpeciesYearsToBreastHeight = startBank.yearsToBreastHeight[activeIndex.get()]; + primarySpeciesYearsAtBreastHeight = bank.yearsAtBreastHeight[activeIndex.get()]; + primarySpeciesYearsToBreastHeight = bank.yearsToBreastHeight[activeIndex.get()]; } } // (3) Site Index - float primarySpeciesSiteIndex = startBank.siteIndices[primarySpeciesIndex]; + float primarySpeciesSiteIndex = bank.siteIndices[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesSiteIndex)) { if (lps.hasSecondarySpeciesIndex() - && !Float.isNaN(startBank.siteIndices[lps.getSecondarySpeciesIndex()])) { + && !Float.isNaN(bank.siteIndices[lps.getSecondarySpeciesIndex()])) { activeIndex = Optional.of(lps.getSecondarySpeciesIndex()); } else { - if (activeIndex.isEmpty() || Float.isNaN(startBank.siteIndices[activeIndex.get()])) { + if (activeIndex.isEmpty() || Float.isNaN(bank.siteIndices[activeIndex.get()])) { for (int i = 1; i <= lps.getNSpecies(); i++) { - if (!Float.isNaN(startBank.siteIndices[i])) { + if (!Float.isNaN(bank.siteIndices[i])) { activeIndex = Optional.of(i); break; } } } } - primarySpeciesSiteIndex = startBank.siteIndices[activeIndex + primarySpeciesSiteIndex = bank.siteIndices[activeIndex .orElseThrow(() -> new ProcessingException("Site Index data unavailable for ALL species", 7))]; } else { activeIndex = Optional.of(primarySpeciesIndex); @@ -2826,10 +2839,10 @@ static void calculateDominantHeightAgeSiteIndex( */ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); - float primarySpeciesSiteIndex = start.siteIndices[primarySpeciesIndex]; + float primarySpeciesSiteIndex = bank.siteIndices[primarySpeciesIndex]; // Determine the default site index by using the site index of the primary species unless // it hasn't been set in which case pick any. Note that there may still not be a @@ -2840,15 +2853,15 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { if (Float.isNaN(defaultSiteIndex)) { for (int i : lps.getIndices()) { - if (!Float.isNaN(start.siteIndices[i])) { - defaultSiteIndex = start.siteIndices[i]; + if (!Float.isNaN(bank.siteIndices[i])) { + defaultSiteIndex = bank.siteIndices[i]; break; } } } for (int i : lps.getIndices()) { - if (!Float.isNaN(start.yearsToBreastHeight[i])) { + if (!Float.isNaN(bank.yearsToBreastHeight[i])) { // was supplied continue; } @@ -2856,18 +2869,18 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { // Note: this block will normally never be executed because of the logic in // the constructor of VdypLayerSpecies that computes missing values when the // other two measurement values are present. - if (!Float.isNaN(start.yearsAtBreastHeight[i]) - && start.ageTotals[i] > start.yearsAtBreastHeight[i]) { - start.yearsToBreastHeight[i] = start.ageTotals[i] - start.yearsAtBreastHeight[i]; + if (!Float.isNaN(bank.yearsAtBreastHeight[i]) + && bank.ageTotals[i] > bank.yearsAtBreastHeight[i]) { + bank.yearsToBreastHeight[i] = bank.ageTotals[i] - bank.yearsAtBreastHeight[i]; continue; } - float siteIndex = !Float.isNaN(start.siteIndices[i]) ? start.siteIndices[i] + float siteIndex = !Float.isNaN(bank.siteIndices[i]) ? bank.siteIndices[i] : defaultSiteIndex; try { SiteIndexEquation curve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); double yearsToBreastHeight = SiteTool.yearsToBreastHeight(curve, siteIndex); - start.yearsToBreastHeight[i] = (float) yearsToBreastHeight; + bank.yearsToBreastHeight[i] = (float) yearsToBreastHeight; } catch (CommonCalculatorException e) { logger.warn(MessageFormat.format("Unable to determine yearsToBreastHeight of species {0}", i), e); } @@ -2890,14 +2903,14 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { */ static void estimateMissingSiteIndices(LayerProcessingState lps) throws ProcessingException { - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); int pspIndex = lps.getPrimarySpeciesIndex(); SiteIndexEquation pspSiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(pspIndex)); // (1) - if (Float.isNaN(start.siteIndices[pspIndex])) { + if (Float.isNaN(bank.siteIndices[pspIndex])) { double otherSiteIndicesSum = 0.0f; int nOtherSiteIndices = 0; @@ -2908,7 +2921,7 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi continue; } - float spSiteIndex = start.siteIndices[spIndex]; + float spSiteIndex = bank.siteIndices[spIndex]; if (!Float.isNaN(spSiteIndex)) { SiteIndexEquation spSiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(spIndex)); @@ -2937,14 +2950,14 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } if (nOtherSiteIndices > 0) { - start.siteIndices[pspIndex] = (float) (otherSiteIndicesSum / nOtherSiteIndices); + bank.siteIndices[pspIndex] = (float) (otherSiteIndicesSum / nOtherSiteIndices); } } // (2) - float pspSiteIndex = start.siteIndices[pspIndex]; - if (!Float.isNaN(start.siteIndices[pspIndex])) { + float pspSiteIndex = bank.siteIndices[pspIndex]; + if (!Float.isNaN(bank.siteIndices[pspIndex])) { for (int spIndex : lps.getIndices()) { @@ -2952,14 +2965,14 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi continue; } - float spSiteIndex = start.siteIndices[spIndex]; + float spSiteIndex = bank.siteIndices[spIndex]; if (Float.isNaN(spSiteIndex)) { SiteIndexEquation spSiteCurve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(spIndex)); try { double mappedSiteIndex = SiteTool .convertSiteIndexBetweenCurves(pspSiteCurve, pspSiteIndex, spSiteCurve); - start.siteIndices[spIndex] = (float) mappedSiteIndex; + bank.siteIndices[spIndex] = (float) mappedSiteIndex; } catch (NoAnswerException e) { logger.warn( MessageFormat.format( @@ -2978,7 +2991,7 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } // Finally, set bank.siteIndices[0] to that of the primary species. - start.siteIndices[0] = pspSiteIndex; + bank.siteIndices[0] = pspSiteIndex; } /** @@ -2989,7 +3002,7 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi */ static void calculateCoverages(LayerProcessingState lps) { - Bank bank = lps.getStartBank(); + Bank bank = lps.getBank(); logger.atDebug().addArgument(lps.getNSpecies()).addArgument(bank.basalAreas[0][0]).log( "Calculating coverages as a ratio of Species BA over Total BA. # species: {}; Layer total 7.5cm+ basal area: {}" @@ -3019,7 +3032,7 @@ static void calculateCoverages(LayerProcessingState lps) { static void calculateMissingSiteCurves( LayerProcessingState lps, MatrixMap2 siteCurveMap ) { - Bank bank = lps.getStartBank(); + Bank bank = lps.getBank(); BecDefinition becZone = bank.getBecZone(); @@ -3120,17 +3133,17 @@ private static void stopIfNoWork(LayerProcessingState lps) throws ProcessingExce void determinePolygonRankings(Collection> speciesToCombine) { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank start = lps.getStartBank(); + Bank bank = lps.getBank(); if (lps.getNSpecies() == 0) { throw new IllegalArgumentException("Can not find primary species as there are no species"); } float[] percentages = Arrays - .copyOf(start.percentagesOfForestedLand, start.percentagesOfForestedLand.length); + .copyOf(bank.percentagesOfForestedLand, bank.percentagesOfForestedLand.length); for (var speciesPair : speciesToCombine) { - combinePercentages(start.speciesNames, speciesPair, percentages); + combinePercentages(bank.speciesNames, speciesPair, percentages); } float highestPercentage = 0.0f; @@ -3159,9 +3172,9 @@ void determinePolygonRankings(Collection> speciesToCombine) { throw new IllegalStateException("There are no species with covering percentage > 0"); } - String primaryGenusName = start.speciesNames[highestPercentageIndex]; + String primaryGenusName = bank.speciesNames[highestPercentageIndex]; Optional secondaryGenusName = secondHighestPercentageIndex != -1 - ? Optional.of(start.speciesNames[secondHighestPercentageIndex]) + ? Optional.of(bank.speciesNames[secondHighestPercentageIndex]) : Optional.empty(); try { @@ -3169,8 +3182,8 @@ void determinePolygonRankings(Collection> speciesToCombine) { int basalAreaGroup1 = 0; - String primarySpeciesName = start.speciesNames[highestPercentageIndex]; - String becZoneAlias = start.getBecZone().getAlias(); + String primarySpeciesName = bank.speciesNames[highestPercentageIndex]; + String becZoneAlias = bank.getBecZone().getAlias(); int defaultEquationGroup = fps.fcm.getDefaultEquationGroup().get(primarySpeciesName, becZoneAlias); Optional equationModifierGroup = fps.fcm.getEquationModifierGroup() @@ -3181,9 +3194,9 @@ void determinePolygonRankings(Collection> speciesToCombine) { basalAreaGroup1 = defaultEquationGroup; } - int primarySpeciesIndex = start.speciesIndices[highestPercentageIndex]; + int primarySpeciesIndex = bank.speciesIndices[highestPercentageIndex]; int basalAreaGroup3 = defaultEquationGroups[primarySpeciesIndex]; - if (Region.INTERIOR.equals(start.getBecZone().getRegion()) + if (Region.INTERIOR.equals(bank.getBecZone().getRegion()) && exceptedSpeciesIndicies.contains(primarySpeciesIndex)) { basalAreaGroup3 += 20; } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 5893697e5..8a11e64f3 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -1,8 +1,6 @@ package ca.bc.gov.nrs.vdyp.forward; -import java.io.IOException; import java.util.Map; -import java.util.Optional; import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.application.VdypApplicationIdentifier; @@ -10,8 +8,6 @@ import ca.bc.gov.nrs.vdyp.common.EstimationMethods; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; -import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; -import ca.bc.gov.nrs.vdyp.io.write.VdypOutputWriter; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; @@ -29,27 +25,11 @@ class ForwardProcessingState { /** The active state */ private LayerProcessingState lps; - /** The entity to which result information is written */ - private Optional outputWriter = Optional.empty(); - public ForwardProcessingState(Map controlMap) throws ProcessingException { - this(controlMap, Optional.empty()); - } - - public ForwardProcessingState(Map controlMap, Optional outputFileResolver) - throws ProcessingException { this.fcm = new ForwardResolvedControlMapImpl(controlMap); this.estimators = new EstimationMethods(this.fcm); this.computers = new ComputationMethods(estimators, VdypApplicationIdentifier.VDYP_FORWARD); - - if (outputFileResolver.isPresent()) { - try { - outputWriter = Optional.of(new VdypOutputWriter(controlMap, outputFileResolver.get())); - } catch (IOException e) { - throw new ProcessingException(e); - } - } } public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { @@ -60,8 +40,4 @@ public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws public LayerProcessingState getLayerProcessingState() { return lps; } - - public Optional getOutputWriter() { - return outputWriter; - } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index a1da74d2e..22896b385 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -16,6 +16,7 @@ import ca.bc.gov.nrs.vdyp.io.FileResolver; import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.write.VdypOutputWriter; /** * @@ -123,7 +124,17 @@ public void process(Set vdypPassSet, Map controlMap if (vdypPassSet.contains(ForwardPass.PASS_3)) { - var fpe = new ForwardProcessingEngine(controlMap, outputFileResolver); + Optional outputWriter = Optional.empty(); + + if (outputFileResolver.isPresent()) { + try { + outputWriter = Optional.of(new VdypOutputWriter(controlMap, outputFileResolver.get())); + } catch (IOException e) { + throw new ProcessingException(e); + } + } + + var fpe = new ForwardProcessingEngine(controlMap, outputWriter); var forwardDataStreamReader = new ForwardDataStreamReader(fpe.fps.fcm); @@ -149,6 +160,14 @@ public void process(Set vdypPassSet, Map controlMap nPolygonsProcessed += 1; } + + outputWriter.ifPresent(ow -> { + try { + ow.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); } } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 3c38ace99..9a65350e1 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -8,7 +8,6 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; -import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.model.BecDefinition; import ca.bc.gov.nrs.vdyp.model.LayerType; @@ -24,10 +23,6 @@ class LayerProcessingState { - enum BankType { - Start, End - }; - private static final String COMPATIBILITY_VARIABLES_SET_CAN_BE_SET_ONCE_ONLY = "CompatibilityVariablesSet can be set once only"; private static final String PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY = "PrimarySpeciesDetails can be set once only"; private static final String SITE_CURVE_NUMBERS_CAN_BE_SET_ONCE_ONLY = "SiteCurveNumbers can be set once only"; @@ -57,17 +52,10 @@ enum BankType { // when copied to "active" in ForwardProcessingEngine. /** - * State of the layer at the start of processing; read-write during preparation for grow - * and read-only after that. + * State of the layer during processing. */ - private Bank startBank; + private Bank bank; - /** - * State of the layer at the end of processing. The information comprising this is calculated - * during the execution of grow(). - */ - private Bank endBank; - // L1COM2 - equation groups. From the configuration, narrowed to the // polygon's BEC zone. @@ -135,27 +123,25 @@ public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, Lay BecDefinition becZone = polygon.getBiogeoclimaticZone(); - this.startBank = new Bank( + this.bank = new Bank( polygon.getLayers().get(subjectLayerType), becZone, s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= ForwardProcessingEngine.MIN_BASAL_AREA); - this.endBank = new Bank(this.startBank, CopyMode.CopyStructure); - var volumeEquationGroupMatrix = this.fps.fcm.getVolumeEquationGroups(); var decayEquationGroupMatrix = this.fps.fcm.getDecayEquationGroups(); var breakageEquationGroupMatrix = this.fps.fcm.getBreakageEquationGroups(); - this.volumeEquationGroups = new int[this.startBank.getNSpecies() + 1]; - this.decayEquationGroups = new int[this.startBank.getNSpecies() + 1]; - this.breakageEquationGroups = new int[this.startBank.getNSpecies() + 1]; + this.volumeEquationGroups = new int[this.bank.getNSpecies() + 1]; + this.decayEquationGroups = new int[this.bank.getNSpecies() + 1]; + this.breakageEquationGroups = new int[this.bank.getNSpecies() + 1]; this.volumeEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; this.decayEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; this.breakageEquationGroups[0] = VdypEntity.MISSING_INTEGER_VALUE; String becZoneAlias = this.getBecZone().getAlias(); - for (int i = 1; i < this.startBank.getNSpecies() + 1; i++) { - String speciesName = this.startBank.speciesNames[i]; + for (int i = 1; i < this.bank.getNSpecies() + 1; i++) { + String speciesName = this.bank.speciesNames[i]; this.volumeEquationGroups[i] = volumeEquationGroupMatrix.get(speciesName, becZoneAlias); // From VGRPFIND, volumeEquationGroup 10 is mapped to 11. if (this.volumeEquationGroups[i] == 10) { @@ -166,16 +152,6 @@ public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, Lay } } - /** - * Set the layer processing state to the given Bank. This is normally done at the conclusion of - * the growth of a layer for one growth period; the Bank resulting from that calculation is - * assigned as the start bank for the next growth period. - */ - public void swapBanks() { - this.startBank = endBank; - this.endBank = new Bank(this.startBank, CopyMode.CopyStructure); - } - public VdypPolygon getPolygon() { return polygon; } @@ -185,15 +161,15 @@ public LayerType getLayerType() { } public int getNSpecies() { - return startBank.getNSpecies(); + return bank.getNSpecies(); } public int[] getIndices() { - return startBank.getIndices(); + return bank.getIndices(); } public BecDefinition getBecZone() { - return startBank.getBecZone(); + return bank.getBecZone(); } public int getPrimarySpeciesIndex() { @@ -207,7 +183,7 @@ public String getPrimarySpeciesAlias() { if (!areRankingDetailsSet) { throw new IllegalStateException("unset primarySpeciesIndex"); } - return startBank.speciesNames[primarySpeciesIndex]; + return bank.speciesNames[primarySpeciesIndex]; } public boolean hasSecondarySpeciesIndex() { @@ -281,12 +257,8 @@ public ForwardProcessingState getFps() { return fps; } - public Bank getStartBank() { - return startBank; - } - - public Bank getEndBank() { - return endBank; + public Bank getBank() { + return bank; } public int[] getVolumeEquationGroups() { @@ -424,26 +396,34 @@ public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { this.primarySpeciesAgeAtBreastHeight = details.primarySpeciesAgeAtBreastHeight(); this.primarySpeciesAgeToBreastHeight = details.primarySpeciesAgeToBreastHeight(); - // Store these values into start - VHDOM1 lines 182 - 186 - if (startBank.dominantHeights[primarySpeciesIndex] <= 0.0) { - startBank.dominantHeights[primarySpeciesIndex] = this.primarySpeciesDominantHeight; + // Store these values into bank if not already set - VHDOM1 lines 182 - 186 + if (bank.dominantHeights[primarySpeciesIndex] <= 0.0) { + bank.dominantHeights[primarySpeciesIndex] = this.primarySpeciesDominantHeight; } - if (startBank.siteIndices[primarySpeciesIndex] <= 0.0) { - startBank.siteIndices[primarySpeciesIndex] = this.primarySpeciesSiteIndex; + if (bank.siteIndices[primarySpeciesIndex] <= 0.0) { + bank.siteIndices[primarySpeciesIndex] = this.primarySpeciesSiteIndex; } - if (startBank.ageTotals[primarySpeciesIndex] <= 0.0) { - startBank.ageTotals[primarySpeciesIndex] = this.primarySpeciesTotalAge; + if (bank.ageTotals[primarySpeciesIndex] <= 0.0) { + bank.ageTotals[primarySpeciesIndex] = this.primarySpeciesTotalAge; } - if (startBank.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { - startBank.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeAtBreastHeight; + if (bank.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { + bank.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeAtBreastHeight; } - if (startBank.yearsAtBreastHeight[primarySpeciesIndex] <= 0.0) { - startBank.yearsAtBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeToBreastHeight; + if (bank.yearsToBreastHeight[primarySpeciesIndex] <= 0.0) { + bank.yearsToBreastHeight[primarySpeciesIndex] = this.primarySpeciesAgeToBreastHeight; } this.arePrimarySpeciesDetailsSet = true; } + /** + * Update the cached primary species details after growth. These changes are made to + * the cached values only at this time. Later, if Control Variable 6 is > 0, + * setPrimarySpeciesDetails will be called before the next growth + * period is run and the bank values will be updated, too. + * + * @param newPrimarySpeciesDominantHeight + */ public void updatePrimarySpeciesDetailsAfterGrowth(float newPrimarySpeciesDominantHeight) { this.primarySpeciesDominantHeight = newPrimarySpeciesDominantHeight; @@ -530,14 +510,12 @@ public float getCVSmall(int speciesIndex, UtilizationClassVariable variable) { return cvPrimaryLayerSmall[speciesIndex].get(variable); } - public VdypLayer getLayerFromBank(BankType bankType) { - - Bank sourceBank = bankType == BankType.Start ? startBank : endBank; + public VdypLayer getLayer() { - VdypLayer updatedLayer = sourceBank.getUpdatedLayer(); + VdypLayer updatedLayer = bank.getUpdatedLayer(); for (int i = 1; i < getNSpecies() + 1; i++) { - VdypSpecies species = updatedLayer.getSpeciesBySp0(sourceBank.speciesNames[i]); + VdypSpecies species = updatedLayer.getSpeciesBySp0(bank.speciesNames[i]); species.setCompatibilityVariables( cvVolume[i], cvBasalArea[i], cvQuadraticMeanDiameter[i], cvPrimaryLayerSmall[i]); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index 8f4ad9368..d5e6979c4 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -87,7 +87,7 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); - var speciesToCombine = Arrays.asList(Arrays.asList(lps.getStartBank().speciesNames[3], lps.getStartBank().speciesNames[4])); + var speciesToCombine = Arrays.asList(Arrays.asList(lps.getBank().speciesNames[3], lps.getBank().speciesNames[4])); ForwardProcessingEngine.calculateCoverages(lps); fpe.determinePolygonRankings(speciesToCombine); @@ -382,7 +382,7 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getLayerProcessingState().getStartBank().siteIndices[4], is((float) expectedValue)); + assertThat(fpe.fps.getLayerProcessingState().getBank().siteIndices[4], is((float) expectedValue)); } @Test @@ -422,7 +422,7 @@ void testEstimateMissingSiteIndicesStep2() throws ProcessingException, IOExcepti double expectedValue = SiteTool .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getLayerProcessingState().getStartBank().siteIndices[2], is((float) expectedValue)); + assertThat(fpe.fps.getLayerProcessingState().getBank().siteIndices[2], is((float) expectedValue)); } @Test @@ -449,7 +449,7 @@ void testEstimateMissingYearsToBreastHeightValues() ); assertThat( - fpe.fps.getLayerProcessingState().getStartBank().yearsToBreastHeight, + fpe.fps.getLayerProcessingState().getBank().yearsToBreastHeight, is(new float[] { 0.0f, 4.0f, 4.6f, 1.0f, 5.0f, 5.0f }) ); } From dc03d5c744d034c1c71301d8ecd5bb023f8918cf Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 29 Aug 2024 16:13:59 -0700 Subject: [PATCH 41/66] Changes to support one Site per Layer (ignoring Site information from non-primary species) --- .../nrs/vdyp/io/write/VdypOutputWriter.java | 27 +- .../bc/gov/nrs/vdyp/model/Coefficients.java | 10 + .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 110 ++++---- .../vdyp/forward/ForwardProcessingEngine.java | 120 ++++---- .../forward/LambdaProcessingException.java | 17 ++ .../vdyp/forward/LayerProcessingState.java | 2 +- .../forward/parsers/VdypSpeciesParser.java | 23 +- .../ca/bc/gov/nrs/vdyp/forward/BankTest.java | 261 ++++++++++++++++++ .../GeneralForwardProcessingEngineTest.java | 34 +-- .../forward/PolygonProcessingStateTest.java | 189 ------------- .../forward/VdypForwardReadPolygonTest.java | 15 +- .../forward/VdypForwardSpeciesParserTest.java | 103 +++---- 12 files changed, 509 insertions(+), 402 deletions(-) create mode 100644 vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java create mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java index fa5d74e14..fe1f54722 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java @@ -33,7 +33,7 @@ public class VdypOutputWriter implements Closeable { private OutputStream speciesFile; private OutputStream utilizationFile; @SuppressWarnings("unused") - private OutputStream compatibilityVariablesFile; + private Optional compatibilityVariablesFile; private Optional currentYear = Optional.empty(); @@ -65,6 +65,22 @@ public class VdypOutputWriter implements Closeable { static final String END_RECORD_FORMAT = POLY_IDENTIFIER_FORMAT + " \n"; + /** + * Create a writer for Vdyp output files using provided OutputStreams. The Streams will be + * closed when the writer is closed. + * + * @param polygonFile + * @param speciesFile + * @param utilizationFile + * @param compatibilityVariablesFile + * @param controlMap + */ + public VdypOutputWriter( + OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile + ) { + this(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. @@ -77,7 +93,7 @@ public class VdypOutputWriter implements Closeable { */ public VdypOutputWriter( OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile, - OutputStream compatibilityVariablesFile + Optional compatibilityVariablesFile ) { this.polygonFile = polygonFile; this.speciesFile = speciesFile; @@ -98,7 +114,7 @@ public VdypOutputWriter(Map controlMap, FileResolver resolver) t 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()), - getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name()) + Optional.of(getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name())) ); } @@ -108,8 +124,8 @@ static OutputStream getOutputStream(Map controlMap, FileResolver return resolver.resolveForOutput(fileName); } - private void setPolygonYear(Optional polygonYear) { - this.currentYear = polygonYear; + public void setPolygonYear(int currentYear) { + this.currentYear = Optional.of(currentYear); } private PolygonIdentifier getCurrentPolygonDescriptor(PolygonIdentifier originalIdentifier) { @@ -128,7 +144,6 @@ private PolygonIdentifier getCurrentPolygonDescriptor(PolygonIdentifier original * @throws IOException */ void writePolygon(VdypPolygon polygon) throws IOException { - setPolygonYear(polygon.getTargetYear()); writeFormat( polygonFile, // diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java index 55d6f8d30..3123f6000 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java @@ -29,6 +29,16 @@ public Coefficients(List coe, int indexFrom) { this(listToArray(coe), indexFrom); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("["); + for (int i = 0; i < coe.length; i++) { + sb.append(indexFrom + i).append(':').append(coe[i]).append(", "); + } + return sb.delete(sb.length() - 2, sb.length()).append(']').toString(); + } private static float[] listToArray(List coe) { float[] floatArray = new float[coe.size()]; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 73f8dc3e7..e25a8ab68 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -100,7 +100,7 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai treesPerHectare = new float[nSpecies + 1][nUtilizationClasses]; wholeStemVolumes = new float[nSpecies + 1][nUtilizationClasses]; - transferUtilizationsIntoBank(0, layer); + transferUtilizationSetIntoBank(0, layer); int nextSlot = 1; for (VdypSpecies s : speciesToRetain) { @@ -207,7 +207,7 @@ void refreshBank(VdypLayer layer) throws ProcessingException { List species = layer.getSpecies().values().stream() .sorted((s1, s2) -> s1.getGenusIndex() - s2.getGenusIndex()).toList(); - transferUtilizationsIntoBank(0, layer); + transferUtilizationSetIntoBank(0, layer); int nextSlot = 1; for (VdypSpecies s : species) { @@ -215,50 +215,38 @@ void refreshBank(VdypLayer layer) throws ProcessingException { } } - /** - * 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 getUpdatedLayer() { - - transferLayerFromBank(); - - return layer; - } - private void transferSpeciesIntoBank(int index, VdypSpecies species) throws ProcessingException { - VdypSite site = species.getSite().orElseThrow( - () -> new ProcessingException( - MessageFormat.format( - "Species {0} of Polygon {1} must contain a Site definition but does not.", - species.getGenus(), species.getPolygonIdentifier().toStringCompact() - ) - ) - ); - speciesNames[index] = species.getGenus(); sp64Distributions[index] = species.getSp64DistributionSet(); - siteIndices[index] = site.getSiteIndex().orElse(VdypEntity.MISSING_FLOAT_VALUE); - dominantHeights[index] = site.getHeight().orElse(VdypEntity.MISSING_FLOAT_VALUE); - ageTotals[index] = site.getAgeTotal().orElse(VdypEntity.MISSING_FLOAT_VALUE); - yearsToBreastHeight[index] = site.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] = site.getSiteCurveNumber().orElse(VdypEntity.MISSING_INTEGER_VALUE); speciesIndices[index] = species.getGenusIndex(); - // percentForestedLand is output-only and so not assigned here. - - transferUtilizationsIntoBank(index, species); + + 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 transferUtilizationsIntoBank(int index, VdypUtilizationHolder uh) { + private void transferUtilizationSetIntoBank(int index, VdypUtilizationHolder uh) { for (UtilizationClass uc : UtilizationClass.values()) { int ucIndex = uc.ordinal(); @@ -276,29 +264,43 @@ private void transferUtilizationsIntoBank(int index, VdypUtilizationHolder uh) { } } - private void transferLayerFromBank() { - + /** + * 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 getLayer() { + transferUtilizationsFromBank(0, layer); for (int i : indices) { transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i])); } + + return layer; } - private void transferSpeciesFromBank(int index, VdypSpecies species) { - - VdypSite site = species.getSite().get(); - - VdypSite updatedSite = new VdypSite.Builder().adapt(site) // - .siteIndex(siteIndices[index]) // - .ageTotal(ageTotals[index]) // - .height(dominantHeights[index]) // - .yearsToBreastHeight(yearsToBreastHeight[index]) // - .build(); - - species = new VdypSpecies.Builder().addSite(updatedSite).adapt(species).build(); + private VdypSpecies transferSpeciesFromBank(int index, VdypSpecies species) { + + VdypSpecies newSpecies = VdypSpecies.build(speciesBuilder -> { + speciesBuilder.adapt(species); + speciesBuilder.percentGenus(this.percentagesOfForestedLand[index]); + species.getSite().ifPresent(site -> + speciesBuilder.addSite(VdypSite.build(siteBuilder -> { + siteBuilder.adapt(site); + siteBuilder.ageTotal(this.ageTotals[index]); + siteBuilder.height(this.dominantHeights[index]); + siteBuilder.siteCurveNumber(this.siteCurveNumbers[index]); + siteBuilder.siteGenus(this.speciesNames[index]); + siteBuilder.siteIndex(this.siteIndices[index]); + siteBuilder.yearsToBreastHeight(this.yearsToBreastHeight[index]); + }))); + }); + + transferUtilizationsFromBank(index, newSpecies); - transferUtilizationsFromBank(index, species); + return newSpecies; } private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 7f1e40d87..551cf3829 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -38,7 +38,6 @@ import ca.bc.gov.nrs.vdyp.forward.model.ControlVariable; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; -import ca.bc.gov.nrs.vdyp.io.FileSystemFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.coe.UpperBoundsParser; import ca.bc.gov.nrs.vdyp.io.write.VdypOutputWriter; import ca.bc.gov.nrs.vdyp.math.FloatMath; @@ -88,12 +87,12 @@ public class ForwardProcessingEngine { /* pp */ final ForwardProcessingState fps; /** The entity to which result information is written */ - private Optional outputWriter; + private Optional outputWriter = Optional.empty(); public ForwardProcessingEngine(Map controlMap, Optional outputWriter) throws ProcessingException { this.fps = new ForwardProcessingState(controlMap); - this.outputWriter = outputWriter; + this.outputWriter = outputWriter == null ? Optional.empty() : outputWriter; } public ForwardProcessingEngine(Map controlMap) @@ -191,7 +190,7 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) executeForwardAlgorithm(lastStepInclusive, targetYear); } - private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilYear) throws ProcessingException { + private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int stoppingYearInclusive) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); @@ -202,11 +201,6 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY veteranLayer = Optional.empty(); } - logger.info( - "Beginning processing of polygon {} Primary layer {}", lps.getPolygon().getPolygonIdentifier() - .toStringCompact() - ); - // BANKCHK1, simplified for the parameters METH_CHK = 4, LayerI = 1, and INSTANCE = 1 if (lastStepInclusive.ordinal() >= ExecutionStep.CHECK_FOR_WORK.ordinal()) { stopIfNoWork(lps); @@ -251,7 +245,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY VdypPolygon vdypPolygon = lps.getPolygon(); - writePolygon(vdypPolygon, startingYear, startingYear, untilYear); + writePolygon(vdypPolygon, startingYear, startingYear, stoppingYearInclusive); Map polygonLayers = vdypPolygon.getLayers(); @@ -262,8 +256,13 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY boolean doRecalculateGroups = fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1; - int currentYear = startingYear; - while (currentYear <= untilYear) { + int currentYear = startingYear + 1; + while (currentYear <= stoppingYearInclusive) { + + logger.info( + "Growing polygon {} Primary layer for year {}", lps.getPolygon().getPolygonIdentifier() + .toStringCompact(), currentYear + ); grow(lps, currentYear, veteranLayer); @@ -273,10 +272,12 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } - polygonLayers.put(LayerType.PRIMARY, lps.getLayer()); + VdypLayer updatedLayer = lps.getLayer(); + polygonLayers.put(LayerType.PRIMARY, updatedLayer); + logger.atInfo().addArgument(updatedLayer.getBaseAreaByUtilization().toString()).log("{}"); // Store polygon (both primary and veteran layers) to output - writePolygon(vdypPolygon, startingYear, currentYear, untilYear); + writePolygon(vdypPolygon, startingYear, currentYear, stoppingYearInclusive); // If update-during-growth is set, and not already recalculated, recalculate // context now. @@ -305,11 +306,8 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int untilY private void grow(LayerProcessingState lps, int currentYear, Optional veteranLayer) throws ProcessingException { - VdypPolygon polygon = lps.getPolygon(); Bank bank = lps.getBank(); - logger.info("Performing grow of {} for year {}", polygon.getPolygonIdentifier().getName(), currentYear); - float dhStart = lps.getPrimarySpeciesDominantHeight(); int pspSiteCurveNumber = lps.getSiteCurveNumber(lps.getPrimarySpeciesIndex()); float pspSiteIndex = lps.getPrimarySpeciesSiteIndex(); @@ -2206,46 +2204,51 @@ private static double ageAndSiteIndexToHeight( private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, int endYear) throws ProcessingException { - logger.info("Writing polygon {} for year {}", polygon, currentYear); + try { + outputWriter.ifPresent((o) -> { + logger.info("Writing polygon {} for year {}", polygon, currentYear); + + int controlVariable4Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.OUTPUT_FILES_4); - int controlVariable4Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.OUTPUT_FILES_4); - - switch (controlVariable4Value) { - case 0: { - /* never write output */ - return; - } - case 1: { - /* write only first growth period */ - if (currentYear != startYear) { - return; - } - } - case 2: { - /* write only first and last growth periods */ - if (currentYear != startYear && currentYear != endYear) { - return; + switch (controlVariable4Value) { + case 0: { + /* never write output */ + return; + } + case 1: { + /* write only first growth period */ + if (currentYear != startYear) { + return; + } + } + case 2: { + /* write only first and last growth periods */ + if (currentYear != startYear && currentYear != endYear) { + return; + } + } + case 4: { + /* write only the first, every tenth subsequent, and the last periods */ + if ((currentYear - startYear) % 10 != 0 && currentYear != endYear) { + return; + } + } + case 3: { + break; + } + default: + throw new LambdaProcessingException(new ProcessingException(MessageFormat.format("Invalid value for control variable 4: {0}", controlVariable4Value))); } - } - case 4: { - /* write only the first, every tenth subsequent, and the last periods */ - if ((currentYear - startYear) % 10 != 0 && currentYear != endYear) { - return; + + try { + o.setPolygonYear(currentYear); + o.writePolygonWithSpeciesAndUtilization(polygon); + } catch (IOException e) { + throw new LambdaProcessingException(new ProcessingException(e)); } - } - case 3: { - break; - } - default: - throw new ProcessingException(MessageFormat.format("Invalid value for control variable 4: {0}", controlVariable4Value)); - } - - if (outputWriter.isPresent()) { - try { - outputWriter.get().writePolygonWithSpeciesAndUtilization(polygon); - } catch (IOException e) { - throw new ProcessingException(e); - } + }); + } catch (LambdaProcessingException e) { + throw e.getCause(); } } @@ -2936,7 +2939,9 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion from curves {0} to {1}. Skipping species {3}", spSiteCurve, pspSiteCurve, spIndex + "there is no conversion from curves {0} to {1}. Excluding species {2}" + + " from the estimation of the site index of {3}", spSiteCurve, pspSiteCurve, + bank.speciesNames[spIndex], bank.speciesNames[pspIndex] ) ); } catch (CurveErrorException | SpeciesErrorException e) { @@ -2976,13 +2981,14 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion between curves {0} and {1}. Skipping species {2}", pspSiteCurve, spSiteCurve, spIndex + "there is no conversion between curves {0} and {1}. Not calculating site index for species {2}", + pspSiteCurve, spSiteCurve, bank.speciesNames[spIndex] ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed. Skipping species {3}", pspSiteCurve, pspSiteIndex, spSiteCurve, spIndex + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", pspSiteCurve, pspSiteIndex, spSiteCurve ), e ); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java new file mode 100644 index 000000000..4b43c0665 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java @@ -0,0 +1,17 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; + +public class LambdaProcessingException extends RuntimeException { + + private static final long serialVersionUID = 7768827464368942152L; + + public LambdaProcessingException(ProcessingException e) { + super(e); + } + + @Override + public ProcessingException getCause() { + return (ProcessingException)super.getCause(); + } +} diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 9a65350e1..aeaabbb0f 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -512,7 +512,7 @@ public float getCVSmall(int speciesIndex, UtilizationClassVariable variable) { public VdypLayer getLayer() { - VdypLayer updatedLayer = bank.getUpdatedLayer(); + VdypLayer updatedLayer = bank.getLayer(); for (int i = 1; i < getNSpecies() + 1; i++) { VdypSpecies species = updatedLayer.getSpeciesBySp0(bank.speciesNames[i]); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 2af63ca73..644fd0e24 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -175,16 +175,19 @@ protected ValueOrMarker, EndOfRecord> convert(Map { - siteBuilder.ageTotal(inferredTotalAge); - siteBuilder.height(dominantHeight); - siteBuilder.polygonIdentifier(polygonId); - siteBuilder.siteCurveNumber(siteCurveNumber); - siteBuilder.layerType(lt); - siteBuilder.siteGenus(genus); - siteBuilder.siteIndex(siteIndex); - siteBuilder.yearsToBreastHeight(inferredYearsToBreastHeight); - }); + + if (isPrimarySpecies.isPresent() && isPrimarySpecies.get() == true) { + speciesBuilder.addSite(siteBuilder -> { + siteBuilder.ageTotal(inferredTotalAge); + siteBuilder.height(dominantHeight); + siteBuilder.polygonIdentifier(polygonId); + siteBuilder.siteCurveNumber(siteCurveNumber); + siteBuilder.layerType(lt); + siteBuilder.siteGenus(genus); + siteBuilder.siteIndex(siteIndex); + siteBuilder.yearsToBreastHeight(inferredYearsToBreastHeight); + }); + } }); })), builder::marker); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java new file mode 100644 index 000000000..71e1a8a88 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java @@ -0,0 +1,261 @@ +package ca.bc.gov.nrs.vdyp.forward; + +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.Bank.CopyMode; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +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.VdypSpecies; +import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; + +class BankTest { + + private ForwardControlParser parser; + private Map controlMap; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @BeforeEach + void before() throws IOException, ResourceParseException { + + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.SP0_DEF, instanceOf(GenusDefinitionMap.class))); + } + + @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()); + + Bank bank = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); + + int nSpecies = pLayer.getSpecies().size(); + + assertThat(bank, notNullValue()); + assertThat(bank.yearsAtBreastHeight.length, is(nSpecies + 1)); + assertThat(bank.ageTotals.length, is(nSpecies + 1)); + assertThat(bank.dominantHeights.length, is(nSpecies + 1)); + assertThat(bank.percentagesOfForestedLand.length, is(nSpecies + 1)); + assertThat(bank.siteIndices.length, is(nSpecies + 1)); + assertThat(bank.sp64Distributions.length, is(nSpecies + 1)); + assertThat(bank.speciesIndices.length, is(nSpecies + 1)); + assertThat(bank.speciesNames.length, is(nSpecies + 1)); + assertThat(bank.yearsToBreastHeight.length, is(nSpecies + 1)); + assertThat(bank.getNSpecies(), is(nSpecies)); + + assertThat(bank.basalAreas.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.basalAreas[i].length, is(UtilizationClass.values().length)); + } + assertThat(bank.closeUtilizationVolumes.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.closeUtilizationVolumes[i].length, is(UtilizationClass.values().length)); + } + assertThat(bank.cuVolumesMinusDecay.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.cuVolumesMinusDecay[i].length, is(UtilizationClass.values().length)); + } + assertThat(bank.cuVolumesMinusDecayAndWastage.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.cuVolumesMinusDecayAndWastage[i].length, is(UtilizationClass.values().length)); + } + + assertThat(bank.loreyHeights.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.loreyHeights[i].length, is(2)); + } + assertThat(bank.quadMeanDiameters.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.quadMeanDiameters[i].length, is(UtilizationClass.values().length)); + } + assertThat(bank.treesPerHectare.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.treesPerHectare[i].length, is(UtilizationClass.values().length)); + } + assertThat(bank.wholeStemVolumes.length, is(nSpecies + 1)); + for (int i = 0; i < nSpecies + 1; i++) { + assertThat(bank.wholeStemVolumes[i].length, is(UtilizationClass.values().length)); + } + } + + @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); + + verifyBankMatchesLayer(bank, pLayer); + + Bank ppsCopy = bank.copy(); + + verifyBankMatchesLayer(ppsCopy, pLayer); + } + + @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()); + + Bank bank1 = new Bank( + pLayer, polygon.getBiogeoclimaticZone(), + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 0.5 + ); + + // the filter should have removed genus B (index 3) since it's ALL basal area is below 0.5 + assertThat(bank1.getNSpecies(), is(pLayer.getSpecies().size() - 1)); + assertThat(bank1.speciesIndices, is(new int[] { 0, 4, 5, 8, 15 })); + + Bank bank2 = new Bank( + pLayer, polygon.getBiogeoclimaticZone(), + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 100.0 + ); + + // the filter should have removed all genera. + assertThat(bank2.getNSpecies(), is(0)); + assertThat(bank2.speciesIndices, is(new int[] { 0 })); + } + + @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, CopyMode.CopyAll); + + 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); + + VdypLayer currentLayer = bank.getLayer(); + + verifyBankMatchesLayer(bank, currentLayer); + + UtilizationVector uv = currentLayer.getBaseAreaByUtilization(); + float newValue = uv.get(UtilizationClass.ALL) + 1.0f; + uv.set(UtilizationClass.ALL, newValue); + currentLayer.setBaseAreaByUtilization(uv); + + bank.refreshBank(currentLayer); + + verifyBankMatchesLayer(bank, currentLayer); + } + + private void verifyBankMatchesLayer(Bank lps, VdypLayer layer) { + + List sortedSpIndices = layer.getSpecies().values().stream().map(s -> s.getGenusIndex()).sorted().toList(); + + int arrayIndex = 1; + for (int i = 0; i < sortedSpIndices.size(); i++) { + VdypSpecies genus = layer.getSpeciesByIndex(sortedSpIndices.get(i)); + + verifyBankSpeciesMatchesSpecies(lps, arrayIndex, genus); + + verifyBankUtilizationsMatchesUtilizations( + lps, arrayIndex, genus + ); + + arrayIndex += 1; + } + + verifyBankUtilizationsMatchesUtilizations(lps, 0, layer); + } + + private void verifyBankUtilizationsMatchesUtilizations( + Bank lps, int spIndex, VdypUtilizationHolder u + ) { + for (UtilizationClass uc : UtilizationClass.values()) { + assertThat(lps.basalAreas[spIndex][uc.index + 1], is(u.getBaseAreaByUtilization().get(uc))); + assertThat(lps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeByUtilization().get(uc))); + assertThat(lps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); + assertThat(lps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc))); + if (uc.index <= 0) { + assertThat(lps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeightByUtilization().get(uc))); + } + assertThat(lps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc))); + assertThat(lps.treesPerHectare[spIndex][uc.index + 1], is(u.getTreesPerHectareByUtilization().get(uc))); + assertThat(lps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolumeByUtilization().get(uc))); + } + } + + private void verifyBankSpeciesMatchesSpecies(Bank bank, int index, VdypSpecies species) { + assertThat(bank.sp64Distributions[index], is(species.getSp64DistributionSet())); + assertThat(bank.speciesIndices[index], is(species.getGenusIndex())); + assertThat(bank.speciesNames[index], is(species.getGenus())); + + species.getSite().ifPresentOrElse(site -> { + assertThat(bank.yearsAtBreastHeight[index], is(site.getYearsAtBreastHeight().get())); + assertThat(bank.ageTotals[index], is(site.getAgeTotal().get())); + assertThat(bank.dominantHeights[index], is(site.getHeight().get())); + assertThat(bank.siteIndices[index], is(site.getSiteIndex().get())); + assertThat(bank.yearsToBreastHeight[index], is(site.getYearsToBreastHeight().get())); + site.getSiteCurveNumber().ifPresentOrElse(scn -> { + assertThat(bank.siteCurveNumbers[index], is(scn)); + }, () -> { + assertThat(bank.siteCurveNumbers[index], is(VdypEntity.MISSING_INTEGER_VALUE)); + }); + assertThat(bank.speciesNames[index], is(site.getSiteGenus())); + }, + () -> { + assertThat(bank.yearsAtBreastHeight[index], is(VdypEntity.MISSING_FLOAT_VALUE)); + assertThat(bank.ageTotals[index], is(VdypEntity.MISSING_FLOAT_VALUE)); + assertThat(bank.dominantHeights[index], is(VdypEntity.MISSING_FLOAT_VALUE)); + assertThat(bank.siteIndices[index], is(VdypEntity.MISSING_FLOAT_VALUE)); + assertThat(bank.yearsToBreastHeight[index], is(VdypEntity.MISSING_FLOAT_VALUE)); + assertThat(bank.siteCurveNumbers[index], is(VdypEntity.MISSING_INTEGER_VALUE)); + }); + } +} diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index d5e6979c4..15e4a3886 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -376,13 +376,17 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.ESTIMATE_MISSING_SITE_INDICES); - var sourceSiteCurve = SiteIndexEquation.SI_CWC_KURUCZ; - var sourceSiteIndex = 13.4; - var targetSiteCurve = SiteIndexEquation.SI_HWC_WILEYAC; - double expectedValue = SiteTool - .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); + // Despite 13.40 being in the data stream, the change (2024/8/29) to ignore site information + // for all species of the layer except the primary means that method (1) will never be + // successful, since none of the non-primary species will have a site index value. + +// var sourceSiteCurve = SiteIndexEquation.SI_CWC_KURUCZ; +// var sourceSiteIndex = 13.4; +// var targetSiteCurve = SiteIndexEquation.SI_HWC_WILEYAC; +// double expectedValue = SiteTool +// .convertSiteIndexBetweenCurves(sourceSiteCurve, sourceSiteIndex, targetSiteCurve); - assertThat(fpe.fps.getLayerProcessingState().getBank().siteIndices[4], is((float) expectedValue)); + assertThat(fpe.fps.getLayerProcessingState().getBank().siteIndices[4], is(VdypEntity.MISSING_FLOAT_VALUE)); } @Test @@ -431,7 +435,7 @@ void testEstimateMissingYearsToBreastHeightValues() buildSpeciesParserForStream( "testSpecies.dat", // - "01002 S000001 00 1970 P 3 B B 100.0 0.0 0.0 0.0 -9.00 -9.00 15.0 11.0 -9.0 0 -9", // + "01002 S000001 00 1970 P 3 B B 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // "01002 S000001 00 1970 P 5 D D 100.0 0.0 0.0 0.0 35.00 35.30 55.0 54.0 1.0 1 13", // "01002 S000001 00 1970 P 8 H H 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // @@ -450,7 +454,7 @@ void testEstimateMissingYearsToBreastHeightValues() assertThat( fpe.fps.getLayerProcessingState().getBank().yearsToBreastHeight, - is(new float[] { 0.0f, 4.0f, 4.6f, 1.0f, 5.0f, 5.0f }) + is(new float[] { 0.0f, 4.7f, 4.6f, 1.0f, 5.0f, 5.0f }) ); } @@ -474,14 +478,12 @@ void testCalculateDominantHeightAgeSiteIndex() throws ProcessingException, IOExc var polygon = reader.readNextPolygon().orElseThrow(); + // Since the change to ignore site information for all but non-primary species, there is + // no way to successfully estimate age for a primary species from the non-primary species. ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX); - - assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesDominantHeight(), is(35.31195f)); - assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesSiteIndex(), is(34.0f)); - assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesTotalAge(), is(15.0f)); - assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesAgeAtBreastHeight(), is(14.0f)); - assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesAgeToBreastHeight(), is(1.0f)); + assertThrows(ProcessingException.class, () -> fpe.processPolygon(polygon, + ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX) + ); } @Test @@ -513,7 +515,7 @@ void testCalculateDominantHeightAgeSiteIndexNoSecondary() buildSpeciesParserForStream( "testSpecies.dat", // - "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 34.00 -9.00 22.0 -9.0 -9.0 0 -9", // + "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 34.00 -9.00 22.0 -9.0 -9.0 1 -9", // "01002 S000001 00 1970" ); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java index dfcfd5d20..430f3ac2b 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/PolygonProcessingStateTest.java @@ -3,29 +3,17 @@ 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.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; 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.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 PolygonProcessingStateTest { @@ -40,181 +28,4 @@ void before() throws IOException, ResourceParseException { controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.SP0_DEF, instanceOf(GenusDefinitionMap.class))); } - - @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()); - - Bank lps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - - int nSpecies = pLayer.getSpecies().size(); - - assertThat(lps, notNullValue()); - assertThat(lps.yearsAtBreastHeight.length, is(nSpecies + 1)); - assertThat(lps.ageTotals.length, is(nSpecies + 1)); - assertThat(lps.dominantHeights.length, is(nSpecies + 1)); - assertThat(lps.percentagesOfForestedLand.length, is(nSpecies + 1)); - assertThat(lps.siteIndices.length, is(nSpecies + 1)); - assertThat(lps.sp64Distributions.length, is(nSpecies + 1)); - assertThat(lps.speciesIndices.length, is(nSpecies + 1)); - assertThat(lps.speciesNames.length, is(nSpecies + 1)); - assertThat(lps.yearsToBreastHeight.length, is(nSpecies + 1)); - assertThat(lps.getNSpecies(), is(nSpecies)); - - assertThat(lps.basalAreas.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.basalAreas[i].length, is(UtilizationClass.values().length)); - } - assertThat(lps.closeUtilizationVolumes.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.closeUtilizationVolumes[i].length, is(UtilizationClass.values().length)); - } - assertThat(lps.cuVolumesMinusDecay.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.cuVolumesMinusDecay[i].length, is(UtilizationClass.values().length)); - } - assertThat(lps.cuVolumesMinusDecayAndWastage.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.cuVolumesMinusDecayAndWastage[i].length, is(UtilizationClass.values().length)); - } - - assertThat(lps.loreyHeights.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.loreyHeights[i].length, is(2)); - } - assertThat(lps.quadMeanDiameters.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.quadMeanDiameters[i].length, is(UtilizationClass.values().length)); - } - assertThat(lps.treesPerHectare.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.treesPerHectare[i].length, is(UtilizationClass.values().length)); - } - assertThat(lps.wholeStemVolumes.length, is(nSpecies + 1)); - for (int i = 0; i < nSpecies + 1; i++) { - assertThat(lps.wholeStemVolumes[i].length, is(UtilizationClass.values().length)); - } - } - - @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 lps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - - verifyProcessingStateMatchesLayer(lps, pLayer); - - Bank ppsCopy = lps.copy(); - - verifyProcessingStateMatchesLayer(ppsCopy, pLayer); - } - - @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()); - - Bank bank1 = new Bank( - pLayer, polygon.getBiogeoclimaticZone(), - s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 0.5 - ); - - // the filter should have removed genus B (index 3) since it's ALL basal area is below 0.5 - assertThat(bank1.getNSpecies(), is(pLayer.getSpecies().size() - 1)); - assertThat(bank1.speciesIndices, is(new int[] { 0, 4, 5, 8, 15 })); - - Bank bank2 = new Bank( - pLayer, polygon.getBiogeoclimaticZone(), - s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= 100.0 - ); - - // the filter should have removed all genera. - assertThat(bank2.getNSpecies(), is(0)); - assertThat(bank2.speciesIndices, is(new int[] { 0 })); - } - - @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 lps = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - - Bank ppsCopy = new Bank(lps, CopyMode.CopyAll); - - verifyProcessingStateMatchesLayer(ppsCopy, pLayer); - } - - private void verifyProcessingStateMatchesLayer(Bank lps, VdypLayer layer) { - - List sortedSpIndices = layer.getSpecies().values().stream().map(s -> s.getGenusIndex()).sorted().toList(); - - int arrayIndex = 1; - for (int i = 0; i < sortedSpIndices.size(); i++) { - VdypSpecies genus = layer.getSpeciesByIndex(sortedSpIndices.get(i)); - - verifyProcessingStateSpeciesMatchesSpecies(lps, arrayIndex, genus); - - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - lps, arrayIndex, genus - ); - - arrayIndex += 1; - } - - verifyProcessingStateSpeciesUtilizationsMatchesUtilizations(lps, 0, layer); - } - - private void verifyProcessingStateSpeciesUtilizationsMatchesUtilizations( - Bank lps, int spIndex, VdypUtilizationHolder u - ) { - - for (UtilizationClass uc : UtilizationClass.values()) { - assertThat(lps.basalAreas[spIndex][uc.index + 1], is(u.getBaseAreaByUtilization().get(uc))); - assertThat(lps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeByUtilization().get(uc))); - assertThat(lps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); - assertThat(lps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc))); - if (uc.index <= 0) { - assertThat(lps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeightByUtilization().get(uc))); - } - assertThat(lps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc))); - assertThat(lps.treesPerHectare[spIndex][uc.index + 1], is(u.getTreesPerHectareByUtilization().get(uc))); - assertThat(lps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolumeByUtilization().get(uc))); - } - } - - private void verifyProcessingStateSpeciesMatchesSpecies(Bank bank, int index, VdypSpecies species) { - VdypSite site = species.getSite().orElseThrow(); - - assertThat(bank.yearsAtBreastHeight[index], is(site.getYearsAtBreastHeight().get())); - assertThat(bank.ageTotals[index], is(site.getAgeTotal().get())); - assertThat(bank.dominantHeights[index], is(site.getHeight().get())); - assertThat(bank.siteIndices[index], is(site.getSiteIndex().get())); - assertThat(bank.sp64Distributions[index], is(species.getSp64DistributionSet())); - assertThat(bank.speciesIndices[index], is(species.getGenusIndex())); - assertThat(bank.speciesNames[index], is(species.getGenus())); - assertThat(bank.yearsToBreastHeight[index], is(site.getYearsToBreastHeight().get())); - } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java index 3b0419ee9..208fc83ea 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java @@ -1,6 +1,5 @@ package ca.bc.gov.nrs.vdyp.forward; -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.hasProperty; @@ -27,7 +26,6 @@ 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.test.TestUtils; @@ -78,13 +76,12 @@ void testReadPolygons() throws Exception { assertThat(species, hasProperty("layerType", is(layer.getLayerType()))); assertThat(species, hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier()))); - assertThat(species.getSite(), present(Matchers.anything())); - - VdypSite site = species.getSite().get(); - assertThat(site, allOf( - hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier())), - hasProperty("layerType", is(layer.getLayerType())) - )); + species.getSite().ifPresent(site -> { + assertThat(site, allOf( + hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier())), + hasProperty("layerType", is(layer.getLayerType())) + )); + }); } } } catch (ResourceParseException | IOException e) { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java index 30c0f16be..8d1c36cf0 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java @@ -2,6 +2,7 @@ import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.assertEmpty; import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.assertNext; +import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.notPresent; import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; @@ -27,6 +28,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypEntity; import ca.bc.gov.nrs.vdyp.model.VdypSpecies; import ca.bc.gov.nrs.vdyp.test.TestUtils; +import ca.bc.gov.nrs.vdyp.test.VdypMatchers; class VdypForwardSpeciesParserTest { @@ -93,8 +95,7 @@ void testParseOneGenus() throws Exception { allOf( hasProperty("polygonIdentifier", hasProperty("base", is("01002 S000001 00"))), hasProperty("polygonIdentifier", hasProperty("year", is(1970))), - hasProperty("layerType", is(LayerType.PRIMARY)), - hasProperty("genusIndex", is(15)), + hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genusIndex", is(15)), hasProperty("genus", is("S")), hasProperty( "sp64DistributionSet", @@ -109,16 +110,7 @@ void testParseOneGenus() throws Exception { ) ) ) - ), - hasProperty("site", present(allOf( - hasProperty("siteIndex", present(is(Float.NaN))), - hasProperty("siteGenus", is("S")), - hasProperty("height", present(is(Float.NaN))), - hasProperty("ageTotal", present(is(Float.NaN))), - hasProperty("yearsToBreastHeight", present(is(Float.NaN))), - hasProperty("layerType", is(LayerType.PRIMARY)), - hasProperty("siteCurveNumber", present(is(VdypEntity.MISSING_INTEGER_VALUE))) - ))) + ), hasProperty("site", VdypMatchers.notPresent()) ) ) ); @@ -205,13 +197,7 @@ void testParseComputesAgesWhenMissing() throws Exception { assertThat( genera, hasItems( - allOf( - hasProperty("layerType", is(LayerType.PRIMARY)), - hasProperty("site", present(allOf( - hasProperty("ageTotal", present(is(20.0f))), - // hasProperty("yearsAtBreastHeight", present(is(12.0f))), - hasProperty("yearsToBreastHeight", present(is(8.0f))) - )))), + allOf(hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("site", notPresent())), allOf( hasProperty( "sp64DistributionSet", @@ -234,13 +220,8 @@ void testParseComputesAgesWhenMissing() throws Exception { ) ) ) - ), - hasProperty("layerType", is(LayerType.VETERAN)), - hasProperty("site", present(allOf( - hasProperty("ageTotal", present(is(12.0f))), - // hasProperty("yearsAtBreastHeight", present(is(8.0f))), - hasProperty("yearsToBreastHeight", present(is(4.0f)))) - ))), + ), hasProperty("layerType", is(LayerType.VETERAN)), hasProperty("site", notPresent()) + ), allOf( hasProperty( "sp64DistributionSet", @@ -277,21 +258,26 @@ void testParseComputesAgesWhenMissing() throws Exception { ) ) ) - ), - hasProperty("layerType", is(LayerType.VETERAN)), - hasProperty("site", present(allOf( - hasProperty("ageTotal", present(is(14.0f))), - // hasProperty("yearsAtBreastHeight", present(is(8.0f))), - hasProperty("yearsToBreastHeight", present(is(6.0f))) - )) + ), hasProperty("layerType", is(LayerType.VETERAN)), + hasProperty( + "site", present( + allOf( + hasProperty("ageTotal", present(is(14.0f))), + // hasProperty("yearsAtBreastHeight", present(is(8.0f))), + hasProperty("yearsToBreastHeight", present(is(6.0f))) + ) + ) ) ) ) ); - assertThat(genera.stream().map(s -> s.getSite().get().getYearsAtBreastHeight()).toList(), - hasItems(present(is(12.0f)), present(is(8.0f)), present(is(8.0f)))); - + assertThat( + genera.stream().filter(s -> s.getSite().isPresent()) + .map(s -> s.getSite().get().getYearsAtBreastHeight()).toList(), + hasItems(present(is(8.0f))) + ); + assertEmpty(stream); } @@ -308,7 +294,7 @@ void testParseTwoGenera() throws Exception { var fileResolver = TestUtils.fileResolver( "test.dat", TestUtils.makeInputStream( - "01002 S000002 00 1970 P 15 S S 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0 0 -9", // + "01002 S000002 00 1970 P 15 S S 100.0 0.0 0.0 0.0 14.50 -9.00 -9.0 -9.0 -9.0 1 -9", // "01002 S000002 00 1970 V 3 B B 50.0 S 50.0 0.0 0.0 -9.00 -9.00 -9.0 -9.0 -9.0", // "01002 S000002 00 1970" // ) @@ -333,8 +319,7 @@ void testParseTwoGenera() throws Exception { allOf( hasProperty("polygonIdentifier", hasProperty("base", is("01002 S000002 00"))), hasProperty("polygonIdentifier", hasProperty("year", is(1970))), - hasProperty("layerType", is(LayerType.PRIMARY)), - hasProperty("genusIndex", is(15)), + hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genusIndex", is(15)), hasProperty("genus", is("S")), hasProperty( "sp64DistributionSet", @@ -350,21 +335,28 @@ void testParseTwoGenera() throws Exception { ) ) ), - hasProperty("site", present(allOf( - hasProperty("siteIndex", present(is(Float.NaN))), - hasProperty("siteGenus", is("S")), - hasProperty("height", present(is(Float.NaN))), - hasProperty("ageTotal", present(is(Float.NaN))), - hasProperty("yearsToBreastHeight", present(is(Float.NaN))), - hasProperty("layerType", is(LayerType.PRIMARY)), - hasProperty("siteCurveNumber", present(is(VdypEntity.MISSING_INTEGER_VALUE))) - ))) + hasProperty( + "site", + present( + allOf( + hasProperty("siteIndex", present(is(14.50f))), + hasProperty("siteGenus", is("S")), + hasProperty("height", present(is(Float.NaN))), + hasProperty("ageTotal", present(is(Float.NaN))), + hasProperty("yearsToBreastHeight", present(is(Float.NaN))), + hasProperty("layerType", is(LayerType.PRIMARY)), + hasProperty( + "siteCurveNumber", + present(is(VdypEntity.MISSING_INTEGER_VALUE)) + ) + ) + ) + ) ), allOf( hasProperty("polygonIdentifier", hasProperty("base", is("01002 S000002 00"))), hasProperty("polygonIdentifier", hasProperty("year", is(1970))), - hasProperty("layerType", is(LayerType.VETERAN)), - hasProperty("genusIndex", is(3)), + hasProperty("layerType", is(LayerType.VETERAN)), hasProperty("genusIndex", is(3)), hasProperty("genus", is("B")), hasProperty( "sp64DistributionSet", @@ -389,16 +381,7 @@ void testParseTwoGenera() throws Exception { ) ) ) - ), - hasProperty("site", present(allOf( - hasProperty("siteIndex", present(is(Float.NaN))), - hasProperty("siteGenus", is("B")), - hasProperty("height", present(is(Float.NaN))), - hasProperty("ageTotal", present(is(Float.NaN))), - hasProperty("yearsAtBreastHeight", present(is(Float.NaN))), - hasProperty("layerType", is(LayerType.VETERAN)), - hasProperty("siteCurveNumber", present(is(VdypEntity.MISSING_INTEGER_VALUE))) - ))) + ), hasProperty("site", notPresent()) ) ) ); From 2e8f9f2b04e22b7d31b29050dbb42465d07b2574 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Sat, 31 Aug 2024 15:26:13 -0700 Subject: [PATCH 42/66] Added GrowLoreyHeightsTest --- ...est.java => ForwardPolygonParserTest.java} | 2 +- ...nTest.java => ForwardReadPolygonTest.java} | 2 +- ...est.java => ForwardSpeciesParserTest.java} | 2 +- ...java => ForwardUtilizationParserTest.java} | 2 +- .../nrs/vdyp/forward/GrowBasalAreaTest.java | 10 +- .../vdyp/forward/GrowLoreyHeightsTest.java | 108 ++++++++++++++++++ 6 files changed, 116 insertions(+), 10 deletions(-) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{VdypForwardPolygonParserTest.java => ForwardPolygonParserTest.java} (99%) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{VdypForwardReadPolygonTest.java => ForwardReadPolygonTest.java} (99%) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{VdypForwardSpeciesParserTest.java => ForwardSpeciesParserTest.java} (99%) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{VdypForwardUtilizationParserTest.java => ForwardUtilizationParserTest.java} (99%) create mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardPolygonParserTest.java similarity index 99% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardPolygonParserTest.java index 43388f9be..44008575d 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardPolygonParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardPolygonParserTest.java @@ -23,7 +23,7 @@ import ca.bc.gov.nrs.vdyp.test.TestUtils; import ca.bc.gov.nrs.vdyp.test.VdypMatchers; -class VdypForwardPolygonParserTest { +class ForwardPolygonParserTest { @Test void testParseEmpty() throws Exception { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java similarity index 99% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java index 208fc83ea..173c7abe4 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardReadPolygonTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java @@ -30,7 +30,7 @@ import ca.bc.gov.nrs.vdyp.test.TestUtils; @SuppressWarnings({ "unchecked" }) -class VdypForwardReadPolygonTest { +class ForwardReadPolygonTest { @Test void testReadPolygons() throws Exception { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardSpeciesParserTest.java similarity index 99% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardSpeciesParserTest.java index 8d1c36cf0..143809bcf 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardSpeciesParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardSpeciesParserTest.java @@ -30,7 +30,7 @@ import ca.bc.gov.nrs.vdyp.test.TestUtils; import ca.bc.gov.nrs.vdyp.test.VdypMatchers; -class VdypForwardSpeciesParserTest { +class ForwardSpeciesParserTest { @Test void testParseEmpty() throws Exception { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardUtilizationParserTest.java similarity index 99% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardUtilizationParserTest.java index 95aa84253..f9ddebc43 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardUtilizationParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardUtilizationParserTest.java @@ -27,7 +27,7 @@ import ca.bc.gov.nrs.vdyp.model.VdypUtilization; import ca.bc.gov.nrs.vdyp.test.TestUtils; -public class VdypForwardUtilizationParserTest { +public class ForwardUtilizationParserTest { @Test void testParseEmpty() throws Exception { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java index d7b8b4ce1..551bd70be 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java @@ -15,7 +15,6 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; -import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -64,7 +63,7 @@ void testStandardPath() throws ProcessingException { float ba = 45.3864441f; float growthInHd = 0.173380271f; - float gba = fpe.growBasalArea(yabh, fpe.fps.fcm.getDebugSettings(), hd, ba, Optional.empty(), growthInHd); + float gba = fpe.growBasalArea(yabh, hd, ba, Optional.empty(), growthInHd); assertThat(gba, is(0.35185286f)); } @@ -84,7 +83,7 @@ void testYoungPath() throws ProcessingException { float ba = 200.0f; float growthInHd = 0.173380271f; - float gba = fpe.growBasalArea(yabh, fpe.fps.fcm.getDebugSettings(), hd, ba, Optional.empty(), growthInHd); + float gba = fpe.growBasalArea(yabh, hd, ba, Optional.empty(), growthInHd); assertThat(gba, is(0.0f)); } @@ -104,10 +103,9 @@ void testDebugSettings3EqualsZeroPath() throws ProcessingException { float ba = 45.3864441f; float hdDelta = 0.173380271f; - ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); - debugSettings.setValue(Vars.BASAL_AREA_GROWTH_MODEL_3, 0); + fpe.fps.fcm.getDebugSettings().setValue(Vars.BASAL_AREA_GROWTH_MODEL_3, 0); - float gba = fpe.growBasalArea(yabh, debugSettings, hd, ba, Optional.empty(), hdDelta); + float gba = fpe.growBasalArea(yabh, hd, ba, Optional.empty(), hdDelta); assertThat(gba, is(-0.10392746f)); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java new file mode 100644 index 000000000..6f13f5766 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java @@ -0,0 +1,108 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; + +class GrowLoreyHeightsTest { + + protected static final Logger logger = LoggerFactory.getLogger(GrowLoreyHeightsTest.class); + + protected static ForwardControlParser parser; + protected static Map controlMap; + + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; + + protected static ForwardDataStreamReader forwardDataStreamReader; + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeTest() throws IOException, ResourceParseException, ProcessingException { + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + .get(ControlKey.FORWARD_INPUT_GROWTO.name()); + polygonDescriptionStream = polygonDescriptionStreamFactory.get(); + + forwardDataStreamReader = new ForwardDataStreamReader(controlMap); + } + + @Test + void testStandardPath() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); + + float dhStart = 35.3f; + float dhEnd = 35.473381f; + float pspTphStart = 290.61615f; + float pspTphEnd = 287.107788f; + float pspLhStart = 33.7439995f; + + fpe.growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); + + // Results are stored in bank.loreyHeights[1..nSpecies] + assertThat(lps.getIndices().length, is(5)); + assertThat(lps.getBank().loreyHeights[1][UtilizationClass.ALL.ordinal()], is(36.9653244f)); + assertThat(lps.getBank().loreyHeights[2][UtilizationClass.ALL.ordinal()], is(23.03769f)); + assertThat(lps.getBank().loreyHeights[3][UtilizationClass.ALL.ordinal()], is(33.930603f)); + assertThat(lps.getBank().loreyHeights[4][UtilizationClass.ALL.ordinal()], is(22.8913193f)); + assertThat(lps.getBank().loreyHeights[5][UtilizationClass.ALL.ordinal()], is(32.2539024f)); + } + + @Test + void testDebug8Setting2Path() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); + + float dhStart = 35.3f; + float dhEnd = 35.3f; + float pspTphStart = 290.61615f; + float pspTphEnd = 287.107788f; + float pspLhStart = 33.7439995f; + + fpe.fps.fcm.getDebugSettings().setValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8, 2); + + fpe.growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); + + // Results are stored in bank.loreyHeights[1..nSpecies] + assertThat(lps.getIndices().length, is(5)); + assertThat(lps.getBank().loreyHeights[1][UtilizationClass.ALL.ordinal()], is(36.7552986f)); + assertThat(lps.getBank().loreyHeights[2][UtilizationClass.ALL.ordinal()], is(22.9584007f)); + assertThat(lps.getBank().loreyHeights[3][UtilizationClass.ALL.ordinal()], is(33.7439995f)); + assertThat(lps.getBank().loreyHeights[4][UtilizationClass.ALL.ordinal()], is(22.7703991f)); + assertThat(lps.getBank().loreyHeights[5][UtilizationClass.ALL.ordinal()], is(32.0125008f)); + } +} From ba7c23f2291338ed710b56ad568838aea70501a6 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Sat, 31 Aug 2024 15:26:26 -0700 Subject: [PATCH 43/66] Added ZipFileResolver --- .../application/VdypStartApplication.java | 29 ++-- .../ca/bc/gov/nrs/vdyp/io/FileResolver.java | 4 + .../nrs/vdyp/io/FileSystemFileResolver.java | 1 + .../nrs/vdyp/io/ZipOutputFileResolver.java | 109 +++++++++++++++ .../ca/bc/gov/nrs/vdyp/model/VdypEntity.java | 5 +- .../vdyp/io/ZipOutputFileResolverTest.java | 49 +++++++ .../ca/bc/gov/nrs/vdyp/test/TestUtils.java | 6 + .../vdyp/forward/ForwardProcessingEngine.java | 128 ++++++++++-------- .../nrs/vdyp/forward/ForwardProcessor.java | 19 +-- .../vdyp/forward/VdypForwardApplication.java | 2 +- .../vdyp/forward/ForwardProcessorTest.java | 29 +++- 11 files changed, 292 insertions(+), 89 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java create mode 100644 vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index 9a6725adc..d839e89a8 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -1457,44 +1457,37 @@ protected void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefin var adjust = new Coefficients(new float[] { 0f, 0f, 0f, 0f }, 1); // EMP091 - EstimationMethods.estimateWholeStemVolume( - controlMap, utilizationClass, volumeAdjustCoe.getCoe(1), vdypSpecies.getVolumeGroup(), hlSp, + estimationMethods.estimateWholeStemVolume( + 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, + estimationMethods.estimateCloseUtilizationVolume( + utilizationClass, adjust, vdypSpecies.getVolumeGroup(), hlSp, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationVolumeUtil ); adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); // EMP093 - EstimationMethods.estimateNetDecayVolume( - controlMap, vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, + estimationMethods.estimateNetDecayVolume( + 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.>expectParsedControl( - controlMap, ControlKey.VOLUME_NET_DECAY_WASTE, java.util.Map.class - ); - final var wasteModifierMap = Utils.>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 + estimationMethods.estimateNetDecayAndWasteVolume( + bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, quadMeanDiameterUtil, + closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil ); if (getId().isStart()) { // EMP095 - EstimationMethods.estimateNetDecayWasteAndBreakageVolume( - controlMap, utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, + estimationMethods.estimateNetDecayWasteAndBreakageVolume( + utilizationClass, vdypSpecies.getBreakageGroup(), quadMeanDiameterUtil, closeUtilizationVolumeUtil, closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil ); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java index ad7ad690e..6b6825c2c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java @@ -3,14 +3,18 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Path; public interface FileResolver { + InputStream resolveForInput(String filename) throws IOException; OutputStream resolveForOutput(String filename) throws IOException; String toString(String filename) throws IOException; + Path toPath(String filename) throws IOException; + /** * Create a FileResolver that resolves relative to a given path * diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java index c1065943b..feaf48c28 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileSystemFileResolver.java @@ -19,6 +19,7 @@ public FileSystemFileResolver() { this.currentDirectory = Optional.empty(); } + @Override public Path toPath(String filename) { return currentDirectory.map(x -> x.resolve(filename)).orElseGet(() -> Path.of(filename).toAbsolutePath()); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java new file mode 100644 index 000000000..32f3ab384 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java @@ -0,0 +1,109 @@ +package ca.bc.gov.nrs.vdyp.io; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class ZipOutputFileResolver implements FileResolver { + + private record OutputStreamDetails(Path outputStreamLocation, OutputStream outputStream) {}; + + private Map entryOutputStreams = new HashMap<>(); + + @Override + public Path toPath(String filename) { + return Path.of(filename).toAbsolutePath(); + } + + @Override + public InputStream resolveForInput(String filename) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public OutputStream resolveForOutput(String filename) throws IOException { + Path tempFile = Files.createTempFile("vdyp", filename); + OutputStream entryOutputStream = Files.newOutputStream(tempFile); + entryOutputStreams.put(filename, new OutputStreamDetails(tempFile, entryOutputStream)); + + return entryOutputStream; + } + + @Override + public String toString(String filename) throws IOException { + return String.format("zip:%s", toPath(filename)); + } + + @Override + public ZipOutputFileResolver relative(String path) throws IOException { + throw new UnsupportedOperationException(); + } + + private static final int BUFFER_SIZE = 64 * 1024; + + public void generate(Path zipFile) throws IOException { + try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile.toFile()))) { + + for (Map.Entry e: entryOutputStreams.entrySet()) { + close(e.getValue().outputStream); + + ZipEntry entry = new ZipEntry(e.getKey()); + try (InputStream entryReader = Files.newInputStream(e.getValue().outputStreamLocation, StandardOpenOption.READ)) { + zipOutputStream.putNextEntry(entry); + + byte[] cBuffer = new byte[BUFFER_SIZE]; + int nCharsRead = entryReader.read(cBuffer, 0, BUFFER_SIZE); + while (nCharsRead >= 0) { + zipOutputStream.write(cBuffer, 0, nCharsRead); + nCharsRead = entryReader.read(cBuffer, 0, BUFFER_SIZE); + } + } finally { + zipOutputStream.closeEntry(); + } + } + } + } + + public InputStream generateStream() throws IOException { + + Path tempFile = Files.createTempFile("vdypOutputZipFile", ".zip"); + + try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(tempFile.toFile()))) { + for (Map.Entry e: entryOutputStreams.entrySet()) { + close(e.getValue().outputStream); + + ZipEntry entry = new ZipEntry(e.getKey()); + try (InputStream entryReader = Files.newInputStream(e.getValue().outputStreamLocation, StandardOpenOption.READ)) { + zipOutputStream.putNextEntry(entry); + + byte[] cBuffer = new byte[BUFFER_SIZE]; + int nCharsRead = entryReader.read(cBuffer, 0, BUFFER_SIZE); + while (nCharsRead >= 0) { + zipOutputStream.write(cBuffer, 0, nCharsRead); + nCharsRead = entryReader.read(cBuffer, 0, BUFFER_SIZE); + } + } finally { + zipOutputStream.closeEntry(); + } + } + } + + return Files.newInputStream(tempFile); + } + + private static void close(OutputStream os) { + try { + os.close(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } +} \ No newline at end of file diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java index d71c16d6c..d451bcf25 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java @@ -1,6 +1,9 @@ package ca.bc.gov.nrs.vdyp.model; public interface VdypEntity { + /** This indicates "not set" for a Float */ Float MISSING_FLOAT_VALUE = Float.NaN; - Integer MISSING_INTEGER_VALUE = Integer.MIN_VALUE; + + /** This is a "special" magic number indicating "not set" for an Integer value - a legacy of VDYP 7 */ + Integer MISSING_INTEGER_VALUE = -9; } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java new file mode 100644 index 000000000..d2574de8a --- /dev/null +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -0,0 +1,49 @@ +package ca.bc.gov.nrs.vdyp.io; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.junit.jupiter.api.Test; + +public class ZipOutputFileResolverTest { + + @Test + void testZipOutputFileResolver() throws IOException { + + ZipOutputFileResolver resolver = new ZipOutputFileResolver(); + + for (int i = 0; i < 5; i++) { + OutputStream os = resolver.resolveForOutput("file" + i); + os.write(String.format("%d", i).getBytes()); + } + + Path zipFile = Files.createTempFile(this.getClass().getName(), ".zip"); + + resolver.generate(zipFile); + + System.out.println("Output zip file written to " + zipFile.toString()); + + try (ZipFile zip = new ZipFile(zipFile.toFile())) { + var entries = zip.entries(); + + byte[] buffer = new byte[16]; + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); + + InputStream is = zip.getInputStream(e); + int nBytesRead = is.read(buffer, 0, 10); + assertTrue(nBytesRead == 1); + String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); + assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); + } + } + } +} diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java index 78b1a04fb..1a87fa688 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -400,6 +401,11 @@ public FileResolver relative(String path) throws IOException { return null; } + @Override + public Path toPath(String filename) throws IOException { + return Path.of(toString(filename)); + } + }; } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 551cf3829..4d50ea6bb 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -276,6 +276,7 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int stoppi polygonLayers.put(LayerType.PRIMARY, updatedLayer); logger.atInfo().addArgument(updatedLayer.getBaseAreaByUtilization().toString()).log("{}"); + // Store polygon (both primary and veteran layers) to output writePolygon(vdypPolygon, startingYear, currentYear, stoppingYearInclusive); @@ -329,27 +330,30 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float lhStart = bank.loreyHeights[0][UC_ALL_INDEX]; float baDelta = growBasalArea( - pspYabhStart, fps.fcm.getDebugSettings(), dhStart, baStart, veteranLayerBasalArea, dhDelta + pspYabhStart, dhStart, baStart, veteranLayerBasalArea, dhDelta ); // (3) Calculate change in quad-mean-diameter (layer) Reference wasDqGrowthLimitApplied = new Reference<>(); float dqDelta = growQuadMeanDiameter( - pspYtbhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied + pspYabhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied ); - if (wasDqGrowthLimitApplied.get() /* is true */) { + int debugSetting9Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9); + if (debugSetting9Value == 1 && wasDqGrowthLimitApplied.get() /* is true */) { // Limit BA growth if DQ hit limit. float dqEnd = dqStart + dqDelta; float baEndMax = baStart * (dqEnd * dqEnd) / (dqStart * dqStart); baDelta = Math.min(baDelta, baEndMax - baStart); } - // Cache some values for calculations below. - float baChangeRate = baDelta / baStart; + // (4) Begin storing computed results - dq, ba and tph for the layer + + // Cache some values for calculations below. + float pspLhStart = bank.loreyHeights[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; float pspTphStart = bank.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; @@ -359,33 +363,40 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float tphEnd = BaseAreaTreeDensityDiameter.treesPerHectare(baEnd, dqEnd); float tphMultiplier = tphEnd / tphStart; - // (4) Begin storing computed results - dq, ba and tph for the layer - bank.quadMeanDiameters[0][UC_ALL_INDEX] = dqEnd; bank.basalAreas[0][UC_ALL_INDEX] = baEnd; bank.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; - // (5) Now do DQ growth by species, using one of several options: "full species", "dynamic", - // "partial dynamics" or "no dynamics." + // (5) Now calculate per-species (UC All only) end values for basal area, quad-mean-diameter + // and trees-per-hectare, using one of several options: "full species dynamics", + // "partial species dynamics" or "no species dynamics." + int debugSetting1Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1); boolean wasSolutionFound = false; if (debugSetting1Value == 2) { // (5a) This is the PARTIAL SPECIES DYNAMICS section. - // (5a1) Begin by updating HL for all species + // (5a1) Begin by updating HL for all species (UC All only), as well + // as the per-layer value (UC All). - // First save the ungrown HLs - float[] startingLoreyHeights = new float[bank.getNSpecies() + 1]; - startingLoreyHeights[0] = bank.loreyHeights[0][UC_ALL_INDEX]; + // First save the at-start Lorey Height values, needed for the - they will be restored + // below and re-calculated later once more precise information is known. + + float[] lhAtStart = new float[bank.getNSpecies() + 1]; + lhAtStart[0] = bank.loreyHeights[0][UC_ALL_INDEX]; for (int i : bank.getIndices()) { - startingLoreyHeights[i] = bank.loreyHeights[i][UC_ALL_INDEX]; + lhAtStart[i] = bank.loreyHeights[i][UC_ALL_INDEX]; } + // Compute the per-species Lorey Height estimates. + float pspTphEndEstimate = pspTphStart * (tphEnd / tphStart); growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEndEstimate, pspLhStart); + // Calculate the per-site Lorey Height estimate. + float sum1 = 0.0f; float sum2 = 0.0f; @@ -396,34 +407,38 @@ private void grow(LayerProcessingState lps, int currentYear, Optional bank.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; - // Now do the actual updates of DQ by species + // Now do the actual per-species updates of ba, qmd and tph, based in part + // on both the starting Lorey Heights and the estimated Lorey Heights at the + // end of the growth period. + wasSolutionFound = growUsingPartialSpeciesDynamics( - dqDelta, baDelta, baStart, dqStart, tphStart, startingLoreyHeights + baStart, baDelta, dqStart, dqDelta, tphStart, lhAtStart ); // Restore the Lorey Heights back to the values at the beginning of the period. // They will be updated below using the new estimate of TPH-primary species. - for (int i = 1; i < bank.getNSpecies(); i++) { - bank.loreyHeights[i][UC_ALL_INDEX] = startingLoreyHeights[i]; + + for (int i = 0; i < bank.getNSpecies(); i++) { + bank.loreyHeights[i][UC_ALL_INDEX] = lhAtStart[i]; } } - // (6) Calculate the basal area, trees-per-hectare and quad-mean-diameter for all - // species in the polygon (UC All) - if (!wasSolutionFound) { + // Calculate the basal area, trees-per-hectare and quad-mean-diameter for all + // species in the polygon (UC All) + if (debugSetting1Value == 1 || bank.getNSpecies() == 1) { - // This is the NO SPECIES DYNAMICS section + // (5b) This is the NO SPECIES DYNAMICS section growUsingNoSpeciesDynamics(baChangeRate, tphMultiplier); } else { - // This is the FULL SPECIES DYNAMICS section - growUsingFullSpeciesDynamics(dqDelta, baDelta, baStart, dqStart, tphStart, lhStart); + // (5c) This is the FULL SPECIES DYNAMICS section + growUsingFullSpeciesDynamics(baStart, baDelta, dqStart, dqDelta, tphStart, lhStart); } } - // (7) Calculate layer trees-per-hectare, uc All + // (6) Calculate layer trees-per-hectare, UC All float tphEndSum = 0.0f; for (int i : bank.getIndices()) { @@ -433,13 +448,13 @@ private void grow(LayerProcessingState lps, int currentYear, Optional } bank.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; - // (8) Calculate layer quad-mean-diameter, uc All + // (7) Calculate layer quad-mean-diameter, uc All bank.quadMeanDiameters[0][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter( bank.basalAreas[0][UC_ALL_INDEX], bank.treesPerHectare[0][UC_ALL_INDEX] ); - // (9) Calculate layer Lorey heights over all species, uc UC_ALL_INDEX + // (8) Calculate layer Lorey heights over all species, uc UC_ALL_INDEX float pspTphEnd = bank.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); @@ -447,13 +462,13 @@ private void grow(LayerProcessingState lps, int currentYear, Optional // We now have site (layer) level predications for basal area, quad-mean-diameter, // trees-per-hectare and Lorey height. Proceed to per-species estimates. - // (10) Calculate basal area percentages per species, uc UC_ALL_INDEX + // (9) Calculate basal area percentages per species, uc UC_ALL_INDEX for (int i : bank.getIndices()) { bank.percentagesOfForestedLand[i] = 100.0f * bank.basalAreas[i][UC_ALL_INDEX] / bank.basalAreas[0][UC_ALL_INDEX]; } - // (11) Update the running values. TODO: why isn't siteIndex being updated? + // (10) Update the running values. TODO: why isn't siteIndex being updated? lps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); for (int i = 1; i < bank.getNSpecies(); i++) { @@ -481,10 +496,10 @@ private void grow(LayerProcessingState lps, int currentYear, Optional } } - // (12) update the compatibility variables to reflect the changes during the growth period + // (11) update the compatibility variables to reflect the changes during the growth period lps.updateCompatibilityVariablesAfterGrowth(); - // (13) calculate All and the large component volumes to reflect the changes in growth + // (12) calculate All and the large component volumes to reflect the changes in growth VdypLayer primaryLayer = lps.getLayer(); @@ -495,7 +510,7 @@ private void grow(LayerProcessingState lps, int currentYear, Optional bank.refreshBank(primaryLayer); - // (14) calculate the small component volumes to reflect the changes in growth + // (13) calculate the small component volumes to reflect the changes in growth calculateSmallComponentYields(lps); } @@ -566,20 +581,20 @@ private record AdjustmentParameters( * GRSPpart - calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare * and quad-mean-diameter at the end of the growth period for all species in the polygon. * - * @param dqDelta change in overall quad-mean-diameter during the growth period - * @param baDelta change in overall basal area during the growth period * @param baStart overall basal area at start of growth period + * @param baDelta change in overall basal area during the growth period * @param dqStart overall quad-mean-diameter at start of growth period + * @param dqDelta change in overall quad-mean-diameter during the growth period * @param tphStart overall trees-per-hectare value at the start of growth period - * @param currentLoreyHeights the current Lorey heights of each of the species - * (indices 1 - # species) | overall (index 0) the start of the growth period + * @param lhAtStart stand and per-species (UC All) Lorey heights at the start of the growth period + * index 0 - stand; indices 1 - # species for the individual species * * @return true if and only if a solution was found. * @throws ProcessingException */ private boolean growUsingPartialSpeciesDynamics( - float dqDelta, float baDelta, float baStart, float dqStart, - float tphStart, float[] currentLoreyHeights + float baStart, float baDelta, float dqStart, float dqDelta, + float tphStart, float[] lhAtStart ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); @@ -622,25 +637,25 @@ private boolean growUsingPartialSpeciesDynamics( dqs1[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( bank.speciesNames[i], - bank.basalAreas[i][0], - bank.quadMeanDiameters[i][0], + lhAtStart[i], + bank.quadMeanDiameters[i][UC_ALL_INDEX], basalAreaPercentagesPerSpecies, lps.getBecZone().getRegion(), dqStart, baStart, tphStart, - currentLoreyHeights[0]); + lhAtStart[0]); dqs2[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( bank.speciesNames[i], - baNew[0], + bank.loreyHeights[i][UC_ALL_INDEX], dqNew[0], basalAreaPercentagesPerSpecies, lps.getBecZone().getRegion(), - dqStart, - baStart, - tphStart, - bank.loreyHeights[i][0]); + dqNew[0], + baNew[0], + tphNew[0], + bank.loreyHeights[0][UC_ALL_INDEX]); } float[] dqLowerBoundBySpecies = new float[lps.getNSpecies() + 1]; @@ -889,16 +904,16 @@ private boolean growUsingPartialSpeciesDynamics( /** * Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth * during the growth period. The result is stored in end, Utilization Class ALL. - * @param dqDelta per-layer change in quad-mean-diameter during growth period - * @param baDelta per-layer change in basal area during growth period * @param baStart per-layer basal area at start of growth period + * @param baDelta per-layer change in basal area during growth period * @param dqStart per-layer quad-mean-diameter at the start of growth period + * @param dqDelta per-layer change in quad-mean-diameter during growth period * @param tphStart per-layer trees-per-breast-height at that of growth period * @param lhStart per-layer Lorey height at the start of the growth period * @throws ProcessingException */ private void growUsingFullSpeciesDynamics( - float dqDelta, float baDelta, float baStart, float dqStart, float tphStart, + float baStart, float baDelta, float dqStart, float dqDelta, float tphStart, float lhStart ) throws ProcessingException { @@ -1445,7 +1460,7 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc * @param pspTphEnd primary species trees-per-hectare at end * @param pspLhStart primary species Lorey height at end */ - private void growLoreyHeights( + void growLoreyHeights( LayerProcessingState lps, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart ) { Bank bank = lps.getBank(); @@ -1482,7 +1497,7 @@ private void growLoreyHeights( ); float otherF = (bank.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (spLhEstimate1 - 1.3f); - otherF = 1.0f - (otherF - 1.0f) * nonPrimaryLhAdjustment; + otherF = 1.0f + (otherF - 1.0f) * nonPrimaryLhAdjustment; bank.loreyHeights[i][UC_ALL_INDEX] = 1.3f + (spLhEstimate2 - 1.3f) * otherF; } } @@ -1559,16 +1574,18 @@ private float estimateNonPrimarySpeciesLoreyHeight( } /** - * EMP117 - Quad Mean Diameter growth for the primary layer. + * EMP117A - Calculate and return the change in quad-mean-diameter for the primary layer over + * the growth period. * * @param pspYabhStart primary species years at breast height (age) at start of growth period + * @param baStart layer basal area at start of growth period * @param dhStart layer dominant height (i.e., the height of the primary species) at start of growth period * @param dqStart layer quad-mean-diameter at start of growth period * @param veteranBaStart veteran layer basal area at start of growth period * @param veteranBaEnd veteran layer basal area at end of growth period * @param dhDelta growth in dominant height during growth period * - * @return growth in quad-mean-diameter for the year. This may be negative. + * @return growth in quad-mean-diameter for the growth period. This may be negative. * * @throws StandProcessingException */ @@ -1780,10 +1797,11 @@ private float[] getSpeciesProportionsByBasalAreaAtStartOfYear() { * @throws StandProcessingException in the event of an error */ float growBasalArea( - float pspYabhStart, ForwardDebugSettings debugSettings, float pspDhStart, - float baStart, Optional veteranLayerBaStart, float dhDelta + float pspYabhStart, float pspDhStart, float baStart, Optional veteranLayerBaStart, + float dhDelta ) throws StandProcessingException { + ForwardDebugSettings debugSettings = fps.fcm.getDebugSettings(); LayerProcessingState lps = fps.getLayerProcessingState(); Bank bank = lps.getBank(); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index 22896b385..294da2695 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -54,14 +54,15 @@ public class ForwardProcessor { /** * Initialize VdypForwardProcessor * - * @param resolver + * @param inputFileResolver + * @param outputFileResolver * @param controlFileNames * * @throws IOException * @throws ResourceParseException * @throws ProcessingException */ - void run(FileResolver resolver, List controlFileNames, Set vdypPassSet) + void run(FileResolver inputFileResolver, FileResolver outputFileResolver, List controlFileNames, Set vdypPassSet) throws IOException, ResourceParseException, ProcessingException { logger.info("VDYPPASS: {}", vdypPassSet); @@ -77,24 +78,18 @@ void run(FileResolver resolver, List controlFileNames, Set var parser = new ForwardControlParser(); - Optional outputFileResolver = Optional.empty(); - for (var controlFileName : controlFileNames) { logger.info("Resolving and parsing {}", controlFileName); - try (var is = resolver.resolveForInput(controlFileName)) { - Path controlFilePath = Path.of(resolver.toString(controlFileName)).getParent(); + try (var is = inputFileResolver.resolveForInput(controlFileName)) { + Path controlFilePath = inputFileResolver.toPath(controlFileName).getParent(); FileSystemFileResolver relativeResolver = new FileSystemFileResolver(controlFilePath); parser.parse(is, relativeResolver, controlMap); - - if (controlMap.containsKey(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name())) { - outputFileResolver = Optional.of(relativeResolver); - } } } - process(vdypPassSet, controlMap, outputFileResolver); + process(vdypPassSet, controlMap, Optional.of(outputFileResolver)); } /** @@ -103,7 +98,7 @@ void run(FileResolver resolver, List controlFileNames, Set * * @throws ProcessingException */ - public void process(Set vdypPassSet, Map controlMap, Optional outputFileResolver) throws ProcessingException { + public void process(Set vdypPassSet, Map controlMap, Optional outputFileResolver) throws ProcessingException { logger.info("Beginning processing with given configuration"); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java index 5f79d2e59..030fea132 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/VdypForwardApplication.java @@ -80,7 +80,7 @@ public static void main(final String... args) { try { ForwardProcessor processor = new ForwardProcessor(); - processor.run(new FileSystemFileResolver(), controlFileNames, vdypPassSet); + processor.run(new FileSystemFileResolver(), new FileSystemFileResolver(), controlFileNames, vdypPassSet); } catch (Exception ex) { logger.error("Error during processing", ex); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index a5d3a401a..a5ac3ca35 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -5,8 +5,13 @@ import static ca.bc.gov.nrs.vdyp.forward.ForwardPass.PASS_3; import static ca.bc.gov.nrs.vdyp.forward.ForwardPass.PASS_4; import static ca.bc.gov.nrs.vdyp.forward.ForwardPass.PASS_5; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -18,6 +23,7 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.io.FileResolver; +import ca.bc.gov.nrs.vdyp.io.ZipOutputFileResolver; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.test.TestUtils; @@ -33,8 +39,27 @@ void test() throws IOException, ResourceParseException, ProcessingException { ForwardProcessor fp = new ForwardProcessor(); - FileResolver fileResolver = TestUtils.fileResolver(TestUtils.class); + FileResolver inputFileResolver = TestUtils.fileResolver(TestUtils.class); - fp.run(fileResolver, List.of("VDYP.CTR"), vdypPassSet); + var outputResolver = new ZipOutputFileResolver(); + + fp.run(inputFileResolver, outputResolver, List.of("VDYP.CTR"), vdypPassSet); + + Path resourceDirectory = Paths.get("src", "test", "resources", "output"); + Files.createDirectories(resourceDirectory); + + Path zipFile = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); + Files.deleteIfExists(zipFile); + + outputResolver.generate(zipFile); + + InputStream os = outputResolver.generateStream(); + + byte[] zipFileBytes = Files.readAllBytes(zipFile); + byte[] zipStreamBytes = os.readAllBytes(); + + assertTrue(zipFileBytes.length == zipStreamBytes.length); + assertTrue(Arrays.equals(zipFileBytes, zipStreamBytes)); + } } From 00024bfebdd4bfebee5509f46ef7f49a2fdceb17 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 4 Sep 2024 10:27:42 -0700 Subject: [PATCH 44/66] Forward unit tests up to GROW_6 + ... formatting! --- .../vdyp-common/GenusDefinitionMapTest.java | 48 - .../application/VdypStartApplication.java | 70 +- .../nrs/vdyp/common/ComputationMethods.java | 97 +- .../nrs/vdyp/common/EstimationMethods.java | 157 +-- .../nrs/vdyp/common/ReconcilationMethods.java | 6 +- .../vdyp/common/UtilizationOperations.java | 50 +- .../java/ca/bc/gov/nrs/vdyp/common/Utils.java | 5 +- .../common_calculators/Height2SiteIndex.java | 35 +- .../SiteClassCode2SiteIndex.java | 3 +- .../common_calculators/SiteIndex2Age.java | 4 +- .../common_calculators/SiteIndex2Height.java | 8 +- .../CachingResolvedControlMapImpl.java | 8 +- .../vdyp/controlmap/ResolvedControlMap.java | 12 +- .../controlmap/ResolvedControlMapImpl.java | 7 +- .../ca/bc/gov/nrs/vdyp/io/FileResolver.java | 4 +- .../nrs/vdyp/io/ZipOutputFileResolver.java | 43 +- .../coe/DqGrowthEmpiricalLimitsParser.java | 3 +- .../io/parse/coe/EquationGroupParser.java | 3 +- .../io/parse/coe/GenusDefinitionParser.java | 10 +- .../vdyp/io/parse/coe/UpperBoundsParser.java | 3 +- .../parse/coe/base/BaseCoefficientParser.java | 14 +- .../BecZoneBySpeciesCoefficientParser.java | 4 +- .../io/parse/coe/base/GrowthFiatParser.java | 3 +- .../base/NonPrimarySpeciesGrowthParser.java | 31 +- .../coe/base/PrimarySpeciesGrowthParser.java | 13 +- .../io/parse/control/NonFipControlParser.java | 12 +- .../nrs/vdyp/io/parse/value/ValueParser.java | 4 +- .../nrs/vdyp/io/write/VdypOutputWriter.java | 32 +- .../ca/bc/gov/nrs/vdyp/math/FloatMath.java | 10 +- .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 11 +- .../gov/nrs/vdyp/model/BaseVdypPolygon.java | 4 +- .../bc/gov/nrs/vdyp/model/BaseVdypSite.java | 8 +- .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 33 +- .../bc/gov/nrs/vdyp/model/Coefficients.java | 2 +- .../vdyp/model/CompatibilityVariableMode.java | 2 +- .../nrs/vdyp/model/Sp64DistributionSet.java | 17 +- .../gov/nrs/vdyp/model/UtilizationVector.java | 5 +- .../ca/bc/gov/nrs/vdyp/model/VdypEntity.java | 2 +- .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 2 +- .../ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 7 +- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 46 +- .../application/VdypStartApplicationTest.java | 167 ++- .../vdyp/application/test/TestPolygon.java | 4 +- .../vdyp/application/test/TestSpecies.java | 5 +- .../vdyp/common/EstimationMethodsTest.java | 31 +- .../vdyp/common/ReconcilationMethodsTest.java | 4 +- .../ca/bc/gov/nrs/vdyp/common/UtilsTest.java | 22 +- .../vdyp/common_calculators/AgeToAgeTest.java | 8 +- .../Height2SiteIndexTest.java | 84 +- .../SiteClassCode2SiteIndexTest.java | 4 +- .../common_calculators/SiteIndex2AgeTest.java | 20 +- .../SiteIndex2HeightSmoothedTest.java | 15 +- .../SiteIndex2HeightTest.java | 24 +- .../vdyp/io/ZipOutputFileResolverTest.java | 44 +- .../BasalAreaGrowthEmpiricalParserTest.java | 4 +- .../parse/BasalAreaGrowthFiatParserTest.java | 48 +- .../io/parse/BasalAreaYieldParserTest.java | 11 +- .../io/parse/DqGrowthEmpiricalParserTest.java | 15 +- ...imarySpeciesBasalAreaGrowthParserTest.java | 5 +- .../NonPrimarySpeciesDqGrowthParserTest.java | 5 +- ...imarySpeciesBasalAreaGrowthParserTest.java | 9 +- .../PrimarySpeciesDqGrowthParserTest.java | 4 +- .../vdyp/io/parse/UpperBoundsParserTest.java | 3 +- .../io/parse/coe/BecDefinitionParserTest.java | 168 ++- .../coe/BySpeciesDqCoefficientParserTest.java | 4 +- .../parse/coe/GenusDefinitionParserTest.java | 54 +- .../vdyp/io/parse/coe/ModifierParserTest.java | 32 +- .../coe/SiteCurveAgeMaximumParserTest.java | 44 +- .../coe/StockingClassFactorParserTest.java | 26 +- .../coe/UtilComponentBaseAreaParserTest.java | 3 +- .../vdyp/io/parse/common/LineParserTest.java | 52 +- .../parse/control/ControlFileParserTest.java | 30 +- .../control/NonFipControlParserTest.java | 249 ++-- .../vdyp/io/parse/value/ValueParserTest.java | 23 +- .../vdyp/io/write/ControlFileWriterTest.java | 31 +- .../io/write/VriAdjustInputWriterTest.java | 2 +- .../bc/gov/nrs/vdyp/model/BecLookupTest.java | 28 +- .../bc/gov/nrs/vdyp/model/CommonDataTest.java | 3 +- .../bc/gov/nrs/vdyp/model/MatrixMapTest.java | 18 +- .../bc/gov/nrs/vdyp/model/VdypLayerTest.java | 42 +- .../gov/nrs/vdyp/model/VdypPolygonTest.java | 5 +- .../bc/gov/nrs/vdyp/model/VdypSiteTest.java | 11 +- .../gov/nrs/vdyp/model/VdypSpeciesTest.java | 24 +- .../ca/bc/gov/nrs/vdyp/test/VdypMatchers.java | 3 +- .../bc/gov/nrs/vdyp/fip/FipControlParser.java | 8 +- .../bc/gov/nrs/vdyp/fip/FipLayerParser.java | 7 +- .../bc/gov/nrs/vdyp/fip/FipSpeciesParser.java | 3 +- .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 54 +- .../bc/gov/nrs/vdyp/fip/model/FipLayer.java | 2 +- .../nrs/vdyp/fip/model/FipLayerPrimary.java | 2 +- .../bc/gov/nrs/vdyp/fip/model/FipPolygon.java | 5 +- .../nrs/vdyp/fip/FipControlParserTest.java | 251 ++-- .../gov/nrs/vdyp/fip/FipLayerParserTest.java | 32 +- .../nrs/vdyp/fip/FipSpeciesParserTest.java | 190 +-- .../ca/bc/gov/nrs/vdyp/fip/FipStartTest.java | 677 ++++++---- .../bc/gov/nrs/vdyp/fip/RootFinderTest.java | 11 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 62 +- .../vdyp/forward/ForwardDataStreamReader.java | 98 +- .../vdyp/forward/ForwardProcessingEngine.java | 1166 +++++++++-------- .../vdyp/forward/ForwardProcessingState.java | 7 +- .../nrs/vdyp/forward/ForwardProcessor.java | 23 +- .../forward/LambdaProcessingException.java | 4 +- .../vdyp/forward/LayerProcessingState.java | 102 +- .../vdyp/forward/SpeciesRankingDetails.java | 4 +- .../controlmap/ForwardResolvedControlMap.java | 30 +- .../ForwardResolvedControlMapImpl.java | 33 +- .../vdyp/forward/model/ControlVariable.java | 12 +- .../model/ForwardControlVariables.java | 32 +- .../forward/model/ForwardDebugSettings.java | 194 ++- .../forward/parsers/VdypPolygonParser.java | 14 +- .../forward/parsers/VdypSpeciesParser.java | 6 +- .../parsers/VdypUtilizationParser.java | 4 +- .../AbstractForwardProcessingEngineTest.java | 4 +- .../ca/bc/gov/nrs/vdyp/forward/BankTest.java | 45 +- ....java => CalculateBasalAreaDeltaTest.java} | 42 +- ... => CalculateDominantHeightDeltaTest.java} | 40 +- ...> CalculateQuadMeanDiameterDeltaTest.java} | 100 +- .../forward/ForwardControlParserTest.java | 14 +- .../forward/ForwardControlVariablesTest.java | 18 +- .../forward/ForwardDebugSettingsTest.java | 29 +- .../vdyp/forward/ForwardGrowStepTests.java | 2 +- .../vdyp/forward/ForwardProcessorTest.java | 16 +- .../vdyp/forward/ForwardReadPolygonTest.java | 18 +- .../GeneralForwardProcessingEngineTest.java | 34 +- .../gov/nrs/vdyp/forward/GrowBaDqTphTest.java | 186 +++ .../vdyp/forward/GrowLoreyHeightsTest.java | 22 +- ...yVariablesForwardProcessingEngineTest.java | 64 +- .../bc/gov/nrs/vdyp/vri/VriControlParser.java | 3 +- .../bc/gov/nrs/vdyp/vri/VriLayerParser.java | 7 +- .../ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java | 22 +- .../bc/gov/nrs/vdyp/vri/VriSpeciesParser.java | 7 +- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 69 +- .../bc/gov/nrs/vdyp/vri/model/VriLayer.java | 9 +- .../bc/gov/nrs/vdyp/vri/model/VriPolygon.java | 5 +- .../gov/nrs/vdyp/vri/ParsersTogetherTest.java | 16 +- .../nrs/vdyp/vri/VriControlParserTest.java | 249 ++-- .../nrs/vdyp/vri/VriInputValidationTest.java | 8 +- .../gov/nrs/vdyp/vri/VriLayerParserTest.java | 24 +- .../nrs/vdyp/vri/VriPolygonParserTest.java | 2 +- .../gov/nrs/vdyp/vri/VriSiteParserTest.java | 62 +- .../nrs/vdyp/vri/VriSpeciesParserTest.java | 204 +-- .../ca/bc/gov/nrs/vdyp/vri/VriStartTest.java | 313 ++--- 142 files changed, 3757 insertions(+), 3136 deletions(-) delete mode 100644 vdyp-lib/vdyp-common/GenusDefinitionMapTest.java rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{GrowBasalAreaTest.java => CalculateBasalAreaDeltaTest.java} (90%) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{GrowDominantHeightTest.java => CalculateDominantHeightDeltaTest.java} (89%) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{GrowQuadMeanDiameterTest.java => CalculateQuadMeanDiameterDeltaTest.java} (89%) create mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java diff --git a/vdyp-lib/vdyp-common/GenusDefinitionMapTest.java b/vdyp-lib/vdyp-common/GenusDefinitionMapTest.java deleted file mode 100644 index 5aa2a6024..000000000 --- a/vdyp-lib/vdyp-common/GenusDefinitionMapTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward; - -import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.controlMapHasEntry; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasProperty; -import static org.hamcrest.Matchers.is; - -import java.io.IOException; -import java.util.Map; - -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.GenusDefinitionMap; -import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; -import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; - -class GenusDefinitionMapTest { - - private ForwardControlParser parser; - private Map controlMap; - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @BeforeEach - void before() throws IOException, ResourceParseException { - - parser = new ForwardControlParser(); - controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - controlMap, - (Matcher) controlMapHasEntry(ControlKey.SP0_DEF, Matchers.instanceOf(GenusDefinitionMap.class)) - ); - } - - @Test - void test() { - var gdMap = (GenusDefinitionMap) controlMap.get(ControlKey.SP0_DEF.name()); - - assertThat(gdMap.contains("AC"), is(true)); - assertThat(gdMap.getByAlias("AC"), hasProperty("alias", is("AC"))); - assertThat(gdMap.getByIndex(3), hasProperty("alias", is("B"))); - assertThat(gdMap.getIndexByAlias("B"), is(3)); - assertThat(gdMap.getNGenera(), is(16)); - } -} diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index d839e89a8..fefdceda9 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -272,8 +272,8 @@ protected Coefficients getCoeForSpecies(BaseVdypSpecies species, ControlKey c protected L requireLayer(P polygon, LayerType type) throws ProcessingException { if (!polygon.getLayers().containsKey(type)) { throw validationError( - "Polygon \"%s\" has no %s layer, or that layer has non-positive height or crown closure.", polygon - .getPolygonIdentifier(), type + "Polygon \"%s\" has no %s layer, or that layer has non-positive height or crown closure.", + polygon.getPolygonIdentifier(), type ); } @@ -294,8 +294,8 @@ protected float getPercentTotal(L layer) throws StandProcessingException { .sum(); if (Math.abs(percentTotal - 100f) > 0.01f) { throw validationError( - "Polygon \"%s\" has %s layer where species entries have a percentage total that does not sum to 100%%.", layer - .getPolygonIdentifier(), LayerType.PRIMARY + "Polygon \"%s\" has %s layer where species entries have a percentage total that does not sum to 100%%.", + layer.getPolygonIdentifier(), LayerType.PRIMARY ); } return percentTotal; @@ -534,8 +534,8 @@ protected float estimatePrimaryBaseArea( var decayBecAlias = bec.getDecayBec().getAlias(); Coefficients coe = weightedCoefficientSum( - List.of(0, 1, 2, 3, 4, 5), 9, 0, layer.getSpecies() - .values(), BaseVdypSpecies::getFractionGenus, s -> coeMap.get(decayBecAlias, s.getGenus()) + List.of(0, 1, 2, 3, 4, 5), 9, 0, layer.getSpecies().values(), BaseVdypSpecies::getFractionGenus, + s -> coeMap.get(decayBecAlias, s.getGenus()) ); float ageToUse = clamp(breastHeightAge, 5f, 350f); @@ -848,8 +848,8 @@ protected float estimatePrimaryQuadMeanDiameter( var decayBecAlias = bec.getDecayBec().getAlias(); Coefficients coe = weightedCoefficientSum( - List.of(0, 1, 2, 3, 4), 8, 0, layer.getSpecies() - .values(), BaseVdypSpecies::getFractionGenus, s -> coeMap.get(decayBecAlias, s.getGenus()) + List.of(0, 1, 2, 3, 4), 8, 0, layer.getSpecies().values(), BaseVdypSpecies::getFractionGenus, + s -> coeMap.get(decayBecAlias, s.getGenus()) ); var trAge = log(clamp(breastHeightAge, 5f, 350f)); @@ -1193,7 +1193,8 @@ public void computeUtilizationComponentsPrimary( // Calculate tree density components for (var uc : VdypStartApplication.UTIL_CLASSES) { treesPerHectareUtil.set( - uc, BaseAreaTreeDensityDiameter + uc, + BaseAreaTreeDensityDiameter .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) ); } @@ -1211,7 +1212,8 @@ public void computeUtilizationComponentsPrimary( for (var uc : VdypStartApplication.UTIL_CLASSES) { treesPerHectareUtil.setCoe( - uc.index, BaseAreaTreeDensityDiameter + uc.index, + BaseAreaTreeDensityDiameter .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) ); } @@ -1228,9 +1230,8 @@ public void computeUtilizationComponentsPrimary( // EMP091 estimationMethods.estimateWholeStemVolume( - UtilizationClass.ALL, adjustCloseUtil.getCoe( - 4 - ), spec.getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil ); if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { @@ -1245,28 +1246,28 @@ public void computeUtilizationComponentsPrimary( // EMP092 estimationMethods.estimateCloseUtilizationVolume( - UtilizationClass.ALL, adjustCloseUtil, spec - .getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil + UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil ); // EMP093 estimationMethods.estimateNetDecayVolume( - spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec - .getDecayGroup(), vdypLayer.getBreastHeightAge() - .orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil + spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), + vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayUtil ); // EMP094 estimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec - .getGenus(), loreyHeightSpec, quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil + bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, + quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil ); if (this.getId().isStart()) { // EMP095 estimationMethods.estimateNetDecayWasteAndBreakageVolume( - UtilizationClass.ALL, spec - .getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil + UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil ); } } @@ -1317,12 +1318,12 @@ public void computeUtilizationComponentsPrimary( "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" ).log(); vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.SMALL, x -> x - + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() + UtilizationClass.SMALL, + x -> x + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() ); vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.ALL, x -> x - + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + UtilizationClass.ALL, + x -> x + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() ); } { @@ -1355,14 +1356,14 @@ protected void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) vdypLayer.getSpecies().values().stream().forEach(spec -> { var ba = spec.getBaseAreaByUtilization(); hlVector.pairwiseInPlace( - spec.getLoreyHeightByUtilization(), (float x, float y, UtilizationClass uc) -> x - + y * ba.get(uc) + spec.getLoreyHeightByUtilization(), + (float x, float y, UtilizationClass uc) -> x + y * ba.get(uc) ); }); 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 + // Update percent based on updated areas vdypLayer.getSpecies().values().stream().forEach(spec -> { spec.setPercentGenus(100 * spec.getBaseAreaByUtilization().getAll() / ba.getAll()); }); @@ -1472,16 +1473,17 @@ protected void computeUtilizationComponentsVeteran(VdypLayer vdypLayer, BecDefin adjust.setCoe(4, volumeAdjustCoe.getCoe(3)); // EMP093 estimationMethods.estimateNetDecayVolume( - vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, - vdypSpecies.getDecayGroup(), vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, - closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil + vdypSpecies.getGenus(), bec.getRegion(), utilizationClass, adjust, vdypSpecies.getDecayGroup(), + vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeUtilizationVolumeUtil, + closeUtilizationNetOfDecayUtil ); adjust.setCoe(4, volumeAdjustCoe.getCoe(4)); // EMP094 estimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, quadMeanDiameterUtil, - closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil + bec.getRegion(), utilizationClass, adjust, vdypSpecies.getGenus(), hlSp, quadMeanDiameterUtil, + closeUtilizationVolumeUtil, closeUtilizationNetOfDecayUtil, + closeUtilizationNetOfDecayAndWasteUtil ); if (getId().isStart()) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java index ca60a1a1b..886521dc5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java @@ -146,7 +146,8 @@ public void computeUtilizationComponentsPrimary( // Calculate tree density components for (var uc : VdypStartApplication.UTIL_CLASSES) { treesPerHectareUtil.set( - uc, BaseAreaTreeDensityDiameter + uc, + BaseAreaTreeDensityDiameter .treesPerHectare(basalAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.get(uc)) ); } @@ -157,27 +158,31 @@ public void computeUtilizationComponentsPrimary( ReconcilationMethods.reconcileComponents(basalAreaUtil, treesPerHectareUtil, quadMeanDiameterUtil); if (compatibilityVariableMode != CompatibilityVariableMode.NONE) { - + float basalAreaSumForSpecies = 0.0f; for (var uc : VdypStartApplication.UTIL_CLASSES) { - + float currentUcBasalArea = basalAreaUtil.get(uc); basalAreaUtil.set(uc, currentUcBasalArea + spec.getCvBasalArea(uc, spec.getLayerType())); if (basalAreaUtil.get(uc) < 0.0f) { basalAreaUtil.set(uc, 0.0f); } - + basalAreaSumForSpecies += basalAreaUtil.get(uc); - float newDqValue = quadMeanDiameterUtil.get(uc) + spec.getCvQuadraticMeanDiameter(uc, spec.getLayerType()); - quadMeanDiameterUtil - .set(uc, FloatMath.clamp( - newDqValue, quadMeanDiameterLowerBounds.get(uc), quadMeanDiameterUpperBounds.get(uc))); + float newDqValue = quadMeanDiameterUtil.get(uc) + + spec.getCvQuadraticMeanDiameter(uc, spec.getLayerType()); + quadMeanDiameterUtil.set( + uc, + FloatMath.clamp( + newDqValue, quadMeanDiameterLowerBounds.get(uc), quadMeanDiameterUpperBounds.get(uc) + ) + ); } - + float baMult = basalAreaUtil.get(UtilizationClass.ALL) / basalAreaSumForSpecies; - - for (UtilizationClass uc: UtilizationClass.ALL_CLASSES) { + + for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { basalAreaUtil.set(uc, basalAreaUtil.get(uc) * baMult); } } @@ -186,7 +191,8 @@ public void computeUtilizationComponentsPrimary( for (var uc : VdypStartApplication.UTIL_CLASSES) { treesPerHectareUtil.setCoe( - uc.index, BaseAreaTreeDensityDiameter + uc.index, + BaseAreaTreeDensityDiameter .treesPerHectare(basalAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) ); } @@ -203,26 +209,37 @@ public void computeUtilizationComponentsPrimary( // EMP091 estimationMethods.estimateWholeStemVolume( - UtilizationClass.ALL, adjustCloseUtil.getCoe(4), - spec.getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, basalAreaUtil, wholeStemVolumeUtil + UtilizationClass.ALL, adjustCloseUtil.getCoe(4), spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, basalAreaUtil, wholeStemVolumeUtil ); if (compatibilityVariableMode == CompatibilityVariableMode.ALL) { // apply compatibility variables to WS volume float wholeStemVolumeSum = 0.0f; - for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { - wholeStemVolumeUtil.set(uc, wholeStemVolumeUtil.get(uc) - * FloatMath.exp(spec.getCvVolume(uc, VolumeVariable.WHOLE_STEM_VOL, spec.getLayerType()))); + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { + wholeStemVolumeUtil.set( + uc, + wholeStemVolumeUtil.get(uc) * FloatMath + .exp(spec.getCvVolume(uc, VolumeVariable.WHOLE_STEM_VOL, spec.getLayerType())) + ); wholeStemVolumeSum += wholeStemVolumeUtil.get(uc); } wholeStemVolumeUtil.set(UtilizationClass.ALL, wholeStemVolumeSum); - + // Set the adjustment factors for next three volume types - for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { - adjustCloseUtil.set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL, spec.getLayerType())); - adjustDecayUtil.set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY, spec.getLayerType())); - adjustDecayWasteUtil.set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, spec.getLayerType())); + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { + adjustCloseUtil + .set(uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL, spec.getLayerType())); + adjustDecayUtil.set( + uc, spec.getCvVolume(uc, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY, spec.getLayerType()) + ); + adjustDecayWasteUtil.set( + uc, + spec.getCvVolume( + uc, VolumeVariable.CLOSE_UTIL_VOL_LESS_DECAY_LESS_WASTAGE, spec.getLayerType() + ) + ); } } else { // Do nothing as the adjustment vectors are already set to 0 @@ -230,28 +247,28 @@ public void computeUtilizationComponentsPrimary( // EMP092 estimationMethods.estimateCloseUtilizationVolume( - UtilizationClass.ALL, adjustCloseUtil, spec - .getVolumeGroup(), loreyHeightSpec, quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil + UtilizationClass.ALL, adjustCloseUtil, spec.getVolumeGroup(), loreyHeightSpec, + quadMeanDiameterUtil, wholeStemVolumeUtil, closeVolumeUtil ); // EMP093 estimationMethods.estimateNetDecayVolume( - spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec - .getDecayGroup(), vdypLayer.getBreastHeightAge() - .orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil + spec.getGenus(), bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getDecayGroup(), + vdypLayer.getBreastHeightAge().orElse(0f), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayUtil ); // EMP094 estimationMethods.estimateNetDecayAndWasteVolume( - bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec - .getGenus(), loreyHeightSpec, quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil + bec.getRegion(), UtilizationClass.ALL, adjustCloseUtil, spec.getGenus(), loreyHeightSpec, + quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayUtil, closeVolumeNetDecayWasteUtil ); if (context.isStart()) { // EMP095 estimationMethods.estimateNetDecayWasteAndBreakageVolume( - UtilizationClass.ALL, spec - .getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil + UtilizationClass.ALL, spec.getBreakageGroup(), quadMeanDiameterUtil, closeVolumeUtil, + closeVolumeNetDecayWasteUtil, closeVolumeNetDecayWasteBreakUtil ); } } @@ -273,7 +290,7 @@ public void computeUtilizationComponentsPrimary( .pairwiseInPlace(closeVolumeNetDecayWasteBreakUtil, EstimationMethods.COPY_IF_NOT_SMALL); } - + computeLayerUtilizationComponentsFromSpecies(vdypLayer); for (VdypSpecies spec : vdypLayer.getSpecies().values()) { @@ -303,12 +320,12 @@ public void computeUtilizationComponentsPrimary( "For species {}, Species LH (7.5cm+): {}, Species BA (7.5cm+): {}, Weighted LH (7.5cm+): {}" ).log(); vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.SMALL, x -> x - + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() + UtilizationClass.SMALL, + x -> x + spec.getLoreyHeightByUtilization().getSmall() * spec.getBaseAreaByUtilization().getSmall() ); vdypLayer.getLoreyHeightByUtilization().scalarInPlace( - UtilizationClass.ALL, x -> x - + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() + UtilizationClass.ALL, + x -> x + spec.getLoreyHeightByUtilization().getAll() * spec.getBaseAreaByUtilization().getAll() ); } { @@ -332,7 +349,7 @@ public void computeUtilizationComponentsPrimary( * @param vdypLayer */ protected static void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdypLayer) { - + // Layer utilization vectors other than quadratic mean diameter are the pairwise // sums of those of their species sumSpeciesUtilizationVectorsToLayer(vdypLayer); @@ -342,15 +359,15 @@ protected static void computeLayerUtilizationComponentsFromSpecies(VdypLayer vdy vdypLayer.getSpecies().values().stream().forEach(spec -> { var ba = spec.getBaseAreaByUtilization(); hlVector.pairwiseInPlace( - spec.getLoreyHeightByUtilization(), (float x, float y, UtilizationClass uc) -> x - + y * ba.get(uc) + spec.getLoreyHeightByUtilization(), + (float x, float y, UtilizationClass uc) -> x + y * ba.get(uc) ); }); var ba = vdypLayer.getBaseAreaByUtilization(); hlVector.scalarInPlace((float x, UtilizationClass uc) -> ba.get(uc) > 0 ? x / ba.get(uc) : x); vdypLayer.setLoreyHeightByUtilization(hlVector); } - + // Quadratic mean diameter for the layer is computed from the BA and TPH after // they have been found from the species { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index 87b1cc64f..488912381 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -38,7 +38,7 @@ public class EstimationMethods { public static final Logger log = LoggerFactory.getLogger(EstimationMethods.class); public static final float EMPIRICAL_OCCUPANCY = 0.85f; - + ResolvedControlMap controlMap; public EstimationMethods(ResolvedControlMap controlMap) { @@ -60,9 +60,7 @@ public EstimationMethods(ResolvedControlMap controlMap) { oldX, newX, uc ) -> UtilizationClass.ALL_BUT_SMALL.contains(uc) ? newX : oldX; - private float heightMultiplier( - String genus, Region region, float treesPerHectarePrimary - ) { + private float heightMultiplier(String genus, Region region, float treesPerHectarePrimary) { final var coeMap = controlMap.getHl1Coefficients(); var coe = coeMap.get(genus, region).reindex(0); return coe.get(0) - coe.getCoe(1) + coe.getCoe(1) * exp(coe.getCoe(2) * (treesPerHectarePrimary - 100f)); @@ -77,9 +75,8 @@ private float heightMultiplier( * @param treesPerHectarePrimary trees per hectare >7.5 cm of the primary species * @return as described */ - public float primaryHeightFromLeadHeight( - float leadHeight, String genus, Region region, float treesPerHectarePrimary - ) { + public float + primaryHeightFromLeadHeight(float leadHeight, String genus, Region region, float treesPerHectarePrimary) { return 1.3f + (leadHeight - 1.3f) * heightMultiplier(genus, region, treesPerHectarePrimary); } @@ -104,9 +101,7 @@ public float leadHeightFromPrimaryHeight( * @param genus Primary species * @param region Region of the polygon */ - public float primaryHeightFromLeadHeightInitial( - float leadHeight, String genus, Region region - ) { + public float primaryHeightFromLeadHeightInitial(float leadHeight, String genus, Region region) { final var coeMap = controlMap.getHl2Coefficients(); var coe = coeMap.get(genus, region); return 1.3f + coe.getCoe(1) * pow(leadHeight - 1.3f, coe.getCoe(2)); @@ -119,7 +114,7 @@ public float primaryHeightFromLeadHeightInitial( * * @param vspec The species. * @param vspecPrime The primary species. - * @param bec The BEC zone containing the species. + * @param bec The BEC zone containing the species. * @param leadHeight lead height of the layer * @param primaryHeight height of the primary species * @throws ProcessingException @@ -138,7 +133,7 @@ public float estimateNonPrimaryLoreyHeight( * * @param vspec The species. * @param vspecPrime The primary species. - * @param bec The BEC zone containing the species. + * @param bec The BEC zone containing the species. * @param leadHeight lead height of the layer * @param primaryHeight height of the primary species * @throws ProcessingException @@ -151,8 +146,8 @@ public float estimateNonPrimaryLoreyHeight( var coe = coeMap.get(vspec, vspecPrime, bec.getRegion()).orElseThrow( () -> new ProcessingException( String.format( - "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, bec - .getRegion() + "Could not find Lorey Height Nonprimary Coefficients for %s %s %s", vspec, vspecPrime, + bec.getRegion() ) ) ); @@ -188,11 +183,9 @@ public float estimateQuadMeanDiameterForSpecies( allSpecies.values().stream().forEach(s -> basalAreaFractionPerSpecies.put(s.getGenus(), s.getFractionGenus())); return estimateQuadMeanDiameterForSpecies( - spec.getGenus(), spec.getLoreyHeightByUtilization().get( - UtilizationClass.ALL - ), spec.getQuadraticMeanDiameterByUtilization().get( - UtilizationClass.ALL - ), basalAreaFractionPerSpecies, region, standQuadMeanDiameter, standBaseArea, standTreesPerHectare, standLoreyHeight + spec.getGenus(), spec.getLoreyHeightByUtilization().get(UtilizationClass.ALL), + spec.getQuadraticMeanDiameterByUtilization().get(UtilizationClass.ALL), basalAreaFractionPerSpecies, + region, standQuadMeanDiameter, standBaseArea, standTreesPerHectare, standLoreyHeight ); } @@ -201,21 +194,20 @@ public float estimateQuadMeanDiameterForSpecies( * * Enforces mins and maxes from EMP061. * - * @param spAlias The alias of the species - * @param spLoreyHeight The lorey height (all utilizations) of the species - * @param spQuadMeanDiameter The quad-mean-diameter (all utilizations) of the species + * @param spAlias The alias of the species + * @param spLoreyHeight The lorey height (all utilizations) of the species + * @param spQuadMeanDiameter The quad-mean-diameter (all utilizations) of the species * @param basalAreaFractionPerSpecies Basal area fractions of the per species in the stand - * @param region BEC Region of the stand - * @param standQuadMeanDiameter Quadratic mean diameter of the stand - * @param standBaseArea Base area of the stand - * @param standTreesPerHectare Density opf the stand - * @param standLoreyHeight Lorey height of the stand + * @param region BEC Region of the stand + * @param standQuadMeanDiameter Quadratic mean diameter of the stand + * @param standBaseArea Base area of the stand + * @param standTreesPerHectare Density opf the stand + * @param standLoreyHeight Lorey height of the stand * @return quadratic mean diameter of the species of interest * @throws ProcessingException */ public float estimateQuadMeanDiameterForSpecies( - String spAlias, - float spLoreyHeight, // HLsp + String spAlias, float spLoreyHeight, // HLsp float spQuadMeanDiameter, // DQsp Map basalAreaFractionPerSpecies, // FR Region region, // INDEX_IC @@ -270,9 +262,7 @@ public float estimateQuadMeanDiameterForSpecies( float loreyHeight2 = (standLoreyHeight - loreyHeightSpec * spFraction) / fractionOther; float loreyHeightRatio = clamp( (loreyHeight1 - 3f) / (loreyHeight2 - 3f), 0.05f, 20f); - float r = exp( - a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter) - ); + float r = exp(a0 + a1 * log(loreyHeightRatio) + a2 * log(standQuadMeanDiameter)); float baseArea1 = spFraction * standBaseArea; float baseArea2 = standBaseArea - baseArea1; @@ -307,7 +297,8 @@ public float estimateQuadMeanDiameterForSpecies( var limits = getLimitsForHeightAndDiameter(spAlias, region); quadMeanDiameter1 = estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, + quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); return quadMeanDiameter1; } @@ -327,7 +318,8 @@ float estimateQuadMeanDiameterClampResult( final float dqMinSp = max(minQuadMeanDiameter, limits.minQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec); final float dqMaxSp = max( - 7.6f, min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) + 7.6f, + min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightSpec) ); if (quadMeanDiameter1 < dqMinSp) { quadMeanDiameter1 = dqMinSp; @@ -362,8 +354,8 @@ float estimateQuadMeanDiameterClampResult( /** * EMP061. Return a ComponentSizeLimits instance for the given sp0 and region. - * - * @param sp0 the SP0 species + * + * @param sp0 the SP0 species * @param region the region * @return as described */ @@ -372,8 +364,8 @@ public ComponentSizeLimits getLimitsForHeightAndDiameter(String sp0, Region regi } /** - * EMP070. Estimate basal area by utilization class from the given parameters, after getting - * the estimation coefficients map from the control map. + * EMP070. Estimate basal area by utilization class from the given parameters, after getting the estimation + * coefficients map from the control map. * * @param bec * @param quadMeanDiameterUtil @@ -433,7 +425,7 @@ public void estimateQuadMeanDiameterByUtilization( .addArgument(genus).addArgument(bec.getName()).addArgument(quadMeanDiameterUtil.getAll()); var coeMap = controlMap.getQuadMeanDiameterUtilizationComponentMap(); - + float quadMeanDiameter07 = quadMeanDiameterUtil.getAll(); for (var uc : UtilizationClass.UTIL_CLASSES) { @@ -508,9 +500,7 @@ public void estimateQuadMeanDiameterByUtilization( * @param quadMeanDiameter the species' quadratic mean diameter * @return as described */ - public float estimateWholeStemVolumePerTree( - int volumeGroup, float loreyHeight, float quadMeanDiameter - ) { + public float estimateWholeStemVolumePerTree(int volumeGroup, float loreyHeight, float quadMeanDiameter) { var totalStandWholeStemVolumeCoeMap = controlMap.getTotalStandWholeStepVolumeCoeMap(); var coe = totalStandWholeStemVolumeCoeMap.get(volumeGroup).reindex(0); @@ -598,7 +588,7 @@ public void estimateCloseUtilizationVolume( UtilizationVector closeUtilizationVolumeUtil ) throws ProcessingException { var closeUtilizationCoeMap = controlMap.getCloseUtilizationCoeMap(); - + estimateUtilization(wholeStemVolumeUtil, closeUtilizationVolumeUtil, utilizationClass, (uc, ws) -> { Coefficients closeUtilCoe = closeUtilizationCoeMap.get(uc.index, volumeGroup).orElseThrow( () -> new ProcessingException( @@ -637,12 +627,12 @@ public void estimateCloseUtilizationVolume( */ public void estimateNetDecayVolume( String genus, Region region, UtilizationClass utilizationClass, Coefficients aAdjust, int decayGroup, - float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, - UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayUtil + float ageBreastHeight, UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, + UtilizationVector closeUtilizationNetOfDecayUtil ) throws ProcessingException { var netDecayCoeMap = controlMap.getNetDecayCoeMap(); var decayModifierMap = controlMap.getDecayModifierMap(); - + var dqSp = quadMeanDiameterUtil.getAll(); final var ageTr = (float) Math.log(Math.max(20.0, ageBreastHeight)); @@ -673,7 +663,7 @@ public void estimateNetDecayVolume( storeSumUtilizationComponents(closeUtilizationNetOfDecayUtil); } } - + /** * EMP094. Estimate utilization net of decay and waste * @@ -697,9 +687,8 @@ public void estimateNetDecayAndWasteVolume( final var wasteModifierMap = controlMap.getWasteModifierMap(); estimateUtilization( - closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, ( - i, netDecay - ) -> { + closeUtilizationNetOfDecayUtil, closeUtilizationNetOfDecayAndWasteUtil, utilizationClass, + (i, netDecay) -> { if (Float.isNaN(netDecay) || netDecay <= 0f) { return 0f; } @@ -767,13 +756,12 @@ public void estimateNetDecayAndWasteVolume( * @throws ProcessingException */ public void estimateNetDecayWasteAndBreakageVolume( - UtilizationClass utilizationClass, int breakageGroup, - UtilizationVector quadMeanDiameterUtil, UtilizationVector closeUtilizationUtil, - UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, + UtilizationClass utilizationClass, int breakageGroup, UtilizationVector quadMeanDiameterUtil, + UtilizationVector closeUtilizationUtil, UtilizationVector closeUtilizationNetOfDecayAndWasteUtil, UtilizationVector closeUtilizationNetOfDecayWasteAndBreakageUtil ) throws ProcessingException { var netBreakageCoeMap = controlMap.getNetBreakageMap(); - + final var coefficients = netBreakageCoeMap.get(breakageGroup); if (coefficients == null) { throw new ProcessingException("Could not find net breakage coefficients for group " + breakageGroup); @@ -785,9 +773,8 @@ public void estimateNetDecayWasteAndBreakageVolume( final var a4 = coefficients.getCoe(4); estimateUtilization( - closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, utilizationClass, ( - uc, netWaste - ) -> { + closeUtilizationNetOfDecayAndWasteUtil, closeUtilizationNetOfDecayWasteAndBreakageUtil, + utilizationClass, (uc, netWaste) -> { if (netWaste <= 0f) { return 0f; @@ -806,39 +793,39 @@ 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 dominantHeight dominant height (m) - * @param breastHeightAge breast height age (years) - * @param veteranBaseArea basal area of overstory (>= 0) - * @param fullOccupancy if true, the empirically fitted curve is increased to become - * a full occupancy curve. If false, BAP is for mean conditions - * @param upperBoundBasalArea limit on the resulting basal area + * @param controlVariable2Setting the value of control variable 2 + * @param dominantHeight dominant height (m) + * @param breastHeightAge breast height age (years) + * @param veteranBaseArea basal area of overstory (>= 0) + * @param fullOccupancy if true, the empirically fitted curve is increased to become a full + * occupancy curve. If false, BAP is for mean conditions + * @param upperBoundBasalArea limit on the resulting basal area * @return as described * @throws StandProcessingException */ public float estimateBaseAreaYield( - Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, + Coefficients estimateBasalAreaYieldCoefficients, int controlVariable2Setting, float dominantHeight, float breastHeightAge, Optional veteranBasalArea, boolean fullOccupancy, float upperBoundBasalArea ) throws StandProcessingException { - + // The original Fortran had the following comment and a commented out modification to upperBoundsBaseArea // (BATOP98): /* * And one POSSIBLY one last vestige of grouping by ITG. - * - * That limit applies to full occupancy and Empirical occupancy. They were derived as the 98th percentile - * of Empirical stocking, though adjusted PSPs were included. If the ouput of this routine is bumped up - * from empirical to full, MIGHT adjust this limit DOWN here, so that at end, it is correct. Tentatively - * decide NOT to do this: + * + * That limit applies to full occupancy and Empirical occupancy. They were derived as the 98th percentile of + * Empirical stocking, though adjusted PSPs were included. If the ouput of this routine is bumped up from + * empirical to full, MIGHT adjust this limit DOWN here, so that at end, it is correct. Tentatively decide NOT + * to do this: */ // if (fullOccupancy) { // upperBoundsBaseArea *= EMPOC; // } - + float ageToUse = breastHeightAge; if (controlVariable2Setting > 0) { @@ -858,7 +845,7 @@ public float estimateBaseAreaYield( float a4 = estimateBasalAreaYieldCoefficients.getCoe(4); float a5 = estimateBasalAreaYieldCoefficients.getCoe(5); float a6 = estimateBasalAreaYieldCoefficients.getCoe(6); - + float a00 = Math.max(a0 + a1 * trAge, 0); float ap = Math.max(a3 + a4 * trAge, 0); @@ -874,31 +861,31 @@ public float estimateBaseAreaYield( if (fullOccupancy) { bap /= EMPIRICAL_OCCUPANCY; } - + return bap; } /** * EMP107 - estimate DQ yield for the primary layer (from IPSJF161.doc) - * - * @param coefficients coefficients weighted by species and decay bec zone - * @param controlVariable2Setting the value of control variable 2 - * @param dominantHeight dominant height (m) - * @param breastHeightAge breast height age (years) - * @param veteranBaseArea basal area of overstory (>= 0) + * + * @param coefficients coefficients weighted by species and decay bec zone + * @param controlVariable2Setting the value of control variable 2 + * @param dominantHeight dominant height (m) + * @param breastHeightAge breast height age (years) + * @param veteranBaseArea basal area of overstory (>= 0) * @param upperBoundQuadMeanDiameter upper bound on the result of this call * @return quad-mean-diameter of primary layer (with DBH >= 7.5) * @throws StandProcessingException in the event of a processing error */ public float estimateQuadMeanDiameterYield( - Coefficients coefficients, int controlVariable2Setting, float dominantHeight, - float breastHeightAge, Optional veteranBaseArea, float upperBoundQuadMeanDiameter + Coefficients coefficients, int controlVariable2Setting, float dominantHeight, float breastHeightAge, + Optional veteranBaseArea, float upperBoundQuadMeanDiameter ) throws StandProcessingException { if (dominantHeight <= 5) { return 7.6f; } - + final float ageUse = breastHeightAge; if (ageUse <= 0f) { @@ -912,7 +899,7 @@ public float estimateQuadMeanDiameterYield( final float c2 = Math.max(coefficients.getCoe(3) + coefficients.getCoe(4) * trAge, 0f); float dq = c0 + c1 * FloatMath.pow(dominantHeight - 5f, c2); - + return FloatMath.clamp(dq, 7.6f, upperBoundQuadMeanDiameter); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java index fdc9ce7e4..180459ace 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java @@ -103,7 +103,8 @@ public static void reconcileComponentsMode1( } UtilizationClass.UTIL_CLASSES.forEach( uc -> treesPerHectareUtil.setCoe( - uc.index, BaseAreaTreeDensityDiameter + uc.index, + BaseAreaTreeDensityDiameter .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) ) ); @@ -221,7 +222,8 @@ public static void reconcileComponentsMode2( for (var uc : UtilizationClass.UTIL_CLASSES) { quadMeanDiameterUtil.setCoe(uc.index, dqTrial.getCoe(uc.index)); treesPerHectareUtil.setCoe( - uc.index, BaseAreaTreeDensityDiameter + uc.index, + BaseAreaTreeDensityDiameter .treesPerHectare(baseAreaUtil.getCoe(uc.index), quadMeanDiameterUtil.getCoe(uc.index)) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java index bb098e642..f51172ead 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java @@ -21,11 +21,11 @@ public class UtilizationOperations { *

  • Scale the per-hectare values of all the utilizations of the primary layer of the given polygon, and *
  • For all utilizations of both the primary and veteran layer (if present) of the polygon: *
      - *
    • Adjust the basal area to be within bounds of the utilization class, and + *
    • Adjust the basal area to be within bounds of the utilization class, and *
    • Calculate the quad-mean-diameter value from the basal area and trees per hectare. *
    * - * + * * @param polygon the polygon on which to operate */ public static void doPostCreateAdjustments(VdypPolygon polygon) throws ProcessingException { @@ -49,7 +49,8 @@ public static void doPostCreateAdjustments(VdypPolygon polygon) throws Processin scale(uh, scalingFactor); } - // Implements the logic in BANKIN2 (ICHECK == 2) adjusting the utilization values according to various rules. + // Implements the logic in BANKIN2 (ICHECK == 2) adjusting the utilization values according to various + // rules. resetOnMissingValues(uh); @@ -58,16 +59,16 @@ public static void doPostCreateAdjustments(VdypPolygon polygon) throws Processin doCalculateQuadMeanDiameter(uh); } } - + /** - * Implements VDYPGETU lines 224 - 229, in which the utilization-per-hectare values are scaled by - * the given factor - the % coverage of the primary layer. + * Implements VDYPGETU lines 224 - 229, in which the utilization-per-hectare values are scaled by the given factor - + * the % coverage of the primary layer. * * @param scalingFactor the factor by which the uh is to be scaled */ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { - - for (UtilizationClass uc: UtilizationClass.values()) { + + for (UtilizationClass uc : UtilizationClass.values()) { float basalArea = uh.getBaseAreaByUtilization().get(uc); if (basalArea > 0) { uh.getBaseAreaByUtilization().set(uc, basalArea * scalingFactor); @@ -92,11 +93,14 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { } float cuVolumeMinusDecayWastage = uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc); if (cuVolumeMinusDecayWastage > 0) { - uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().set(uc, cuVolumeMinusDecayWastage * scalingFactor); + uh.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization() + .set(uc, cuVolumeMinusDecayWastage * scalingFactor); } - float cuVolumeMinusDecayWastageBreakage = uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().get(uc); + float cuVolumeMinusDecayWastageBreakage = uh + .getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().get(uc); if (cuVolumeMinusDecayWastageBreakage > 0) { - uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization().set(uc, cuVolumeMinusDecayWastageBreakage * scalingFactor); + uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() + .set(uc, cuVolumeMinusDecayWastageBreakage * scalingFactor); } // quadratic mean diameter is not a per-hectare value and // therefore not scaled. @@ -104,8 +108,12 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { } private static final float MAX_ACCEPTABLE_BASAL_AREA_ERROR = 0.1f; - private static final UtilizationVector CLASS_LOWER_BOUNDS = new UtilizationVector(4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f); - private static final UtilizationVector CLASS_UPPER_BOUNDS = new UtilizationVector(7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f); + private static final UtilizationVector CLASS_LOWER_BOUNDS = new UtilizationVector( + 4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f + ); + private static final UtilizationVector CLASS_UPPER_BOUNDS = new UtilizationVector( + 7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f + ); private static final float DQ_EPS = 0.005f; /** @@ -113,7 +121,7 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { */ private static void resetOnMissingValues(VdypUtilizationHolder uh) { - for (UtilizationClass uc: UtilizationClass.values()) { + for (UtilizationClass uc : UtilizationClass.values()) { if (uh.getBaseAreaByUtilization().get(uc) <= 0.0f || uh.getTreesPerHectareByUtilization().get(uc) <= 0.0f) { uh.getBaseAreaByUtilization().set(uc, 0.0f); uh.getTreesPerHectareByUtilization().set(uc, 0.0f); @@ -134,18 +142,18 @@ private static void resetOnMissingValues(VdypUtilizationHolder uh) { */ private static void adjustBasalAreaToMatchTreesPerHectare(VdypUtilizationHolder uh) throws ProcessingException { - for (UtilizationClass uc: UtilizationClass.values()) { + for (UtilizationClass uc : UtilizationClass.values()) { float tph = uh.getTreesPerHectareByUtilization().get(uc); if (tph > 0.0f) { float basalAreaLowerBound = BaseAreaTreeDensityDiameter .basalArea(CLASS_LOWER_BOUNDS.get(uc) + DQ_EPS, tph); float basalAreaUpperBound = BaseAreaTreeDensityDiameter .basalArea(CLASS_UPPER_BOUNDS.get(uc) - DQ_EPS, tph); - + float basalAreaError; float newBasalArea; String message = null; - + float basalArea = uh.getBaseAreaByUtilization().get(uc); if (basalArea < basalAreaLowerBound) { basalAreaError = FloatMath.abs(basalArea - basalAreaLowerBound); @@ -165,7 +173,7 @@ private static void adjustBasalAreaToMatchTreesPerHectare(VdypUtilizationHolder basalAreaError = 0.0f; newBasalArea = basalArea; } - + if (basalAreaError > MAX_ACCEPTABLE_BASAL_AREA_ERROR) { throw new ProcessingException(message); } else { @@ -184,12 +192,12 @@ private static void adjustBasalAreaToMatchTreesPerHectare(VdypUtilizationHolder */ private static void doCalculateQuadMeanDiameter(VdypUtilizationHolder uh) throws ProcessingException { - for (UtilizationClass uc: UtilizationClass.values()) { + for (UtilizationClass uc : UtilizationClass.values()) { float basalArea = uh.getBaseAreaByUtilization().get(uc); if (basalArea > 0.0f) { float tph = uh.getTreesPerHectareByUtilization().get(uc); float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, tph); - + if (qmd < CLASS_LOWER_BOUNDS.get(uc)) { qmd = qmd + DQ_EPS; if (qmd /* is still */ < CLASS_LOWER_BOUNDS.get(uc)) { @@ -211,7 +219,7 @@ private static void doCalculateQuadMeanDiameter(VdypUtilizationHolder uh) throws ); } } - + uh.getQuadraticMeanDiameterByUtilization().set(uc, qmd); } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java index f53c8a799..78158d894 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/Utils.java @@ -320,9 +320,8 @@ public static int getGenusIndex(String genusAlias, Map controlMa } public static GenusDefinition getGenusDefinition(String genusAlias, Map controlMap) { - return (GenusDefinition) expectParsedControl( - controlMap, ControlKey.SP0_DEF, GenusDefinitionMap.class - ).getByAlias(genusAlias); + return (GenusDefinition) expectParsedControl(controlMap, ControlKey.SP0_DEF, GenusDefinitionMap.class) + .getByAlias(genusAlias); } /** diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java index d6d62aaea..986ff0f51 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndex.java @@ -133,7 +133,8 @@ public static double heightToIndex( break; case SI_FDI_MILNER: index = Utils.computeInFeet( - height, heightFt -> 57.3 + height, + heightFt -> 57.3 + (7.06 + 0.02275 * bhage - 1.858 * Math.log(bhage) + 5.496 / (bhage * bhage)) * (heightFt - 4.5 - 114.6 * Math.pow(1 - Math.exp(-0.01462 * bhage), 1.179)) ); @@ -157,7 +158,8 @@ public static double heightToIndex( // #define LW_MILNER 1 Removed since never used again? case SI_LW_MILNER: index = Utils.computeInFeet( - height, heightFt -> 69.0 + height, + heightFt -> 69.0 + (-0.8019 + 17.06 / bhage + 0.4268 * Math.log(bhage) - 0.00009635 * bhage * bhage) * (heightFt - 4.5 - 127.8 * Math.pow(1 - Math.exp(-0.01655 * bhage), 1.196)) ); @@ -172,14 +174,15 @@ public static double heightToIndex( break; case SI_PLI_MILNER: index = Utils.computeInFeet( - height, heightFt -> 59.6 - + (1.055 - 0.006344 * bhage + 14.82 / bhage - 5.212 / (bhage * bhage)) - * (heightFt - 4.5 - 96.93 * Math.pow(1 - Math.exp(-0.01955 * bhage), 1.216)) + height, + heightFt -> 59.6 + (1.055 - 0.006344 * bhage + 14.82 / bhage - 5.212 / (bhage * bhage)) + * (heightFt - 4.5 - 96.93 * Math.pow(1 - Math.exp(-0.01955 * bhage), 1.216)) ); break; case SI_PY_MILNER: index = Utils.computeInFeet( - height, heightFt -> 59.6 + height, + heightFt -> 59.6 + (4.787 + 0.012544 * bhage - 1.141 * Math.log(bhage) + 11.44 / (bhage * bhage)) * (heightFt - 4.5 - 121.4 * Math.pow(1 - Math.exp(-0.01756 * bhage), 1.483)) ); @@ -189,7 +192,8 @@ public static double heightToIndex( x2 = x1 * x1; index = Utils.computeInFeet( - height, heightFt -> Math.exp(-2.608801 * x1 - 0.715601 * x2) + height, + heightFt -> Math.exp(-2.608801 * x1 - 0.715601 * x2) * Math.pow(heightFt, 1.0 + 0.408404 * x1 + 0.138199 * x2) ); break; @@ -243,13 +247,15 @@ public static double heightToIndex( break; case SI_FDI_VDP_MONT: index = Utils.computeInFeet( - height, heightFt -> 4.5 + 111.832 + 0.721 * (heightFt - 4.5) - 28.2175 * Math.log(bhage) + height, + heightFt -> 4.5 + 111.832 + 0.721 * (heightFt - 4.5) - 28.2175 * Math.log(bhage) - 731.551 / (bhage * bhage) + 13.164 * (heightFt - 4.5) / bhage ); break; case SI_FDI_VDP_WASH: index = Utils.computeInFeet( - height, heightFt -> 4.5 + 146.274 + 0.809 * (heightFt - 4.5) - 37.218 * Math.log(bhage) + height, + heightFt -> 4.5 + 146.274 + 0.809 * (heightFt - 4.5) - 37.218 * Math.log(bhage) - 1064.4055 / (bhage * bhage) + 9.511 * (heightFt - 4.5) / bhage ); break; @@ -260,7 +266,8 @@ public static double heightToIndex( logBhAge = Math.log(bhage); index = Utils.computeInFeet( - height, heightFt -> 4.5 + 38.787 - 2.805 * logBhAge * logBhAge + 0.0216 * bhage * logBhAge + height, + heightFt -> 4.5 + 38.787 - 2.805 * logBhAge * logBhAge + 0.0216 * bhage * logBhAge + x1 * heightFt + x2 * heightFt / bhage ); break; @@ -3649,8 +3656,8 @@ private static double findSiteIndex1(double bhage, double height, double x1, dou logBhAge = Math.log(bhage); index = Utils.computeInFeet( - height, heightFt -> 4.5 + 38.787 - 2.805 * logBhAge * logBhAge + 0.0216 * bhage * logBhAge - + x1 * heightFt + height, + heightFt -> 4.5 + 38.787 - 2.805 * logBhAge * logBhAge + 0.0216 * bhage * logBhAge + x1 * heightFt + x2 * heightFt / bhage ); return index; @@ -3693,8 +3700,8 @@ public static double siteIterate(SiteIndexEquation cuIndex, double age, SiteInde } else { /* was age - y2bh */ testTop = SiteIndex2Height.indexToHeight( - cuIndex, AgeToAge - .ageToAge(cuIndex, age, SI_AT_TOTAL, SI_AT_BREAST, y2bh), SI_AT_BREAST, site, y2bh, 0.5 + cuIndex, AgeToAge.ageToAge(cuIndex, age, SI_AT_TOTAL, SI_AT_BREAST, y2bh), SI_AT_BREAST, site, + y2bh, 0.5 ); // 0.5 may have to change } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java index f01b4219a..93c300ae6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndex.java @@ -308,7 +308,8 @@ public static double classToIndex(SiteIndexSpecies spIndex, char siteClass, char throw new SpeciesErrorException( MessageFormat.format( - "classToIndex: not found: spIndex {0}, sitecl {1}, fiz {2}", spIndex, siteClass, forestInventoryZone + "classToIndex: not found: spIndex {0}, sitecl {1}, fiz {2}", spIndex, siteClass, + forestInventoryZone ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java index ca8b506f2..0c7b6db62 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Age.java @@ -550,8 +550,8 @@ private static double iterate( // Write to the file fileWriter.write( String.format( - "before index_to_height(age=%.2f, age_type=%s, site_index=%.2f, y2bh=%.2f)%n", si2age, ageType - .toString(), siteIndex, yearsToBreastHeight + "before index_to_height(age=%.2f, age_type=%s, site_index=%.2f, y2bh=%.2f)%n", + si2age, ageType.toString(), siteIndex, yearsToBreastHeight ) ); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java index d5d253736..2fc70f2ab 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2Height.java @@ -163,8 +163,8 @@ public static double indexToHeight( siteIndex = -1.73 + 3.149 * ppow(siteIndex, 0.8279); height = 1.37 + (22.87 + 0.9502 * (siteIndex - 1.37)) * ppow( - 1 - Math.exp(-0.0020647 * ppow(siteIndex - 1.37, 0.5) * breastHeightAge), 1.3656 - + 2.046 / (siteIndex - 1.37) + 1 - Math.exp(-0.0020647 * ppow(siteIndex - 1.37, 0.5) * breastHeightAge), + 1.3656 + 2.046 / (siteIndex - 1.37) ); } else height = totalAge * totalAge * 1.37 / years2BreastHeight / years2BreastHeight; @@ -175,8 +175,8 @@ public static double indexToHeight( siteIndex = -1.73 + 3.149 * ppow(siteIndex, 0.8279); height = 1.37 + (22.87 + 0.9502 * (siteIndex - 1.37)) * ppow( - 1 - Math.exp(-0.0020647 * ppow(siteIndex - 1.37, 0.5) * (breastHeightAge - 0.5)), 1.3656 - + 2.046 / (siteIndex - 1.37) + 1 - Math.exp(-0.0020647 * ppow(siteIndex - 1.37, 0.5) * (breastHeightAge - 0.5)), + 1.3656 + 2.046 / (siteIndex - 1.37) ); } else { height = totalAge * totalAge * 1.37 / years2BreastHeight / years2BreastHeight; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index 4bbce7825..1dd9ee223 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -49,13 +49,13 @@ public class CachingResolvedControlMapImpl implements ResolvedControlMap { final MatrixMap2 decayEquationGroups; final MatrixMap2 breakageEquationGroups; final Map quadMeanDiameterBySpeciesCoefficients; - + private final Map controlMap; - + public CachingResolvedControlMapImpl(Map controlMap) { this.controlMap = controlMap; - + this.becLookup = this.get(ControlKey.BEC_DEF, BecLookup.class); this.genusDefinitionMap = this.get(ControlKey.SP0_DEF, GenusDefinitionMap.class); @@ -89,7 +89,7 @@ public CachingResolvedControlMapImpl(Map controlMap) { this.quadMeanDiameterBySpeciesCoefficients = this.get(ControlKey.BY_SPECIES_DQ, Map.class); } - /** + /** * @return the underlying control map */ @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index 188708cc5..54a8d29be 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -16,7 +16,7 @@ public interface ResolvedControlMap { Map getControlMap(); - + /** 9 - BEC_DEF */ BecLookup getBecLookup(); @@ -25,13 +25,13 @@ public interface ResolvedControlMap { /** 20 - VOLUME_EQN_GROUPS */ MatrixMap2 getVolumeEquationGroups(); - + /** 21 - DECAY_GROUPS */ MatrixMap2 getDecayEquationGroups(); /** 22 - BREAKAGE_GROUPS */ MatrixMap2 getBreakageEquationGroups(); - + /** 26 - SITE_CURVE_AGE_MAX */ Map getMaximumAgeBySiteCurveNumber(); @@ -49,7 +49,7 @@ public interface ResolvedControlMap { /** 52 - HL_PRIMARY_SP_EQN_P3 */ MatrixMap2 getHl3Coefficients(); - + /** 53 - HL_NONPRIMARY */ MatrixMap3> getHlNonPrimaryCoefficients(); @@ -58,7 +58,7 @@ public interface ResolvedControlMap { /** 61 - SPECIES_COMPONENT_SIZE_LIMIT */ MatrixMap2 getComponentSizeLimits(); - + /** 70 - UTIL_COMP_BA */ MatrixMap3 getBasalAreaDiameterUtilizationComponentMap(); @@ -97,7 +97,7 @@ public interface ResolvedControlMap { /** 95 - BREAKAGE */ Map getNetBreakageMap(); - + /** 108 - BA_DQ_UPPER_BOUNDS */ Map getUpperBounds(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java index 2d2765995..e69a60e1a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMapImpl.java @@ -28,14 +28,14 @@ public ResolvedControlMapImpl(Map controlMap) { this.controlMap = controlMap; } - /** + /** * @return the underlying control map */ @Override public Map getControlMap() { return Collections.unmodifiableMap(controlMap); } - + @SuppressWarnings("unchecked") private U get(ControlKey key, Class clazz) { @@ -50,7 +50,8 @@ private U get(ControlKey key, Class clazz) { @Override public GenusDefinitionMap getGenusDefinitionMap() { - GenusDefinitionMap genusDefinitions = this.get(ControlKey.SP0_DEF, GenusDefinitionMap.class); + GenusDefinitionMap genusDefinitions = this + .get(ControlKey.SP0_DEF, GenusDefinitionMap.class); return genusDefinitions; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java index 6b6825c2c..e349b4361 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/FileResolver.java @@ -6,7 +6,7 @@ import java.nio.file.Path; public interface FileResolver { - + InputStream resolveForInput(String filename) throws IOException; OutputStream resolveForOutput(String filename) throws IOException; @@ -14,7 +14,7 @@ public interface FileResolver { String toString(String filename) throws IOException; Path toPath(String filename) throws IOException; - + /** * Create a FileResolver that resolves relative to a given path * diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java index 32f3ab384..b618e4c10 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java @@ -14,8 +14,9 @@ public class ZipOutputFileResolver implements FileResolver { - private record OutputStreamDetails(Path outputStreamLocation, OutputStream outputStream) {}; - + private record OutputStreamDetails(Path outputStreamLocation, OutputStream outputStream) { + }; + private Map entryOutputStreams = new HashMap<>(); @Override @@ -33,7 +34,7 @@ public OutputStream resolveForOutput(String filename) throws IOException { Path tempFile = Files.createTempFile("vdyp", filename); OutputStream entryOutputStream = Files.newOutputStream(tempFile); entryOutputStreams.put(filename, new OutputStreamDetails(tempFile, entryOutputStream)); - + return entryOutputStream; } @@ -46,19 +47,22 @@ public String toString(String filename) throws IOException { public ZipOutputFileResolver relative(String path) throws IOException { throw new UnsupportedOperationException(); } - + private static final int BUFFER_SIZE = 64 * 1024; - + public void generate(Path zipFile) throws IOException { try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(zipFile.toFile()))) { - - for (Map.Entry e: entryOutputStreams.entrySet()) { + + for (Map.Entry e : entryOutputStreams.entrySet()) { close(e.getValue().outputStream); ZipEntry entry = new ZipEntry(e.getKey()); - try (InputStream entryReader = Files.newInputStream(e.getValue().outputStreamLocation, StandardOpenOption.READ)) { + try ( + InputStream entryReader = Files + .newInputStream(e.getValue().outputStreamLocation, StandardOpenOption.READ) + ) { zipOutputStream.putNextEntry(entry); - + byte[] cBuffer = new byte[BUFFER_SIZE]; int nCharsRead = entryReader.read(cBuffer, 0, BUFFER_SIZE); while (nCharsRead >= 0) { @@ -71,19 +75,22 @@ public void generate(Path zipFile) throws IOException { } } } - + public InputStream generateStream() throws IOException { - + Path tempFile = Files.createTempFile("vdypOutputZipFile", ".zip"); - + try (ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(tempFile.toFile()))) { - for (Map.Entry e: entryOutputStreams.entrySet()) { + for (Map.Entry e : entryOutputStreams.entrySet()) { close(e.getValue().outputStream); - + ZipEntry entry = new ZipEntry(e.getKey()); - try (InputStream entryReader = Files.newInputStream(e.getValue().outputStreamLocation, StandardOpenOption.READ)) { + try ( + InputStream entryReader = Files + .newInputStream(e.getValue().outputStreamLocation, StandardOpenOption.READ) + ) { zipOutputStream.putNextEntry(entry); - + byte[] cBuffer = new byte[BUFFER_SIZE]; int nCharsRead = entryReader.read(cBuffer, 0, BUFFER_SIZE); while (nCharsRead >= 0) { @@ -95,10 +102,10 @@ public InputStream generateStream() throws IOException { } } } - + return Files.newInputStream(tempFile); } - + private static void close(OutputStream os) { try { os.close(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java index edc3cf26e..f2b1836f4 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/DqGrowthEmpiricalLimitsParser.java @@ -68,7 +68,8 @@ public Map parse(InputStream is, Map cont if (basalAreaGroupId < 1 || basalAreaGroupId > MAX_BASAL_AREA_GROUP_ID) { throw new ValueParseException( MessageFormat.format( - "Line {0}: basal area group id {1} is out of range; expecting a value from 1 to {2}", lineNumber, basalAreaGroupId, MAX_BASAL_AREA_GROUP_ID + "Line {0}: basal area group id {1} is out of range; expecting a value from 1 to {2}", + lineNumber, basalAreaGroupId, MAX_BASAL_AREA_GROUP_ID ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java index 0f80b3130..043948690 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/EquationGroupParser.java @@ -53,7 +53,8 @@ public boolean isIgnoredSegment(List entry) { } }.strippedString(2, SP0_ALIAS_KEY).space(1).strippedString(4, BEC_ALIAS_KEY).space(1).value( - identifierLength, GROUP_ID_KEY, ValueParser.validate( + identifierLength, GROUP_ID_KEY, + ValueParser.validate( ValueParser.INTEGER, ValueParser.validateRangeInclusive(MIN_GROUP, MAX_GROUP, GROUP_ID_KEY) ) ); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java index a79389450..d3abaffb7 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParser.java @@ -49,7 +49,8 @@ public class GenusDefinitionParser implements ControlMapSubResourceParser ValueParser.optional(ValueParser.INTEGER).parse(s) + 2, "preference", + (s, c) -> ValueParser.optional(ValueParser.INTEGER).parse(s) .flatMap(v -> v == 0 ? Optional.empty() : Optional.of(v)) ); @@ -87,7 +88,8 @@ public GenusDefinitionMap parse(InputStream is, Map control) throw new ValueParseException( Integer.toString(index), String.format( - "preference values must be between %d and %d (inclusive); saw value %d", 1, numSp0, index + "preference values must be between %d and %d (inclusive); saw value %d", 1, numSp0, + index ) ); } @@ -95,8 +97,8 @@ public GenusDefinitionMap parse(InputStream is, Map control) throw new ValueParseException( Integer.toString(index), String.format( - "Genera ordering %d has already been specified for genera %s", index, r[index - 1] - .getAlias() + "Genera ordering %d has already been specified for genera %s", index, + r[index - 1].getAlias() ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java index 33b4bae69..a7d994b94 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UpperBoundsParser.java @@ -80,7 +80,8 @@ public Map parse(InputStream is, Map cont if (baGroupId < 0 || baGroupId >= LAST_BA_GROUP_ID) { throw new ValueParseException( MessageFormat.format( - "Line {0}: Basal Area Group Id {0} is out of range; expecting a value from 1 to {1}", lineNumber, baGroupId, LAST_BA_GROUP_ID + "Line {0}: Basal Area Group Id {0} is out of range; expecting a value from 1 to {1}", + lineNumber, baGroupId, LAST_BA_GROUP_ID ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java index b156d5eee..71c8b38d2 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BaseCoefficientParser.java @@ -109,7 +109,8 @@ public BaseCoefficientParser key( ); } var validParser = ControlledValueParser.validate( - parser, (v, control) -> range.apply(control).contains(v) ? Optional.empty() + parser, + (v, control) -> range.apply(control).contains(v) ? Optional.empty() : Optional.of(String.format(errorTemplate, v)) ); lineParser.value(length, name, validParser); @@ -134,22 +135,23 @@ public BaseCoefficientParser regionKey() { public BaseCoefficientParser ucIndexKey() { var indicies = Arrays.asList(1, 2, 3, 4); return key( - 2, UC_INDEX, ValueParser.INTEGER, indicies, "%s is not a valid UC Index, should be 1 to 4 inclusive", BLANK_OR_ZERO - .asPredicate() + 2, UC_INDEX, ValueParser.INTEGER, indicies, "%s is not a valid UC Index, should be 1 to 4 inclusive", + BLANK_OR_ZERO.asPredicate() ); } public BaseCoefficientParser groupIndexKey(int maxGroups) { var indicies = Stream.iterate(1, x -> x + 1).limit(maxGroups).toList(); return key( - 3, GROUP_INDEX, ValueParser.INTEGER, indicies, "%s is not a valid Group Index, should be 1 to " - + maxGroups + " inclusive", BLANK_OR_ZERO.asPredicate() + 3, GROUP_INDEX, ValueParser.INTEGER, indicies, + "%s is not a valid Group Index, should be 1 to " + maxGroups + " inclusive", BLANK_OR_ZERO.asPredicate() ); } public BaseCoefficientParser speciesKey(String name) { return key( - 2, name, ControlledValueParser.GENUS, GenusDefinitionParser::getSpeciesAliases, "%s is not a valid species", String::isBlank + 2, name, ControlledValueParser.GENUS, GenusDefinitionParser::getSpeciesAliases, + "%s is not a valid species", String::isBlank ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java index da76c0c51..32cfe1b26 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/BecZoneBySpeciesCoefficientParser.java @@ -55,8 +55,8 @@ public boolean isIgnoredLine(String line) { .value(4, BEC_ZONE_ID_KEY, ControlledValueParser.BEC) // .space(2) // .value( - 1, INDEX_KEY, ValueParser - .range(ValueParser.INTEGER, 0, true, nCoefficients, false, "Index value") + 1, INDEX_KEY, + ValueParser.range(ValueParser.INTEGER, 0, true, nCoefficients, false, "Index value") ) // .value(2, INDICATOR_KEY, ValueParser.range(ValueParser.INTEGER, 0, true, 1, true, "Indicator value")) // .multiValue(NUM_SPECIES, 8, COEFFICIENTS_KEY, ValueParser.FLOAT); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java index fa5e1fbda..48db3df5b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/GrowthFiatParser.java @@ -45,7 +45,8 @@ public Map parse(InputStream is, Map if (regionId != 1 && regionId != 2) { throw new ValueParseException( MessageFormat.format( - "Line {0}: region id {1} is not recognized; the value must be 1 or 2", lineNumber, regionId + "Line {0}: region id {1} is not recognized; the value must be 1 or 2", lineNumber, + regionId ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java index 0502a3494..23d545a09 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/NonPrimarySpeciesGrowthParser.java @@ -1,50 +1,25 @@ package ca.bc.gov.nrs.vdyp.io.parse.coe.base; -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.IntStream; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.Utils; -import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.io.parse.value.ValueParser; -import ca.bc.gov.nrs.vdyp.model.Coefficients; -import ca.bc.gov.nrs.vdyp.model.MatrixMap2; public abstract class NonPrimarySpeciesGrowthParser extends OptionalCoefficientParser2 { private static final int MAX_BASAL_AREA_GROUP_ID = 30; - private static final Optional defaultCoefficients = Optional - .of(new Coefficients(new float[] { 0.0f, 0.0f, 0.0f }, 1)); - private static final String BASAL_AREA_GROUP_ID_KEY = "BasalAreaGroupId"; protected NonPrimarySpeciesGrowthParser(ControlKey controlKey) { super(1, controlKey); this.speciesKey() .key( - 3, BASAL_AREA_GROUP_ID_KEY, ValueParser.INTEGER, IntStream - .rangeClosed(0, MAX_BASAL_AREA_GROUP_ID).boxed().collect( - Collectors.toList() - ), "%s is not a valid basal area group id", k -> Utils.nullOrBlank(k) + 3, BASAL_AREA_GROUP_ID_KEY, ValueParser.INTEGER, + IntStream.rangeClosed(0, MAX_BASAL_AREA_GROUP_ID).boxed().collect(Collectors.toList()), + "%s is not a valid basal area group id", k -> Utils.nullOrBlank(k) ).coefficients(3, 10); } - - @Override - public MatrixMap2> parse(InputStream is, Map control) - throws IOException, ResourceParseException { - var m = super.parse(is, control); - - m.eachKey(k -> { - if (m.getM(k).isEmpty()) { - m.put((String) k[0], (Integer) k[1], defaultCoefficients); - } - }); - - return m; - } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java index f37280cab..50d80db6c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/coe/base/PrimarySpeciesGrowthParser.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.IntStream; import ca.bc.gov.nrs.vdyp.io.parse.common.LineParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; @@ -36,10 +35,6 @@ public abstract class PrimarySpeciesGrowthParser private static final int MAX_BASAL_AREA_GROUP_NUMBER = 30; - private static final ModelCoefficients defaultModelCoefficients = new ModelCoefficients( - 0, new Coefficients(new float[] { 0.0f, 0.0f, 0.0f }, 1) - ); - public static final String BASAL_AREA_GROUP_ID_KEY = "BasalAreaGroupId"; public static final String MODEL_NUMBER_KEY = "Model"; public static final String COEFFICIENTS_KEY = "Coefficients"; @@ -73,7 +68,8 @@ public Map parse(InputStream is, Map if (basalAreaGroupId < 1 || basalAreaGroupId > MAX_BASAL_AREA_GROUP_NUMBER) { throw new ValueParseException( MessageFormat.format( - "Line {0}: basal area group id {1} is out of range; expecting a value from 1 to {2}", lineNumber, basalAreaGroupId, MAX_BASAL_AREA_GROUP_NUMBER + "Line {0}: basal area group id {1} is out of range; expecting a value from 1 to {2}", + lineNumber, basalAreaGroupId, MAX_BASAL_AREA_GROUP_NUMBER ) ); } @@ -87,11 +83,6 @@ public Map parse(InputStream is, Map return r; }, control); - IntStream.rangeClosed(1, MAX_BASAL_AREA_GROUP_NUMBER).forEach(i -> { - if (!result.containsKey(i)) - result.put(i, defaultModelCoefficients); - }); - return result; } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java index 434999424..9e59c4137 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParser.java @@ -40,9 +40,10 @@ protected NonFipControlParser() { .record(ControlKey.BA_DQ_UPPER_BOUNDS, FILENAME) // COE108 .record( - ControlKey.MINIMA, ValueParser.toMap( - ValueParser.list(ValueParser.FLOAT), Collections - .singletonMap(MINIMUM_VETERAN_HEIGHT, 10.0f), MINIMUM_HEIGHT, // VMINH + ControlKey.MINIMA, + ValueParser.toMap( + ValueParser.list(ValueParser.FLOAT), + Collections.singletonMap(MINIMUM_VETERAN_HEIGHT, 10.0f), MINIMUM_HEIGHT, // VMINH MINIMUM_BASE_AREA, // VMINBA MINIMUM_PREDICTED_BASE_AREA, // VMINBAeqn MINIMUM_VETERAN_HEIGHT // VMINVetH @@ -84,9 +85,8 @@ protected void applyAllModifiers(Map map, FileResolver fileResol protected ValueParser> minimaParser() { return ValueParser.callback( ValueParser.toMap( - ValueParser.list(ValueParser.FLOAT), Collections.singletonMap( - MINIMUM_VETERAN_HEIGHT, 10.0f - ), MINIMUM_HEIGHT, MINIMUM_BASE_AREA, MINIMUM_PREDICTED_BASE_AREA, MINIMUM_VETERAN_HEIGHT + ValueParser.list(ValueParser.FLOAT), Collections.singletonMap(MINIMUM_VETERAN_HEIGHT, 10.0f), + MINIMUM_HEIGHT, MINIMUM_BASE_AREA, MINIMUM_PREDICTED_BASE_AREA, MINIMUM_VETERAN_HEIGHT ), minima -> { log.atDebug().setMessage( "Minima read from VRISTART Control at line {}\n Minimum Height: {}\n Minimum BA: {}\n Minimum Predicted BA: {}\n Minimum Veteran Height: {}" diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java index 38a3c63b0..1277dd5d5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParser.java @@ -161,8 +161,8 @@ public static ValueParser indexParser(String sequenceName, int indexFro if (x.compareTo(min) < (includeMin ? 0 : 1)) { return Optional.of( String.format( - RANGE_ERROR_TEMPLATE, name, includeMin ? "greater than or equal to" - : "greater than", min + RANGE_ERROR_TEMPLATE, name, includeMin ? "greater than or equal to" : "greater than", + min ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java index fe1f54722..b4c81c8bb 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java @@ -34,7 +34,7 @@ public class VdypOutputWriter implements Closeable { private OutputStream utilizationFile; @SuppressWarnings("unused") private Optional compatibilityVariablesFile; - + private Optional currentYear = Optional.empty(); static final String POLY_IDENTIFIER_FORMAT = "%-25s"; @@ -66,8 +66,8 @@ public class VdypOutputWriter implements Closeable { static final String END_RECORD_FORMAT = POLY_IDENTIFIER_FORMAT + " \n"; /** - * Create a writer for Vdyp output files using provided OutputStreams. The Streams will be - * closed when the writer is closed. + * Create a writer for Vdyp output files using provided OutputStreams. The Streams will be closed when the writer is + * closed. * * @param polygonFile * @param speciesFile @@ -75,15 +75,13 @@ public class VdypOutputWriter implements Closeable { * @param compatibilityVariablesFile * @param controlMap */ - public VdypOutputWriter( - OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile - ) { + public VdypOutputWriter(OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile) { this(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. + * Create a writer for Vdyp output files using provided OutputStreams. The Streams will be closed when the writer is + * closed. * * @param polygonFile * @param speciesFile @@ -114,7 +112,9 @@ public VdypOutputWriter(Map controlMap, FileResolver resolver) t 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()), - Optional.of(getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name())) + Optional.of( + getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name()) + ) ); } @@ -127,7 +127,7 @@ static OutputStream getOutputStream(Map controlMap, FileResolver public void setPolygonYear(int currentYear) { this.currentYear = Optional.of(currentYear); } - + private PolygonIdentifier getCurrentPolygonDescriptor(PolygonIdentifier originalIdentifier) { if (currentYear.isPresent()) { return new PolygonIdentifier(originalIdentifier.getBase(), currentYear.get()); @@ -135,7 +135,7 @@ private PolygonIdentifier getCurrentPolygonDescriptor(PolygonIdentifier original return originalIdentifier; } } - + // V7W_AIP /** * Write a polygon record to the polygon file @@ -144,7 +144,7 @@ private PolygonIdentifier getCurrentPolygonDescriptor(PolygonIdentifier original * @throws IOException */ void writePolygon(VdypPolygon polygon) throws IOException { - + writeFormat( polygonFile, // POLY_FORMAT, // @@ -171,8 +171,8 @@ 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)) + 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 boolean isSiteSpec = layer.getSiteGenus().map(spec.getGenus()::equals).orElse(false); @@ -233,8 +233,8 @@ void writeUtilization(VdypLayer layer, VdypUtilizationHolder utils) throws IOExc if (utils.getBaseAreaByUtilization().getCoe(uc.index) > 0) { quadMeanDiameter = Optional.of( BaseAreaTreeDensityDiameter.quadMeanDiameter( - utils.getBaseAreaByUtilization().getCoe(uc.index), utils - .getTreesPerHectareByUtilization().getCoe(uc.index) + utils.getBaseAreaByUtilization().getCoe(uc.index), + utils.getTreesPerHectareByUtilization().getCoe(uc.index) ) ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java index 94223fcaa..ab1376a3a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/math/FloatMath.java @@ -95,8 +95,8 @@ public static float safeExponent(float logit) throws ProcessingException { } /** - * Compute the maximum of three float values, using Math.max to do pairwise - * comparisons. + * Compute the maximum of three float values, using Math.max to do pairwise comparisons. + * * @param f1 * @param f2 * @param f3 @@ -105,10 +105,10 @@ public static float safeExponent(float logit) throws ProcessingException { public static float max(float f1, float f2, float f3) { return Math.max(f1, Math.max(f2, f3)); } - + /** - * Compute the maximum of four float values, using Math.max to do pairwise - * comparisons. + * Compute the maximum of four float values, using Math.max to do pairwise comparisons. + * * @param f1 * @param f2 * @param f3 diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index ace759c84..408abf02f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -52,7 +52,7 @@ public void setSpecies(Map species) { public void setSpecies(Collection species) { this.speciesBySp0.clear(); this.speciesByIndex.clear(); - species.forEach(spec -> { + species.forEach(spec -> { this.speciesBySp0.put(spec.getGenus(), spec); this.speciesByIndex.put(spec.getGenusIndex(), spec); }); @@ -65,7 +65,7 @@ public S getSpeciesBySp0(String sp0) { public S getSpeciesByIndex(int index) { return speciesByIndex.get(index); } - + public LinkedHashMap getSites() { var result = new LinkedHashMap(speciesBySp0.size()); speciesBySp0.forEach((key, spec) -> spec.getSite().ifPresent(site -> result.put(key, site))); @@ -79,18 +79,17 @@ public Optional getInventoryTypeGroup() { public void setInventoryTypeGroup(Optional inventoryTypeGroup) { this.inventoryTypeGroup = inventoryTypeGroup; } - + @Override public String toString() { return polygonIdentifier.toStringCompact() + "-" + layerType; } - + @Override public boolean equals(Object other) { if (other instanceof BaseVdypLayer that) { // This is the "business key" of a layer. - return this.polygonIdentifier.equals(that.polygonIdentifier) - && this.layerType.equals(that.layerType); + return this.polygonIdentifier.equals(that.polygonIdentifier) && this.layerType.equals(that.layerType); } else { return false; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java index 30e84065a..01e9a6431 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java @@ -114,12 +114,12 @@ public Optional getMode() { public void setMode(Optional mode) { this.mode = mode; } - + @Override public String toString() { return polygonIdentifier.toStringCompact(); } - + @Override public boolean equals(Object other) { if (other instanceof BaseVdypPolygon that) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java index cd60faf01..f59d507e3 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java @@ -71,18 +71,17 @@ public Optional getYearsToBreastHeight() { public Optional getYearsAtBreastHeight() { return Utils.mapBoth(ageTotal, yearsToBreastHeight, (age, ytbh) -> age - ytbh); } - + @Override public String toString() { return polygonIdentifier.toStringCompact() + "-" + layerType + "-" + siteGenus; } - + @Override public boolean equals(Object other) { if (other instanceof BaseVdypSite that) { // This is the "business key" of a site. - return this.polygonIdentifier.equals(that.polygonIdentifier) - && this.layerType.equals(that.layerType) + return this.polygonIdentifier.equals(that.polygonIdentifier) && this.layerType.equals(that.layerType) && this.siteGenus.equals(that.siteGenus); } else { return false; @@ -198,7 +197,6 @@ protected void check(Collection errors) { requirePresent(layerType, "layerType", errors); requirePresent(siteGenus, "siteGenus", errors); } - @Override protected String getBuilderId() { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 3523784dd..613695604 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -39,8 +39,8 @@ public abstract class BaseVdypSpecies { private Optional site; protected BaseVdypSpecies( - PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, int genusIndex, Optional percentGenus, - Sp64DistributionSet sp64DistributionSet, Optional site + PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, int genusIndex, + Optional percentGenus, Sp64DistributionSet sp64DistributionSet, Optional site ) { this.polygonIdentifier = polygonIdentifier; this.layerType = layerType; @@ -60,7 +60,9 @@ public LayerType getLayerType() { } public float getPercentGenus() { - return percentGenus.orElseThrow(() -> new InitializationIncompleteException(MessageFormat.format("Species {0}, percentGenus", this))); + return percentGenus.orElseThrow( + () -> new InitializationIncompleteException(MessageFormat.format("Species {0}, percentGenus", this)) + ); } public void setPercentGenus(float value) { @@ -71,7 +73,9 @@ public void setPercentGenus(float value) { @Computed public float getFractionGenus() { - return fractionGenus.orElseThrow(() -> new InitializationIncompleteException(MessageFormat.format("Species {0}, fractionGenus", this))); + return fractionGenus.orElseThrow( + () -> new InitializationIncompleteException(MessageFormat.format("Species {0}, fractionGenus", this)) + ); } @Computed @@ -88,13 +92,12 @@ public Sp64DistributionSet getSp64DistributionSet() { public String toString() { return MessageFormat.format("{0} {1} {2}", polygonIdentifier, layerType, genus); } - + @Override public boolean equals(Object other) { if (other instanceof BaseVdypSpecies that) { // This is the "business key" of a species. - return this.polygonIdentifier.equals(that.polygonIdentifier) - && this.layerType.equals(that.layerType) + return this.polygonIdentifier.equals(that.polygonIdentifier) && this.layerType.equals(that.layerType) && this.genus.equals(that.genus); } else { return false; @@ -181,7 +184,8 @@ public Builder layerType(LayerType layer) { /** * Set both the genus, and at the same time calculates genusIndex from the given controlMap. - * @param genus the species genus + * + * @param genus the species genus * @param controlMap the control map defining the configuration * @return this builder */ @@ -192,12 +196,11 @@ public Builder genus(String genus, Map controlMap) { } /** - * Set both the genus and its index. It is the responsibility of the caller to ensure - * that the index is correct for the given genus. Use of this method is appropriate - * only when logic dictates the given genusIndex is correct or in those unit tests - * where correctness isn't critical. - * - * @param genus the species genus + * Set both the genus and its index. It is the responsibility of the caller to ensure that the index is correct + * for the given genus. Use of this method is appropriate only when logic dictates the given genusIndex is + * correct or in those unit tests where correctness isn't critical. + * + * @param genus the species genus * @param genusIndex the index of the genus in the configuration (control map entry 10) * @return this builder */ @@ -260,7 +263,7 @@ protected void check(Collection errors) { requirePresent(layerType, "layerType", errors); requirePresent(genus, "genus", errors); requirePresent(genusIndex, "genusIndex", errors); - + // percentGenus is not required on build because the Forward // input data format does not include it in the species data files. // requirePresent(percentGenus, "percentGenus", errors); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java index 3123f6000..597c163e0 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Coefficients.java @@ -29,7 +29,7 @@ public Coefficients(List coe, int indexFrom) { this(listToArray(coe), indexFrom); } - + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java index 6bdbc69bd..4a6910a94 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/CompatibilityVariableMode.java @@ -13,7 +13,7 @@ public enum CompatibilityVariableMode { * Apply compatibility variables to all components */ ALL; // 2 - + public static CompatibilityVariableMode getByInteger(int v) { return values()[v]; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java index cb1a89295..aff21b5e6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/Sp64DistributionSet.java @@ -96,8 +96,9 @@ public int getSize() { } /** - * Returns the Sp64Distribution at index withIndex. THIS INDEX is - * one-based - that is, the first entry has index one. + * Returns the Sp64Distribution at index withIndex. THIS INDEX is one-based - that is, the first entry + * has index one. + * * @param withIndex index, one-based, in list. * @return as described */ @@ -140,8 +141,8 @@ private static void validate(int maxIndex, List gdList) throws if (gd.getIndex() < 1 || gd.getIndex() > maxIndex) { throw new InvalidGenusDistributionSet( MessageFormat.format( - "Index {0} is out of range - acceptable values are between 1 and {1}, inclusive", gd - .getIndex(), maxIndex + "Index {0} is out of range - acceptable values are between 1 and {1}, inclusive", + gd.getIndex(), maxIndex ) ); } @@ -149,8 +150,8 @@ private static void validate(int maxIndex, List gdList) throws if (prevGd != null && prevGd.getPercentage() < gd.getPercentage()) { throw new InvalidGenusDistributionSet( MessageFormat.format( - "The percentage of index {0} is {1} and is greater than {2}, that of a species distribution with a lower index", gd - .getIndex(), maxIndex + "The percentage of index {0} is {1} and is greater than {2}, that of a species distribution with a lower index", + gd.getIndex(), maxIndex ) ); } @@ -210,8 +211,8 @@ public int compareTo(Sp64DistributionSet that) { return 1; } } - - @Override + + @Override public String toString() { return this.sp64DistributionList.toString(); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java index 1f63471f4..9f021b8bd 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/UtilizationVector.java @@ -9,7 +9,10 @@ public class UtilizationVector extends Coefficients { public UtilizationVector() { - super(new float[] { Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN }, UtilizationClass.SMALL.index); + super( + new float[] { Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN }, + UtilizationClass.SMALL.index + ); } public UtilizationVector(float small, float all, float uc1, float uc2, float uc3, float uc4) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java index d451bcf25..8abb01d80 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypEntity.java @@ -3,7 +3,7 @@ public interface VdypEntity { /** This indicates "not set" for a Float */ Float MISSING_FLOAT_VALUE = Float.NaN; - + /** This is a "special" magic number indicating "not set" for an Integer value - a legacy of VDYP 7 */ Integer MISSING_INTEGER_VALUE = -9; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 4d57177ec..23037c039 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -154,7 +154,7 @@ public void setEmpericalRelationshipParameterIndex(Optional empericalRe * VdypLayer myLayer = VdypLayer.build(builder-> { builder.polygonIdentifier(polygonId); builder.layerType(LayerType.VETERAN); - + builder.crownClosure(0.9f); * }) * diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index 229033ca1..0df19ce8d 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -98,7 +98,12 @@ public void targetYear(Optional targetYear) { public void setTargetYear(int year) { if (targetYear.isPresent()) { - throw new IllegalStateException(MessageFormat.format("Polygon {} has already had a target year ({}) assigned", this.getPolygonIdentifier(), this.getTargetYear())); + throw new IllegalStateException( + MessageFormat.format( + "Polygon {} has already had a target year ({}) assigned", this.getPolygonIdentifier(), + this.getTargetYear() + ) + ); } else { this.targetYear = Optional.of(year); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index 3e6b20158..343bbbab1 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -26,18 +26,18 @@ public class VdypSpecies extends BaseVdypSpecies implements VdypUtiliz private Optional volumeGroup; private Optional decayGroup; private Optional breakageGroup; - + // Compatibility Variables - + private Optional> cvVolume = Optional.empty(); private Optional> cvBasalArea = Optional.empty(); private Optional> cvQuadraticMeanDiameter = Optional.empty(); private Optional> cvPrimaryLayerSmall = Optional.empty(); public VdypSpecies( - PolygonIdentifier polygonIdentifier, LayerType layer, String genus, int genusIndex, Optional percentGenus, - Sp64DistributionSet sp64DistributionSet, Optional site, Optional volumeGroup, - Optional decayGroup, Optional breakageGroup + PolygonIdentifier polygonIdentifier, LayerType layer, String genus, int genusIndex, + Optional percentGenus, Sp64DistributionSet sp64DistributionSet, Optional site, + Optional volumeGroup, Optional decayGroup, Optional breakageGroup ) { super(polygonIdentifier, layer, genus, genusIndex, percentGenus, sp64DistributionSet, site); this.volumeGroup = volumeGroup; @@ -78,41 +78,46 @@ public void setLoreyHeightByUtilization(UtilizationVector loreyHeightByUtilizati } public int getVolumeGroup() { - return volumeGroup.orElseThrow(() -> new NoSuchElementException(MessageFormat.format("Species {0} volumeGroup", - toString()))); + return volumeGroup.orElseThrow( + () -> new NoSuchElementException(MessageFormat.format("Species {0} volumeGroup", toString())) + ); } public void setVolumeGroup(int volumeGroup) { if (this.volumeGroup.isPresent()) { throw new IllegalStateException(MessageFormat.format("Species {0} volumeGroup is already set", toString())); } - + this.volumeGroup = Optional.of(volumeGroup); } public int getDecayGroup() { - return decayGroup.orElseThrow(() -> new NoSuchElementException(MessageFormat.format("Species {0} decayGroup", - toString()))); + return decayGroup.orElseThrow( + () -> new NoSuchElementException(MessageFormat.format("Species {0} decayGroup", toString())) + ); } public void setDecayGroup(int decayGroup) { if (this.decayGroup.isPresent()) { throw new IllegalStateException(MessageFormat.format("Species {0} decayGroup is already set", toString())); } - + this.decayGroup = Optional.of(decayGroup); } public int getBreakageGroup() { - return breakageGroup.orElseThrow(() -> new NoSuchElementException(MessageFormat.format("Species {0} breakageGroup", - toString()))); + return breakageGroup.orElseThrow( + () -> new NoSuchElementException(MessageFormat.format("Species {0} breakageGroup", toString())) + ); } public void setBreakageGroup(int breakageGroup) { if (this.breakageGroup.isPresent()) { - throw new IllegalStateException(MessageFormat.format("Species {0} breakageGroup is already set", toString())); + throw new IllegalStateException( + MessageFormat.format("Species {0} breakageGroup is already set", toString()) + ); } - + this.breakageGroup = Optional.of(breakageGroup); } @@ -196,8 +201,9 @@ public void setCompatibilityVariables( MatrixMap3 cvVolume, MatrixMap2 cvBasalArea, MatrixMap2 cvQuadraticMeanDiameter, - Map cvPrimaryLayerSmall) { - + Map cvPrimaryLayerSmall + ) { + this.cvVolume = Optional.of(cvVolume); this.cvBasalArea = Optional.of(cvBasalArea); this.cvQuadraticMeanDiameter = Optional.of(cvQuadraticMeanDiameter); @@ -220,7 +226,9 @@ public float getCvBasalArea(UtilizationClass uc, LayerType lt) { public float getCvQuadraticMeanDiameter(UtilizationClass uc, LayerType lt) { if (cvQuadraticMeanDiameter.isEmpty()) { - throw new InitializationIncompleteException(MessageFormat.format("Species {0}: cvQuadraticMeanDiameter", this)); + throw new InitializationIncompleteException( + MessageFormat.format("Species {0}: cvQuadraticMeanDiameter", this) + ); } return cvQuadraticMeanDiameter.get().get(uc, lt); } @@ -316,7 +324,7 @@ public void quadMeanDiameter(float small, float u1, float u2, float u3, float u4 public void quadMeanDiameter(float height) { this.quadMeanDiameter = Utils.utilizationVector(height); } - + protected UtilizationVector wholeStemVolume = VdypUtilizationHolder.emptyUtilization(); public void wholeStemVolume(float small, float u1, float u2, float u3, float u4) { diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index 216fff620..20afd4e3f 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -519,9 +519,8 @@ void assertItgMixed(VdypStartApplication app, int expected, String primary, Stri for (var sec : secondary) { var result = app.findItg(primarySecondarySpecies(primary, sec)); assertThat( - result, describedAs( - "ITG for " + primary + " and " + sec + " should be " + expected, is(expected) - ) + result, + describedAs("ITG for " + primary + " and " + sec + " should be " + expected, is(expected)) ); } } @@ -532,9 +531,8 @@ void assertItgMixed(VdypStartApplication app, int expected, String primary, Coll var mocks = primarySecondarySpecies(primary, sec); var result = app.findItg(mocks); assertThat( - result, describedAs( - "ITG for " + primary + " and " + sec + " should be " + expected, is(expected) - ) + result, + describedAs("ITG for " + primary + " and " + sec + " should be " + expected, is(expected)) ); } } @@ -639,12 +637,12 @@ void testModified() throws Exception { var mockControl = EasyMock.createControl(); controlMap.put( - ControlKey.DEFAULT_EQ_NUM.name(), new MatrixMap2Impl( - Collections.singletonList("D"), Collections.singletonList("CDF"), (x, y) -> 42 - ) + ControlKey.DEFAULT_EQ_NUM.name(), + new MatrixMap2Impl(Collections.singletonList("D"), Collections.singletonList("CDF"), (x, y) -> 42) ); controlMap.put( - ControlKey.EQN_MODIFIERS.name(), new MatrixMap2Impl( + ControlKey.EQN_MODIFIERS.name(), + new MatrixMap2Impl( Collections.singletonList(42), Collections.singletonList(37), (x, y) -> Optional.of(64) ) ); @@ -670,12 +668,12 @@ void testUnmodified() throws Exception { var mockControl = EasyMock.createControl(); controlMap.put( - ControlKey.DEFAULT_EQ_NUM.name(), new MatrixMap2Impl( - Collections.singletonList("D"), Collections.singletonList("CDF"), (x, y) -> 42 - ) + ControlKey.DEFAULT_EQ_NUM.name(), + new MatrixMap2Impl(Collections.singletonList("D"), Collections.singletonList("CDF"), (x, y) -> 42) ); controlMap.put( - ControlKey.EQN_MODIFIERS.name(), new MatrixMap2Impl( + ControlKey.EQN_MODIFIERS.name(), + new MatrixMap2Impl( Collections.singletonList(42), Collections.singletonList(37), (x, y) -> Optional.empty() ) ); @@ -843,8 +841,8 @@ void testLowResult() throws Exception { }); var ex = assertThrows( - LowValueException.class, () -> app - .estimatePrimaryBaseArea(layer, bec, 1f, 79.5999985f, 3.13497972f) + LowValueException.class, + () -> app.estimatePrimaryBaseArea(layer, bec, 1f, 79.5999985f, 3.13497972f) ); assertThat(ex, hasProperty("value", is(0f))); @@ -1545,8 +1543,10 @@ void testRequireLayer() throws ProcessingException, IOException { assertThat(result, is(layer)); var ex = assertThrows(StandProcessingException.class, () -> app.requireLayer(poly, LayerType.VETERAN)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon \"TestPoly 2024\" has no VETERAN layer, or that layer has non-positive height or crown closure." ) ) @@ -1603,9 +1603,10 @@ void testWeightedCoefficientSum() { }); assertThat( - result, coe( - 1, 2f, 2f + 0.3f + 0.3f, 7f, 6f * 0.4f - 3f * 0.1f + 0.3f * 1f, 9f, 4f * 0.4f + 3f * 0.1f - + 0.3f * 1f + result, + coe( + 1, 2f, 2f + 0.3f + 0.3f, 7f, 6f * 0.4f - 3f * 0.1f + 0.3f * 1f, 9f, + 4f * 0.4f + 3f * 0.1f + 0.3f * 1f ) ); } @@ -1684,7 +1685,9 @@ void testComputeUtilizationComponentsPrimaryByUtilNoCV() throws ProcessingExcept layer.setSpecies(Arrays.asList(spec1, spec2)); EstimationMethods estimationMethods = new EstimationMethods(new ResolvedControlMapImpl(controlMap)); - ComputationMethods computationMethods = new ComputationMethods(estimationMethods, VdypApplicationIdentifier.FIP_START); + ComputationMethods computationMethods = new ComputationMethods( + estimationMethods, VdypApplicationIdentifier.FIP_START + ); computationMethods.computeUtilizationComponentsPrimary( bec, layer, VolumeComputeMode.BY_UTIL, CompatibilityVariableMode.NONE ); @@ -1696,131 +1699,107 @@ void testComputeUtilizationComponentsPrimaryByUtilNoCV() throws ProcessingExcept assertThat(spec2.getLoreyHeightByUtilization(), utilizationHeight(7.81696558f, 12.9176102f)); assertThat( - spec1.getBaseAreaByUtilization(), utilization( - 0.012636207f, 2.20898318f, 0.691931725f, 0.862404406f, 0.433804274f, 0.220842764f - ) + spec1.getBaseAreaByUtilization(), + utilization(0.012636207f, 2.20898318f, 0.691931725f, 0.862404406f, 0.433804274f, 0.220842764f) ); assertThat( - spec2.getBaseAreaByUtilization(), utilization( - 0.0160128288f, 17.7696857f, 6.10537529f, 7.68449211f, 3.20196891f, 0.777849257f - ) + spec2.getBaseAreaByUtilization(), + utilization(0.0160128288f, 17.7696857f, 6.10537529f, 7.68449211f, 3.20196891f, 0.777849257f) ); assertThat( - layer.getBaseAreaByUtilization(), utilization( - 0.0286490358f, 19.9786682f, 6.79730701f, 8.54689693f, 3.63577318f, 0.998692036f - ) + layer.getBaseAreaByUtilization(), + utilization(0.0286490358f, 19.9786682f, 6.79730701f, 8.54689693f, 3.63577318f, 0.998692036f) ); assertThat( - spec1.getTreesPerHectareByUtilization(), utilization( - 3.68722916f, 154.454025f, 84.0144501f, 51.3837852f, 14.7746315f, 4.28116179f - ) + spec1.getTreesPerHectareByUtilization(), + utilization(3.68722916f, 154.454025f, 84.0144501f, 51.3837852f, 14.7746315f, 4.28116179f) ); assertThat( - spec2.getTreesPerHectareByUtilization(), utilization( - 5.60301685f, 1331.36682f, 750.238892f, 457.704498f, 108.785675f, 14.6378069f - ) + spec2.getTreesPerHectareByUtilization(), + utilization(5.60301685f, 1331.36682f, 750.238892f, 457.704498f, 108.785675f, 14.6378069f) ); assertThat( - layer.getTreesPerHectareByUtilization(), utilization( - 9.29024601f, 1485.8208f, 834.253357f, 509.088287f, 123.560303f, 18.9189682f - ) + layer.getTreesPerHectareByUtilization(), + utilization(9.29024601f, 1485.8208f, 834.253357f, 509.088287f, 123.560303f, 18.9189682f) ); assertThat( - spec1.getQuadraticMeanDiameterByUtilization(), utilization( - 6.60561657f, 13.4943399f, 10.2402296f, 14.6183214f, 19.3349762f, 25.6280651f - ) + spec1.getQuadraticMeanDiameterByUtilization(), + utilization(6.60561657f, 13.4943399f, 10.2402296f, 14.6183214f, 19.3349762f, 25.6280651f) ); assertThat( - spec2.getQuadraticMeanDiameterByUtilization(), utilization( - 6.03223324f, 13.0360518f, 10.1791487f, 14.6207638f, 19.3587704f, 26.0114632f - ) + spec2.getQuadraticMeanDiameterByUtilization(), + utilization(6.03223324f, 13.0360518f, 10.1791487f, 14.6207638f, 19.3587704f, 26.0114632f) ); assertThat( - layer.getQuadraticMeanDiameterByUtilization(), utilization( - 6.26608753f, 13.0844393f, 10.1853161f, 14.6205177f, 19.3559265f, 25.9252014f - ) + layer.getQuadraticMeanDiameterByUtilization(), + utilization(6.26608753f, 13.0844393f, 10.1853161f, 14.6205177f, 19.3559265f, 25.9252014f) ); assertThat( - spec1.getWholeStemVolumeByUtilization(), utilization( - 0.0411359742f, 11.7993851f, 3.13278913f, 4.76524019f, 2.63645673f, 1.26489878f - ) + spec1.getWholeStemVolumeByUtilization(), + utilization(0.0411359742f, 11.7993851f, 3.13278913f, 4.76524019f, 2.63645673f, 1.26489878f) ); assertThat( - spec2.getWholeStemVolumeByUtilization(), utilization( - 0.0665520951f, 106.194412f, 30.2351704f, 47.6655998f, 22.5931034f, 5.70053911f - ) + spec2.getWholeStemVolumeByUtilization(), + utilization(0.0665520951f, 106.194412f, 30.2351704f, 47.6655998f, 22.5931034f, 5.70053911f) ); assertThat( - layer.getWholeStemVolumeByUtilization(), utilization( - 0.107688069f, 117.993797f, 33.3679581f, 52.4308395f, 25.2295609f, 6.96543789f - ) + layer.getWholeStemVolumeByUtilization(), + utilization(0.107688069f, 117.993797f, 33.3679581f, 52.4308395f, 25.2295609f, 6.96543789f) ); assertThat( - spec1.getCloseUtilizationVolumeByUtilization(), utilization( - 0f, 6.41845179f, 0.0353721268f, 2.99654913f, 2.23212862f, 1.1544019f - ) + spec1.getCloseUtilizationVolumeByUtilization(), + utilization(0f, 6.41845179f, 0.0353721268f, 2.99654913f, 2.23212862f, 1.1544019f) ); assertThat( - spec2.getCloseUtilizationVolumeByUtilization(), utilization( - 0f, 61.335495f, 2.38199472f, 33.878521f, 19.783432f, 5.29154539f - ) + spec2.getCloseUtilizationVolumeByUtilization(), + utilization(0f, 61.335495f, 2.38199472f, 33.878521f, 19.783432f, 5.29154539f) ); assertThat( - layer.getCloseUtilizationVolumeByUtilization(), utilization( - 0f, 67.7539444f, 2.41736674f, 36.8750687f, 22.0155602f, 6.44594717f - ) + layer.getCloseUtilizationVolumeByUtilization(), + utilization(0f, 67.7539444f, 2.41736674f, 36.8750687f, 22.0155602f, 6.44594717f) ); assertThat( - spec1.getCloseUtilizationVolumeNetOfDecayByUtilization(), utilization( - 0f, 6.26433992f, 0.0349677317f, 2.95546484f, 2.18952441f, 1.08438313f - ) + spec1.getCloseUtilizationVolumeNetOfDecayByUtilization(), + utilization(0f, 6.26433992f, 0.0349677317f, 2.95546484f, 2.18952441f, 1.08438313f) ); assertThat( - spec2.getCloseUtilizationVolumeNetOfDecayByUtilization(), utilization( - 0f, 60.8021164f, 2.36405492f, 33.6109734f, 19.6035042f, 5.2235837f - ) + spec2.getCloseUtilizationVolumeNetOfDecayByUtilization(), + utilization(0f, 60.8021164f, 2.36405492f, 33.6109734f, 19.6035042f, 5.2235837f) ); assertThat( - layer.getCloseUtilizationVolumeNetOfDecayByUtilization(), utilization( - 0f, 67.0664597f, 2.39902258f, 36.5664368f, 21.7930279f, 6.30796671f - ) + layer.getCloseUtilizationVolumeNetOfDecayByUtilization(), + utilization(0f, 67.0664597f, 2.39902258f, 36.5664368f, 21.7930279f, 6.30796671f) ); assertThat( - spec1.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), utilization( - 0f, 6.18276405f, 0.0347718038f, 2.93580461f, 2.16927385f, 1.04291379f - ) + spec1.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), + utilization(0f, 6.18276405f, 0.0347718038f, 2.93580461f, 2.16927385f, 1.04291379f) ); assertThat( - spec2.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), utilization( - 0f, 60.6585732f, 2.36029577f, 33.544487f, 19.5525551f, 5.20123625f - ) + spec2.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), + utilization(0f, 60.6585732f, 2.36029577f, 33.544487f, 19.5525551f, 5.20123625f) ); assertThat( - layer.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), utilization( - 0f, 66.8413391f, 2.39506769f, 36.4802933f, 21.7218285f, 6.24415016f - ) + layer.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), + utilization(0f, 66.8413391f, 2.39506769f, 36.4802933f, 21.7218285f, 6.24415016f) ); assertThat( - spec1.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), utilization( - 0f, 5.989573f, 0.0337106399f, 2.84590816f, 2.10230994f, 1.00764418f - ) + spec1.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), + utilization(0f, 5.989573f, 0.0337106399f, 2.84590816f, 2.10230994f, 1.00764418f) ); assertThat( - spec2.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), utilization( - 0f, 59.4318657f, 2.31265593f, 32.8669167f, 19.1568871f, 5.09540558f - ) + spec2.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), + utilization(0f, 59.4318657f, 2.31265593f, 32.8669167f, 19.1568871f, 5.09540558f) ); assertThat( - layer.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), utilization( - 0f, 65.4214401f, 2.34636664f, 35.7128258f, 21.2591972f, 6.10304976f - ) + layer.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), + utilization(0f, 65.4214401f, 2.34636664f, 35.7128258f, 21.2591972f, 6.10304976f) ); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java index 297ea6b95..7b3fdc527 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestPolygon.java @@ -17,8 +17,8 @@ public static TestPolygon build(Consumer config) { } protected TestPolygon( - PolygonIdentifier polygonIdentifier, Optional percentAvailable, String fiz, - BecDefinition bec, Optional mode + PolygonIdentifier polygonIdentifier, Optional percentAvailable, String fiz, BecDefinition bec, + Optional mode ) { super(polygonIdentifier, percentAvailable, fiz, bec, mode, Optional.empty()); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java index bcc16ce40..358acdb17 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/test/TestSpecies.java @@ -14,7 +14,10 @@ protected TestSpecies( PolygonIdentifier polygonIdentifier, LayerType layerType, String genus, int genusIndex, float percentGenus, Optional site ) { - super(polygonIdentifier, layerType, genus, genusIndex, Optional.of(percentGenus), new Sp64DistributionSet(), site); + super( + polygonIdentifier, layerType, genus, genusIndex, Optional.of(percentGenus), new Sp64DistributionSet(), + site + ); } public static TestSpecies build(Consumer config) { diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java index f306931c9..d7d7b1210 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/EstimationMethodsTest.java @@ -105,9 +105,8 @@ void testTypical() throws ProcessingException { // Result of run in FORTRAN VDYP7 with the above parameters. assertThat( - basalAreaByUtilization, contains( - 0.0f, 0.406989872f, 0.00509467721f, 0.0138180256f, 0.023145527f, 0.36493164f - ) + basalAreaByUtilization, + contains(0.0f, 0.406989872f, 0.00509467721f, 0.0138180256f, 0.023145527f, 0.36493164f) ); } @@ -128,7 +127,8 @@ void testWithInstantiatedControlMap() throws ProcessingException { emp.estimateBaseAreaByUtilization(bec, dq, ba, "B"); assertThat( - ba, VdypMatchers + ba, + VdypMatchers .utilization(0f, 0.397305071f, 0.00485289097f, 0.0131751001f, 0.0221586525f, 0.357118428f) ); @@ -210,7 +210,8 @@ void testVeteran() throws Exception { var closeUtilizationUtil = Utils.utilizationVector(0f, 0f, 0f, 0f, 0f); emp.estimateCloseUtilizationVolume( - utilizationClass, aAdjust, volumeGroup, lorieHeight, quadMeanDiameterUtil, wholeStemVolumeUtil, closeUtilizationUtil + utilizationClass, aAdjust, volumeGroup, lorieHeight, quadMeanDiameterUtil, wholeStemVolumeUtil, + closeUtilizationUtil ); assertThat(closeUtilizationUtil, utilization(0f, 0f, 0f, 0f, 0f, 5.86088896f)); @@ -520,7 +521,8 @@ void testClampSimple() throws Exception { float quadMeanDiameter2 = 30.249138f; float dq = emp.estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, + quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); assertThat(dq, is(quadMeanDiameter1)); @@ -545,7 +547,8 @@ void testClampToLow2() throws Exception { float quadMeanDiameter1 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea1, treesPerHectare1); float dq = emp.estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, + quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); assertThat(dq, closeTo(30.722431f)); @@ -570,7 +573,8 @@ void testClampToLow1() throws Exception { float quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); float dq = emp.estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, + quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); assertThat(dq, closeTo(28.245578f)); @@ -595,7 +599,8 @@ void testClampToHigh1() throws Exception { float quadMeanDiameter2 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseArea2, treesPerHectare2); float dq = emp.estimateQuadMeanDiameterClampResult( - limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 + limits, standTreesPerHectare, minQuadMeanDiameter, loreyHeightSpec, baseArea1, baseArea2, + quadMeanDiameter1, treesPerHectare2, quadMeanDiameter2 ); assertThat(dq, closeTo(66.565033f)); @@ -634,9 +639,8 @@ void testPrimary() throws ProcessingException { // Result of run in FORTRAN VDYP7 with the above parameters. assertThat( - wholeStemVolumeByUtilization, contains( - 0.0f, 6.27250576f, 0.01865777f, 0.07648385f, 0.17615195f, 6.00121212f - ) + wholeStemVolumeByUtilization, + contains(0.0f, 6.27250576f, 0.01865777f, 0.07648385f, 0.17615195f, 6.00121212f) ); } @@ -651,7 +655,8 @@ void testVeteran() throws Exception { var wholeStemVolumeUtil = Utils.utilizationVector(); emp.estimateWholeStemVolume( - utilizationClass, aAdjust, volumeGroup, lorieHeight, quadMeanDiameterUtil, baseAreaUtil, wholeStemVolumeUtil + utilizationClass, aAdjust, volumeGroup, lorieHeight, quadMeanDiameterUtil, baseAreaUtil, + wholeStemVolumeUtil ); assertThat(wholeStemVolumeUtil, utilization(0f, 0f, 0f, 0f, 0f, 6.11904192f)); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java index f1c264fdd..cc09df0d3 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethodsTest.java @@ -84,8 +84,8 @@ void testReconcileComponentsMode2() throws ProcessingException { ReconcilationMethods.reconcileComponents(ba, tph, dq); assertThat( - ba, VdypMatchers - .utilization(0f, 0.397305071f, 0.00485289097f, 0.0131751001f, 0.0221586525f, 0.357118428f) + ba, + VdypMatchers.utilization(0f, 0.397305071f, 0.00485289097f, 0.0131751001f, 0.0221586525f, 0.357118428f) ); assertThat( tph, VdypMatchers.utilization(0f, 5.04602766f, 0.733301044f, 0.899351299f, 0.851697803f, 2.56167722f) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java index 19832fe8b..e47390913 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java @@ -43,8 +43,8 @@ class ExpectParsedControl { @Test void testMissing() { var ex = assertThrows( - IllegalStateException.class, () -> Utils - .expectParsedControl(Collections.emptyMap(), "NOT_PRESENT", Integer.class) + IllegalStateException.class, + () -> Utils.expectParsedControl(Collections.emptyMap(), "NOT_PRESENT", Integer.class) ); assertThat( ex, hasProperty("message", stringContainsInOrder("Expected control map to have", "NOT_PRESENT")) @@ -54,13 +54,16 @@ ex, hasProperty("message", stringContainsInOrder("Expected control map to have", @Test void testWrongType() { var ex = assertThrows( - IllegalStateException.class, () -> Utils.expectParsedControl( + IllegalStateException.class, + () -> Utils.expectParsedControl( Collections.singletonMap("WRONG_TYPE", 2d), "WRONG_TYPE", Integer.class ) ); assertThat( - ex, hasProperty( - "message", stringContainsInOrder( + ex, + hasProperty( + "message", + stringContainsInOrder( "Expected control map entry", "WRONG_TYPE", "to be", "Integer", "was", "Double" ) ) @@ -70,13 +73,16 @@ ex, hasProperty( @Test void testStillString() { var ex = assertThrows( - IllegalStateException.class, () -> Utils.expectParsedControl( + IllegalStateException.class, + () -> Utils.expectParsedControl( Collections.singletonMap("WRONG_TYPE", "UNPARSED"), "WRONG_TYPE", Integer.class ) ); assertThat( - ex, hasProperty( - "message", stringContainsInOrder( + ex, + hasProperty( + "message", + stringContainsInOrder( "Expected control map entry", "WRONG_TYPE", "to be parsed but was still a String" ) ) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java index d0a56b0c1..f7ce4709e 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/AgeToAgeTest.java @@ -50,13 +50,13 @@ class AgeToAgeTest { @Test void testShouldBranchInvalid() { assertThrows( - AgeTypeErrorException.class, () -> AgeToAge - .ageToAge(SI_ACB_HUANGAC, 0.0, SI_AT_BREAST, SI_AT_BREAST, 0.0) + AgeTypeErrorException.class, + () -> AgeToAge.ageToAge(SI_ACB_HUANGAC, 0.0, SI_AT_BREAST, SI_AT_BREAST, 0.0) ); assertThrows( - AgeTypeErrorException.class, () -> AgeToAge - .ageToAge(SI_ACT_THROWERAC, 0.0, SI_AT_TOTAL, SI_AT_TOTAL, 0.0) + AgeTypeErrorException.class, + () -> AgeToAge.ageToAge(SI_ACT_THROWERAC, 0.0, SI_AT_TOTAL, SI_AT_TOTAL, 0.0) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java index 49f87e496..4dccfa14a 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/Height2SiteIndexTest.java @@ -90,24 +90,24 @@ class Height_to_indexTest { @Test void testInvalidHeightForBreastHeightAge() { assertThrows( - LessThan13Exception.class, () -> Height2SiteIndex - .heightToIndex(null, 0.0, SI_AT_BREAST, 1.2, SI_EST_ITERATE) + LessThan13Exception.class, + () -> Height2SiteIndex.heightToIndex(null, 0.0, SI_AT_BREAST, 1.2, SI_EST_ITERATE) ); } @Test void testInvalidHeightForIteration() { assertThrows( - NoAnswerException.class, () -> Height2SiteIndex - .heightToIndex(null, 0.0, SI_AT_TOTAL, 0, SI_EST_ITERATE) + NoAnswerException.class, + () -> Height2SiteIndex.heightToIndex(null, 0.0, SI_AT_TOTAL, 0, SI_EST_ITERATE) ); } @Test void testInvalidAgeForIteration() { assertThrows( - NoAnswerException.class, () -> Height2SiteIndex - .heightToIndex(null, 0.0, SI_AT_TOTAL, 1.3, SI_EST_ITERATE) + NoAnswerException.class, + () -> Height2SiteIndex.heightToIndex(null, 0.0, SI_AT_TOTAL, 1.3, SI_EST_ITERATE) ); } @@ -178,8 +178,8 @@ class ba_height_to_indexTest { @Test void testInvalidBhage() { assertThrows( - GrowthInterceptMinimumException.class, () -> Height2SiteIndex - .baHeightToIndex(null, 0.5, 1.0, SiteIndexEstimationType.SI_EST_ITERATE) + GrowthInterceptMinimumException.class, + () -> Height2SiteIndex.baHeightToIndex(null, 0.5, 1.0, SiteIndexEstimationType.SI_EST_ITERATE) ); // SI_AT_TOTAL = 0 } @@ -750,8 +750,8 @@ private static double calculateExpectedResultSI_FDI_NIGHGI(int bhage, double hei void testInvalidSI_FDI_NIGHGI() { double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_FDI_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_FDI_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -990,8 +990,8 @@ private static double calculateExpectedResultSI_PLI_NIGHGI97(int bhage, double h void testInvalidSI_PLI_NIGHGI97() { double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_PLI_NIGHGI97, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_PLI_NIGHGI97, 51, height, SI_EST_DIRECT) ); } @@ -1149,8 +1149,8 @@ private static double calculateExpectedResultSI_SW_NIGHGI(int bhage, double heig void testInvalidSI_SW_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_SW_NIGHGI, 31, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_SW_NIGHGI, 31, height, SI_EST_DIRECT) ); } @@ -1388,8 +1388,8 @@ private static double calculateExpectedResultSI_SW_NIGHGI99(int bhage, double he void testInvalidSI_SW_NIGHGI99() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_SW_NIGHGI99, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_SW_NIGHGI99, 51, height, SI_EST_DIRECT) ); } @@ -1628,8 +1628,8 @@ private static double calculateExpectedResultSI_SW_NIGHGI2004(int bhage, double void testInvalidSI_SW_NIGHGI2004() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_SW_NIGHGI2004, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_SW_NIGHGI2004, 51, height, SI_EST_DIRECT) ); } @@ -1868,8 +1868,8 @@ private static double calculateExpectedResultSI_HWC_NIGHGI99(int bhage, double h void testInvalidSI_HWC_NIGHGI99() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_HWC_NIGHGI99, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_HWC_NIGHGI99, 51, height, SI_EST_DIRECT) ); } @@ -2028,8 +2028,8 @@ private static double calculateExpectedResultSI_HWC_NIGHGI(int bhage, double hei void testInvalidSI_HWC_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_HWC_NIGHGI, 31, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_HWC_NIGHGI, 31, height, SI_EST_DIRECT) ); } @@ -2268,8 +2268,8 @@ private static double calculateExpectedResultSI_HWI_NIGHGI(int bhage, double hei void testInvalidSI_HWI_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_HWI_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_HWI_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -2508,8 +2508,8 @@ private static double calculateExpectedResultSI_FDC_NIGHGI(int bhage, double hei void testInvalidSI_FDC_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_FDC_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_FDC_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -2745,8 +2745,8 @@ private static double calculateExpectedResultSI_SE_NIGHGI(int bhage, double heig void testInvalidSI_SE_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_SE_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_SE_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -2903,8 +2903,8 @@ private static double calculateExpectedResultSI_SS_NIGHGI(int bhage, double heig void testInvalidSI_SS_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_SS_NIGHGI, 31, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_SS_NIGHGI, 31, height, SI_EST_DIRECT) ); } @@ -3142,8 +3142,8 @@ void testInvalidSI_SS_NIGHGI99() throws CommonCalculatorException { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_SS_NIGHGI99, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_SS_NIGHGI99, 51, height, SI_EST_DIRECT) ); } @@ -3380,8 +3380,8 @@ private static double calculateExpectedResultSI_CWI_NIGHGI(int bhage, double hei void testInvalidSI_CWI_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_CWI_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_CWI_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -3618,8 +3618,8 @@ private static double calculateExpectedResultSI_LW_NIGHGI(int bhage, double heig void testInvalidSI_LW_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_LW_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_LW_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -3856,8 +3856,8 @@ private static double calculateExpectedResultSI_PY_NIGHGI(int bhage, double heig void testInvalidSI_PY_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_PY_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_PY_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -4094,8 +4094,8 @@ private static double calculateExpectedResultSI_BA_NIGHGI(int bhage, double heig void testInvalidSI_BA_NIGHGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_BA_NIGHGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_BA_NIGHGI, 51, height, SI_EST_DIRECT) ); } @@ -4332,8 +4332,8 @@ private static double calculateExpectedResultSI_BL_THROWERGI(int bhage, double h void testInvalidSI_BL_THROWERGI() { // checks minimum and maximum for bhage double height = 1.3; assertThrows( - GrowthInterceptMaximumException.class, () -> Height2SiteIndex - .baHeightToIndex(SI_BL_THROWERGI, 51, height, SI_EST_DIRECT) + GrowthInterceptMaximumException.class, + () -> Height2SiteIndex.baHeightToIndex(SI_BL_THROWERGI, 51, height, SI_EST_DIRECT) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java index 014fc83dc..27ea5665a 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteClassCode2SiteIndexTest.java @@ -207,8 +207,8 @@ void testSI_SPEC_Hwc() throws CommonCalculatorException { assertEquals(actualResult, (double) 4); assertThrows( - ForestInventoryZoneException.class, () -> SiteClassCode2SiteIndex - .classToIndex(SI_SPEC_HWC, validSiteCl[3], 'X') + ForestInventoryZoneException.class, + () -> SiteClassCode2SiteIndex.classToIndex(SI_SPEC_HWC, validSiteCl[3], 'X') ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java index e594500c1..f6adc12fe 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2AgeTest.java @@ -47,8 +47,8 @@ class index_to_ageTest { void testSiteHeightLessTooSmall() throws CommonCalculatorException { // Test where SiteHeight < 1.3, AgeType = 1 (SI_AT_BREAST) assertThrows( - LessThan13Exception.class, () -> SiteIndex2Age - .indexToAge(SI_BL_THROWERGI, 0.0, SI_AT_BREAST, 1.0, 0.0) + LessThan13Exception.class, + () -> SiteIndex2Age.indexToAge(SI_BL_THROWERGI, 0.0, SI_AT_BREAST, 1.0, 0.0) ); // Test where SiteHeight <= 0.0001 @@ -61,8 +61,8 @@ void testSiteHeightLessTooSmall() throws CommonCalculatorException { void testSiteIndexLessTooSmall() { // Test where SiteHeight < 1.3, AgeType = 1 (SI_AT_BREAST) assertThrows( - LessThan13Exception.class, () -> SiteIndex2Age - .indexToAge(SI_BL_THROWERGI, 1.4, SI_AT_BREAST, 1.0, 0.0) + LessThan13Exception.class, + () -> SiteIndex2Age.indexToAge(SI_BL_THROWERGI, 1.4, SI_AT_BREAST, 1.0, 0.0) ); } @@ -90,8 +90,8 @@ void testSI_FDC_BRUCEInvalidDenominator() { double site_height = 0.00011; assertThrows( - ArithmeticException.class, () -> SiteIndex2Age - .indexToAge(SI_FDC_BRUCE, site_height, null, site_index, 12) + ArithmeticException.class, + () -> SiteIndex2Age.indexToAge(SI_FDC_BRUCE, site_height, null, site_index, 12) ); } @@ -101,8 +101,8 @@ void testSI_FDC_BRUCEX1TooSmall() { double site_height = 1.31; assertThrows( - NoAnswerException.class, () -> SiteIndex2Age - .indexToAge(SI_FDC_BRUCE, site_height, SI_AT_BREAST, site_index, 12.0) + NoAnswerException.class, + () -> SiteIndex2Age.indexToAge(SI_FDC_BRUCE, site_height, SI_AT_BREAST, site_index, 12.0) ); } @@ -112,8 +112,8 @@ void testSI_FDC_BRUCEAgeTooBig() { double site_height = 1.6; assertThrows( - NoAnswerException.class, () -> SiteIndex2Age - .indexToAge(SI_FDC_BRUCE, site_height, SI_AT_BREAST, site_index, 12.0) + NoAnswerException.class, + () -> SiteIndex2Age.indexToAge(SI_FDC_BRUCE, site_height, SI_AT_BREAST, site_index, 12.0) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java index 72ce5b817..109bfd061 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightSmoothedTest.java @@ -23,24 +23,24 @@ class IndexToHeightSmoothedTest { @Test void testInvalidSiteIndex() throws CommonCalculatorException { assertThrows( - LessThan13Exception.class, () -> SiteIndex2HeightSmoothed - .indexToHeightSmoothed(null, 0.0, SI_AT_TOTAL, 1.2, 0.0, 0.0, 0.0) + LessThan13Exception.class, + () -> SiteIndex2HeightSmoothed.indexToHeightSmoothed(null, 0.0, SI_AT_TOTAL, 1.2, 0.0, 0.0, 0.0) ); } @Test void testInvalidY2BH() throws CommonCalculatorException { assertThrows( - NoAnswerException.class, () -> SiteIndex2HeightSmoothed - .indexToHeightSmoothed(null, 0.0, SI_AT_TOTAL, 1.31, -1.0, 0.0, 0.0) + NoAnswerException.class, + () -> SiteIndex2HeightSmoothed.indexToHeightSmoothed(null, 0.0, SI_AT_TOTAL, 1.31, -1.0, 0.0, 0.0) ); } @Test void testItageInvalid() throws CommonCalculatorException { assertThrows( - NoAnswerException.class, () -> SiteIndex2HeightSmoothed - .indexToHeightSmoothed(null, -1.0, SI_AT_BREAST, 1.31, 0.0, 0.0, 0.0) + NoAnswerException.class, + () -> SiteIndex2HeightSmoothed.indexToHeightSmoothed(null, -1.0, SI_AT_BREAST, 1.31, 0.0, 0.0, 0.0) ); double actualResult = SiteIndex2HeightSmoothed @@ -52,7 +52,8 @@ void testItageInvalid() throws CommonCalculatorException { @Test void testIterationCannotConverge() throws CommonCalculatorException { assertThrows( - NoAnswerException.class, () -> SiteIndex2HeightSmoothed + NoAnswerException.class, + () -> SiteIndex2HeightSmoothed .indexToHeightSmoothed(SI_PLI_THROWER, 0.0, SI_AT_BREAST, 1.31, 1.0, 0, 0) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java index a14d6be67..7b51ca669 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common_calculators/SiteIndex2HeightTest.java @@ -67,8 +67,8 @@ class Index_to_heightTest { @Test void testInvalidSiteIndex() throws CommonCalculatorException { assertThrows( - LessThan13Exception.class, () -> SiteIndex2Height - .indexToHeight(null, 0.0, SI_AT_TOTAL, 1.2, 0.0, 0.0) + LessThan13Exception.class, + () -> SiteIndex2Height.indexToHeight(null, 0.0, SI_AT_TOTAL, 1.2, 0.0, 0.0) ); } @@ -80,8 +80,8 @@ void testInvalidTage() throws CommonCalculatorException { assertThat(actualResult, closeTo(expectedResult, ERROR_TOLERANCE)); assertThrows( - NoAnswerException.class, () -> SiteIndex2Height - .indexToHeight(SI_CWC_KURUCZAC, (short) -1, SI_AT_TOTAL, 1.31, 0.0, 0.0) + NoAnswerException.class, + () -> SiteIndex2Height.indexToHeight(SI_CWC_KURUCZAC, (short) -1, SI_AT_TOTAL, 1.31, 0.0, 0.0) ); } @@ -204,8 +204,8 @@ void testSI_HWC_FARRBhageLessThanZero() throws CommonCalculatorException { // Le void testSI_HWC_BARKER() throws CommonCalculatorException { double actualResult = SiteIndex2Height.indexToHeight(SI_HWC_BARKER, 0.0, SI_AT_BREAST, 1.31, 1.0, 0.0); double expectedResult = Math.exp(4.35753) * SiteIndexUtilities.ppow( - (-10.45 + 1.30049 * 1.31 - 0.0022 * 1.7161) / Math.exp(4.35753), SiteIndexUtilities - .ppow(50.0, 0.756313) + (-10.45 + 1.30049 * 1.31 - 0.0022 * 1.7161) / Math.exp(4.35753), + SiteIndexUtilities.ppow(50.0, 0.756313) ); assertThat(actualResult, closeTo(expectedResult, ERROR_TOLERANCE)); @@ -218,8 +218,8 @@ void testSI_HM_MEANSBhageGreaterThanZero() throws CommonCalculatorException { site_index = -1.73 + 3.149 * SiteIndexUtilities.ppow(site_index, 0.8279); double expectedResult = 1.37 + (22.87 + 0.9502 * (site_index - 1.37)) * SiteIndexUtilities.ppow( - 1 - Math.exp(-0.0020647 * SiteIndexUtilities.ppow(site_index - 1.37, 0.5) * 5), 1.3656 - + 2.046 / (site_index - 1.37) + 1 - Math.exp(-0.0020647 * SiteIndexUtilities.ppow(site_index - 1.37, 0.5) * 5), + 1.3656 + 2.046 / (site_index - 1.37) ); assertThat(actualResult, closeTo(expectedResult, ERROR_TOLERANCE)); @@ -242,8 +242,8 @@ void testSI_HM_MEANSACBhageGreaterThanHalf() throws CommonCalculatorException { site_index = -1.73 + 3.149 * SiteIndexUtilities.ppow(site_index, 0.8279); double expectedResult = 1.37 + (22.87 + 0.9502 * (site_index - 1.37)) * SiteIndexUtilities.ppow( - 1 - Math.exp(-0.0020647 * SiteIndexUtilities.ppow(site_index - 1.37, 0.5) * 5), 1.3656 - + 2.046 / (site_index - 1.37) + 1 - Math.exp(-0.0020647 * SiteIndexUtilities.ppow(site_index - 1.37, 0.5) * 5), + 1.3656 + 2.046 / (site_index - 1.37) ); assertThat(actualResult, closeTo(expectedResult, ERROR_TOLERANCE)); @@ -456,8 +456,8 @@ void testSI_BA_NIGHGI() throws CommonCalculatorException { @Test void testDefaultSwitchStatement() throws CommonCalculatorException { assertThrows( - CurveErrorException.class, () -> SiteIndex2Height - .indexToHeight(null, 5, SI_AT_BREAST, 1.31, 1.5, 0.0) + CurveErrorException.class, + () -> SiteIndex2Height.indexToHeight(null, 5, SI_AT_BREAST, 1.31, 1.5, 0.0) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index d2574de8a..99f0d0be1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -17,33 +17,37 @@ public class ZipOutputFileResolverTest { @Test void testZipOutputFileResolver() throws IOException { - + ZipOutputFileResolver resolver = new ZipOutputFileResolver(); - + for (int i = 0; i < 5; i++) { OutputStream os = resolver.resolveForOutput("file" + i); os.write(String.format("%d", i).getBytes()); } - + Path zipFile = Files.createTempFile(this.getClass().getName(), ".zip"); - - resolver.generate(zipFile); - - System.out.println("Output zip file written to " + zipFile.toString()); - - try (ZipFile zip = new ZipFile(zipFile.toFile())) { - var entries = zip.entries(); - - byte[] buffer = new byte[16]; - while (entries.hasMoreElements()) { - ZipEntry e = entries.nextElement(); - - InputStream is = zip.getInputStream(e); - int nBytesRead = is.read(buffer, 0, 10); - assertTrue(nBytesRead == 1); - String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); - assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); + try + { + resolver.generate(zipFile); + + System.out.println("Output zip file written to " + zipFile.toString()); + + try (ZipFile zip = new ZipFile(zipFile.toFile())) { + var entries = zip.entries(); + + byte[] buffer = new byte[16]; + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); + + InputStream is = zip.getInputStream(e); + int nBytesRead = is.read(buffer, 0, 10); + assertTrue(nBytesRead == 1); + String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); + assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); + } } + } finally { + Files.delete(zipFile); } } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java index 1acbcff0c..5b3a594e9 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthEmpiricalParserTest.java @@ -37,8 +37,8 @@ void testParseSimple() throws Exception { assertTrue(m.isFull()); assertThat(m.get("AT", "AC"), hasSize(8)); assertThat( - m.get("AT", "AC"), Matchers - .contains(7.9550f, -0.5818f, 0.00538f, 3.90488f, -1.0999f, 0.01348f, 0.82063f, 0.69837f) + m.get("AT", "AC"), + Matchers.contains(7.9550f, -0.5818f, 0.00538f, 3.90488f, -1.0999f, 0.01348f, 0.82063f, 0.69837f) ); assertThat(m.get("AT", "AT"), Matchers.contains(0.0f, 0.0f, 0.0f, 0.0f, 0.0766f, -0.01473f, 0.0f, 0.0f)); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java index 8489dfd23..e9cf59f8d 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaGrowthFiatParserTest.java @@ -35,21 +35,19 @@ void testParseSimple() throws Exception { assertThat(m, Matchers.aMapWithSize(2)); assertThat(m.get(Region.COASTAL).getNAgesSupplied(), Matchers.is(3)); assertThat( - m.get(Region.COASTAL), Matchers.allOf( - Matchers.hasProperty( - "ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f) - ), Matchers.hasProperty( - "coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f) - ), Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) + m.get(Region.COASTAL), + Matchers.allOf( + Matchers.hasProperty("ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f)), + Matchers.hasProperty("coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f)), + Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) ) ); assertThat( - m.get(Region.INTERIOR), Matchers.allOf( - Matchers.hasProperty( - "ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f) - ), Matchers.hasProperty( - "coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f) - ), Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) + m.get(Region.INTERIOR), + Matchers.allOf( + Matchers.hasProperty("ages", Matchers.arrayContaining(1f, 100f, 200f, 0.0f)), + Matchers.hasProperty("coefficients", Matchers.arrayContaining(0.02f, 0.01f, 0.0f, 0.0f)), + Matchers.hasProperty("mixedCoefficients", Matchers.arrayContaining(100.0f, 150.0f, 1.0f)) ) ); } @@ -62,8 +60,8 @@ void testParseMissingInteriorRegion() throws Exception { var is = TestUtils.makeInputStream(" 1 1 .02 100 .01 200 0 0 0 100 150 1.0"); assertThat( - assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), Matchers - .hasProperty("message", Matchers.is("Details for Interior region missing")) + assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), + Matchers.hasProperty("message", Matchers.is("Details for Interior region missing")) ); } @@ -75,8 +73,8 @@ void testParseMissingCoastalRegion() throws Exception { var is = TestUtils.makeInputStream(" 2 1 .02 100 .01 200 0 0 0 100 150 1.0"); assertThat( - assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), Matchers - .hasProperty("message", Matchers.is("Details for Coastal region missing")) + assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), + Matchers.hasProperty("message", Matchers.is("Details for Coastal region missing")) ); } @@ -88,8 +86,8 @@ void testParseMissingRegions() throws Exception { var is = TestUtils.makeInputStream(); assertThat( - assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), Matchers - .hasProperty("message", Matchers.is("Details for Interior and Coastal regions missing")) + assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), + Matchers.hasProperty("message", Matchers.is("Details for Interior and Coastal regions missing")) ); } @@ -104,8 +102,8 @@ void testParseMissingAges() throws Exception { ); assertThat( - assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), Matchers - .hasProperty("message", Matchers.is("Error at line 1: Region Id 1 contains no age ranges")) + assertThrows(ResourceParseException.class, () -> parser.parse(is, new HashMap<>())), + Matchers.hasProperty("message", Matchers.is("Error at line 1: Region Id 1 contains no age ranges")) ); } @@ -121,11 +119,11 @@ void testDuplicatedLines() throws Exception { ); assertThat( - assertThrows(ResourceParseLineException.class, () -> parser.parse(is, new HashMap<>())), Matchers - .hasProperty( - "message", Matchers - .is("Error at line 3: Region Id INTERIOR is present multiple times in the file") - ) + assertThrows(ResourceParseLineException.class, () -> parser.parse(is, new HashMap<>())), + Matchers.hasProperty( + "message", + Matchers.is("Error at line 3: Region Id INTERIOR is present multiple times in the file") + ) ); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java index d18dd44ea..c06745cc7 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/BasalAreaYieldParserTest.java @@ -38,9 +38,10 @@ void testParseSimple() throws Exception { m.get("AT", "AC"), Matchers.contains(-4.8137f, 3.2029f, 7.2295f, 0.5142f, -0.0026f, -0.0054f, -0.0090f) ); assertThat( - m.get("AT", "AT"), Matchers.contains( - -4.8137f - 0.8603f, 3.2029f - 0.2732f, 7.2295f, 0.5142f + 0.1973f, -0.0026f - 0.0272f, -0.0054f - - 0.0007f, -0.0090f + m.get("AT", "AT"), + Matchers.contains( + -4.8137f - 0.8603f, 3.2029f - 0.2732f, 7.2295f, 0.5142f + 0.1973f, -0.0026f - 0.0272f, + -0.0054f - 0.0007f, -0.0090f ) ); } @@ -66,8 +67,8 @@ void testParseContentWithBlankLines() throws Exception { assertThat(m.get("AT", "AC"), Matchers.contains(-4.8137f, 3.2029f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)); assertThat( - m.get("AT", "AT"), Matchers - .contains(-4.8137f - 0.8603f, 3.2029f - 0.2732f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f) + m.get("AT", "AT"), + Matchers.contains(-4.8137f - 0.8603f, 3.2029f - 0.2732f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f) ); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java index 77dc7adb5..e2436193d 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/DqGrowthEmpiricalParserTest.java @@ -31,19 +31,16 @@ void testParseSimple() throws Exception { assertThat(m.get(1), hasSize(10)); assertThat( - m.get(1), contains( - -0.76723f, 0.00000f, -0.18524f, 0.02194f, -0.00752f, -0.00339f, 0.41806f, 0.0f, 0.0f, 0.0f - ) + m.get(1), + contains(-0.76723f, 0.00000f, -0.18524f, 0.02194f, -0.00752f, -0.00339f, 0.41806f, 0.0f, 0.0f, 0.0f) ); assertThat( - m.get(6), contains( - 0.36789f, 0.43192f, -0.73431f, 0.01266f, 0.02527f, 0.00007f, 0.00000f, 0.0f, 0.0f, 0.0f - ) + m.get(6), + contains(0.36789f, 0.43192f, -0.73431f, 0.01266f, 0.02527f, 0.00007f, 0.00000f, 0.0f, 0.0f, 0.0f) ); assertThat( - m.get(30), contains( - 0.54463f, 0.20881f, -1.16629f, 0.06061f, 0.00743f, 0.01324f, 0.99554f, 0.0f, 0.0f, 0.0f - ) + m.get(30), + contains(0.54463f, 0.20881f, -1.16629f, 0.06061f, 0.00743f, 0.01324f, 0.99554f, 0.0f, 0.0f, 0.0f) ); // Verify that defaults are applied diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java index 771ef468c..787ebdbb9 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesBasalAreaGrowthParserTest.java @@ -2,6 +2,7 @@ import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe; import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; +import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.notPresent; import static org.hamcrest.MatcherAssert.assertThat; import java.util.HashMap; @@ -34,7 +35,7 @@ public void readAllTest() { assertThat(m.get("AC", 0), present(coe(1, -0.08787f, 0.016335f, 0.00907f))); assertThat(m.get("Y", 30), present(coe(1, 0.05873f, -0.011052f, -0.02011f))); - // Check that defaults are applied - assertThat(m.get("PY", 3), present(coe(1, 0.0f, 0.0f, 0.0f))); + // Check that data missing from the source is not present in the map. + assertThat(m.get("PY", 3), notPresent()); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java index f6a68b911..b9551486a 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/NonPrimarySpeciesDqGrowthParserTest.java @@ -2,6 +2,7 @@ import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.coe; import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.present; +import static ca.bc.gov.nrs.vdyp.test.VdypMatchers.notPresent; import static org.hamcrest.MatcherAssert.assertThat; import java.util.HashMap; @@ -34,7 +35,7 @@ public void readAllTest() { assertThat(m.get("AC", 0), present(coe(1, -0.010264f, 0.005373f, -0.016904f))); assertThat(m.get("Y", 30), present(coe(1, 0.069221f, -0.024821f, 0.001982f))); - // Check that defaults are applied - assertThat(m.get("PY", 3), present(coe(1, 0.0f, 0.0f, 0.0f))); + // Check that data not present in the source is not in the map + assertThat(m.get("PY", 3), notPresent()); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java index 863825c27..198b16a38 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesBasalAreaGrowthParserTest.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.Map; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; @@ -35,9 +36,8 @@ void testParseSimple() throws Exception { assertThat(m.get(30), hasProperty("model", is(8))); assertThat(m.get(30), hasProperty("coefficients", contains(0.00579f, -0.000076f, 0.00449f))); - // Check that defaults are applied - assertThat(m.get(27), hasProperty("model", is(0))); - assertThat(m.get(27), hasProperty("coefficients", contains(0.0f, 0.0f, 0.0f))); + // Check that missing entries are null + assertThat(m.get(27), Matchers.nullValue()); } @Test @@ -52,7 +52,6 @@ void testBlankLinesStopParse() throws Exception { Map m = parser.parse(is, controlMap); assertThat(m.get(1), hasProperty("model", is(9))); assertThat(m.get(1), hasProperty("coefficients", contains(-0.08960f, 0.007892f, 0.00105f))); - assertThat(m.get(2), hasProperty("model", is(0))); - assertThat(m.get(2), hasProperty("coefficients", contains(0.0f, 0.0f, 0.0f))); + assertThat(m.get(2), Matchers.nullValue()); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java index d23ca0f6f..0840aa5ad 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/PrimarySpeciesDqGrowthParserTest.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.Map; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import ca.bc.gov.nrs.vdyp.common.ControlKey; @@ -36,7 +37,6 @@ void testParseSimple() throws Exception { assertThat(m.get(30), hasProperty("coefficients", contains(0.004418f, 0.010218f, -0.000047f))); // Check that defaults are applied - assertThat(m.get(27), hasProperty("model", is(0))); - assertThat(m.get(27), hasProperty("coefficients", contains(0.0f, 0.0f, 0.0f))); + assertThat(m.get(27), Matchers.nullValue()); } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java index 255919436..9b699822d 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/UpperBoundsParserTest.java @@ -44,7 +44,8 @@ void testParseBlank() throws Exception { Map controlMap = new HashMap<>(); InputStream is = TestUtils.makeInputStream( - " 1 74.78 76.10 AC", "", "0 ", " 00", " 0 ", "000", " ", " ", " ", " xxx", " 11 50.77 34.70 AT" + " 1 74.78 76.10 AC", "", "0 ", " 00", " 0 ", "000", " ", " ", " ", " xxx", + " 11 50.77 34.70 AT" ); TestUtils.populateControlMapFromStream(controlMap, parser, is); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java index ae4a76e68..d57bb4215 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BecDefinitionParserTest.java @@ -26,12 +26,14 @@ void testParse() throws Exception { var result = parser.parse(TestUtils.class, "coe/Becdef.dat", Collections.emptyMap()); assertThat( - result, hasBec( - "AT", present( + result, + hasBec( + "AT", + present( allOf( - hasProperty("alias", equalTo("AT")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Alpine Tundra")) + hasProperty("alias", equalTo("AT")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Alpine Tundra")) ) ) ) @@ -40,12 +42,14 @@ result, hasBec( assertThat(result.get("AT").get().getDecayBec(), sameInstance(result.get("AT").get())); assertThat(result.get("AT").get().getVolumeBec(), sameInstance(result.get("AT").get())); assertThat( - result, hasBec( - "BG", present( + result, + hasBec( + "BG", + present( allOf( - hasProperty("alias", equalTo("BG")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Bunchgrass")) + hasProperty("alias", equalTo("BG")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Bunchgrass")) ) ) ) @@ -54,12 +58,14 @@ result, hasBec( assertThat(result.get("BG").get().getDecayBec(), sameInstance(result.get("BG").get())); assertThat(result.get("BG").get().getVolumeBec(), sameInstance(result.get("ESSF").get())); assertThat( - result, hasBec( - "BWBS", present( + result, + hasBec( + "BWBS", + present( allOf( - hasProperty("alias", equalTo("BWBS")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Boreal White and Black Spruce")) + hasProperty("alias", equalTo("BWBS")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Boreal White and Black Spruce")) ) ) ) @@ -68,12 +74,14 @@ result, hasBec( assertThat(result.get("BWBS").get().getDecayBec(), sameInstance(result.get("BWBS").get())); assertThat(result.get("BWBS").get().getVolumeBec(), sameInstance(result.get("BWBS").get())); assertThat( - result, hasBec( - "CDF", present( + result, + hasBec( + "CDF", + present( allOf( - hasProperty("alias", equalTo("CDF")), hasProperty( - "region", equalTo(Region.COASTAL) - ), hasProperty("name", equalTo("Coastal Dougfir")) + hasProperty("alias", equalTo("CDF")), + hasProperty("region", equalTo(Region.COASTAL)), + hasProperty("name", equalTo("Coastal Dougfir")) ) ) ) @@ -82,12 +90,14 @@ result, hasBec( assertThat(result.get("CDF").get().getDecayBec(), sameInstance(result.get("CDF").get())); assertThat(result.get("CDF").get().getVolumeBec(), sameInstance(result.get("CDF").get())); assertThat( - result, hasBec( - "CWH", present( + result, + hasBec( + "CWH", + present( allOf( - hasProperty("alias", equalTo("CWH")), hasProperty( - "region", equalTo(Region.COASTAL) - ), hasProperty("name", equalTo("Coastal Western Hemlock")) + hasProperty("alias", equalTo("CWH")), + hasProperty("region", equalTo(Region.COASTAL)), + hasProperty("name", equalTo("Coastal Western Hemlock")) ) ) ) @@ -96,12 +106,14 @@ result, hasBec( assertThat(result.get("CWH").get().getDecayBec(), sameInstance(result.get("CWH").get())); assertThat(result.get("CWH").get().getVolumeBec(), sameInstance(result.get("CWH").get())); assertThat( - result, hasBec( - "ESSF", present( + result, + hasBec( + "ESSF", + present( allOf( - hasProperty("alias", equalTo("ESSF")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Englemann Sruce -SubAlpine Fir")) + hasProperty("alias", equalTo("ESSF")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Englemann Sruce -SubAlpine Fir")) ) ) ) @@ -110,12 +122,14 @@ result, hasBec( assertThat(result.get("ESSF").get().getDecayBec(), sameInstance(result.get("ESSF").get())); assertThat(result.get("ESSF").get().getVolumeBec(), sameInstance(result.get("ESSF").get())); assertThat( - result, hasBec( - "ICH", present( + result, + hasBec( + "ICH", + present( allOf( - hasProperty("alias", equalTo("ICH")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Interior Cedar-Hemlock")) + hasProperty("alias", equalTo("ICH")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Interior Cedar-Hemlock")) ) ) ) @@ -124,12 +138,14 @@ result, hasBec( assertThat(result.get("ICH").get().getDecayBec(), sameInstance(result.get("ICH").get())); assertThat(result.get("ICH").get().getVolumeBec(), sameInstance(result.get("ICH").get())); assertThat( - result, hasBec( - "IDF", present( + result, + hasBec( + "IDF", + present( allOf( - hasProperty("alias", equalTo("IDF")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Interior DougFir")) + hasProperty("alias", equalTo("IDF")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Interior DougFir")) ) ) ) @@ -138,12 +154,14 @@ result, hasBec( assertThat(result.get("IDF").get().getDecayBec(), sameInstance(result.get("IDF").get())); assertThat(result.get("IDF").get().getVolumeBec(), sameInstance(result.get("IDF").get())); assertThat( - result, hasBec( - "MH", present( + result, + hasBec( + "MH", + present( allOf( - hasProperty("alias", equalTo("MH")), hasProperty( - "region", equalTo(Region.COASTAL) - ), hasProperty("name", equalTo("Mountain Hemlock")) + hasProperty("alias", equalTo("MH")), + hasProperty("region", equalTo(Region.COASTAL)), + hasProperty("name", equalTo("Mountain Hemlock")) ) ) ) @@ -152,12 +170,14 @@ result, hasBec( assertThat(result.get("MH").get().getDecayBec(), sameInstance(result.get("MH").get())); assertThat(result.get("MH").get().getVolumeBec(), sameInstance(result.get("MH").get())); assertThat( - result, hasBec( - "MS", present( + result, + hasBec( + "MS", + present( allOf( - hasProperty("alias", equalTo("MS")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Montane Spruce")) + hasProperty("alias", equalTo("MS")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Montane Spruce")) ) ) ) @@ -166,12 +186,14 @@ result, hasBec( assertThat(result.get("MS").get().getDecayBec(), sameInstance(result.get("MS").get())); assertThat(result.get("MS").get().getVolumeBec(), sameInstance(result.get("MS").get())); assertThat( - result, hasBec( - "PP", present( + result, + hasBec( + "PP", + present( allOf( - hasProperty("alias", equalTo("PP")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Ponderosa Pine")) + hasProperty("alias", equalTo("PP")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Ponderosa Pine")) ) ) ) @@ -180,12 +202,14 @@ result, hasBec( assertThat(result.get("PP").get().getDecayBec(), sameInstance(result.get("PP").get())); assertThat(result.get("PP").get().getVolumeBec(), sameInstance(result.get("PP").get())); assertThat( - result, hasBec( - "SBPS", present( + result, + hasBec( + "SBPS", + present( allOf( - hasProperty("alias", equalTo("SBPS")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("SubBoreal Pine-Spruce")) + hasProperty("alias", equalTo("SBPS")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("SubBoreal Pine-Spruce")) ) ) ) @@ -194,12 +218,14 @@ result, hasBec( assertThat(result.get("SBPS").get().getDecayBec(), sameInstance(result.get("SBPS").get())); assertThat(result.get("SBPS").get().getVolumeBec(), sameInstance(result.get("SBPS").get())); assertThat( - result, hasBec( - "SBS", present( + result, + hasBec( + "SBS", + present( allOf( - hasProperty("alias", equalTo("SBS")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("SubBoreal Spruce")) + hasProperty("alias", equalTo("SBS")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("SubBoreal Spruce")) ) ) ) @@ -208,12 +234,14 @@ result, hasBec( assertThat(result.get("SBS").get().getDecayBec(), sameInstance(result.get("SBS").get())); assertThat(result.get("SBS").get().getVolumeBec(), sameInstance(result.get("SBS").get())); assertThat( - result, hasBec( - "SWB", present( + result, + hasBec( + "SWB", + present( allOf( - hasProperty("alias", equalTo("SWB")), hasProperty( - "region", equalTo(Region.INTERIOR) - ), hasProperty("name", equalTo("Spruce-Willow-Birch")) + hasProperty("alias", equalTo("SWB")), + hasProperty("region", equalTo(Region.INTERIOR)), + hasProperty("name", equalTo("Spruce-Willow-Birch")) ) ) ) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java index 8f8cec4bd..c7c7310d5 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/BySpeciesDqCoefficientParserTest.java @@ -21,7 +21,9 @@ void testParseSimple() throws Exception { var parser = new BySpeciesDqCoefficientParser(); var is = TestUtils.makeInputStream( - "A0 1 -0.65484 -0.48275 -0.75134 0.04482 -0.31195 -0.53012 -0.12645 -0.64668 -0.43538 -0.31134 -0.03435 -0.27833 -0.32476 0.10819 -0.38103 -0.12273", "A1 2 2.26389 0.19886 -0.25704 0.18579 -0.38547 -0.14115 -0.10146 0.09067 0.54304 -0.02947 0.08473 -0.39934 0.02206 -0.18235 0.01411 -0.21683", "A2 0 0.23162" + "A0 1 -0.65484 -0.48275 -0.75134 0.04482 -0.31195 -0.53012 -0.12645 -0.64668 -0.43538 -0.31134 -0.03435 -0.27833 -0.32476 0.10819 -0.38103 -0.12273", + "A1 2 2.26389 0.19886 -0.25704 0.18579 -0.38547 -0.14115 -0.10146 0.09067 0.54304 -0.02947 0.08473 -0.39934 0.02206 -0.18235 0.01411 -0.21683", + "A2 0 0.23162" ); Map controlMap = new HashMap<>(); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java index c02328dd7..b1b483fa1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/GenusDefinitionParserTest.java @@ -39,63 +39,78 @@ void testParse() throws Exception { Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AC")), // Matchers.hasProperty("name", equalTo("Cottonwood")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AT")), // Matchers.hasProperty("name", equalTo("Aspen")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("B")), // Matchers.hasProperty("name", equalTo("Balsam")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("C")), // Matchers.hasProperty("name", equalTo("Cedar (X yellow)")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("D")), // Matchers.hasProperty("name", equalTo("Alder")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("E")), // Matchers.hasProperty("name", equalTo("Birch")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("F")), // Matchers.hasProperty("name", equalTo("Douglas Fir")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("H")), // Matchers.hasProperty("name", equalTo("Hemlock")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("L")), // Matchers.hasProperty("name", equalTo("Larch")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("MB")), // Matchers.hasProperty("name", equalTo("Maple")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("PA")), // Matchers.hasProperty("name", equalTo("White-bark pine")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("PL")), // Matchers.hasProperty("name", equalTo("Lodgepole Pine")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("PW")), // Matchers.hasProperty("name", equalTo("White pine")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("PY")), // Matchers.hasProperty("name", equalTo("Yellow pine")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("S")), // Matchers.hasProperty("name", equalTo("Spruce")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("Y")), // Matchers.hasProperty("name", equalTo("Yellow cedar")) @@ -123,7 +138,8 @@ void testOrderByPreference() throws Exception { Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AC")), // Matchers.hasProperty("name", equalTo("Cottonwood")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AT")), // Matchers.hasProperty("name", equalTo("Aspen")) @@ -150,7 +166,8 @@ void testOrderByLinesBlank() throws Exception { Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AT")), // Matchers.hasProperty("name", equalTo("Aspen")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AC")), // Matchers.hasProperty("name", equalTo("Cottonwood")) @@ -177,7 +194,8 @@ void testOrderByLinesZero() throws Exception { Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AT")), // Matchers.hasProperty("name", equalTo("Aspen")) - ), allOf( + ), + allOf( Matchers.instanceOf(GenusDefinition.class), // Matchers.hasProperty("alias", equalTo("AC")), // Matchers.hasProperty("name", equalTo("Cottonwood")) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java index f1c620482..707a37263 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/ModifierParserTest.java @@ -100,35 +100,35 @@ protected void modifierDefaultAsserts(Map controlMap) { assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.MODIFIER_FILE, present(is("testFilename")))); assertThat( - controlMap, (Matcher) controlMapHasEntry( - ControlKey.BA_MODIFIERS, mmDimensions( - contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values()) - ) + controlMap, + (Matcher) controlMapHasEntry( + ControlKey.BA_MODIFIERS, + mmDimensions(contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values())) ) ); assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.BA_MODIFIERS, mmAll(is(1.0f)))); assertThat( - controlMap, (Matcher) controlMapHasEntry( - ControlKey.DQ_MODIFIERS, mmDimensions( - contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values()) - ) + controlMap, + (Matcher) controlMapHasEntry( + ControlKey.DQ_MODIFIERS, + mmDimensions(contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values())) ) ); assertThat(controlMap, (Matcher) controlMapHasEntry(ControlKey.DQ_MODIFIERS, mmAll(is(1.0f)))); assertThat( - controlMap, (Matcher) controlMapHasEntry( - ModifierParser.CONTROL_KEY_MOD301_DECAY, mmDimensions( - contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values()) - ) + controlMap, + (Matcher) controlMapHasEntry( + ModifierParser.CONTROL_KEY_MOD301_DECAY, + mmDimensions(contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values())) ) ); assertThat(controlMap, (Matcher) controlMapHasEntry(ModifierParser.CONTROL_KEY_MOD301_DECAY, mmAll(is(0.0f)))); assertThat( - controlMap, (Matcher) controlMapHasEntry( - ModifierParser.CONTROL_KEY_MOD301_WASTE, mmDimensions( - contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values()) - ) + controlMap, + (Matcher) controlMapHasEntry( + ModifierParser.CONTROL_KEY_MOD301_WASTE, + mmDimensions(contains((Object[]) expectedSp0Aliases), contains((Object[]) Region.values())) ) ); assertThat(controlMap, (Matcher) controlMapHasEntry(ModifierParser.CONTROL_KEY_MOD301_WASTE, mmAll(is(0.0f)))); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java index 2bfab35ea..e09d789d2 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/SiteCurveAgeMaximumParserTest.java @@ -31,11 +31,12 @@ void testSimple() throws Exception { var result = parser.parse(is, controlMap); assertThat( - result, hasEntry( - is(16), allOf( - hasAge(Region.COASTAL, is(150.0f)), hasAge(Region.INTERIOR, is(150.0f)), hasProperty( - "t1", is(20.0f) - ), hasProperty("t2", is(60.0f)) + result, + hasEntry( + is(16), + allOf( + hasAge(Region.COASTAL, is(150.0f)), hasAge(Region.INTERIOR, is(150.0f)), + hasProperty("t1", is(20.0f)), hasProperty("t2", is(60.0f)) ) ) ); @@ -51,11 +52,12 @@ void testDefault() throws Exception { var result = parser.parse(is, controlMap); assertThat( - result, hasEntry( - is(SiteCurveAgeMaximumParser.DEFAULT_SC), allOf( - hasAge(Region.COASTAL, is(150.0f)), hasAge(Region.INTERIOR, is(150.0f)), hasProperty( - "t1", is(20.0f) - ), hasProperty("t2", is(60.0f)) + result, + hasEntry( + is(SiteCurveAgeMaximumParser.DEFAULT_SC), + allOf( + hasAge(Region.COASTAL, is(150.0f)), hasAge(Region.INTERIOR, is(150.0f)), + hasProperty("t1", is(20.0f)), hasProperty("t2", is(60.0f)) ) ) ); @@ -65,7 +67,8 @@ result, hasEntry( void testEndLine() throws Exception { var parser = new SiteCurveAgeMaximumParser(); var is = TestUtils.makeInputStream( - " -1 150.0 150.0 20.0 60.0", "999 End of usuable info", " 42 160.0 145.0 25.0 65.0" + " -1 150.0 150.0 20.0 60.0", "999 End of usuable info", + " 42 160.0 145.0 25.0 65.0" ); Map controlMap = new HashMap<>(); @@ -73,11 +76,12 @@ void testEndLine() throws Exception { var result = parser.parse(is, controlMap); assertThat( - result, hasEntry( - is(SiteCurveAgeMaximumParser.DEFAULT_SC), allOf( - hasAge(Region.COASTAL, is(150.0f)), hasAge(Region.INTERIOR, is(150.0f)), hasProperty( - "t1", is(20.0f) - ), hasProperty("t2", is(60.0f)) + result, + hasEntry( + is(SiteCurveAgeMaximumParser.DEFAULT_SC), + allOf( + hasAge(Region.COASTAL, is(150.0f)), hasAge(Region.INTERIOR, is(150.0f)), + hasProperty("t1", is(20.0f)), hasProperty("t2", is(60.0f)) ) ) ); @@ -97,10 +101,10 @@ void testDefaultValue() throws Exception { var result = map.get(27); assertThat( - result, allOf( - hasAge(Region.COASTAL, is(140.0f)), hasAge(Region.INTERIOR, is(140.0f)), hasProperty( - "t1", is(0.0f) - ), hasProperty("t2", is(0.0f)) + result, + allOf( + hasAge(Region.COASTAL, is(140.0f)), hasAge(Region.INTERIOR, is(140.0f)), + hasProperty("t1", is(0.0f)), hasProperty("t2", is(0.0f)) ) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java index 8d453af92..31fc1e2bf 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/StockingClassFactorParserTest.java @@ -35,10 +35,10 @@ void testSimple() throws Exception { var result = parser.parse(is, Collections.emptyMap()); assertThat( - result, mmHasEntry( - present( - allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100)))) - ), 'R', Region.INTERIOR + result, + mmHasEntry( + present(allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100))))), 'R', + Region.INTERIOR ) ); } @@ -51,27 +51,25 @@ void testMultiple() throws Exception { var result = parser.parse(is, Collections.emptyMap()); assertThat( - result, mmHasEntry( - present( - allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100)))) - ), 'R', Region.INTERIOR + result, + mmHasEntry( + present(allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100))))), + 'R', Region.INTERIOR ) ); assertThat( result, mmHasEntry( - present( - allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100)))) - ), 'R', Region.COASTAL + present(allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100))))), + 'R', Region.COASTAL ) ); assertThat( result, mmHasEntry( - present( - allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100)))) - ), '4', Region.COASTAL + present(allOf(hasProperty("factor", is(1.0f)), allOf(hasProperty("npctArea", is(100))))), + '4', Region.COASTAL ) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java index 64181b264..235d60968 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/coe/UtilComponentBaseAreaParserTest.java @@ -199,7 +199,8 @@ void testParseTwoBecsWithBlank() throws Exception { var parser = new UtilComponentBaseAreaParser(); var is = TestUtils.makeInputStream( - "BA12 S1 B1 -23.22790 12.60472", " S1 B2 -77.22790 77.60472", "BA12 S1 B2 -42.22790 64.60472" + "BA12 S1 B1 -23.22790 12.60472", " S1 B2 -77.22790 77.60472", + "BA12 S1 B2 -42.22790 64.60472" ); Map controlMap = new HashMap<>(); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java index 04f41285c..8c7e7059f 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/common/LineParserTest.java @@ -122,14 +122,16 @@ void testUnbounded() throws Exception { parser.string(4, "part1").string("part2"); var result1 = parser.parseLine( - "123 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ", Collections - .emptyMap() + "123 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ", + Collections.emptyMap() ); assertThat(result1, hasEntry("part1", "123 ")); assertThat( - result1, hasEntry( - "part2", " 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 " + result1, + hasEntry( + "part2", + " 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 " ) ); @@ -141,14 +143,16 @@ void testStripped() throws Exception { parser.strippedString(4, "part1").strippedString("part2"); var result1 = parser.parseLine( - "123 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ", Collections - .emptyMap() + "123 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 ", + Collections.emptyMap() ); assertThat(result1, hasEntry("part1", "123")); assertThat( - result1, hasEntry( - "part2", "67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + result1, + hasEntry( + "part2", + "67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" ) ); @@ -177,15 +181,15 @@ void testMultiLine() throws Exception { } assertThat( - result, contains( + result, + contains( allOf( - (Matcher) hasEntry("part1", 42), (Matcher) hasEntry( - "part2", "Value1" - ), (Matcher) hasEntry(LineParser.LINE_NUMBER_KEY, 1) - ), allOf( - (Matcher) hasEntry("part1", 43), (Matcher) hasEntry( - "part2", "Value2" - ), (Matcher) hasEntry(LineParser.LINE_NUMBER_KEY, 2) + (Matcher) hasEntry("part1", 42), (Matcher) hasEntry("part2", "Value1"), + (Matcher) hasEntry(LineParser.LINE_NUMBER_KEY, 1) + ), + allOf( + (Matcher) hasEntry("part1", 43), (Matcher) hasEntry("part2", "Value2"), + (Matcher) hasEntry(LineParser.LINE_NUMBER_KEY, 2) ) ) ); @@ -269,10 +273,10 @@ public boolean isIgnoredLine(String line) { } assertThat( - result, contains( - allOf((Matcher) hasEntry("part1", 42), (Matcher) hasEntry("part2", "Value1")), allOf( - (Matcher) hasEntry("part1", 43), (Matcher) hasEntry("part2", "Value2") - ) + result, + contains( + allOf((Matcher) hasEntry("part1", 42), (Matcher) hasEntry("part2", "Value1")), + allOf((Matcher) hasEntry("part1", 43), (Matcher) hasEntry("part2", "Value2")) ) ); } @@ -296,10 +300,10 @@ public boolean isIgnoredSegment(List segments) { } assertThat( - result, contains( - allOf((Matcher) hasEntry("part1", 42), (Matcher) hasEntry("part2", "Value1")), allOf( - (Matcher) hasEntry("part1", 43), (Matcher) hasEntry("part2", "Value2") - ) + result, + contains( + allOf((Matcher) hasEntry("part1", 42), (Matcher) hasEntry("part2", "Value1")), + allOf((Matcher) hasEntry("part1", 43), (Matcher) hasEntry("part2", "Value2")) ) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java index b83075a2d..1767b4764 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/ControlFileParserTest.java @@ -61,11 +61,11 @@ void testParsesEntriesExtended() throws Exception { var result = parser.parse(is); assertThat( - result.entrySet(), contains( + result.entrySet(), + contains( controlEntry( - equalTo(1), equalTo("X"), equalTo( - "Control that is longer than 50 characters. Blah Blah Blah Blah." - ) + equalTo(1), equalTo("X"), + equalTo("Control that is longer than 50 characters. Blah Blah Blah Blah.") ) ) ); @@ -81,11 +81,11 @@ void testParsesEntriesExtendedAlternate() throws Exception { var result = parser.parse(is); assertThat( - result.entrySet(), contains( + result.entrySet(), + contains( controlEntry( - equalTo(1), equalTo(">"), equalTo( - "Control that is longer than 50 characters. Blah Blah Blah Blah." - ) + equalTo(1), equalTo(">"), + equalTo("Control that is longer than 50 characters. Blah Blah Blah Blah.") ) ) ); @@ -197,10 +197,10 @@ void testParsesMultipleEntries() throws Exception { var result = parser.parse(is); assertThat( - result.entrySet(), contains( - controlEntry(equalTo(1), equalTo(" "), equalTo("Control 1")), controlEntry( - equalTo(2), equalTo(" "), equalTo("Control 2") - ) + result.entrySet(), + contains( + controlEntry(equalTo(1), equalTo(" "), equalTo("Control 1")), + controlEntry(equalTo(2), equalTo(" "), equalTo("Control 2")) ) ); } @@ -286,8 +286,10 @@ void testParseToMapWithConfiguration() throws Exception { assertThat(result, hasEntry(equalTo("MINIMA"), (Matcher) contains(5.0f, 0.0f, 2.0f))); assertThat(result, hasEntry(equalTo("MODIFIER_FILE"), equalTo("coe\\MOD19813.prm"))); assertThat( - result, hasEntry( - equalTo("DEBUG_SWITCHES"), (Matcher) contains( + result, + hasEntry( + equalTo("DEBUG_SWITCHES"), + (Matcher) contains( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 ) ) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java index 1267e38d4..752feffcb 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/control/NonFipControlParserTest.java @@ -60,10 +60,10 @@ void testParseBec() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.BEC_DEF, allOf( - instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class))) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.BEC_DEF, + allOf(instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class)))) ) ); } @@ -80,7 +80,8 @@ void testParseVGRP() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VOLUME_EQN_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(7), "AT", "CDF")) ) ); @@ -91,7 +92,8 @@ void testParseDGRP() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.DECAY_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(5), "AT", "CDF")) ) ); @@ -102,7 +104,8 @@ void testParseBGRP() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BREAKAGE_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(3), "AT", "CDF")) ) ); @@ -113,7 +116,8 @@ void testParseGRBA1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.DEFAULT_EQ_NUM, allOf(isA(MatrixMap2.class), mmHasEntry(is(11), "AT", "CDF")) ) ); @@ -176,8 +180,8 @@ void testParseE026Empty() throws Exception { // Map is empty but gives appropriate default values assertThat(result, (Matcher) controlMapHasEntry(ControlKey.SITE_CURVE_AGE_MAX, Matchers.anEmptyMap())); assertThat( - ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())) - .get(1), (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) + ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())).get(1), + (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) ); } @@ -186,12 +190,16 @@ void testParseE040() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.COE_BA, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.COE_BA, + allOf( mmHasEntry( coe( - 0, contains( - 2.0028f, 0.2426f, 10.1668f, -0.9042f, -5.0012f, -0.0068f, -0.0095f, 1.1938f, -0.2749f, 0f + 0, + contains( + 2.0028f, 0.2426f, 10.1668f, -0.9042f, -5.0012f, -0.0068f, + -0.0095f, 1.1938f, -0.2749f, 0f ) ), "AT", "AC" ) @@ -205,12 +213,16 @@ void testParseE041() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.COE_DQ, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.COE_DQ, + allOf( mmHasEntry( coe( - 0, contains( - 6.6190f, -0.5579f, -1.9421f, -0.7092f, -5.2290f, 4.8473f, 0.2629f, -0.0062f, 0f, 0f + 0, + contains( + 6.6190f, -0.5579f, -1.9421f, -0.7092f, -5.2290f, 4.8473f, + 0.2629f, -0.0062f, 0f, 0f ) ), "AT", "AC" ) @@ -224,7 +236,8 @@ void testParseE043() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.UPPER_BA_BY_CI_S0_P, allOf(mmHasEntry(is(109.27f), Region.COASTAL, "AC", 1)) ) ); @@ -235,10 +248,10 @@ void testParseE050() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P1, allOf( - mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P1, + allOf(mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL)) ) ); } @@ -248,10 +261,10 @@ void testParseE051() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P2, allOf( - mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P2, + allOf(mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL)) ) ); } @@ -261,8 +274,10 @@ void testParseE052() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P3, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P3, + allOf( mmHasEntry( coe(1, contains(1.04422f, 0.93010f, -0.05745f, -2.50000f)), "AC", Region.COASTAL ) @@ -276,10 +291,10 @@ void testParseE053() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_NONPRIMARY, allOf( - mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_NONPRIMARY, + allOf(mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL)) ) ); } @@ -289,7 +304,8 @@ void testParseE060() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162f)) ) ); @@ -298,20 +314,21 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 @Test void testParseE061() throws Exception { BaseControlParser parser = getUnit(); - var result = (Map)parse(parser, TestUtils.class, CONTROL_FILE); + var result = (Map) parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - mmHasEntry(instanceOf(ComponentSizeLimits.class) - , "AC", Region.COASTAL - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, + mmHasEntry(instanceOf(ComponentSizeLimits.class), "AC", Region.COASTAL) ) ); - var mm = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); - + var mm = Utils.>expectParsedControl( + result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class + ); + var csl = mm.get("AC", Region.COASTAL); - + assertThat(csl.loreyHeightMaximum(), is(49.4f)); assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); @@ -323,10 +340,10 @@ void testParseUBA1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_BA, allOf( - mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH") - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.UTIL_COMP_BA, + allOf(mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH")) ) ); } @@ -336,10 +353,10 @@ void testParseYVC1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.CLOSE_UTIL_VOLUME, allOf( - mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.CLOSE_UTIL_VOLUME, + allOf(mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53)) ) ); } @@ -349,10 +366,10 @@ void testParseYVD1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY, allOf( - mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VOLUME_NET_DECAY, + allOf(mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53)) ) ); } @@ -362,10 +379,10 @@ void testParseSBA1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_PROBABILITY, allOf( - hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_PROBABILITY, + allOf(hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f))) ) ); } @@ -375,10 +392,10 @@ void testParseSBA2() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_BA, allOf( - hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_BA, + allOf(hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f))) ) ); } @@ -388,7 +405,8 @@ void testParseSDQ1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.SMALL_COMP_DQ, allOf(hasEntry(is("B"), contains(-0.33485f, 0.02029f))) ) ); @@ -399,7 +417,8 @@ void testParseSHL1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.SMALL_COMP_HL, allOf(hasEntry(is("B"), contains(-8.5269f, -0.20000f))) ) ); @@ -410,10 +429,10 @@ void testParseSVT1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_WS_VOLUME, allOf( - hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_WS_VOLUME, + allOf(hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f))) ) ); } @@ -423,11 +442,15 @@ void testParseYVT1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, + allOf( hasEntry( - is(2), contains( - -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, 0.0000000f, 0.0000000f, 0.19884f + is(2), + contains( + -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, + 0.0000000f, 0.0000000f, 0.19884f ) ) ) @@ -440,10 +463,10 @@ void testParseYVT2() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_WS_VOLUME, allOf( - mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.UTIL_COMP_WS_VOLUME, + allOf(mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11)) ) ); } @@ -453,10 +476,10 @@ void testParseYVW1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY_WASTE, allOf( - hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VOLUME_NET_DECAY_WASTE, + allOf(hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f))) ) ); } @@ -466,7 +489,8 @@ void testParseE095() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BREAKAGE, allOf(hasEntry(is(10), contains(-0.7153f, 2.0108f, 4.00f, 8.00f))) ) ); @@ -477,10 +501,10 @@ void testParseYVVET() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_VOLUME_ADJUST, allOf( - hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VETERAN_LAYER_VOLUME_ADJUST, + allOf(hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f))) ) ); } @@ -490,15 +514,14 @@ void testParseYDQV() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_DQ, allOf( - mmHasEntry( - coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL - ), mmHasEntry( - coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR - ), mmHasEntry( - coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL - ), mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) + result, + (Matcher) controlMapHasEntry( + ControlKey.VETERAN_LAYER_DQ, + allOf( + mmHasEntry(coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL), + mmHasEntry(coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR), + mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL), + mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) ) ) ); @@ -513,13 +536,10 @@ void testParseE098() throws Exception { ControlKey.VETERAN_BQ, // Includes modifiers from 198 allOf( - mmHasEntry( - contains(0.12874f * 0.311f, 8.00000f, 1.26982f), "B", Region.COASTAL - ), mmHasEntry( - contains(0.70932f * 0.374f, 7.63269f, 0.62545f), "B", Region.INTERIOR - ), mmHasEntry( - contains(0.07962f * 0.311f, 6.60231f, 1.37998f), "D", Region.COASTAL - ), mmHasEntry(contains(0.07962f * 0.374f, 6.60231f, 1.37998f), "D", Region.INTERIOR) + mmHasEntry(contains(0.12874f * 0.311f, 8.00000f, 1.26982f), "B", Region.COASTAL), + mmHasEntry(contains(0.70932f * 0.374f, 7.63269f, 0.62545f), "B", Region.INTERIOR), + mmHasEntry(contains(0.07962f * 0.311f, 6.60231f, 1.37998f), "D", Region.COASTAL), + mmHasEntry(contains(0.07962f * 0.374f, 6.60231f, 1.37998f), "D", Region.INTERIOR) ) ) ); @@ -534,11 +554,10 @@ void testParseMinima() throws Exception { ControlKey.MINIMA, // Includes modifiers from 198 allOf( - hasEntry(is(BaseControlParser.MINIMUM_HEIGHT), is(6.0f)), hasEntry( - is(BaseControlParser.MINIMUM_BASE_AREA), is(0.0f) - ), hasEntry( - is(BaseControlParser.MINIMUM_PREDICTED_BASE_AREA), is(2.0f) - ), hasEntry(is(BaseControlParser.MINIMUM_VETERAN_HEIGHT), is(10.0f)) + hasEntry(is(BaseControlParser.MINIMUM_HEIGHT), is(6.0f)), + hasEntry(is(BaseControlParser.MINIMUM_BASE_AREA), is(0.0f)), + hasEntry(is(BaseControlParser.MINIMUM_PREDICTED_BASE_AREA), is(2.0f)), + hasEntry(is(BaseControlParser.MINIMUM_VETERAN_HEIGHT), is(10.0f)) ) ) ); @@ -550,9 +569,8 @@ void testParseV7R_RIP1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VRI_INPUT_YIELD_POLY, instanceOf(StreamingParserFactory.class) - ) + result, + (Matcher) controlMapHasEntry(ControlKey.VRI_INPUT_YIELD_POLY, instanceOf(StreamingParserFactory.class)) ); } @@ -562,9 +580,8 @@ void testParseV7R_RIL1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VRI_INPUT_YIELD_LAYER, instanceOf(StreamingParserFactory.class) - ) + result, + (Matcher) controlMapHasEntry(ControlKey.VRI_INPUT_YIELD_LAYER, instanceOf(StreamingParserFactory.class)) ); } @@ -574,7 +591,8 @@ void testParseV7R_RIT1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VRI_INPUT_YIELD_HEIGHT_AGE_SI, instanceOf(StreamingParserFactory.class) ) ); @@ -586,7 +604,8 @@ void testParseV7R_RIS1() throws Exception { BaseControlParser parser = getUnit(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VRI_INPUT_YIELD_SPEC_DIST, instanceOf(StreamingParserFactory.class) ) ); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java index 6fc830cb3..94c3b80f1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/parse/value/ValueParserTest.java @@ -78,14 +78,12 @@ void testRangeSilentLow() throws Exception { assertThat(parser.parse("3.99999"), present(closeTo(3.99999f))); assertThat( - assertThrows(ValueParseException.class, () -> parser.parse("4")), hasProperty( - "message", is("test must be less than 4.0.") - ) + assertThrows(ValueParseException.class, () -> parser.parse("4")), + hasProperty("message", is("test must be less than 4.0.")) ); assertThat( - assertThrows(ValueParseException.class, () -> parser.parse("5")), hasProperty( - "message", is("test must be less than 4.0.") - ) + assertThrows(ValueParseException.class, () -> parser.parse("5")), + hasProperty("message", is("test must be less than 4.0.")) ); var parser2 = ValueParser.rangeSilentLow(ValueParser.FLOAT, 1f, false, 4f, true, "test"); @@ -97,14 +95,12 @@ void testRangeSilentLow() throws Exception { assertThat(parser2.parse("4"), present(closeTo(4f))); assertThat( - assertThrows(ValueParseException.class, () -> parser2.parse("4.0001")), hasProperty( - "message", is("test must be less than or equal to 4.0.") - ) + assertThrows(ValueParseException.class, () -> parser2.parse("4.0001")), + hasProperty("message", is("test must be less than or equal to 4.0.")) ); assertThat( - assertThrows(ValueParseException.class, () -> parser2.parse("5")), hasProperty( - "message", is("test must be less than or equal to 4.0.") - ) + assertThrows(ValueParseException.class, () -> parser2.parse("5")), + hasProperty("message", is("test must be less than or equal to 4.0.")) ); } @@ -301,7 +297,8 @@ void testDefaultsMustComeAfterRequired() throws Exception { defaults.put("B", 6); var ex = assertThrows( - IllegalArgumentException.class, () -> ValueParser + IllegalArgumentException.class, + () -> ValueParser .toMap(ValueParser.segmentList(3, ValueParser.INTEGER), defaults, "A", "B", "C", "D") ); assertThat(ex, hasProperty("message", is("Keys with defaults must follow those without"))); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java index ebc16276b..11ee6649b 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/ControlFileWriterTest.java @@ -18,9 +18,8 @@ public void testWriteEntry() throws Exception { writer.writeEntry(1, "Value"); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( - "001 Value \r\n" - ) + output.toString(ControlFileWriter.CHARSET), + equalTo("001 Value \r\n") ); } @@ -34,9 +33,8 @@ public void testWriteEntryWithComment() throws Exception { writer.writeEntry(1, "Value", "Comment"); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( - "001 Value Comment\r\n" - ) + output.toString(ControlFileWriter.CHARSET), + equalTo("001 Value Comment\r\n") ); } @@ -50,7 +48,8 @@ public void testWriteExtendedEntry() throws Exception { writer.writeEntry(1, "Long Value........................................."); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( + output.toString(ControlFileWriter.CHARSET), + equalTo( "001XLong Value......................................... \r\n" ) ); @@ -66,7 +65,8 @@ public void testWriteExtendedEntryWithComment() throws Exception { writer.writeEntry(1, "Long Value.........................................", "Comment"); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( + output.toString(ControlFileWriter.CHARSET), + equalTo( "001XLong Value......................................... Comment\r\n" ) ); @@ -104,7 +104,8 @@ public void testValidateIndex() throws Exception { }); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( + output.toString(ControlFileWriter.CHARSET), + equalTo( "001 Low \r\n200 High \r\n" ) ); @@ -119,11 +120,13 @@ public void testValidateValue() throws Exception { writer.writeEntry(1, ""); writer.writeEntry( - 2, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + 2, + "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" ); assertThrows(IllegalArgumentException.class, () -> { writer.writeEntry( - 3, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789X" + 3, + "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789X" ); }); assertThrows(IllegalArgumentException.class, () -> { @@ -137,7 +140,8 @@ public void testValidateValue() throws Exception { }); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( + output.toString(ControlFileWriter.CHARSET), + equalTo( "001 \r\n002X012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\r\n" ) ); @@ -171,7 +175,8 @@ public void testValidateComment() throws Exception { }); assertThat( - output.toString(ControlFileWriter.CHARSET), equalTo( + output.toString(ControlFileWriter.CHARSET), + equalTo( "001 Value \r\n" + "002 Value Comment\r\n" + "003 Value ! Comment\r\n" + " \r\n" diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java index 11a7d4bdf..7a52992ea 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java @@ -319,7 +319,7 @@ void testWriteUtilizationZeroBaseArea() throws IOException { "082E004 615 1988 P 12 PL 1 6.79731 834.25 -9.0000 33.3680 2.4174 2.3990 2.3951 2.3464 10.2", // "082E004 615 1988 P 12 PL 2 8.54690 509.09 -9.0000 52.4308 36.8751 36.5664 36.4803 35.7128 14.6", // "082E004 615 1988 P 12 PL 3 3.63577 123.56 -9.0000 25.2296 22.0156 21.7930 21.7218 21.2592 19.4", // - "082E004 615 1988 P 12 PL 4 0.00000 18.92 -9.0000 6.9654 6.4459 6.3080 6.2442 6.1030 -9.0" // + "082E004 615 1988 P 12 PL 4 0.00000 18.92 -9.0000 6.9654 6.4459 6.3080 6.2442 6.1030 -9.0" // /* DQ should be -9 */ ) ); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java index 7e8c8b81e..6c9ce4a60 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/BecLookupTest.java @@ -44,9 +44,8 @@ void testGetBecs() throws Exception { var result = lookup.getBecs(); assertThat( - result, containsInAnyOrder( - allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF"))) - ) + result, + containsInAnyOrder(allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF")))) ); } @@ -77,9 +76,8 @@ void testGetCoastalBecs() throws Exception { var result = lookup.getBecsForRegion(Region.COASTAL); assertThat( - result, containsInAnyOrder( - allOf(hasProperty("alias", is("CDF"))), allOf(hasProperty("alias", is("CWH"))) - ) + result, + containsInAnyOrder(allOf(hasProperty("alias", is("CDF"))), allOf(hasProperty("alias", is("CWH")))) ); } @@ -94,9 +92,8 @@ void testGetInteriorBecs() throws Exception { var result = lookup.getBecsForRegion(Region.INTERIOR); assertThat( - result, containsInAnyOrder( - allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF"))) - ) + result, + containsInAnyOrder(allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF")))) ); } @@ -111,10 +108,10 @@ void testGetByBlankScope() throws Exception { var result = lookup.getBecsForScope(""); assertThat( - result, containsInAnyOrder( - allOf(hasProperty("alias", is("CDF"))), allOf(hasProperty("alias", is("CWH"))), allOf( - hasProperty("alias", is("BG")) - ), allOf(hasProperty("alias", is("ESSF"))) + result, + containsInAnyOrder( + allOf(hasProperty("alias", is("CDF"))), allOf(hasProperty("alias", is("CWH"))), + allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF"))) ) ); } @@ -130,9 +127,8 @@ void testGetByRegionScope() throws Exception { var result = lookup.getBecsForScope("I"); assertThat( - result, containsInAnyOrder( - allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF"))) - ) + result, + containsInAnyOrder(allOf(hasProperty("alias", is("BG"))), allOf(hasProperty("alias", is("ESSF")))) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java index fe7f0bdd4..ae21c0f85 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/CommonDataTest.java @@ -13,7 +13,8 @@ class CommonDataTest { void test() { assertThat(CommonData.ITG_PURE, aMapWithSize(16)); assertThat( - CommonData.ITG_PURE.keySet(), containsInAnyOrder( + CommonData.ITG_PURE.keySet(), + containsInAnyOrder( "AC", "AT", "B", "C", "D", "E", "F", "H", "L", "MB", "PA", "PL", "PW", "PY", "S", "Y" ) ); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java index 708b313fc..99d8ffce0 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/MatrixMapTest.java @@ -30,9 +30,8 @@ class MatrixMapTest { void testContructNoDimensionsFails() { List> dims = Collections.emptyList(); Assertions.assertThrows( - IllegalArgumentException.class, () -> new MatrixMapImpl>( - k -> Optional.empty(), dims - ) + IllegalArgumentException.class, + () -> new MatrixMapImpl>(k -> Optional.empty(), dims) ); } @@ -42,9 +41,8 @@ void testContructEmptyDimensionsFails() { var dim1 = Collections.emptyList(); var dims = Arrays.asList(dim1); Assertions.assertThrows( - IllegalArgumentException.class, () -> new MatrixMapImpl>( - k -> Optional.empty(), dims - ) + IllegalArgumentException.class, + () -> new MatrixMapImpl>(k -> Optional.empty(), dims) ); } @@ -152,10 +150,10 @@ void testEachKey() { var result = new ArrayList(); map.eachKey(result::add); assertThat( - result, containsInAnyOrder( - arrayContaining("a", 1), arrayContaining("b", 1), arrayContaining("a", 2), arrayContaining( - "b", 2 - ) + result, + containsInAnyOrder( + arrayContaining("a", 1), arrayContaining("b", 1), arrayContaining("a", 2), + arrayContaining("b", 2) ) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java index 0320ec23c..8c4ab7810 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java @@ -209,12 +209,14 @@ void buildAdaptSpecies() throws Exception { assertThat(resultSpecies, hasProperty("percentGenus", is(100f))); assertThat(resultSpecies, hasProperty("fractionGenus", is(1f))); assertThat( - resultSpecies, hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("BL")), hasProperty("percentage", is(75f)) - ) + resultSpecies, + hasProperty( + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + hasEntry( + is(1), + allOf(hasProperty("genusAlias", is("BL")), hasProperty("percentage", is(75f))) ) ) ) @@ -264,20 +266,24 @@ void buildCopySpecies() throws Exception { assertThat(resultSpecies, hasProperty("decayGroup", is(2))); assertThat(resultSpecies, hasProperty("breakageGroup", is(3))); assertThat( - resultSpecies, hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( + resultSpecies, + hasProperty( + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("BL")), hasProperty( - "percentage", is(75f) - ) + is(1), + allOf( + hasProperty("genusAlias", is("BL")), + hasProperty("percentage", is(75f)) ) - ), hasEntry( - is(2), allOf( - hasProperty("genusAlias", is("BX")), hasProperty( - "percentage", is(25f) - ) + ), + hasEntry( + is(2), + allOf( + hasProperty("genusAlias", is("BX")), + hasProperty("percentage", is(25f)) ) ) ) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java index 907f007d4..d73c700e8 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java @@ -49,9 +49,8 @@ void buildNoProperties() throws Exception { var ex = assertThrows(IllegalStateException.class, () -> VdypPolygon.build(builder -> { })); assertThat( - ex, hasProperty( - "message", allOf(containsString("polygonIdentifier"), containsString("percentAvailable")) - ) + ex, + hasProperty("message", allOf(containsString("polygonIdentifier"), containsString("percentAvailable"))) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java index bebbbf587..7a6b8ca8a 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java @@ -42,11 +42,12 @@ void buildNoProperties() throws Exception { var ex = assertThrows(IllegalStateException.class, () -> VdypSite.build(builder -> { })); assertThat( - ex, hasProperty( - "message", allOf( - containsString("polygonIdentifier"), containsString("layerType"), containsString( - "siteGenus" - ) + ex, + hasProperty( + "message", + allOf( + containsString("polygonIdentifier"), containsString("layerType"), + containsString("siteGenus") ) ) ); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java index 461e93ba1..08799f176 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java @@ -41,12 +41,10 @@ void buildNoProperties() throws Exception { var ex = assertThrows(IllegalStateException.class, () -> VdypSpecies.build(builder -> { })); assertThat( - ex, hasProperty( - "message", allOf( - containsString("polygonIdentifier"), containsString("layer"), containsString( - "genus" - ) - ) + ex, + hasProperty( + "message", + allOf(containsString("polygonIdentifier"), containsString("layer"), containsString("genus")) ) ); } @@ -99,12 +97,14 @@ void buildAddSpeciesPercent() throws Exception { builder.addSp64Distribution("B", 100f); }); assertThat( - result, hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty("percentage", is(100f)) - ) + result, + hasProperty( + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + hasEntry( + is(1), + allOf(hasProperty("genusAlias", is("B")), hasProperty("percentage", is(100f))) ) ) ) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java index 171737102..7bdad058f 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/VdypMatchers.java @@ -601,7 +601,8 @@ boolean matchesComponent(Description description, float expected, float result) @Override public void describeTo(Description description) { String utilizationRep = String.format( - "[Small: %f, All: %f, 7.5cm: %f, 12.5cm: %f, 17.5cm: %f, 22.5cm: %f]", small, all, util1, util2, util3, util4 + "[Small: %f, All: %f, 7.5cm: %f, 12.5cm: %f, 17.5cm: %f, 22.5cm: %f]", small, all, util1, util2, + util3, util4 ); description.appendText("A utilization vector ").appendValue(utilizationRep); } diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java index a7d740600..98943158b 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java @@ -44,9 +44,8 @@ public FipControlParser() { protected ValueParser> minimaParser() { return ValueParser.callback( ValueParser.toMap( - ValueParser.list(ValueParser.FLOAT), Collections.singletonMap( - MINIMUM_VETERAN_HEIGHT, 10.0f - ), MINIMUM_HEIGHT, MINIMUM_BASE_AREA, MINIMUM_FULLY_STOCKED_AREA, MINIMUM_VETERAN_HEIGHT + ValueParser.list(ValueParser.FLOAT), Collections.singletonMap(MINIMUM_VETERAN_HEIGHT, 10.0f), + MINIMUM_HEIGHT, MINIMUM_BASE_AREA, MINIMUM_FULLY_STOCKED_AREA, MINIMUM_VETERAN_HEIGHT ), minima -> { log.atDebug().setMessage( "Minima read from FIPSTART Control at line {}\n Minimum Height: {}\n Minimum BA: {}\n Minimum BA Fully Stocked: {}\n Minimum Veteran Height: {}" @@ -126,7 +125,8 @@ protected List> inputFileParsers() { @Override protected List outputFileParsers() { return List.of( - ControlKey.VRI_OUTPUT_VDYP_POLYGON, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL + ControlKey.VRI_OUTPUT_VDYP_POLYGON, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES, + ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL ); } diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java index 55ac7c6ee..8b8585aab 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParser.java @@ -51,9 +51,10 @@ public ControlKey getControlKey() { var lineParser = new LineParser() // .strippedString(25, FipPolygonParser.POLYGON_IDENTIFIER).space(1) // .value( - 1, LAYER, ValueParser.valueOrMarker( - ValueParser.LAYER, ValueParser - .optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) + 1, LAYER, + ValueParser.valueOrMarker( + ValueParser.LAYER, + ValueParser.optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) ) ) // .floating(4, AGE_TOTAL) // diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java index ac583acdc..cbb79fd61 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParser.java @@ -50,7 +50,8 @@ public ControlKey getControlKey() { throws IOException, ResourceParseException { return () -> { var lineParser = new LineParser().strippedString(25, FipPolygonParser.POLYGON_IDENTIFIER).space(1).value( - 1, FipLayerParser.LAYER, ValueParser.valueOrMarker( + 1, FipLayerParser.LAYER, + ValueParser.valueOrMarker( ValueParser.LAYER, ValueParser.optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) ) ).space(1).value(2, GENUS, ControlledValueParser.optional(ValueParser.GENUS)) diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index 27cae2ab6..c69aa47d2 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -188,8 +188,8 @@ Optional processPolygon(int polygonsRead, FipPolygon polygon) FipLayerPrimary fipPrimeLayer = (FipLayerPrimary) fipLayers.get(LayerType.PRIMARY); assert fipPrimeLayer != null; var resultPrimeLayer = processLayerAsPrimary( - polygon, fipPrimeLayer, resultVetLayer.map(VdypLayer::getBaseAreaByUtilization).map(coe -> coe.getAll()) - .orElse(0f) + polygon, fipPrimeLayer, + resultVetLayer.map(VdypLayer::getBaseAreaByUtilization).map(coe -> coe.getAll()).orElse(0f) ); processedLayers.put(LayerType.PRIMARY, resultPrimeLayer); @@ -357,8 +357,8 @@ void findPrimaryHeightPass( .primaryHeightFromLeadHeightInitial(leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion()); } else { primaryHeight = estimationMethods.primaryHeightFromLeadHeight( - leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), vdypPrimarySpecies - .getTreesPerHectareByUtilization().getAll() + leadHeight, vdypPrimarySpecies.getGenus(), bec.getRegion(), + vdypPrimarySpecies.getTreesPerHectareByUtilization().getAll() ); } vdypPrimarySpecies.getLoreyHeightByUtilization().setAll(primaryHeight); @@ -466,17 +466,18 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, // EMP061 var limits = estimationMethods.getLimitsForHeightAndDiameter(spec.getGenus(), bec.getRegion()); - var dqMin = limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll(); + var dqMin = limits.minQuadMeanDiameterLoreyHeightRatio() + * spec.getLoreyHeightByUtilization().getAll(); var dqMax = max( - limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() - * spec.getLoreyHeightByUtilization().getAll() + limits.quadMeanDiameterMaximum(), + limits.maxQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll() ); // EMP060 float quadMeanDiameter = clamp( estimationMethods.estimateQuadMeanDiameterForSpecies( - spec, result.getSpecies(), bec - .getRegion(), quadMeanDiameterTotal, baseAreaTotal, treesPerHectareTotal, loreyHeightTotal + spec, result.getSpecies(), bec.getRegion(), quadMeanDiameterTotal, baseAreaTotal, + treesPerHectareTotal, loreyHeightTotal ), // dqMin, dqMax ); @@ -583,8 +584,8 @@ VdypLayer processLayerAsVeteran(FipPolygon fipPolygon, FipLayer fipLayer) throws assert fipLayer.getLayerType().equals(LayerType.VETERAN) : "Layer must be VETERAN"; assert fipPolygon.getPolygonIdentifier().equals(fipLayer.getPolygonIdentifier()) : String.format( - "Polygon polygonIdentifier '%s' doesn't match that of layer '%s'", fipPolygon - .getPolygonIdentifier(), fipLayer.getPolygonIdentifier() + "Polygon polygonIdentifier '%s' doesn't match that of layer '%s'", fipPolygon.getPolygonIdentifier(), + fipLayer.getPolygonIdentifier() ); var layer = LayerType.VETERAN; @@ -712,8 +713,8 @@ protected FipPolygon getPolygon( for (var layer : layers.values()) { if (!layer.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { throw validationError( - "Record in layer file contains layer for polygon %s when expecting one for %s.", layer - .getPolygonIdentifier(), polygon.getPolygonIdentifier() + "Record in layer file contains layer for polygon %s when expecting one for %s.", + layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() ); } speciesPerLayerMap.put(layer.getLayerType(), new HashMap<>()); @@ -724,14 +725,14 @@ protected FipPolygon getPolygon( // Validate that species belong to the correct polygon if (!spec.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { throw validationError( - "Record in species file contains species for polygon %s when expecting one for %s.", layer - .getPolygonIdentifier(), polygon.getPolygonIdentifier() + "Record in species file contains species for polygon %s when expecting one for %s.", + layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() ); } if (Objects.isNull(layer)) { throw validationError( - "Species entry references layer %s of polygon %s but it is not present.", layer, polygon - .getPolygonIdentifier() + "Species entry references layer %s of polygon %s but it is not present.", layer, + polygon.getPolygonIdentifier() ); } speciesPerLayerMap.get(spec.getLayerType()).put(spec.getGenus(), spec); @@ -777,8 +778,8 @@ void checkPolygon(FipPolygon polygon) throws ProcessingException { var ageTotal = primaryLayer.getAgeTotal().map(Object::toString).orElse("N/A (0)"); var ytbh = primaryLayer.getYearsToBreastHeight().map(Object::toString).orElse("N/A (0)"); throw validationError( - "Polygon %s has %s layer where total age (%s) is less than YTBH (%s).", polygon - .getPolygonIdentifier(), LayerType.PRIMARY, ageTotal, ytbh + "Polygon %s has %s layer where total age (%s) is less than YTBH (%s).", + polygon.getPolygonIdentifier(), LayerType.PRIMARY, ageTotal, ytbh ); } @@ -794,9 +795,8 @@ void checkPolygon(FipPolygon polygon) throws ProcessingException { throwIfPresent( heightMinimum(layer.getLayerType()).filter(minimum -> height < minimum).map( minimum -> validationError( - "Polygon %s has %s layer where height %.1f is less than minimum %.1f.", polygon - .getPolygonIdentifier(), layer - .getLayerType(), layer.getHeightSafe(), minimum + "Polygon %s has %s layer where height %.1f is less than minimum %.1f.", + polygon.getPolygonIdentifier(), layer.getLayerType(), layer.getHeightSafe(), minimum ) ) ); @@ -810,16 +810,16 @@ void checkPolygon(FipPolygon polygon) throws ProcessingException { if (primaryLayer.getYearsToBreastHeight().orElse(0f) < 0.5) { throw validationError( - "Polygon %s has %s layer where years to breast height %.1f is less than minimum %.1f years.", polygon - .getPolygonIdentifier(), LayerType.PRIMARY, primaryLayer.getYearsToBreastHeightSafe(), 0.5f + "Polygon %s has %s layer where years to breast height %.1f is less than minimum %.1f years.", + polygon.getPolygonIdentifier(), LayerType.PRIMARY, primaryLayer.getYearsToBreastHeightSafe(), 0.5f ); } if (primaryLayer.getSiteIndex().orElse(0f) < 0.5) { throw validationError( - "Polygon %s has %s layer where site index %s is less than minimum %.1f years.", polygon - .getPolygonIdentifier(), LayerType.PRIMARY, primaryLayer.getSiteIndex() - .map(x -> String.format("%.1f", x)).orElse("N/A"), 0.5f + "Polygon %s has %s layer where site index %s is less than minimum %.1f years.", + polygon.getPolygonIdentifier(), LayerType.PRIMARY, + primaryLayer.getSiteIndex().map(x -> String.format("%.1f", x)).orElse("N/A"), 0.5f ); } diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java index 7597d6bf4..650f877f1 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayer.java @@ -100,7 +100,7 @@ public void setSpecies(Collection species) { builder.ageTotal(8f); builder.yearsToBreastHeight(7f); builder.height(6f); - + builder.siteIndex(5f); builder.crownClosure(0.9f); builder.siteGenus("B"); diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java index 9c402d667..e3e04baa0 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipLayerPrimary.java @@ -53,7 +53,7 @@ public Optional getPrimarySpeciesRecord() { builder.ageTotal(8f); builder.yearsToBreastHeight(7f); builder.height(6f); - + @Override builder.siteIndex(5f); builder.crownClosure(0.9f); diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java index aa1b8238c..c557715c1 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/model/FipPolygon.java @@ -15,9 +15,8 @@ public class FipPolygon extends BaseVdypPolygon, FipSp private float yieldFactor; // FIP_P4/YLDFACT public FipPolygon( - PolygonIdentifier polygonIdentifier, String fiz, BecDefinition bec, - Optional percentAvailable, Optional modeFip, Optional nonproductiveDescription, - float yieldFactor + PolygonIdentifier polygonIdentifier, String fiz, BecDefinition bec, Optional percentAvailable, + Optional modeFip, Optional nonproductiveDescription, float yieldFactor ) { super(polygonIdentifier, percentAvailable, fiz, bec, modeFip, Optional.empty()); this.nonproductiveDescription = nonproductiveDescription; diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java index 3d44fe298..b2957acf4 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipControlParserTest.java @@ -51,10 +51,10 @@ void testParseBec() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.BEC_DEF, allOf( - instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class))) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.BEC_DEF, + allOf(instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class)))) ) ); } @@ -71,7 +71,8 @@ void testParseVGRP() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VOLUME_EQN_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(7), "AT", "CDF")) ) ); @@ -82,7 +83,8 @@ void testParseDGRP() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.DECAY_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(5), "AT", "CDF")) ) ); @@ -93,7 +95,8 @@ void testParseBGRP() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BREAKAGE_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(3), "AT", "CDF")) ) ); @@ -104,7 +107,8 @@ void testParseGRBA1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.DEFAULT_EQ_NUM, allOf(isA(MatrixMap2.class), mmHasEntry(is(11), "AT", "CDF")) ) ); @@ -132,9 +136,8 @@ void testParseSTK33() throws Exception { result, (Matcher) controlMapHasEntry( ControlKey.STOCKING_CLASS_FACTORS, allOf( // STK - isA(MatrixMap2.class), mmHasEntry( - present(isA(StockingClassFactor.class)), 'R', Region.COASTAL - ) + isA(MatrixMap2.class), + mmHasEntry(present(isA(StockingClassFactor.class)), 'R', Region.COASTAL) ) ) ); @@ -183,8 +186,8 @@ void testParseE026Empty() throws Exception { // Map is empty but gives appropriate default values assertThat(result, (Matcher) controlMapHasEntry(ControlKey.SITE_CURVE_AGE_MAX, Matchers.anEmptyMap())); assertThat( - ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())) - .get(1), (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) + ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())).get(1), + (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) ); } @@ -193,12 +196,16 @@ void testParseE040() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.COE_BA, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.COE_BA, + allOf( mmHasEntry( coe( - 0, contains( - 2.0028f, 0.2426f, 10.1668f, -0.9042f, -5.0012f, -0.0068f, -0.0095f, 1.1938f, -0.2749f, 0f + 0, + contains( + 2.0028f, 0.2426f, 10.1668f, -0.9042f, -5.0012f, -0.0068f, + -0.0095f, 1.1938f, -0.2749f, 0f ) ), "AT", "AC" ) @@ -212,12 +219,16 @@ void testParseE041() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.COE_DQ, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.COE_DQ, + allOf( mmHasEntry( coe( - 0, contains( - 6.6190f, -0.5579f, -1.9421f, -0.7092f, -5.2290f, 4.8473f, 0.2629f, -0.0062f, 0f, 0f + 0, + contains( + 6.6190f, -0.5579f, -1.9421f, -0.7092f, -5.2290f, 4.8473f, + 0.2629f, -0.0062f, 0f, 0f ) ), "AT", "AC" ) @@ -231,7 +242,8 @@ void testParseE043() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.UPPER_BA_BY_CI_S0_P, allOf(mmHasEntry(is(109.27f), Region.COASTAL, "AC", 1)) ) ); @@ -242,10 +254,10 @@ void testParseE050() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P1, allOf( - mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P1, + allOf(mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL)) ) ); } @@ -255,10 +267,10 @@ void testParseE051() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P2, allOf( - mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P2, + allOf(mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL)) ) ); } @@ -268,8 +280,10 @@ void testParseE052() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P3, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P3, + allOf( mmHasEntry( coe(1, contains(1.04422f, 0.93010f, -0.05745f, -2.50000f)), "AC", Region.COASTAL ) @@ -283,10 +297,10 @@ void testParseE053() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_NONPRIMARY, allOf( - mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_NONPRIMARY, + allOf(mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL)) ) ); } @@ -296,7 +310,8 @@ void testParseE060() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162f)) ) ); @@ -305,21 +320,22 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 @Test void testParseE061() throws Exception { BaseControlParser parser = new FipControlParser(); - var result = (Map)parse(parser, TestUtils.class, "FIPSTART.CTR"); + var result = (Map) parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - mmHasEntry(instanceOf(ComponentSizeLimits.class) - , "AC", Region.COASTAL - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, + mmHasEntry(instanceOf(ComponentSizeLimits.class), "AC", Region.COASTAL) ) ); - var mm = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); - + var mm = Utils.>expectParsedControl( + result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class + ); + var csl = mm.get("AC", Region.COASTAL); - + assertThat(csl.loreyHeightMaximum(), is(49.4f)); assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); @@ -331,10 +347,10 @@ void testParseUBA1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_BA, allOf( - mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH") - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.UTIL_COMP_BA, + allOf(mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH")) ) ); } @@ -344,10 +360,10 @@ void testParseYVC1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.CLOSE_UTIL_VOLUME, allOf( - mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.CLOSE_UTIL_VOLUME, + allOf(mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53)) ) ); } @@ -357,10 +373,10 @@ void testParseYVD1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY, allOf( - mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VOLUME_NET_DECAY, + allOf(mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53)) ) ); } @@ -370,10 +386,10 @@ void testParseSBA1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_PROBABILITY, allOf( - hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_PROBABILITY, + allOf(hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f))) ) ); } @@ -383,10 +399,10 @@ void testParseSBA2() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_BA, allOf( - hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_BA, + allOf(hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f))) ) ); } @@ -396,7 +412,8 @@ void testParseSDQ1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.SMALL_COMP_DQ, allOf(hasEntry(is("B"), contains(-0.33485f, 0.02029f))) ) ); @@ -407,7 +424,8 @@ void testParseSHL1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.SMALL_COMP_HL, allOf(hasEntry(is("B"), contains(-8.5269f, -0.20000f))) ) ); @@ -418,10 +436,10 @@ void testParseSVT1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_WS_VOLUME, allOf( - hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_WS_VOLUME, + allOf(hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f))) ) ); } @@ -431,11 +449,15 @@ void testParseYVT1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, + allOf( hasEntry( - is(2), contains( - -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, 0.0000000f, 0.0000000f, 0.19884f + is(2), + contains( + -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, + 0.0000000f, 0.0000000f, 0.19884f ) ) ) @@ -448,10 +470,10 @@ void testParseYVT2() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_WS_VOLUME, allOf( - mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.UTIL_COMP_WS_VOLUME, + allOf(mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11)) ) ); } @@ -461,10 +483,10 @@ void testParseYVW1() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY_WASTE, allOf( - hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VOLUME_NET_DECAY_WASTE, + allOf(hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f))) ) ); } @@ -474,7 +496,8 @@ void testParseE095() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BREAKAGE, allOf(hasEntry(is(10), contains(-0.7153f, 2.0108f, 4.00f, 8.00f))) ) ); @@ -485,10 +508,10 @@ void testParseYVVET() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_VOLUME_ADJUST, allOf( - hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VETERAN_LAYER_VOLUME_ADJUST, + allOf(hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f))) ) ); } @@ -498,15 +521,14 @@ void testParseYDQV() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_DQ, allOf( - mmHasEntry( - coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL - ), mmHasEntry( - coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR - ), mmHasEntry( - coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL - ), mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) + result, + (Matcher) controlMapHasEntry( + ControlKey.VETERAN_LAYER_DQ, + allOf( + mmHasEntry(coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL), + mmHasEntry(coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR), + mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL), + mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) ) ) ); @@ -521,13 +543,10 @@ void testParseE098() throws Exception { ControlKey.VETERAN_BQ, // Includes modifiers from 198 allOf( - mmHasEntry( - contains(0.12874f * 0.311f, 8.00000f, 1.26982f), "B", Region.COASTAL - ), mmHasEntry( - contains(0.70932f * 0.374f, 7.63269f, 0.62545f), "B", Region.INTERIOR - ), mmHasEntry( - contains(0.07962f * 0.311f, 6.60231f, 1.37998f), "D", Region.COASTAL - ), mmHasEntry(contains(0.07962f * 0.374f, 6.60231f, 1.37998f), "D", Region.INTERIOR) + mmHasEntry(contains(0.12874f * 0.311f, 8.00000f, 1.26982f), "B", Region.COASTAL), + mmHasEntry(contains(0.70932f * 0.374f, 7.63269f, 0.62545f), "B", Region.INTERIOR), + mmHasEntry(contains(0.07962f * 0.311f, 6.60231f, 1.37998f), "D", Region.COASTAL), + mmHasEntry(contains(0.07962f * 0.374f, 6.60231f, 1.37998f), "D", Region.INTERIOR) ) ) ); @@ -542,11 +561,10 @@ void testParseMinima() throws Exception { ControlKey.MINIMA, // Includes modifiers from 198 allOf( - hasEntry(is(BaseControlParser.MINIMUM_HEIGHT), is(5.0f)), hasEntry( - is(BaseControlParser.MINIMUM_BASE_AREA), is(0.0f) - ), hasEntry( - is(BaseControlParser.MINIMUM_FULLY_STOCKED_AREA), is(2.0f) - ), hasEntry(is(BaseControlParser.MINIMUM_VETERAN_HEIGHT), is(10.0f)) + hasEntry(is(BaseControlParser.MINIMUM_HEIGHT), is(5.0f)), + hasEntry(is(BaseControlParser.MINIMUM_BASE_AREA), is(0.0f)), + hasEntry(is(BaseControlParser.MINIMUM_FULLY_STOCKED_AREA), is(2.0f)), + hasEntry(is(BaseControlParser.MINIMUM_VETERAN_HEIGHT), is(10.0f)) ) ) ); @@ -557,9 +575,8 @@ void testParseV7O_FIP() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.FIP_INPUT_YIELD_POLY, instanceOf(StreamingParserFactory.class) - ) + result, + (Matcher) controlMapHasEntry(ControlKey.FIP_INPUT_YIELD_POLY, instanceOf(StreamingParserFactory.class)) ); } @@ -568,9 +585,8 @@ void testParseV7O_FIL() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.FIP_INPUT_YIELD_LAYER, instanceOf(StreamingParserFactory.class) - ) + result, + (Matcher) controlMapHasEntry(ControlKey.FIP_INPUT_YIELD_LAYER, instanceOf(StreamingParserFactory.class)) ); } @@ -579,7 +595,8 @@ void testParseV7O_FIS() throws Exception { BaseControlParser parser = new FipControlParser(); var result = parse(parser, TestUtils.class, "FIPSTART.CTR"); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.FIP_INPUT_YIELD_LX_SP0, instanceOf(StreamingParserFactory.class) ) ); diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java index 68d80ff94..aa1ad0f26 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipLayerParserTest.java @@ -64,7 +64,8 @@ void testParseLayer() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 55 35.3 35.0 87.4 D D 1.0 0 13", // "01002 S000001 00 1970 Z 55 0.0 0.0 0.0 0.0" // ) @@ -86,7 +87,8 @@ void testParseLayer() throws Exception { assertThat(layers, aMapWithSize(1)); assertThat( - layers, hasSpecificEntry( + layers, + hasSpecificEntry( LayerType.PRIMARY, allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000001 00", 1970)), // hasProperty("layerType", is(LayerType.PRIMARY)), // @@ -118,7 +120,8 @@ void testParseTwoLayers() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000004 00 1970 V 195 45.2 22.3 4.0 B B 9.4 2 8", // "01002 S000004 00 1970 1 85 42.3 31.9 82.8 H H 4.9 0 34", // "01002 S000004 00 1970 Z 85 0.0 0.0 0.0 0.0" // @@ -141,7 +144,8 @@ void testParseTwoLayers() throws Exception { assertThat(layers, aMapWithSize(2)); assertThat( - layers, hasSpecificEntry( + layers, + hasSpecificEntry( LayerType.PRIMARY, allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000004 00", 1970)), // hasProperty("layerType", is(LayerType.PRIMARY)), // @@ -159,7 +163,8 @@ LayerType.PRIMARY, allOf( ) ); assertThat( - layers, hasSpecificEntry( + layers, + hasSpecificEntry( LayerType.VETERAN, allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000004 00", 1970)), // hasProperty("layerType", is(LayerType.VETERAN)), // @@ -190,7 +195,8 @@ void testIgnoreLayerIfHeightZero() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000004 00 1970 V 195 45.2 22.3 0.0 B B 9.4 2 8", // "01002 S000004 00 1970 1 85 42.3 31.9 82.8 H H 4.9 0 34", // "01002 S000004 00 1970 Z 85 0.0 0.0 0.0 0.0" // @@ -213,7 +219,8 @@ void testIgnoreLayerIfHeightZero() throws Exception { assertThat(layers, aMapWithSize(1)); assertThat( - layers, hasSpecificEntry( + layers, + hasSpecificEntry( LayerType.PRIMARY, allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000004 00", 1970)), // hasProperty("layerType", is(LayerType.PRIMARY)), // @@ -245,7 +252,8 @@ void testIgnoreLayerIfCrownClosureZero() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000004 00 1970 V 195 0.0 22.3 4.0 B B 9.4 2 8", // "01002 S000004 00 1970 1 85 42.3 31.9 82.8 H H 4.9 0 34", // "01002 S000004 00 1970 Z 85 0.0 0.0 0.0 0.0" // @@ -268,7 +276,8 @@ void testIgnoreLayerIfCrownClosureZero() throws Exception { assertThat(layers, aMapWithSize(1)); assertThat( - layers, hasSpecificEntry( + layers, + hasSpecificEntry( LayerType.PRIMARY, allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000004 00", 1970)), // hasProperty("layerType", is(LayerType.PRIMARY)), // @@ -278,9 +287,8 @@ LayerType.PRIMARY, allOf( hasProperty("crownClosure", is(82.8f)), // hasProperty("siteGenus", present(is("H"))), // hasProperty("siteSpecies", present(is("H"))), // - hasProperty("yearsToBreastHeightSafe", is(4.9f)), hasProperty( - "stockingClass", present(is('0')) - ), // + hasProperty("yearsToBreastHeightSafe", is(4.9f)), + hasProperty("stockingClass", present(is('0'))), // hasProperty("inventoryTypeGroup", notPresent()), // hasProperty("siteCurveNumber", present(is(34))) ) diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java index 65a6f9c1d..761bcdbc9 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipSpeciesParserTest.java @@ -64,7 +64,8 @@ void testParseOneGenus() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" // ) @@ -90,13 +91,16 @@ genera, containsInAnyOrder( hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -120,7 +124,8 @@ void testParseTwoGenera() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 75.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 1 C 25.0C 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" // @@ -147,30 +152,37 @@ genera, containsInAnyOrder( hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(75.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) ) ) - ), allOf( + ), + allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000001 00", 1970)), // hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("C")), // hasProperty("percentGenus", is(25.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("C")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("C")), + hasProperty("percentage", is(100f)) ) ) ) @@ -195,7 +207,8 @@ void testParseTwoLayers() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 V B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" // @@ -222,30 +235,37 @@ genera, containsInAnyOrder( hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) ) ) - ), allOf( + ), + allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000001 00", 1970)), // hasProperty("layerType", is(LayerType.VETERAN)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -269,7 +289,8 @@ void testParseTwoPolygons() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0", // "01002 S000002 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // @@ -297,13 +318,16 @@ genera, containsInAnyOrder( hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -322,13 +346,16 @@ genera, containsInAnyOrder( hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -352,7 +379,8 @@ void testParseMultipleSpecies() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 100.0B1 75.0B2 10.0B3 8.0B4 7.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" // ) @@ -378,31 +406,37 @@ genera, containsInAnyOrder( hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(4), hasEntry( - is(1), allOf( - hasProperty( - "genusAlias", is("B1") - ), hasProperty("percentage", is(75f)) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(4), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B1")), + hasProperty("percentage", is(75f)) ) - ), hasEntry( - is(2), allOf( - hasProperty( - "genusAlias", is("B2") - ), hasProperty("percentage", is(10f)) + ), + hasEntry( + is(2), + allOf( + hasProperty("genusAlias", is("B2")), + hasProperty("percentage", is(10f)) ) - ), hasEntry( - is(3), allOf( - hasProperty( - "genusAlias", is("B3") - ), hasProperty("percentage", is(8f)) + ), + hasEntry( + is(3), + allOf( + hasProperty("genusAlias", is("B3")), + hasProperty("percentage", is(8f)) ) - ), hasEntry( - is(4), allOf( - hasProperty( - "genusAlias", is("B4") - ), hasProperty("percentage", is(7f)) + ), + hasEntry( + is(4), + allOf( + hasProperty("genusAlias", is("B4")), + hasProperty("percentage", is(7f)) ) ) ) diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java index 9d154438f..e9b2d404c 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java @@ -161,8 +161,10 @@ void testPolygonWithNoPrimaryLayer() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon \"" + polygonId + "\" has no " + LayerType.PRIMARY + " layer, or that layer has non-positive height or crown closure." ) @@ -187,8 +189,10 @@ void testPrimaryLayerHeightLessThanMinimum() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon " + polygonId + " has " + LayerType.PRIMARY + " layer where height 4.0 is less than minimum 5.0." ) @@ -215,8 +219,10 @@ void testVeteranLayerHeightLessThanMinimum() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon " + polygonId + " has " + LayerType.VETERAN + " layer where height 9.0 is less than minimum 10.0." ) @@ -243,8 +249,10 @@ void testPrimaryLayerYearsToBreastHeightLessThanMinimum() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon " + polygonId + " has " + LayerType.PRIMARY + " layer where years to breast height 0.2 is less than minimum 0.5 years." ) @@ -275,8 +283,10 @@ void testPrimaryLayerTotalAgeLessThanYearsToBreastHeight() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon " + polygonId + " has " + LayerType.PRIMARY + " layer where total age (7.0) is less than YTBH (8.0)." ) @@ -301,8 +311,10 @@ void testPrimaryLayerSiteIndexLessThanMinimum() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon " + polygonId + " has " + LayerType.PRIMARY + " layer where site index 0.2 is less than minimum 0.5 years." ) @@ -327,10 +339,10 @@ void testPolygonWithModeFipYoung() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( - "Polygon " + polygonId + " is using unsupported mode " + PolygonMode.YOUNG + "." - ) + ex, + hasProperty( + "message", + is("Polygon " + polygonId + " is using unsupported mode " + PolygonMode.YOUNG + ".") ) ); } @@ -356,8 +368,10 @@ void testOneSpeciesLessThan100Percent() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon \"" + polygonId + "\" has PRIMARY layer where species entries have a percentage total that does not sum to 100%." ) @@ -386,8 +400,10 @@ void testOneSpeciesMoreThan100Percent() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon \"" + polygonId + "\" has PRIMARY layer where species entries have a percentage total that does not sum to 100%." ) @@ -443,8 +459,10 @@ void testTwoSpeciesSumToLessThan100Percent() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon \"" + polygonId + "\" has PRIMARY layer where species entries have a percentage total that does not sum to 100%." ) @@ -476,8 +494,10 @@ void testTwoSpeciesSumToMoreThan100Percent() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(polygon)); assertThat( - ex, hasProperty( - "message", is( + ex, + hasProperty( + "message", + is( "Polygon \"" + polygonId + "\" has PRIMARY layer where species entries have a percentage total that does not sum to 100%." ) @@ -768,45 +788,47 @@ speciesResult3, hasProperty("sp64DistributionSet", hasProperty("sp64Distribution var holder = speciesResult1; String reason = "Genus " + holder.getGenus(); assertThat( - reason, holder, hasProperty( - "baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(0.492921442f) - ) + reason, holder, + hasProperty("baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(0.492921442f)) ); assertThat( - reason, holder, hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(2.3357718f) - ) + reason, holder, + hasProperty("treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(2.3357718f)) ); assertThat( - reason, holder, hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(6.11904192f) - ) + reason, holder, + hasProperty("wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(6.11904192f)) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "closeUtilizationVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(5.86088896f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayByUtilization", VdypMatchers - .utilizationAllAndBiggest(5.64048958f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayByUtilization", + VdypMatchers.utilizationAllAndBiggest(5.64048958f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", VdypMatchers - .utilizationAllAndBiggest(5.57935333f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", + VdypMatchers.utilizationAllAndBiggest(5.57935333f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilizationAllAndBiggest(5.27515411f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilizationAllAndBiggest(5.27515411f) ) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "quadraticMeanDiameterByUtilization", VdypMatchers.utilizationAllAndBiggest(51.8356705f) ) ); @@ -815,45 +837,47 @@ reason, holder, hasProperty( var holder = speciesResult2; String reason = "Genus " + holder.getGenus(); assertThat( - reason, holder, hasProperty( - "baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(1.34433115f) - ) + reason, holder, + hasProperty("baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(1.34433115f)) ); assertThat( - reason, holder, hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(5.95467329f) - ) + reason, holder, + hasProperty("treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(5.95467329f)) ); assertThat( - reason, holder, hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(14.5863571f) - ) + reason, holder, + hasProperty("wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(14.5863571f)) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "closeUtilizationVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(13.9343023f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayByUtilization", VdypMatchers - .utilizationAllAndBiggest(13.3831034f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayByUtilization", + VdypMatchers.utilizationAllAndBiggest(13.3831034f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", VdypMatchers - .utilizationAllAndBiggest(13.2065458f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", + VdypMatchers.utilizationAllAndBiggest(13.2065458f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilizationAllAndBiggest(12.4877129f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilizationAllAndBiggest(12.4877129f) ) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "quadraticMeanDiameterByUtilization", VdypMatchers.utilizationAllAndBiggest(53.6141243f) ) ); @@ -862,45 +886,47 @@ reason, holder, hasProperty( var holder = speciesResult3; String reason = "Genus " + holder.getGenus(); assertThat( - reason, holder, hasProperty( - "baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(0.403299361f) - ) + reason, holder, + hasProperty("baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(0.403299361f)) ); assertThat( - reason, holder, hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(2.38468361f) - ) + reason, holder, + hasProperty("treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(2.38468361f)) ); assertThat( - reason, holder, hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(4.04864883f) - ) + reason, holder, + hasProperty("wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(4.04864883f)) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "closeUtilizationVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(3.81141663f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayByUtilization", VdypMatchers - .utilizationAllAndBiggest(3.75043678f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayByUtilization", + VdypMatchers.utilizationAllAndBiggest(3.75043678f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", VdypMatchers - .utilizationAllAndBiggest(3.72647476f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", + VdypMatchers.utilizationAllAndBiggest(3.72647476f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilizationAllAndBiggest(3.56433797f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilizationAllAndBiggest(3.56433797f) ) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "quadraticMeanDiameterByUtilization", VdypMatchers.utilizationAllAndBiggest(46.4037895f) ) ); @@ -909,45 +935,47 @@ reason, holder, hasProperty( var holder = result; String reason = "Layer"; assertThat( - reason, holder, hasProperty( - "baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(2.24055195f) - ) + reason, holder, + hasProperty("baseAreaByUtilization", VdypMatchers.utilizationAllAndBiggest(2.24055195f)) ); assertThat( - reason, holder, hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(10.6751289f) - ) + reason, holder, + hasProperty("treesPerHectareByUtilization", VdypMatchers.utilizationAllAndBiggest(10.6751289f)) ); assertThat( - reason, holder, hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(24.7540474f) - ) + reason, holder, + hasProperty("wholeStemVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(24.7540474f)) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "closeUtilizationVolumeByUtilization", VdypMatchers.utilizationAllAndBiggest(23.6066074f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayByUtilization", VdypMatchers - .utilizationAllAndBiggest(22.7740307f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayByUtilization", + VdypMatchers.utilizationAllAndBiggest(22.7740307f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", VdypMatchers - .utilizationAllAndBiggest(22.5123749f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", + VdypMatchers.utilizationAllAndBiggest(22.5123749f) ) ); assertThat( - reason, holder, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilizationAllAndBiggest(21.3272057f) + reason, holder, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilizationAllAndBiggest(21.3272057f) ) ); assertThat( - reason, holder, hasProperty( + reason, holder, + hasProperty( "quadraticMeanDiameterByUtilization", VdypMatchers.utilizationAllAndBiggest(51.6946983f) ) ); @@ -1073,23 +1101,22 @@ result, hasProperty( // Species distribution assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(2)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(2))) ); var distributionResult = speciesResult.getSp64DistributionSet(); assertThat( - distributionResult.getSp64DistributionMap(), allOf( + distributionResult.getSp64DistributionMap(), + allOf( hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("S1")), hasProperty("percentage", is(75f)) - ) - ), hasEntry( - is(2), allOf( - hasProperty("genusAlias", is("S2")), hasProperty("percentage", is(25f)) - ) + is(1), + allOf(hasProperty("genusAlias", is("S1")), hasProperty("percentage", is(75f))) + ), + hasEntry( + is(2), + allOf(hasProperty("genusAlias", is("S2")), hasProperty("percentage", is(25f))) ) ) ); @@ -1155,24 +1182,35 @@ void testProcessPrimary() throws Exception { assertThat(result, hasProperty("breastHeightAge", present(is(54f)))); assertThat( - result, allOf( + result, + allOf( hasProperty( "loreyHeightByUtilization", VdypMatchers.utilizationHeight(7.14446497f, 31.3307228f) - ), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( - 0.0153773092f, 44.6249809f, 0.513127923f, 1.26773751f, 2.5276401f, 40.3164787f + ), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( + 0.0153773092f, 44.6249809f, 0.513127923f, 1.26773751f, 2.5276401f, + 40.3164787f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 6.05058956f, 30.2606678f, 10.208025f, 15.0549212f, 20.11759f, 35.5117531f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 5.34804535f, 620.484802f, 62.6977997f, 71.2168045f, 79.5194702f, 407.05072f ) - ), hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilization( - 0.0666879341f, 635.659668f, 2.66822577f, 9.68201256f, 26.5469246f, 596.762512f + ), + hasProperty( + "wholeStemVolumeByUtilization", + VdypMatchers.utilization( + 0.0666879341f, 635.659668f, 2.66822577f, 9.68201256f, 26.5469246f, + 596.762512f ) ), @@ -1181,10 +1219,10 @@ result, allOf( // wrong hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilization( - 0f, 563.218933f, 0.414062887f, 7.01947737f, 22.6179276f, 533.16748f - ) + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilization( + 0f, 563.218933f, 0.414062887f, 7.01947737f, 22.6179276f, 533.16748f + ) ) ) @@ -1215,27 +1253,35 @@ result, hasProperty( assertThat(speciesResult, hasProperty("fractionGenus", closeTo(0.00890319888f))); assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1))) ); assertThat( - speciesResult, allOf( - hasProperty("loreyHeightByUtilization", coe(-1, 8.39441967f, 38.6004372f)), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( + speciesResult, + allOf( + hasProperty("loreyHeightByUtilization", coe(-1, 8.39441967f, 38.6004372f)), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( 0f, 0.397305071f, 0.00485289097f, 0.0131751001f, 0.0221586525f, 0.357118428f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 6.13586617f, 31.6622887f, 9.17939758f, 13.6573782f, 18.2005272f, 42.1307297f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 0f, 5.04602766f, 0.733301044f, 0.899351299f, 0.851697803f, 2.56167722f ) - ), hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "wholeStemVolumeByUtilization", + VdypMatchers.utilization( 0f, 6.35662031f, 0.0182443243f, 0.0747248605f, 0.172960356f, 6.09069061f ) ), @@ -1245,10 +1291,10 @@ speciesResult, allOf( // wrong hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilization( - 0f, 5.65764236f, 0.000855736958f, 0.046797853f, 0.143031254f, 5.46695757f - ) + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilization( + 0f, 5.65764236f, 0.000855736958f, 0.046797853f, 0.143031254f, 5.46695757f + ) ) ) @@ -1263,28 +1309,38 @@ speciesResult, allOf( assertThat(speciesResult, hasProperty("fractionGenus", closeTo(0.114011094f))); assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1))) ); assertThat( - speciesResult, allOf( - hasProperty("loreyHeightByUtilization", coe(-1, 6.61517191f, 22.8001652f)), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( - 0.0131671466f, 5.08774281f, 0.157695293f, 0.365746498f, 0.565057278f, 3.99924374f + speciesResult, + allOf( + hasProperty("loreyHeightByUtilization", coe(-1, 6.61517191f, 22.8001652f)), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( + 0.0131671466f, 5.08774281f, 0.157695293f, 0.365746498f, 0.565057278f, + 3.99924374f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 5.99067688f, 26.4735165f, 10.1137667f, 14.9345293f, 19.964777f, 38.7725677f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 4.67143154f, 92.4298019f, 19.6292171f, 20.8788815f, 18.0498524f, 33.8718452f ) - ), hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilization( - 0.0556972362f, 44.496151f, 0.78884691f, 2.40446854f, 4.43335152f, 36.8694839f + ), + hasProperty( + "wholeStemVolumeByUtilization", + VdypMatchers.utilization( + 0.0556972362f, 44.496151f, 0.78884691f, 2.40446854f, 4.43335152f, + 36.8694839f ) ), @@ -1293,10 +1349,10 @@ speciesResult, allOf( // wrong hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilization( - 0f, 33.6030083f, 0.138336331f, 1.6231581f, 3.49037051f, 28.3511429f - ) + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilization( + 0f, 33.6030083f, 0.138336331f, 1.6231581f, 3.49037051f, 28.3511429f + ) ) ) @@ -1311,28 +1367,39 @@ speciesResult, allOf( assertThat(speciesResult, hasProperty("fractionGenus", closeTo(0.661987007f))); assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1))) ); assertThat( - speciesResult, allOf( - hasProperty("loreyHeightByUtilization", coe(-1, 10.8831682f, 33.5375252f)), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( - 0.00163476227f, 29.5411568f, 0.0225830078f, 0.0963115692f, 0.748186111f, 28.6740761f + speciesResult, + allOf( + hasProperty("loreyHeightByUtilization", coe(-1, 10.8831682f, 33.5375252f)), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( + 0.00163476227f, 29.5411568f, 0.0225830078f, 0.0963115692f, 0.748186111f, + 28.6740761f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 6.46009731f, 33.9255791f, 10.4784775f, 15.5708427f, 20.4805717f, 35.0954628f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( - 0.498754263f, 326.800781f, 2.61875916f, 5.05783129f, 22.7109661f, 296.413239f + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( + 0.498754263f, 326.800781f, 2.61875916f, 5.05783129f, 22.7109661f, + 296.413239f ) - ), hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilization( - 0.0085867513f, 470.388489f, 0.182312608f, 1.08978188f, 10.1118069f, 459.004578f + ), + hasProperty( + "wholeStemVolumeByUtilization", + VdypMatchers.utilization( + 0.0085867513f, 470.388489f, 0.182312608f, 1.08978188f, 10.1118069f, + 459.004578f ) ), @@ -1341,10 +1408,10 @@ speciesResult, allOf( // wrong hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilization( - 0f, 424.163849f, 0.0895428956f, 0.929004371f, 8.9712553f, 414.174042f - ) + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilization( + 0f, 424.163849f, 0.0895428956f, 0.929004371f, 8.9712553f, 414.174042f + ) ) ) @@ -1359,27 +1426,35 @@ speciesResult, allOf( assertThat(speciesResult, hasProperty("fractionGenus", closeTo(0.123297341f))); assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1))) ); assertThat( - speciesResult, allOf( - hasProperty("loreyHeightByUtilization", coe(-1, 7.93716192f, 24.3451157f)), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( + speciesResult, + allOf( + hasProperty("loreyHeightByUtilization", coe(-1, 7.93716192f, 24.3451157f)), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( 0f, 5.50214148f, 0.311808586f, 0.736046314f, 0.988982677f, 3.4653039f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 6.03505516f, 21.4343796f, 10.260808f, 15.0888424f, 20.0664616f, 32.2813988f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 0f, 152.482513f, 37.7081375f, 41.1626587f, 31.2721119f, 42.3395996f ) - ), hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "wholeStemVolumeByUtilization", + VdypMatchers.utilization( 0f, 57.2091446f, 1.57991886f, 5.59581661f, 9.53606987f, 40.4973412f ) ), @@ -1389,10 +1464,10 @@ speciesResult, allOf( // wrong hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilization( - 0f, 48.1333618f, 0.168331802f, 4.01862335f, 8.05745506f, 35.8889503f - ) + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilization( + 0f, 48.1333618f, 0.168331802f, 4.01862335f, 8.05745506f, 35.8889503f + ) ) ) @@ -1407,28 +1482,38 @@ speciesResult, allOf( assertThat(speciesResult, hasProperty("fractionGenus", closeTo(0.0918014571f))); assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1))) ); assertThat( - speciesResult, allOf( - hasProperty("loreyHeightByUtilization", coe(-1, 8.63455391f, 34.6888771f)), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( - 0.000575399841f, 4.0966382f, 0.0161881447f, 0.0564579964f, 0.203255415f, 3.82073665f + speciesResult, + allOf( + hasProperty("loreyHeightByUtilization", coe(-1, 8.63455391f, 34.6888771f)), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( + 0.000575399841f, 4.0966382f, 0.0161881447f, 0.0564579964f, 0.203255415f, + 3.82073665f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 6.41802597f, 34.5382729f, 10.1304808f, 14.9457884f, 19.7497196f, 39.0729332f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 0.17785944f, 43.7256737f, 2.00838566f, 3.21808815f, 6.63483906f, 31.8643608f ) - ), hasProperty( - "wholeStemVolumeByUtilization", VdypMatchers.utilization( - 0.00240394124f, 57.2092552f, 0.0989032984f, 0.517220974f, 2.29273605f, 54.300396f + ), + hasProperty( + "wholeStemVolumeByUtilization", + VdypMatchers.utilization( + 0.00240394124f, 57.2092552f, 0.0989032984f, 0.517220974f, 2.29273605f, + 54.300396f ) ), @@ -1437,10 +1522,10 @@ speciesResult, allOf( // wrong hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", VdypMatchers - .utilization( - 0f, 51.6610985f, 0.0169961192f, 0.401893795f, 1.95581412f, 49.286396f - ) + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + VdypMatchers.utilization( + 0f, 51.6610985f, 0.0169961192f, 0.401893795f, 1.95581412f, 49.286396f + ) ) ) @@ -1527,25 +1612,31 @@ result, hasProperty( assertThat(speciesResult, hasProperty("fractionGenus", closeTo(0.787526369f))); assertThat( - speciesResult, hasProperty( - "sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1)) - ) + speciesResult, + hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", aMapWithSize(1))) ); assertThat( - speciesResult, allOf( + speciesResult, + allOf( hasProperty( "loreyHeightByUtilization", VdypMatchers.utilizationHeight(7.00809479f, 20.9070625f) - ), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( 0.512469947f, 35.401783f, 2.32033157f, 5.18892097f, 6.6573391f, 21.2351913f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 5.94023561f, 20.7426338f, 10.2836504f, 15.1184902f, 20.1040707f, 31.6741638f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 184.914597f, 1047.62891f, 279.36087f, 289.048248f, 209.72142f, 269.49826f ) ) @@ -1554,17 +1645,25 @@ speciesResult, allOf( ); assertThat( - result, allOf( - hasProperty("loreyHeightByUtilization", coe(-1, 7.01034021f, 21.1241722f)), hasProperty( - "baseAreaByUtilization", VdypMatchers.utilization( - 0.553745031f, 44.9531403f, 2.83213019f, 6.17823505f, 8.11753464f, 27.8252392f + result, + allOf( + hasProperty("loreyHeightByUtilization", coe(-1, 7.01034021f, 21.1241722f)), + hasProperty( + "baseAreaByUtilization", + VdypMatchers.utilization( + 0.553745031f, 44.9531403f, 2.83213019f, 6.17823505f, 8.11753464f, + 27.8252392f ) - ), hasProperty( - "quadraticMeanDiameterByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "quadraticMeanDiameterByUtilization", + VdypMatchers.utilization( 5.9399271f, 21.0548763f, 10.235322f, 15.0843554f, 20.0680523f, 32.0662689f ) - ), hasProperty( - "treesPerHectareByUtilization", VdypMatchers.utilization( + ), + hasProperty( + "treesPerHectareByUtilization", + VdypMatchers.utilization( 199.828629f, 1291.1145f, 344.207489f, 345.717224f, 256.639709f, 344.549957f ) ) @@ -1888,11 +1987,12 @@ void testVeteranLayerLoreyHeight() throws Exception { Matcher zeroMatcher = is(0.0f); // Expect the estimated HL in 0 (-1 to 0) assertThat( - result, hasProperty( - "species", hasEntry( - is("B"), hasProperty( - "loreyHeightByUtilization", contains(zeroMatcher, heightMatcher) - ) + result, + hasProperty( + "species", + hasEntry( + is("B"), + hasProperty("loreyHeightByUtilization", contains(zeroMatcher, heightMatcher)) ) ) ); @@ -2018,39 +2118,43 @@ else if (s.equals("C") && r == Region.INTERIOR) var resultB = result.getSpecies().get("B"); assertThat( - resultB, hasProperty( - "quadraticMeanDiameterByUtilization", contains( - zeroMatcher, closeTo(expectedDqB), zeroMatcher, zeroMatcher, zeroMatcher, closeTo( - expectedDqB - ) + resultB, + hasProperty( + "quadraticMeanDiameterByUtilization", + contains( + zeroMatcher, closeTo(expectedDqB), zeroMatcher, zeroMatcher, zeroMatcher, + closeTo(expectedDqB) ) ) ); assertThat( - resultB, hasProperty( - "treesPerHectareByUtilization", contains( - zeroMatcher, closeTo(3.8092144f), zeroMatcher, zeroMatcher, zeroMatcher, closeTo( - 3.8092144f - ) + resultB, + hasProperty( + "treesPerHectareByUtilization", + contains( + zeroMatcher, closeTo(3.8092144f), zeroMatcher, zeroMatcher, zeroMatcher, + closeTo(3.8092144f) ) ) ); var resultC = result.getSpecies().get("C"); assertThat( - resultC, hasProperty( - "quadraticMeanDiameterByUtilization", contains( - zeroMatcher, closeTo(expectedDqC), zeroMatcher, zeroMatcher, zeroMatcher, closeTo( - expectedDqC - ) + resultC, + hasProperty( + "quadraticMeanDiameterByUtilization", + contains( + zeroMatcher, closeTo(expectedDqC), zeroMatcher, zeroMatcher, zeroMatcher, + closeTo(expectedDqC) ) ) ); assertThat( - resultC, hasProperty( - "treesPerHectareByUtilization", contains( - zeroMatcher, closeTo(2.430306f), zeroMatcher, zeroMatcher, zeroMatcher, closeTo( - 2.430306f - ) + resultC, + hasProperty( + "treesPerHectareByUtilization", + contains( + zeroMatcher, closeTo(2.430306f), zeroMatcher, zeroMatcher, zeroMatcher, + closeTo(2.430306f) ) ) ); @@ -3099,9 +3203,8 @@ void testApplyStockingFactor() throws ProcessingException { assertThat(vdypLayer, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiedValue)); assertThat(vdypLayer, hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiedValue)); assertThat( - vdypLayer, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiedValue - ) + vdypLayer, + hasProperty("closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiedValue) ); assertThat(spec1, hasProperty("loreyHeightByUtilization", neverModifiedValue)); @@ -3254,12 +3357,12 @@ void testApplyStockingFactorNoFactorForLayer() throws ProcessingException { vdypLayer, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiableNotModifiedValue) ); assertThat( - vdypLayer, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue - ) + vdypLayer, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue) ); assertThat( - vdypLayer, hasProperty( + vdypLayer, + hasProperty( "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiableNotModifiedValue ) ); @@ -3271,12 +3374,12 @@ vdypLayer, hasProperty( assertThat(spec1, hasProperty("treesPerHectareByUtilization", modifiableNotModifiedValue)); assertThat(spec1, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiableNotModifiedValue)); assertThat( - spec1, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue - ) + spec1, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue) ); assertThat( - spec1, hasProperty( + spec1, + hasProperty( "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiableNotModifiedValue ) ); @@ -3288,12 +3391,12 @@ spec1, hasProperty( assertThat(spec2, hasProperty("treesPerHectareByUtilization", modifiableNotModifiedValue)); assertThat(spec2, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiableNotModifiedValue)); assertThat( - spec2, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue - ) + spec2, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue) ); assertThat( - spec2, hasProperty( + spec2, + hasProperty( "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiableNotModifiedValue ) ); @@ -3438,12 +3541,12 @@ void testApplyStockingFactorNoFactorForClass() throws ProcessingException { vdypLayer, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiableNotModifiedValue) ); assertThat( - vdypLayer, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue - ) + vdypLayer, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue) ); assertThat( - vdypLayer, hasProperty( + vdypLayer, + hasProperty( "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiableNotModifiedValue ) ); @@ -3455,12 +3558,12 @@ vdypLayer, hasProperty( assertThat(spec1, hasProperty("treesPerHectareByUtilization", modifiableNotModifiedValue)); assertThat(spec1, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiableNotModifiedValue)); assertThat( - spec1, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue - ) + spec1, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue) ); assertThat( - spec1, hasProperty( + spec1, + hasProperty( "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiableNotModifiedValue ) ); @@ -3472,12 +3575,12 @@ spec1, hasProperty( assertThat(spec2, hasProperty("treesPerHectareByUtilization", modifiableNotModifiedValue)); assertThat(spec2, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", modifiableNotModifiedValue)); assertThat( - spec2, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue - ) + spec2, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", modifiableNotModifiedValue) ); assertThat( - spec2, hasProperty( + spec2, + hasProperty( "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", modifiableNotModifiedValue ) ); diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java index c7f3820f5..26139184c 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/RootFinderTest.java @@ -44,10 +44,10 @@ void testRootFunction() throws IOException { double[] y = func.value(x); assertThat( - Arrays.stream(y).mapToObj(d -> d).toList(), contains( - closeTo(1 + 8.190178e-2), closeTo(7 - 2.869991e0), closeTo(74 + 5.996042e0), closeTo( - 9 - 2.689271e0 - ), closeTo(30.2601795 + 1.002164e0) + Arrays.stream(y).mapToObj(d -> d).toList(), + contains( + closeTo(1 + 8.190178e-2), closeTo(7 - 2.869991e0), closeTo(74 + 5.996042e0), + closeTo(9 - 2.689271e0), closeTo(30.2601795 + 1.002164e0) ) ); } @@ -99,7 +99,8 @@ void testRootFunctionSolve() throws IOException { var point = app.findRoot(diameterBase, goal, x, layer, 2.0e-3f); assertThat( - point, vectorCloseTo( + point, + vectorCloseTo( new double[] { 0.891877294, 11.4491625, 66.0574265, 12.3855982, 0.00443319743 }, 2.0E-03 ) ); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index e25a8ab68..884510e5e 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -189,21 +189,26 @@ 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. - * + /** + * 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 + * @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)); + + 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(); @@ -214,13 +219,13 @@ void refreshBank(VdypLayer layer) throws ProcessingException { transferSpeciesIntoBank(nextSlot++, s); } } - + private void transferSpeciesIntoBank(int index, VdypSpecies species) throws ProcessingException { 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); @@ -242,7 +247,7 @@ private void transferSpeciesIntoBank(int index, VdypSpecies species) throws Proc yearsAtBreastHeight[index] = VdypEntity.MISSING_FLOAT_VALUE; siteCurveNumbers[index] = VdypEntity.MISSING_INTEGER_VALUE; }); - + transferUtilizationSetIntoBank(index, species); } @@ -267,17 +272,17 @@ private void transferUtilizationSetIntoBank(int index, VdypUtilizationHolder uh) /** * 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 getLayer() { - + transferUtilizationsFromBank(0, layer); for (int i : indices) { - transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i])); + transferSpeciesFromBank(i, layer.getSpecies().get(speciesNames[i])); } - + return layer; } @@ -286,20 +291,19 @@ private VdypSpecies transferSpeciesFromBank(int index, VdypSpecies species) { VdypSpecies newSpecies = VdypSpecies.build(speciesBuilder -> { speciesBuilder.adapt(species); speciesBuilder.percentGenus(this.percentagesOfForestedLand[index]); - species.getSite().ifPresent(site -> - speciesBuilder.addSite(VdypSite.build(siteBuilder -> { - siteBuilder.adapt(site); - siteBuilder.ageTotal(this.ageTotals[index]); - siteBuilder.height(this.dominantHeights[index]); - siteBuilder.siteCurveNumber(this.siteCurveNumbers[index]); - siteBuilder.siteGenus(this.speciesNames[index]); - siteBuilder.siteIndex(this.siteIndices[index]); - siteBuilder.yearsToBreastHeight(this.yearsToBreastHeight[index]); + species.getSite().ifPresent(site -> speciesBuilder.addSite(VdypSite.build(siteBuilder -> { + siteBuilder.adapt(site); + siteBuilder.ageTotal(this.ageTotals[index]); + siteBuilder.height(this.dominantHeights[index]); + siteBuilder.siteCurveNumber(this.siteCurveNumbers[index]); + siteBuilder.siteGenus(this.speciesNames[index]); + siteBuilder.siteIndex(this.siteIndices[index]); + siteBuilder.yearsToBreastHeight(this.yearsToBreastHeight[index]); }))); }); - + transferUtilizationsFromBank(index, newSpecies); - + return newSpecies; } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 53f39b8fb..7bdac239d 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -35,7 +35,7 @@ public class ForwardDataStreamReader { private static final Logger logger = LoggerFactory.getLogger(ForwardDataStreamReader.class); private final ForwardResolvedControlMap resolvedControlMap; - + private final StreamingParser polygonStream; private final StreamingParser> layerSpeciesStream; private final StreamingParser> speciesUtilizationStream; @@ -43,26 +43,29 @@ public class ForwardDataStreamReader { @SuppressWarnings("unchecked") public ForwardDataStreamReader(ForwardResolvedControlMap resolvedControlMap) throws ProcessingException { - + try { this.resolvedControlMap = resolvedControlMap; Map controlMap = resolvedControlMap.getControlMap(); - + var polygonStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_POLY.name()); polygonStream = ((StreamingParserFactory) polygonStreamFactory).get(); - + var layerSpeciesStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SPECIES.name()); layerSpeciesStream = ((StreamingParserFactory>) layerSpeciesStreamFactory).get(); - - var speciesUtilizationStreamFactory = controlMap.get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()); + + var speciesUtilizationStreamFactory = controlMap + .get(ControlKey.FORWARD_INPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()); speciesUtilizationStream = ((StreamingParserFactory>) speciesUtilizationStreamFactory) .get(); - + polygonDescriptionStream = Optional.empty(); if (controlMap.containsKey(ControlKey.FORWARD_INPUT_GROWTO.name())) { - var polygonDescriptionStreamFactory = Utils.> - expectParsedControl(controlMap, ControlKey.FORWARD_INPUT_GROWTO, StreamingParserFactory.class); - + var polygonDescriptionStreamFactory = Utils + .>expectParsedControl( + controlMap, ControlKey.FORWARD_INPUT_GROWTO, StreamingParserFactory.class + ); + polygonDescriptionStream = Optional.of(polygonDescriptionStreamFactory.get()); } else { polygonDescriptionStream = Optional.empty(); @@ -72,12 +75,12 @@ public ForwardDataStreamReader(ForwardResolvedControlMap resolvedControlMap) thr } } - /** - * Constructor that takes a raw control map. This should only be used from unit tests. - * + /** + * Constructor that takes a raw control map. This should only be used from unit tests. + * * @param controlMap - * @throws IOException in the event of an error - * @throws ProcessingException + * @throws IOException in the event of an error + * @throws ProcessingException */ ForwardDataStreamReader(Map controlMap) throws ProcessingException { @@ -105,22 +108,30 @@ public Optional readNextPolygon() throws ProcessingException { utilizationsBySpeciesMap.putIfAbsent(key, new EnumMap<>(UtilizationClass.class)); utilizationsBySpeciesMap.get(key).put(utilization.getUcIndex(), utilization); } - + if (polygonDescriptionStream.isPresent()) { var pdStream = polygonDescriptionStream.get(); if (!pdStream.hasNext()) { - throw new ProcessingException(MessageFormat.format("Grow-to-year file at {0} in the control file does" - + " not contain a record for {1} as expected, but instead the end-of-file was reached" - , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getPolygonIdentifier().getName())); + throw new ProcessingException( + MessageFormat.format( + "Grow-to-year file at {0} in the control file does" + + " not contain a record for {1} as expected, but instead the end-of-file was reached", + ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getPolygonIdentifier().getName() + ) + ); } var polygonDescription = pdStream.next(); - if (! polygonDescription.getName().equals(polygon.getPolygonIdentifier().getName())) { - throw new ProcessingException(MessageFormat.format("Grow-to-year file at {0} in the control file does" - + " not contain a record for {1} as expected, but instead contains a record for {2}" - , ControlKey.FORWARD_INPUT_GROWTO.name(), polygon.getPolygonIdentifier().getName() - , polygonDescription.getName())); + if (!polygonDescription.getName().equals(polygon.getPolygonIdentifier().getName())) { + throw new ProcessingException( + MessageFormat.format( + "Grow-to-year file at {0} in the control file does" + + " not contain a record for {1} as expected, but instead contains a record for {2}", + ControlKey.FORWARD_INPUT_GROWTO.name(), + polygon.getPolygonIdentifier().getName(), polygonDescription.getName() + ) + ); } - + polygon.setTargetYear(polygonDescription.getYear()); } @@ -131,20 +142,20 @@ public Optional readNextPolygon() throws ProcessingException { logger.trace("Saw species {}", s); applyGroups(polygon.getBiogeoclimaticZone(), s.getGenus(), s); - + var perSpeciesKey = new UtilizationBySpeciesKey(s.getLayerType(), s.getGenusIndex()); var speciesUtilizations = utilizationsBySpeciesMap.get(perSpeciesKey); - if (speciesUtilizations != null) { + if (speciesUtilizations != null) { setUtilizations(s, speciesUtilizations); - + var defaultKey = new UtilizationBySpeciesKey(LayerType.PRIMARY, 0); Map defaultUtilization = utilizationsBySpeciesMap .get(defaultKey); calculateSpeciesCoverage(s, defaultUtilization); } - + if (LayerType.PRIMARY.equals(s.getLayerType())) { primarySpecies.put(s.getGenusIndex(), s); } else if (LayerType.VETERAN.equals(s.getLayerType())) { @@ -152,15 +163,15 @@ public Optional readNextPolygon() throws ProcessingException { } else { throw new IllegalStateException( MessageFormat.format( - "Unrecognized layer type {} for species {} of polygon {}", - s.getLayerType(), s.getGenusIndex(), polygon.getPolygonIdentifier() + "Unrecognized layer type {} for species {} of polygon {}", s.getLayerType(), + s.getGenusIndex(), polygon.getPolygonIdentifier() ) ); } } Map layerMap = new HashMap<>(); - + VdypLayer primaryLayer = null; if (primarySpecies.size() > 0) { @@ -174,9 +185,9 @@ public Optional readNextPolygon() throws ProcessingException { builder.inventoryTypeGroup(polygon.getInventoryTypeGroup()); builder.addSpecies(layerSpeciesSet); }); - + setUtilizations(primaryLayer, defaultSpeciesUtilization); - + layerMap.put(LayerType.PRIMARY, primaryLayer); } @@ -184,8 +195,7 @@ public Optional readNextPolygon() throws ProcessingException { if (veteranSpecies.size() > 0) { var key = new UtilizationBySpeciesKey(LayerType.VETERAN, 0); - Map defaultUtilization = utilizationsBySpeciesMap - .get(key); + Map defaultUtilization = utilizationsBySpeciesMap.get(key); veteranLayer = VdypLayer.build(builder -> { builder.layerType(LayerType.VETERAN); @@ -193,9 +203,9 @@ public Optional readNextPolygon() throws ProcessingException { builder.inventoryTypeGroup(polygon.getInventoryTypeGroup()); builder.addSpecies(layerSpeciesSet); }); - + setUtilizations(veteranLayer, defaultUtilization); - + layerMap.put(LayerType.VETERAN, veteranLayer); } @@ -212,7 +222,7 @@ public Optional readNextPolygon() throws ProcessingException { } private void calculateSpeciesCoverage(VdypSpecies s, Map defaultUtilization) { - + float speciesCoverage = s.getBaseAreaByUtilization().get(UtilizationClass.ALL) / defaultUtilization.get(UtilizationClass.ALL).getBasalArea(); @@ -239,8 +249,8 @@ protected void applyGroups(BecDefinition bec, String genus, VdypSpecies species) } private void setUtilizations(VdypUtilizationHolder u, Map speciesUtilizations) { - - for (var e: speciesUtilizations.entrySet()) { + + for (var e : speciesUtilizations.entrySet()) { var uc = e.getKey(); var ucUtilizations = e.getValue(); @@ -252,8 +262,10 @@ private void setUtilizations(VdypUtilizationHolder u, MapprocessPolygon for each polygon to be processed. All calls - * to processPolygon are entirely independent of one another, allowing (different) - * polygons to the processed in parallel. + * This class manages "growing" polygons. Create an instance of the class, providing a control map, and then call + * processPolygon for each polygon to be processed. All calls to processPolygon are entirely + * independent of one another, allowing (different) polygons to the processed in parallel. */ public class ForwardProcessingEngine { @@ -85,18 +84,17 @@ public class ForwardProcessingEngine { public static final float PI_40K = (float) (Math.PI / 40_000); /* pp */ final ForwardProcessingState fps; - + /** The entity to which result information is written */ private Optional outputWriter = Optional.empty(); - public ForwardProcessingEngine(Map controlMap, Optional outputWriter) + public ForwardProcessingEngine(Map controlMap, Optional outputWriter) throws ProcessingException { this.fps = new ForwardProcessingState(controlMap); this.outputWriter = outputWriter == null ? Optional.empty() : outputWriter; } - public ForwardProcessingEngine(Map controlMap) - throws ProcessingException { + public ForwardProcessingEngine(Map controlMap) throws ProcessingException { this.fps = new ForwardProcessingState(controlMap); } @@ -112,6 +110,19 @@ public enum ExecutionStep { ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES, // CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX, // SET_COMPATIBILITY_VARIABLES, // + GROW_1_LAYER_DHDELTA, // + GROW_2_LAYER_BADELTA, // + GROW_3_LAYER_DQDELTA, // + GROW_4_LAYER_BA_AND_DQTPH_EST, // + GROW_5_SPECIES_BADQTPH, // + GROW_6_LAYER_TPH2, // + GROW_7_LAYER_DQ2, // + GROW_8_SPECIES_LH, // + GROW_9_SPECIES_PCT, // + GROW_10_PRIMARY_SPECIES_DETAILS, // + GROW_11_COMPATIBILITY_VARS, // + GROW_12_SPECIES_UC, // + GROW_13_SPECIES_UC_SMALL, // GROW, // // Must be last @@ -132,13 +143,33 @@ public ExecutionStep successor() { return ExecutionStep.values()[ordinal() + 1]; } + + public boolean lt(ExecutionStep that) { + return this.ordinal() < that.ordinal(); + } + + public boolean le(ExecutionStep that) { + return this.ordinal() <= that.ordinal(); + } + + public boolean eq(ExecutionStep that) { + return this.ordinal() == that.ordinal(); + } + + public boolean ge(ExecutionStep that) { + return this.ordinal() >= that.ordinal(); + } + + public boolean gt(ExecutionStep that) { + return this.ordinal() > that.ordinal(); + } } /** * Run all steps of the engine on the given polygon. - * + * * @param polygon the polygon on which to operate - * + * * @throws ProcessingException should an error with the data occur during processing */ public void processPolygon(VdypPolygon polygon) throws ProcessingException { @@ -148,10 +179,10 @@ public void processPolygon(VdypPolygon polygon) throws ProcessingException { /** * Run all steps of the engine on the given polygon up to and including the given lastStep. - * - * @param polygon the polygon on which to operate + * + * @param polygon the polygon on which to operate * @param lastStepInclusive execute up to and including this step - * + * * @throws ProcessingException should an error with the data occur during processing */ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) throws ProcessingException { @@ -190,99 +221,99 @@ public void processPolygon(VdypPolygon polygon, ExecutionStep lastStepInclusive) executeForwardAlgorithm(lastStepInclusive, targetYear); } - private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int stoppingYearInclusive) throws ProcessingException { + private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int stoppingYearInclusive) + throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); Optional veteranLayer; - if (lps.getPolygon().getLayers().containsKey(LayerType.VETERAN)){ + if (lps.getPolygon().getLayers().containsKey(LayerType.VETERAN)) { veteranLayer = Optional.of(lps.getPolygon().getLayers().get(LayerType.VETERAN)); } else { veteranLayer = Optional.empty(); } // BANKCHK1, simplified for the parameters METH_CHK = 4, LayerI = 1, and INSTANCE = 1 - if (lastStepInclusive.ordinal() >= ExecutionStep.CHECK_FOR_WORK.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.CHECK_FOR_WORK)) { stopIfNoWork(lps); } // SCINXSET - note these are calculated directly from the Primary bank of instance 1 - if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_MISSING_SITE_CURVES.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.CALCULATE_MISSING_SITE_CURVES)) { calculateMissingSiteCurves(lps, fps.fcm.getSiteCurveMap()); } // VPRIME1, method == 1 - if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_COVERAGES.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.CALCULATE_COVERAGES)) { calculateCoverages(lps); } - if (lastStepInclusive.ordinal() >= ExecutionStep.DETERMINE_POLYGON_RANKINGS.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.DETERMINE_POLYGON_RANKINGS)) { determinePolygonRankings(CommonData.PRIMARY_SPECIES_TO_COMBINE); } // SITEADD (TODO: SITEADDU when NDEBUG 11 > 0) - if (lastStepInclusive.ordinal() >= ExecutionStep.ESTIMATE_MISSING_SITE_INDICES.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.ESTIMATE_MISSING_SITE_INDICES)) { estimateMissingSiteIndices(lps); } - if (lastStepInclusive.ordinal() >= ExecutionStep.ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.ESTIMATE_MISSING_YEARS_TO_BREAST_HEIGHT_VALUES)) { estimateMissingYearsToBreastHeightValues(lps); } // VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2 - if (lastStepInclusive.ordinal() >= ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX)) { calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } // CVSET1 - if (lastStepInclusive.ordinal() >= ExecutionStep.SET_COMPATIBILITY_VARIABLES.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.SET_COMPATIBILITY_VARIABLES)) { setCompatibilityVariables(); } // VGROW1 - if (lastStepInclusive.ordinal() >= ExecutionStep.GROW.ordinal()) { + if (lastStepInclusive.ge(ExecutionStep.GROW)) { int startingYear = lps.getPolygon().getPolygonIdentifier().getYear(); VdypPolygon vdypPolygon = lps.getPolygon(); - + writePolygon(vdypPolygon, startingYear, startingYear, stoppingYearInclusive); Map polygonLayers = vdypPolygon.getLayers(); - + boolean doRecalculateGroupsPriorToOutput = fps.fcm.getDebugSettings() - .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 - && lps.getNSpecies() > 1; + .getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1) != 1 && lps.getNSpecies() > 1; boolean doRecalculateGroups = fps.fcm.getForwardControlVariables() .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) >= 1; - + int currentYear = startingYear + 1; while (currentYear <= stoppingYearInclusive) { logger.info( - "Growing polygon {} Primary layer for year {}", lps.getPolygon().getPolygonIdentifier() - .toStringCompact(), currentYear + "Growing polygon {} Primary layer for year {}", + lps.getPolygon().getPolygonIdentifier().toStringCompact(), currentYear ); - grow(lps, currentYear, veteranLayer); - + grow(lps, currentYear, veteranLayer, lastStepInclusive); + // If update-during-growth is set, update the context prior to output if (doRecalculateGroupsPriorToOutput) { calculateCoverages(lps); calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } - + VdypLayer updatedLayer = lps.getLayer(); polygonLayers.put(LayerType.PRIMARY, updatedLayer); - + logger.atInfo().addArgument(updatedLayer.getBaseAreaByUtilization().toString()).log("{}"); - + // Store polygon (both primary and veteran layers) to output writePolygon(vdypPolygon, startingYear, currentYear, stoppingYearInclusive); - // If update-during-growth is set, and not already recalculated, recalculate + // If update-during-growth is set, and not already recalculated, recalculate // context now. - if (! doRecalculateGroupsPriorToOutput && doRecalculateGroups) { + if (!doRecalculateGroupsPriorToOutput && doRecalculateGroups) { calculateCoverages(lps); calculateDominantHeightAgeSiteIndex(lps, fps.fcm.getHl1Coefficients()); } @@ -293,19 +324,22 @@ private void executeForwardAlgorithm(ExecutionStep lastStepInclusive, int stoppi } /** - * VGROW1 - "grow" the primary layer, located in lps.bank, starting at the - * given year, and return the resulting bank. The veteran layer instance is supplied but at - * this point is ignored. - * - * @param lps the layer processing state - * @param currentYear the current growth period - * @param veteranLayer the polygon's veteran layer + * VGROW1 - "grow" the primary layer, located in lps.bank, starting at the given year, and return the + * resulting bank. The veteran layer instance is supplied but at this point is ignored. + * + * @param lps the layer processing state + * @param currentYear the current growth period + * @param veteranLayer the polygon's veteran layer + * @param lastStepInclusive * @return as described - * + * * @throws ProcessingException */ - private void grow(LayerProcessingState lps, int currentYear, Optional veteranLayer) - throws ProcessingException { + private void grow( + LayerProcessingState lps, int currentYear, Optional veteranLayer, ExecutionStep lastStepInclusive + ) throws ProcessingException { + + assert lastStepInclusive.ge(ExecutionStep.GROW_1_LAYER_DHDELTA); Bank bank = lps.getBank(); @@ -317,30 +351,36 @@ private void grow(LayerProcessingState lps, int currentYear, Optional // (1) Calculate change in dominant height (layer) - float dhDelta = growDominantHeight(dhStart, pspSiteCurveNumber, pspSiteIndex, pspYtbhStart); + float dhDelta = calculateDominantHeightDelta(dhStart, pspSiteCurveNumber, pspSiteIndex, pspYtbhStart); + + if (ExecutionStep.GROW_1_LAYER_DHDELTA.eq(lastStepInclusive)) + return; // (2) Calculate change in basal area (layer) - final Optional veteranLayerBasalArea = - veteranLayer.flatMap((l) -> Optional.of(l.getBaseAreaByUtilization().get(UtilizationClass.ALL))); + final Optional veteranLayerBasalArea = veteranLayer + .flatMap((l) -> Optional.of(l.getBaseAreaByUtilization().get(UtilizationClass.ALL))); float dqStart = bank.quadMeanDiameters[0][UC_ALL_INDEX]; float baStart = bank.basalAreas[0][UC_ALL_INDEX]; float tphStart = bank.treesPerHectare[0][UC_ALL_INDEX]; float lhStart = bank.loreyHeights[0][UC_ALL_INDEX]; - float baDelta = growBasalArea( - pspYabhStart, dhStart, baStart, veteranLayerBasalArea, dhDelta - ); + float baDelta = calculateBasalAreaDelta(pspYabhStart, dhStart, baStart, veteranLayerBasalArea, dhDelta); + + if (ExecutionStep.GROW_2_LAYER_BADELTA.eq(lastStepInclusive)) + return; // (3) Calculate change in quad-mean-diameter (layer) Reference wasDqGrowthLimitApplied = new Reference<>(); - float dqDelta = growQuadMeanDiameter( - pspYabhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, wasDqGrowthLimitApplied + float dqDelta = calculateQuadMeanDiameterDelta( + pspYabhStart, baStart, dhStart, dqStart, veteranLayerBasalArea, veteranLayerBasalArea, dhDelta, + wasDqGrowthLimitApplied ); - int debugSetting9Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9); + int debugSetting9Value = fps.fcm.getDebugSettings() + .getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9); if (debugSetting9Value == 1 && wasDqGrowthLimitApplied.get() /* is true */) { // Limit BA growth if DQ hit limit. float dqEnd = dqStart + dqDelta; @@ -350,8 +390,11 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float baChangeRate = baDelta / baStart; + if (ExecutionStep.GROW_3_LAYER_DQDELTA.eq(lastStepInclusive)) + return; + // (4) Begin storing computed results - dq, ba and tph for the layer - + // Cache some values for calculations below. float pspLhStart = bank.loreyHeights[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; @@ -367,22 +410,25 @@ private void grow(LayerProcessingState lps, int currentYear, Optional bank.basalAreas[0][UC_ALL_INDEX] = baEnd; bank.treesPerHectare[0][UC_ALL_INDEX] = tphEnd; - // (5) Now calculate per-species (UC All only) end values for basal area, quad-mean-diameter - // and trees-per-hectare, using one of several options: "full species dynamics", + if (ExecutionStep.GROW_4_LAYER_BA_AND_DQTPH_EST.eq(lastStepInclusive)) + return; + + // (5) Now calculate per-species (UC All only) end values for basal area, quad-mean-diameter + // and trees-per-hectare, using one of several options: "full species dynamics", // "partial species dynamics" or "no species dynamics." - + int debugSetting1Value = fps.fcm.getDebugSettings().getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1); boolean wasSolutionFound = false; if (debugSetting1Value == 2) { - // (5a) This is the PARTIAL SPECIES DYNAMICS section. + // (5a) This is the PARTIAL SPECIES DYNAMICS section. // (5a1) Begin by updating HL for all species (UC All only), as well // as the per-layer value (UC All). - + // First save the at-start Lorey Height values, needed for the - they will be restored // below and re-calculated later once more precise information is known. - + float[] lhAtStart = new float[bank.getNSpecies() + 1]; lhAtStart[0] = bank.loreyHeights[0][UC_ALL_INDEX]; for (int i : bank.getIndices()) { @@ -390,13 +436,13 @@ private void grow(LayerProcessingState lps, int currentYear, Optional } // Compute the per-species Lorey Height estimates. - + float pspTphEndEstimate = pspTphStart * (tphEnd / tphStart); growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEndEstimate, pspLhStart); // Calculate the per-site Lorey Height estimate. - + float sum1 = 0.0f; float sum2 = 0.0f; @@ -407,17 +453,15 @@ private void grow(LayerProcessingState lps, int currentYear, Optional bank.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; - // Now do the actual per-species updates of ba, qmd and tph, based in part - // on both the starting Lorey Heights and the estimated Lorey Heights at the + // Now do the actual per-species updates of ba, qmd and tph, based in part + // on both the starting Lorey Heights and the estimated Lorey Heights at the // end of the growth period. - - wasSolutionFound = growUsingPartialSpeciesDynamics( - baStart, baDelta, dqStart, dqDelta, tphStart, lhAtStart - ); + + wasSolutionFound = growUsingPartialSpeciesDynamics(baStart, baDelta, dqStart, dqDelta, tphStart, lhAtStart); // Restore the Lorey Heights back to the values at the beginning of the period. // They will be updated below using the new estimate of TPH-primary species. - + for (int i = 0; i < bank.getNSpecies(); i++) { bank.loreyHeights[i][UC_ALL_INDEX] = lhAtStart[i]; } @@ -426,7 +470,7 @@ private void grow(LayerProcessingState lps, int currentYear, Optional if (!wasSolutionFound) { // Calculate the basal area, trees-per-hectare and quad-mean-diameter for all // species in the polygon (UC All) - + if (debugSetting1Value == 1 || bank.getNSpecies() == 1) { // (5b) This is the NO SPECIES DYNAMICS section @@ -438,6 +482,9 @@ private void grow(LayerProcessingState lps, int currentYear, Optional } } + if (ExecutionStep.GROW_5_SPECIES_BADQTPH.eq(lastStepInclusive)) + return; + // (6) Calculate layer trees-per-hectare, UC All float tphEndSum = 0.0f; @@ -448,26 +495,37 @@ private void grow(LayerProcessingState lps, int currentYear, Optional } bank.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; + if (ExecutionStep.GROW_6_LAYER_TPH2.eq(lastStepInclusive)) + return; + // (7) Calculate layer quad-mean-diameter, uc All - bank.quadMeanDiameters[0][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter.quadMeanDiameter( - bank.basalAreas[0][UC_ALL_INDEX], bank.treesPerHectare[0][UC_ALL_INDEX] - ); + bank.quadMeanDiameters[0][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter + .quadMeanDiameter(bank.basalAreas[0][UC_ALL_INDEX], bank.treesPerHectare[0][UC_ALL_INDEX]); - // (8) Calculate layer Lorey heights over all species, uc UC_ALL_INDEX + if (ExecutionStep.GROW_7_LAYER_DQ2.eq(lastStepInclusive)) + return; + + // (8) Calculate per-species Lorey heights, uc All float pspTphEnd = bank.treesPerHectare[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); - // We now have site (layer) level predications for basal area, quad-mean-diameter, + // We now have site (layer) level predications for basal area, quad-mean-diameter, // trees-per-hectare and Lorey height. Proceed to per-species estimates. + if (ExecutionStep.GROW_8_SPECIES_LH.eq(lastStepInclusive)) + return; + // (9) Calculate basal area percentages per species, uc UC_ALL_INDEX for (int i : bank.getIndices()) { bank.percentagesOfForestedLand[i] = 100.0f * bank.basalAreas[i][UC_ALL_INDEX] / bank.basalAreas[0][UC_ALL_INDEX]; } + if (ExecutionStep.GROW_9_SPECIES_PCT.eq(lastStepInclusive)) + return; + // (10) Update the running values. TODO: why isn't siteIndex being updated? lps.updatePrimarySpeciesDetailsAfterGrowth(dhEnd); @@ -483,10 +541,10 @@ private void grow(LayerProcessingState lps, int currentYear, Optional float spYtbhStart = bank.yearsToBreastHeight[i]; float spYabhStart = bank.yearsAtBreastHeight[i]; - if (!Float.isNaN(spSiStart) && !Float.isNaN(spDhStart) - && !Float.isNaN(spYtbhStart) && !Float.isNaN(spYabhStart)) { + if (!Float.isNaN(spSiStart) && !Float.isNaN(spDhStart) && !Float.isNaN(spYtbhStart) + && !Float.isNaN(spYabhStart)) { - float dhGrowth = growDominantHeight( + float dhGrowth = calculateDominantHeightDelta( spDhStart, pspSiteCurveNumber, spSiStart, spYtbhStart ); bank.dominantHeights[i] += dhGrowth; @@ -496,36 +554,51 @@ private void grow(LayerProcessingState lps, int currentYear, Optional } } + if (ExecutionStep.GROW_10_PRIMARY_SPECIES_DETAILS.eq(lastStepInclusive)) + return; + // (11) update the compatibility variables to reflect the changes during the growth period lps.updateCompatibilityVariablesAfterGrowth(); + if (ExecutionStep.GROW_11_COMPATIBILITY_VARS.eq(lastStepInclusive)) + return; + // (12) calculate All and the large component volumes to reflect the changes in growth - + VdypLayer primaryLayer = lps.getLayer(); - + VolumeComputeMode volumeComputationMode = VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC; - int controlVariable3Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); - CompatibilityVariableMode compatibilityVariableMode = CompatibilityVariableMode.getByInteger(controlVariable3Value); - lps.getFps().computers.computeUtilizationComponentsPrimary(lps.getBecZone(), primaryLayer, volumeComputationMode, compatibilityVariableMode); + int controlVariable3Value = fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); + CompatibilityVariableMode compatibilityVariableMode = CompatibilityVariableMode + .getByInteger(controlVariable3Value); + lps.getFps().computers.computeUtilizationComponentsPrimary( + lps.getBecZone(), primaryLayer, volumeComputationMode, compatibilityVariableMode + ); bank.refreshBank(primaryLayer); - + + if (ExecutionStep.GROW_12_SPECIES_UC.eq(lastStepInclusive)) + return; + // (13) calculate the small component volumes to reflect the changes in growth - + calculateSmallComponentYields(lps); + + if (ExecutionStep.GROW_13_SPECIES_UC_SMALL.eq(lastStepInclusive)) + return; } /** - * Calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare - * and quad-mean-diameter at the end of the growth period for all species in the polygon, given - * the per-layer basal area and trees-per-hectare rate of change. - * @param baChangeRate the rate of change of the basal area during the growth period, - * expressed as a percentage / 100. So a rate of 10% (i.e., 1.1 times the starting - * value) would be expressed at 0.1f. - * @param tphChangeRate the rate of change of trees-per-hectare during the growth period, - * expressed the same way. + * Calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare and quad-mean-diameter at + * the end of the growth period for all species in the polygon, given the per-layer basal area and trees-per-hectare + * rate of change. + * + * @param baChangeRate the rate of change of the basal area during the growth period, expressed as a percentage / + * 100. So a rate of 10% (i.e., 1.1 times the starting value) would be expressed at 0.1f. + * @param tphChangeRate the rate of change of trees-per-hectare during the growth period, expressed the same way. */ - private void growUsingNoSpeciesDynamics(float baChangeRate, float tphChangeRate) { + void growUsingNoSpeciesDynamics(float baChangeRate, float tphChangeRate) { LayerProcessingState lps = fps.getLayerProcessingState(); Bank bank = lps.getBank(); @@ -551,19 +624,20 @@ private void growUsingNoSpeciesDynamics(float baChangeRate, float tphChangeRate) } private static final int NSTAGES = 10; - - private record AdjustmentParameters( - /** normal maximum change towards zero */ - float cjMax, - /** true iff allowed to cross the zero boundary */ - boolean canCrossZero, - /** allowable wrong-way change for species closest to zero */ - float cjWrongWayChange1, - /** allowable wrong-way change for other species */ - float cjWrongWayChangeX) {} - + + private record AdjustmentParameters( + /** normal maximum change towards zero */ + float cjMax, + /** true iff allowed to cross the zero boundary */ + boolean canCrossZero, + /** allowable wrong-way change for species closest to zero */ + float cjWrongWayChange1, /** allowable wrong-way change for other species */ + float cjWrongWayChangeX + ) { + } + private static AdjustmentParameters[] adjustmentParametersByStage = new AdjustmentParameters[NSTAGES]; - + static { adjustmentParametersByStage[0] = new AdjustmentParameters(0.01f, false, 0.0f, 0.0f); adjustmentParametersByStage[1] = new AdjustmentParameters(0.015f, true, 0.005f, 0.0f); @@ -576,29 +650,28 @@ private record AdjustmentParameters( adjustmentParametersByStage[8] = adjustmentParametersByStage[3]; adjustmentParametersByStage[9] = adjustmentParametersByStage[4]; } - + /** - * GRSPpart - calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare - * and quad-mean-diameter at the end of the growth period for all species in the polygon. - * - * @param baStart overall basal area at start of growth period - * @param baDelta change in overall basal area during the growth period - * @param dqStart overall quad-mean-diameter at start of growth period - * @param dqDelta change in overall quad-mean-diameter during the growth period - * @param tphStart overall trees-per-hectare value at the start of growth period - * @param lhAtStart stand and per-species (UC All) Lorey heights at the start of the growth period - * index 0 - stand; indices 1 - # species for the individual species - * + * GRSPpart - calculate, using the "no species dynamics" algorithm, the basal area, trees-per-hectare and + * quad-mean-diameter at the end of the growth period for all species in the current layer of the polygon. + * + * @param baStart overall basal area at start of growth period + * @param baDelta change in overall basal area during the growth period + * @param dqStart overall quad-mean-diameter at start of growth period + * @param dqDelta change in overall quad-mean-diameter during the growth period + * @param tphStart overall trees-per-hectare value at the start of growth period + * @param lhAtStart stand and per-species (UC All) Lorey heights at the start of the growth period index 0 - stand; + * indices 1 - # species for the individual species + * * @return true if and only if a solution was found. - * @throws ProcessingException + * @throws ProcessingException */ - private boolean growUsingPartialSpeciesDynamics( - float baStart, float baDelta, float dqStart, float dqDelta, - float tphStart, float[] lhAtStart + boolean growUsingPartialSpeciesDynamics( + float baStart, float baDelta, float dqStart, float dqDelta, float tphStart, float[] lhAtStart ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); - Bank bank = lps.getBank(); + Bank bank = lps.getBank(); VdypPolygon polygon = lps.getPolygon(); Region polygonRegion = polygon.getBiogeoclimaticZone().getRegion(); @@ -616,154 +689,138 @@ private boolean growUsingPartialSpeciesDynamics( float[] baNew = new float[lps.getNSpecies() + 1]; baNew[0] = baStart + baDelta; for (int i : lps.getIndices()) { - baNew[i] = bank.basalAreas[i][0] * baNew[0] / bank.basalAreas[0][0]; + baNew[i] = bank.basalAreas[i][UC_ALL_INDEX] * baNew[0] / bank.basalAreas[0][UC_ALL_INDEX]; } - + float[] dqNew = new float[lps.getNSpecies() + 1]; dqNew[0] = dqStart + dqDelta; float[] tphNew = new float[lps.getNSpecies() + 1]; - tphNew[0] = tphStart + BaseAreaTreeDensityDiameter.treesPerHectare(baNew[0], dqNew[0]); + tphNew[0] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[0], dqNew[0]); Map basalAreaPercentagesPerSpecies = new HashMap<>(); for (String spAlias : fps.fcm.getGenusDefinitionMap().getAllGeneraAliases()) { basalAreaPercentagesPerSpecies.put(spAlias, 0.0f); } for (int i : lps.getIndices()) { - basalAreaPercentagesPerSpecies.put(bank.speciesNames[i], bank.percentagesOfForestedLand[i]); + basalAreaPercentagesPerSpecies.put(bank.speciesNames[i], bank.percentagesOfForestedLand[i] / 100.0f); } - + for (int i : lps.getIndices()) { dqs1[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( - bank.speciesNames[i], - lhAtStart[i], - bank.quadMeanDiameters[i][UC_ALL_INDEX], - basalAreaPercentagesPerSpecies, - lps.getBecZone().getRegion(), - dqStart, - baStart, - tphStart, - lhAtStart[0]); - + bank.speciesNames[i], lhAtStart[i], bank.quadMeanDiameters[i][UC_ALL_INDEX], + basalAreaPercentagesPerSpecies, lps.getBecZone().getRegion(), dqStart, baStart, tphStart, + lhAtStart[0] + ); + dqs2[i] = fps.estimators.estimateQuadMeanDiameterForSpecies( - bank.speciesNames[i], - bank.loreyHeights[i][UC_ALL_INDEX], - dqNew[0], - basalAreaPercentagesPerSpecies, - lps.getBecZone().getRegion(), - dqNew[0], - baNew[0], - tphNew[0], - bank.loreyHeights[0][UC_ALL_INDEX]); + bank.speciesNames[i], bank.loreyHeights[i][UC_ALL_INDEX], dqNew[0], basalAreaPercentagesPerSpecies, + lps.getBecZone().getRegion(), dqNew[0], baNew[0], tphNew[0], bank.loreyHeights[0][UC_ALL_INDEX] + ); } - + float[] dqLowerBoundBySpecies = new float[lps.getNSpecies() + 1]; float[] dqUpperBoundBySpecies = new float[lps.getNSpecies() + 1]; float[] tphLowerBoundBySpecies = new float[lps.getNSpecies() + 1]; float[] tphUpperBoundBySpecies = new float[lps.getNSpecies() + 1]; boolean exactMatchFound = false; - boolean biggerD; int incorrectlySignedSpeciesIndex = 0; - + float tphLow = 0.0f; float tphHigh = 0.0f; - + int stage; for (stage = 0; stage < NSTAGES; stage++) { - - if (stage == 1 || stage == 6) { + + if (stage == 0 || stage == 5) { // Set bounds - + for (int i : lps.getIndices()) { - dqLowerBoundBySpecies[i] = 7.51f; dqUpperBoundBySpecies[i] = 100.0f; - + if (bank.treesPerHectare[i][UC_ALL_INDEX] <= 0) { continue; - } - + } + var sizeLimits = fps.estimators.getLimitsForHeightAndDiameter(bank.speciesNames[i], polygonRegion); var spDqMax = sizeLimits.quadMeanDiameterMaximum(); - + float spDqStart = bank.quadMeanDiameters[i][UC_ALL_INDEX]; - + // Non-negotiable bounds - dqUpperBoundBySpecies[i] = FloatMath.max(dqNew[i], dqStart, spDqMax, spDqStart); - + dqUpperBoundBySpecies[i] = FloatMath.max(dqNew[0], dqStart, spDqMax, spDqStart) + 10.0f; + // Non-decline constraint imposed unless net change in ba/tree < 1% - float dqNetChange = dqNew[0] / spDqStart; + float dqNetChange = dqNew[0] / dqStart; float rateDq2 = dqNetChange * dqNetChange - 1.0f; if (rateDq2 > 0.01) { dqLowerBoundBySpecies[i] = spDqStart; } else { float dq2Min = spDqStart * spDqStart * (1.0f + rateDq2 - 0.01f); if (dq2Min > 0.0f) { - dqLowerBoundBySpecies[i] = Math.max(dqLowerBoundBySpecies[i], - Math.min(FloatMath.sqrt(dq2Min), spDqStart)); + dqLowerBoundBySpecies[i] = Math + .max(dqLowerBoundBySpecies[i], Math.min(FloatMath.sqrt(dq2Min), spDqStart)); } } - - if (stage > 5) { + + if (stage >= 5) { continue; } - - // More restrictive bounds, stages 1 - 5 only. - + + // More restrictive bounds, stages 0 - 4 only. + float spHlStart = bank.loreyHeights[i][UC_ALL_INDEX]; - + float trialMax = Math.max(spDqStart, spDqMax); if (spDqStart < 1.001 * sizeLimits.maxQuadMeanDiameterLoreyHeightRatio() * spHlStart) { trialMax = Math.min(trialMax, sizeLimits.maxQuadMeanDiameterLoreyHeightRatio() * spHlStart); } - + dqUpperBoundBySpecies[i] = Math.min(dqUpperBoundBySpecies[i], trialMax); - + float spDqMin = sizeLimits.minQuadMeanDiameterLoreyHeightRatio() * spHlStart; if (spDqStart > 0.999 * spDqMin) { dqLowerBoundBySpecies[i] = Math.max(dqLowerBoundBySpecies[i], spDqMin); } } } - + // Bounds now set - + // With CJ = 0, subject to constraints, find the resultant trees-per-hectare. - + float tphSum = 0.0f; for (int i : lps.getIndices()) { if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { continue; } - + float spDqStart = bank.quadMeanDiameters[i][UC_ALL_INDEX]; - tryDq[i] = 7.5f + (dqs2[i] - 7.5f) * ((spDqStart - 7.5f)/(dqs1[i] - 7.5f)); - if (tryDq[i] < dqLowerBoundBySpecies[i]) { - tryDq[i] = dqLowerBoundBySpecies[i]; - } - if (tryDq[i] > dqUpperBoundBySpecies[i]) { - tryDq[i] = dqUpperBoundBySpecies[i]; - } - rs1[i] = FloatMath.log(spDqStart - 7.5f / dqs1[i] - 7.5f); + + tryDq[i] = 7.5f + (dqs2[i] - 7.5f) * ( (spDqStart - 7.5f) / (dqs1[i] - 7.5f)); + tryDq[i] = FloatMath.clamp(tryDq[i], dqLowerBoundBySpecies[i], dqUpperBoundBySpecies[i]); + + rs1[i] = FloatMath.log( (spDqStart - 7.5f) / (dqs1[i] - 7.5f)); tryTph[i] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[i], tryDq[i]); tphSum += tryTph[i]; } - + if (tphSum == tphNew[0]) { exactMatchFound = true; break; } - - biggerD = tphSum > tphNew[0]; + + boolean biggerD = tphSum > tphNew[0]; incorrectlySignedSpeciesIndex = 0; float amountWrong = 50000.0f; - + for (int i : lps.getIndices()) { if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { continue; } - + if (biggerD && rs1[i] > 0.0f) { if (rs1[i] < amountWrong) { incorrectlySignedSpeciesIndex = i; @@ -776,29 +833,32 @@ private boolean growUsingPartialSpeciesDynamics( } } } - + // Calculate the low and high quad-mean-diameters - + + tphLow = 0.0f; + tphHigh = 0.0f; + float cjLow; float cjHigh; float cjOther; - + for (int i : lps.getIndices()) { if (bank.basalAreas[i][UC_ALL_INDEX] <= 0.0f) { continue; } - + if (i == incorrectlySignedSpeciesIndex) { cjOther = adjustmentParametersByStage[stage].cjWrongWayChange1; } else { cjOther = adjustmentParametersByStage[stage].cjWrongWayChangeX; } - + if (biggerD) { if (rs1[i] <= 0.0f) { cjLow = -cjOther; cjHigh = adjustmentParametersByStage[stage].cjMax; - if (! adjustmentParametersByStage[stage].canCrossZero) { + if (!adjustmentParametersByStage[stage].canCrossZero) { cjHigh = Math.min(cjHigh, -rs1[i]); } } else { @@ -811,7 +871,7 @@ private boolean growUsingPartialSpeciesDynamics( cjHigh = 0.0f; } else { cjLow = -adjustmentParametersByStage[stage].cjMax; - if (! adjustmentParametersByStage[stage].canCrossZero) { + if (!adjustmentParametersByStage[stage].canCrossZero) { cjLow = Math.max(-adjustmentParametersByStage[stage].cjMax, -rs1[i]); } cjHigh = 0.0f; @@ -819,56 +879,48 @@ private boolean growUsingPartialSpeciesDynamics( } float trialDqLow = 7.5f + (dqs2[i] - 7.5f) * FloatMath.exp(rs1[i] + cjLow); + trialDqLow = FloatMath.clamp(trialDqLow, dqLowerBoundBySpecies[i], dqUpperBoundBySpecies[i]); float trialDqHigh = 7.5f + (dqs2[i] - 7.5f) * FloatMath.exp(rs1[i] + cjHigh); - - if (trialDqLow < dqLowerBoundBySpecies[i]) { - trialDqLow = dqLowerBoundBySpecies[i]; - } - if (trialDqLow > dqUpperBoundBySpecies[i]) { - trialDqLow = dqUpperBoundBySpecies[i]; - } - - if (trialDqHigh < dqLowerBoundBySpecies[i]) { - trialDqHigh = dqLowerBoundBySpecies[i]; - } - if (trialDqHigh > dqUpperBoundBySpecies[i]) { - trialDqHigh = dqUpperBoundBySpecies[i]; - } - + trialDqHigh = FloatMath.clamp(trialDqHigh, dqLowerBoundBySpecies[i], dqUpperBoundBySpecies[i]); + tphUpperBoundBySpecies[i] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[i], trialDqLow); tphLowerBoundBySpecies[i] = BaseAreaTreeDensityDiameter.treesPerHectare(baNew[i], trialDqHigh); - + tphLow += tphLowerBoundBySpecies[i]; tphHigh += tphUpperBoundBySpecies[i]; } - + if (tphNew[0] >= tphLow && tphNew[0] <= tphHigh) { break; } } - - if (stage == NSTAGES) { + + if (stage + 1 == NSTAGES) { // Finished all stages and no viable solution found. return false; } - + if (!exactMatchFound) { // A viable solution was found, but not an exact one. Find the solution for trees. - + if (tphLow > tphHigh) { - throw new ProcessingException(MessageFormat.format("Polygon {0}, layer {1}: while computing growth" - + " using partial species dynamics, trees-per-hectare lower bound ({2}) was found to be" - + " greater than the upper bound ({3})" - , polygon.getPolygonIdentifier().toStringCompact(), lps.getLayerType(), tphLow, tphHigh)); + throw new ProcessingException( + MessageFormat.format( + "Polygon {0}, layer {1}: while computing growth" + + " using partial species dynamics, trees-per-hectare lower bound ({2}) was found to be" + + " greater than the upper bound ({3})", + polygon.getPolygonIdentifier().toStringCompact(), lps.getLayerType(), tphLow, tphHigh + ) + ); } float k; if (tphLow == tphHigh) { k = 0.0f; } else { - k = (tphNew[0] - tphLow)/(tphHigh - tphLow); + k = (tphNew[0] - tphLow) / (tphHigh - tphLow); } - + for (int i : lps.getIndices()) { if (bank.basalAreas[i][UC_ALL_INDEX] >= 0.0f) { tphNew[i] = tphLowerBoundBySpecies[i] + k * (tphUpperBoundBySpecies[i] - tphLowerBoundBySpecies[i]); @@ -891,44 +943,44 @@ private boolean growUsingPartialSpeciesDynamics( } } } - + for (int i : lps.getIndices()) { bank.basalAreas[i][UC_ALL_INDEX] = baNew[i]; bank.quadMeanDiameters[i][UC_ALL_INDEX] = dqNew[i]; bank.treesPerHectare[i][UC_ALL_INDEX] = tphNew[i]; } - + return true /* was successful */; } /** - * Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth - * during the growth period. The result is stored in end, Utilization Class ALL. - * @param baStart per-layer basal area at start of growth period - * @param baDelta per-layer change in basal area during growth period - * @param dqStart per-layer quad-mean-diameter at the start of growth period - * @param dqDelta per-layer change in quad-mean-diameter during growth period + * Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth during the growth + * period. The result is stored in end, Utilization Class ALL. + * + * @param baStart per-layer basal area at start of growth period + * @param baDelta per-layer change in basal area during growth period + * @param dqStart per-layer quad-mean-diameter at the start of growth period + * @param dqDelta per-layer change in quad-mean-diameter during growth period * @param tphStart per-layer trees-per-breast-height at that of growth period - * @param lhStart per-layer Lorey height at the start of the growth period + * @param lhStart per-layer Lorey height at the start of the growth period * @throws ProcessingException */ - private void growUsingFullSpeciesDynamics( - float baStart, float baDelta, float dqStart, float dqDelta, float tphStart, - float lhStart + void growUsingFullSpeciesDynamics( + float baStart, float baDelta, float dqStart, float dqDelta, float tphStart, float lhStart ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); Bank bank = lps.getBank(); float spBaEnd[] = new float[lps.getNSpecies() + 1]; - float spTphNew[] = new float[lps.getNSpecies() + 1]; - float spDqNew[] = new float[lps.getNSpecies() + 1]; + float spTphEnd[] = new float[lps.getNSpecies() + 1]; + float spDqEnd[] = new float[lps.getNSpecies() + 1]; boolean doSkip[] = new boolean[lps.getNSpecies() + 1]; for (int i : lps.getIndices()) { - spBaEnd[i] = bank.basalAreas[i][UC_ALL_INDEX]; - spTphNew[i] = bank.treesPerHectare[i][UC_ALL_INDEX]; - spDqNew[i] = bank.quadMeanDiameters[i][UC_ALL_INDEX]; + spBaEnd[i] = Float.NaN; + spTphEnd[i] = Float.NaN; + spDqEnd[i] = Float.NaN; doSkip[i] = false; } @@ -936,8 +988,8 @@ private void growUsingFullSpeciesDynamics( float sumSpBaDelta = 0.0f; float spBaDelta[] = new float[lps.getNSpecies() + 1]; + float pspLhStart = bank.loreyHeights[lps.getPrimarySpeciesIndex()][UC_ALL_INDEX]; for (int i : lps.getIndices()) { - float pspLhStart = bank.loreyHeights[i][UC_ALL_INDEX]; if (i == lps.getPrimarySpeciesIndex()) { float pspBaStart = bank.basalAreas[i][UC_ALL_INDEX]; float pspYabhStart = lps.getPrimarySpeciesAgeAtBreastHeight(); @@ -964,7 +1016,7 @@ private void growUsingFullSpeciesDynamics( // Iteratively attempt to find a value f such that: // - // if revised spBaDelta = spBaStart * (f + spBaDelta / spBaStart) + // if revised spBaDelta = spBaStart * (f + spBaDelta / spBaStart) // then sum(revised spBaDelta) = baDelta // // for all species whose basal area after growth is non-negative. @@ -1004,7 +1056,8 @@ private void growUsingFullSpeciesDynamics( throw new ProcessingException( MessageFormat.format( "Unable to converge on a value for \"f\" in" - + " growUsingFullSpeciesDynamics({0}, {1}, {2}, {3}, {4}, {5})", dqDelta, baDelta, baStart, dqStart, tphStart, lhStart + + " growUsingFullSpeciesDynamics({0}, {1}, {2}, {3}, {4}, {5})", + dqDelta, baDelta, baStart, dqStart, tphStart, lhStart ) ); } @@ -1013,7 +1066,7 @@ private void growUsingFullSpeciesDynamics( { // Estimate of quad-mean-diameter growth by species - + var passNumber = 0; var bestScore = 1000.0; var bestF = Float.NaN; @@ -1031,11 +1084,11 @@ private void growUsingFullSpeciesDynamics( float spDqDelta; if (i == lps.getPrimarySpeciesIndex()) { - spDqDelta = growQuadMeanDiameterForPrimarySpecies( + spDqDelta = calculateQuadMeanDiameterDeltaForPrimarySpecies( dqStart, dqDelta, spDqStart, lhStart, spLhStart ); } else { - spDqDelta = growQuadMeanDiameterForNonPrimarySpecies( + spDqDelta = calculateQuadMeanDiameterDeltaForNonPrimarySpecies( i, dqStart, dqDelta, spDqStart, lhStart, spLhStart ); } @@ -1066,17 +1119,17 @@ private void growUsingFullSpeciesDynamics( totalBasalAreaSkipped += bank.basalAreas[i][UC_ALL_INDEX]; } - spDqNew[i] = spDqStart + spDqDelta; + spDqEnd[i] = spDqStart + spDqDelta; } float tph = 0.0f; for (int i : bank.getIndices()) { if (spBaEnd[i] > 0.0f) { - spTphNew[i] = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd[i], spDqNew[i]); + spTphEnd[i] = BaseAreaTreeDensityDiameter.treesPerHectare(spBaEnd[i], spDqEnd[i]); } else { - spTphNew[i] = 0.0f; + spTphEnd[i] = 0.0f; } - tph += spTphNew[i]; + tph += spTphEnd[i]; } if (passNumber == 15 || (nSkipped == lps.getNSpecies() && passNumber > 2)) { @@ -1112,10 +1165,10 @@ private void growUsingFullSpeciesDynamics( for (int i : bank.getIndices()) { bank.basalAreas[i][UC_ALL_INDEX] = spBaEnd[i]; - bank.treesPerHectare[i][UC_ALL_INDEX] = spTphNew[i]; + bank.treesPerHectare[i][UC_ALL_INDEX] = spTphEnd[i]; if (spBaEnd[i] > 0.0f) { bank.quadMeanDiameters[i][UC_ALL_INDEX] = BaseAreaTreeDensityDiameter - .quadMeanDiameter(spBaEnd[i], spTphNew[i]); + .quadMeanDiameter(spBaEnd[i], spTphEnd[i]); } } } @@ -1123,10 +1176,10 @@ private void growUsingFullSpeciesDynamics( /** * EMP061 - get the component size limits for the given genus and alias. - * + * * @param genusAlias the alias of the genus in question - * @param region the region in question - * + * @param region the region in question + * * @return as described */ private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region region) { @@ -1134,19 +1187,19 @@ private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region reg } /** - * EMP150 - return the quad-mean-diameter growth for the primary species of the - * Primary layer. Based on IPSJF150.doc (July, 1999). - * - * @param dqStart primary layer quad-mean-diameter at start of growth period - * @param dqDelta change in quad-mean-diameter of primary layer during growth period + * EMP150 - return the change in quad-mean-diameter over the growth period for the + * primary species of the Primary layer. Based on IPSJF150.doc (July, 1999). + * + * @param dqStart primary layer quad-mean-diameter at start of growth period + * @param dqDelta change in quad-mean-diameter of primary layer during growth period * @param pspDqStart primary species quad-mean-diameter at start of growth period - * @param lhStart primary layer Lorey height at start of growth period + * @param lhStart primary layer Lorey height at start of growth period * @param pspLhStart primary species Lorey height at start of growth period - + * * @return as described * @throws ProcessingException in the event of an error */ - private float growQuadMeanDiameterForPrimarySpecies( + private float calculateQuadMeanDiameterDeltaForPrimarySpecies( float dqStart, float dqDelta, float pspDqStart, float lhStart, float pspLhStart ) throws ProcessingException { @@ -1160,15 +1213,29 @@ private float growQuadMeanDiameterForPrimarySpecies( MessageFormat.format( "primaryQuadMeanDiameterGrowthCoefficients do not exist" + " for stratum number {0}, call growQuadMeanDiameterForPrimarySpecies(" - + "{1}, {2}, {3}, {4}, {5})", dqStart, dqDelta, pspDqStart, lhStart, pspLhStart + + "{1}, {2}, {3}, {4}, {5})", + dqStart, dqDelta, pspDqStart, lhStart, pspLhStart ) ); } - return growQuadMeanDiameter(mc.getCoefficients(), dqStart, dqDelta, pspDqStart, lhStart, pspLhStart); + return calculateQuadMeanDiameterDelta(mc.getCoefficients(), dqStart, dqDelta, pspDqStart, lhStart, pspLhStart); } - private float growQuadMeanDiameterForNonPrimarySpecies( + /** + * EMP151 - calculate and return the quad-mean-diameter delta over the growth period for a + * non-primary species. + * + * @param speciesIndex the index of the species (1..nSpecies) in the current bank + * @param dqStart layer quad-mean-diameter at start of growth period + * @param dqDelta layer quad-mean-diameter delta over growth period + * @param spDqStart species quad-mean-diameter at start of growth period + * @param lhStart layer Lorey height at start of growth period + * @param spLhStart species Lorey height at start of growth period + * @return as described + * @throws ProcessingException + */ + private float calculateQuadMeanDiameterDeltaForNonPrimarySpecies( int speciesIndex, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart ) throws ProcessingException { @@ -1188,15 +1255,29 @@ private float growQuadMeanDiameterForNonPrimarySpecies( throw new ProcessingException( MessageFormat.format( "No nonPrimarySpeciesQuadMeanDiameterGrowthCoefficients exist for stratum {0}" - + "; call growQuadMeanDiameterForNonPrimarySpecies({1}, {2}, {3}, {4}, {5}, {6})", pspStratumNumber, speciesIndex, dqStart, dqDelta, lhStart, spDqStart, spLhStart + + "; call growQuadMeanDiameterForNonPrimarySpecies({1}, {2}, {3}, {4}, {5}, {6})", + pspStratumNumber, speciesIndex, dqStart, dqDelta, lhStart, spDqStart, spLhStart ) ); } - return growQuadMeanDiameter(modelCoefficientsOpt.get(), dqStart, dqDelta, spDqStart, lhStart, spLhStart); + return calculateQuadMeanDiameterDelta(modelCoefficientsOpt.get(), dqStart, dqDelta, spDqStart, lhStart, spLhStart); } - private static float growQuadMeanDiameter( + /** + * Calculate and return the quad-mean-diameter delta over the growth period for a + * non-primary species. + * + * @param mc coefficients to use for the calculation + * @param dqStart layer quad-mean-diameter at start of growth period + * @param dqDelta layer quad-mean-diameter delta over growth period + * @param spDqStart species quad-mean-diameter at start of growth period + * @param lhStart layer Lorey height at start of growth period + * @param spLhStart species Lorey height at start of growth period + * @return as described + * @throws ProcessingException + */ + private static float calculateQuadMeanDiameterDelta( Coefficients mc, float dqStart, float dqDelta, float spDqStart, float lhStart, float spLhStart ) { float a0 = mc.getCoe(1); @@ -1221,19 +1302,19 @@ private static float growQuadMeanDiameter( } /** - * EMP149 - return the basal area growth for non-Primary species of Primary layer. Based on - * IPSJF149.doc (July, 1999). - * + * EMP149 - return the basal area growth for non-Primary species of Primary layer. Based on IPSJF149.doc (July, + * 1999). + * * @param speciesName - * @param baStart layer basal area at start of growth period - * @param baDelta layer basal area growth during period - * @param lhStart layer Lorey height at start of growth period - * @param spBaStart this species basal area at start of growth period - * @param spDqStart this species quad-mean-diameter at start of growth period - * @param spLhStart this species Lorey height at start of growth period\ - * + * @param baStart layer basal area at start of growth period + * @param baDelta layer basal area growth during period + * @param lhStart layer Lorey height at start of growth period + * @param spBaStart this species basal area at start of growth period + * @param spDqStart this species quad-mean-diameter at start of growth period + * @param spLhStart this species Lorey height at start of growth period\ + * * @return as described - * @throws ProcessingException + * @throws ProcessingException */ private float growBasalAreaForNonPrimarySpecies( String speciesName, float baStart, float baDelta, float lhStart, float spBaStart, float spDqStart, @@ -1246,15 +1327,16 @@ private float growBasalAreaForNonPrimarySpecies( throw new ProcessingException( MessageFormat.format( "Species basal area {0} is out of range; it must be" - + " positive and less that overall basal area {1}", spBaStart, baStart + + " positive and less that overall basal area {1}", + spBaStart, baStart ) ); } int pspStratumNumber = lps.getPrimarySpeciesStratumNumber(); - var modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients() - .get(speciesName, pspStratumNumber); + var coe = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients(); + var modelCoefficientsOpt = coe.get(speciesName, pspStratumNumber); if (modelCoefficientsOpt.isEmpty()) { modelCoefficientsOpt = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients().get(speciesName, 0); @@ -1264,7 +1346,8 @@ private float growBasalAreaForNonPrimarySpecies( throw new ProcessingException( MessageFormat.format( "No nonPrimarySpeciesBasalAreaGrowthCoefficients exist for stratum {0}" - + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", pspStratumNumber, speciesName, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart + + "; call growBasalAreaForNonPrimarySpecies({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7})", + pspStratumNumber, speciesName, baStart, baDelta, lhStart, spBaStart, spDqStart, spLhStart ) ); } @@ -1276,7 +1359,7 @@ private float growBasalAreaForNonPrimarySpecies( float a2 = mc.getCoe(3); var baProportionStart = spBaStart / baStart; - var logBaProportionStart = FloatMath.log(baProportionStart / 1.0f - baProportionStart); + var logBaProportionStart = FloatMath.log(baProportionStart / (1.0f - baProportionStart)); var logBaDeltaProportion = a0 + a1 * FloatMath.log(spDqStart) + a2 * spLhStart / lhStart; var logBaProportionEnd = logBaProportionStart + logBaDeltaProportion; @@ -1287,27 +1370,27 @@ private float growBasalAreaForNonPrimarySpecies( return spDeltaBa; } - /** - * EMP148 - return the basal area growth for Primary species of Primary layer. Based on - * IPSJF148.doc (July, 1999). - * - * @param baStart layer basal area at start of growth period - * @param baDelta layer basal area growth during period - * @param pspBaStart primary species basal area at start of growth period - * @param dhStart dominant height of primary species at start of growth period + /** + * EMP148 - return the basal area growth for Primary species of Primary layer. Based on IPSJF148.doc (July, 1999). + * + * @param baStart layer basal area at start of growth period + * @param baDelta layer basal area growth during period + * @param pspBaStart primary species basal area at start of growth period + * @param dhStart dominant height of primary species at start of growth period * @param pspYabhStart primary species years at breast height at start of growth period - * @param pspLhStart primary species Lorey height at start of growth period - * + * @param pspLhStart primary species Lorey height at start of growth period + * * @return as described * @throws ProcessingException */ private float growBasalAreaForPrimarySpecies( - float baStart, float baDelta, float pspBaStart, float dhStart, float pspYabhStart, - float pspLhStart + float baStart, float baDelta, float pspBaStart, float dhStart, float pspYabhStart, float pspLhStart ) throws ProcessingException { LayerProcessingState lps = fps.getLayerProcessingState(); + float pspBaDelta; + float spToAllProportionStart = pspBaStart / baStart; if (spToAllProportionStart <= 0.999f) { var psStratumNumber = lps.getPrimarySpeciesStratumNumber(); @@ -1335,17 +1418,18 @@ private float growBasalAreaForPrimarySpecies( } var x = FloatMath.exp(logBaProportionStart + logBaDeltaProportion); - var spToAllProportionEnd = FloatMath.exp(x) / (1 + FloatMath.exp(x)); - baDelta = spToAllProportionEnd * (baStart + baDelta) - pspBaStart; + var spToAllProportionEnd = x / (1 + x); + pspBaDelta = spToAllProportionEnd * (baStart + baDelta) - pspBaStart; + } else { + pspBaDelta = baDelta; } - return baDelta; + return pspBaDelta; } /** - * YSMALL - records in end the small component utilization values for - * current layer. - * + * YSMALL - records in end the small component utilization values for current layer. + * * @throws ProcessingException */ private void calculateSmallComponentYields(LayerProcessingState lps) throws ProcessingException { @@ -1377,7 +1461,9 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc } // EMP081 - float conditionalExpectedBasalArea = calculateConditionalExpectedBasalArea(speciesName, spBaAll, spLhAll, region); + float conditionalExpectedBasalArea = calculateConditionalExpectedBasalArea( + speciesName, spBaAll, spLhAll, region + ); if (fractionAvailable > 0.0f) { conditionalExpectedBasalArea /= fractionAvailable; @@ -1449,16 +1535,16 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc bank.cuVolumesMinusDecayAndWastage[0][UC_SMALL_INDEX] = 0.0f; } - /** - * GRSPHL - estimate the Lorey Heights of all species at end of growth period. The results of - * the calculations are persisted in {@code lps.bank}. - * - * @param lps processing state context - * @param dhStart (primary species) dominant height at start - * @param dhEnd (primary species) dominant height at end + /** + * GRSPHL - estimate the Lorey Heights of all species at end of growth period. The results of the calculations are + * persisted in {@code lps.bank}. + * + * @param lps processing state context + * @param dhStart (primary species) dominant height at start + * @param dhEnd (primary species) dominant height at end * @param pspTphStart primary species trees-per-hectare at start - * @param pspTphEnd primary species trees-per-hectare at end - * @param pspLhStart primary species Lorey height at end + * @param pspTphEnd primary species trees-per-hectare at end + * @param pspLhStart primary species Lorey height at end */ void growLoreyHeights( LayerProcessingState lps, float dhStart, float dhEnd, float pspTphStart, float pspTphEnd, float pspLhStart @@ -1489,12 +1575,8 @@ void growLoreyHeights( for (int i : lps.getIndices()) { if (i != primarySpeciesIndex && bank.basalAreas[i][UC_ALL_INDEX] > 0.0f) { if (! (dhEnd == dhStart && debugSetting8Value >= 1)) { - float spLhEstimate1 = estimateNonPrimarySpeciesLoreyHeight( - i, dhStart, pspLhStart - ); - float spLhEstimate2 = estimateNonPrimarySpeciesLoreyHeight( - i, dhEnd, pspLhEnd - ); + float spLhEstimate1 = estimateNonPrimarySpeciesLoreyHeight(i, dhStart, pspLhStart); + float spLhEstimate2 = estimateNonPrimarySpeciesLoreyHeight(i, dhEnd, pspLhEnd); float otherF = (bank.loreyHeights[i][UC_ALL_INDEX] - 1.3f) / (spLhEstimate1 - 1.3f); otherF = 1.0f + (otherF - 1.0f) * nonPrimaryLhAdjustment; @@ -1505,12 +1587,12 @@ void growLoreyHeights( } /** - * EMP050, method 1. Estimate the Lorey height of the primary species from the - * its dominant height and trees-per-hectare. - * - * @param dh the dominantHeight (of the primary species) + * EMP050, method 1. Estimate the Lorey height of the primary species from the its dominant height and + * trees-per-hectare. + * + * @param dh the dominantHeight (of the primary species) * @param pspTph trees-per-hectare of the primary species - * + * * @return as described */ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { @@ -1529,18 +1611,15 @@ private float estimatePrimarySpeciesLoreyHeight(float dh, float pspTph) { } /** - * EMP053 - function that returns an estimate of the Lorey height of a non-primary - * species of the polygon. - * - * @param speciesIndex (non-primary) species index - * @param dh (primary species) dominant height + * EMP053 - function that returns an estimate of the Lorey height of a non-primary species of the polygon. + * + * @param speciesIndex (non-primary) species index + * @param dh (primary species) dominant height * @param pspLoreyHeight primary species Lorey height - * + * * @return as described */ - private float estimateNonPrimarySpeciesLoreyHeight( - int speciesIndex, float dh, float pspLoreyHeight - ) { + private float estimateNonPrimarySpeciesLoreyHeight(int speciesIndex, float dh, float pspLoreyHeight) { LayerProcessingState lps = fps.getLayerProcessingState(); Bank bank = lps.getBank(); @@ -1574,27 +1653,24 @@ private float estimateNonPrimarySpeciesLoreyHeight( } /** - * EMP117A - Calculate and return the change in quad-mean-diameter for the primary layer over - * the growth period. - * - * @param pspYabhStart primary species years at breast height (age) at start of growth period - * @param baStart layer basal area at start of growth period - * @param dhStart layer dominant height (i.e., the height of the primary species) at start of growth period - * @param dqStart layer quad-mean-diameter at start of growth period + * EMP117A - Calculate and return the change in quad-mean-diameter for the primary layer over the growth period. + * + * @param pspYabhStart primary species years at breast height (age) at start of growth period + * @param baStart layer basal area at start of growth period + * @param dhStart layer dominant height (i.e., the height of the primary species) at start of growth period + * @param dqStart layer quad-mean-diameter at start of growth period * @param veteranBaStart veteran layer basal area at start of growth period - * @param veteranBaEnd veteran layer basal area at end of growth period - * @param dhDelta growth in dominant height during growth period - * + * @param veteranBaEnd veteran layer basal area at end of growth period + * @param dhDelta growth in dominant height during growth period + * * @return growth in quad-mean-diameter for the growth period. This may be negative. - * + * * @throws StandProcessingException */ - float growQuadMeanDiameter( - float pspYabhStart, float baStart, float dhStart, float dqStart, - Optional veteranBaStart, Optional veteranBaEnd, float dhDelta, - Reference dqGrowthLimitApplied - ) - throws StandProcessingException { + float calculateQuadMeanDiameterDelta( + float pspYabhStart, float baStart, float dhStart, float dqStart, Optional veteranBaStart, + Optional veteranBaEnd, float dhDelta, Reference dqGrowthLimitApplied + ) throws StandProcessingException { var lps = fps.getLayerProcessingState(); var becZone = lps.getBecZone(); @@ -1621,14 +1697,16 @@ float growQuadMeanDiameter( .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float dqYieldStart = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhStart, pspYabhStart, veteranBaStart, dqLimit + coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhStart, pspYabhStart, veteranBaStart, + dqLimit ); float dhEnd = dhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float dqYieldEnd = fps.estimators.estimateQuadMeanDiameterYield( - coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhEnd, pspYabhEnd, veteranBaEnd, dqLimit + coefficientsWeightedBySpeciesAndDecayBec, controlVariable2Value, dhEnd, pspYabhEnd, veteranBaEnd, + dqLimit ); float dqYieldGrowth = dqYieldEnd - dqYieldStart; @@ -1699,24 +1777,24 @@ float growQuadMeanDiameter( } /** - * EMP122. Function that returns the quad mean diameter growth quad-mean-diameter value - * computed using the empirical model. - * + * EMP122. Function that returns the quad mean diameter growth quad-mean-diameter value computed using the empirical + * model. + * * @param pspYabhStart primary species years at breast height at start of growth period - * @param dhStart primary species dominant height at start of growth period - * @param baStart basal area of primary layer at start of growth period - * @param dqStart quad mean diameter at start of growth period - * @param hdGrowth growth in dominant height + * @param dhStart primary species dominant height at start of growth period + * @param baStart basal area of primary layer at start of growth period + * @param dqStart quad mean diameter at start of growth period + * @param hdGrowth growth in dominant height * @param dqYieldStart quad mean diameter yield at start of growth period - * @param dqYieldEnd quad mean diameter yield at end of growth period - * + * @param dqYieldEnd quad mean diameter yield at end of growth period + * * @return the change in primary layer basal area from start to start + 1 year */ private float calculateQuadMeanDiameterGrowthEmpirical( - float pspYabhStart, float dhStart, - float baStart, float dqStart, float hdGrowth, float dqYieldStart, float dqYieldEnd + float pspYabhStart, float dhStart, float baStart, float dqStart, float hdGrowth, float dqYieldStart, + float dqYieldEnd ) { - // Compute the growth in quadratic mean diameter + // Compute the growth in quadratic mean diameter var dqGrowthEmpiricalCoefficients = fps.fcm.getQuadMeanDiameterGrowthEmpiricalCoefficients(); @@ -1734,15 +1812,13 @@ private float calculateQuadMeanDiameterGrowthEmpirical( pspYabhStart = Math.max(pspYabhStart, 1.0f); float dqYieldGrowth = dqYieldEnd - dqYieldStart; - float dqDelta = FloatMath.exp( - a0 + a2 * FloatMath.log(pspYabhStart) + a3 * dqStart - + a4 * dhStart + a5 * baStart + a6 * hdGrowth - ) + float dqDelta = FloatMath + .exp(a0 + a2 * FloatMath.log(pspYabhStart) + a3 * dqStart + a4 * dhStart + a5 * baStart + a6 * hdGrowth) + a1 * dqYieldGrowth; dqDelta = Math.max(dqDelta, 0.0f); - // Compute min/max growth in quadratic mean diameter + // Compute min/max growth in quadratic mean diameter Map quadMeanDiameterGrowthEmpiricalLimits = fps.fcm .getQuadMeanDiameterGrowthEmpiricalLimits(); @@ -1777,8 +1853,7 @@ private float[] getSpeciesProportionsByBasalAreaAtStartOfYear() { float[] speciesProportionsByBasalArea = new float[lps.getNSpecies() + 1]; for (int i = 1; i <= lps.getNSpecies(); i++) { - speciesProportionsByBasalArea[i] = bank.basalAreas[i][UC_ALL_INDEX] - / bank.basalAreas[0][UC_ALL_INDEX]; + speciesProportionsByBasalArea[i] = bank.basalAreas[i][UC_ALL_INDEX] / bank.basalAreas[0][UC_ALL_INDEX]; } return speciesProportionsByBasalArea; @@ -1786,19 +1861,18 @@ private float[] getSpeciesProportionsByBasalAreaAtStartOfYear() { /** * EMP111A - Basal area growth for the primary layer. - * - * @param pspYabhStart primary species years-at-breast-height at the start of the year - * @param pspDhStart primary species dominant height at start of year - * @param baStart primary layer basal area at the start of the year + * + * @param pspYabhStart primary species years-at-breast-height at the start of the year + * @param pspDhStart primary species dominant height at start of year + * @param baStart primary layer basal area at the start of the year * @param veteranLayerBaStart veteran layer basal area at the start of the year - * @param dhDelta primary layer during the year - * + * @param dhDelta primary layer during the year + * * @return the growth in the basal area of the primary layer for the year * @throws StandProcessingException in the event of an error */ - float growBasalArea( - float pspYabhStart, float pspDhStart, float baStart, Optional veteranLayerBaStart, - float dhDelta + float calculateBasalAreaDelta( + float pspYabhStart, float pspDhStart, float baStart, Optional veteranLayerBaStart, float dhDelta ) throws StandProcessingException { ForwardDebugSettings debugSettings = fps.fcm.getDebugSettings(); @@ -1827,17 +1901,20 @@ float growBasalArea( var baUpperBound = growBasalAreaUpperBound(); boolean isFullOccupancy = true; - int controlVariable2Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); + int controlVariable2Value = fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2); float baYieldStart = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, veteranLayerBaStart, isFullOccupancy, baUpperBound + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhStart, pspYabhStart, + veteranLayerBaStart, isFullOccupancy, baUpperBound ); float pspDhEnd = pspDhStart + dhDelta; float pspYabhEnd = pspYabhStart + 1.0f; float baYieldEnd = fps.estimators.estimateBaseAreaYield( - estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBaStart, isFullOccupancy, baUpperBound + estimateBasalAreaYieldCoefficients, controlVariable2Value, pspDhEnd, pspYabhEnd, veteranLayerBaStart, + isFullOccupancy, baUpperBound ); var growthFaitDetails = fps.fcm.getBasalAreaGrowthFiatDetails() @@ -1849,9 +1926,9 @@ float growBasalArea( var adjust = -convergenceCoefficient * (baStart - baYieldStart); baGrowth += adjust; - // Special check at young ages. + // Special check at young ages. if (pspYabhStart < 40.0f && baStart > 5.0f * baYieldStart) { - // This stand started MUCH faster than base yield model. We'll let it keep going like + // This stand started MUCH faster than base yield model. We'll let it keep going like // this for a while. baGrowth = Math.min(baYieldStart / pspYabhStart, Math.min(0.5f, baGrowth)); } @@ -1889,7 +1966,7 @@ float growBasalArea( baGrowth = Math.max(baLimit - baStart, 0.0f); } - // Undocumented check to prevent negative growth that causes BA to go to less than + // Undocumented check to prevent negative growth that causes BA to go to less than // 1.0. It is doubtful that this condition will ever occur... if (baGrowth < 0.0f && baStart + baGrowth < 1.0f) { baGrowth = -baStart + 1.0f; @@ -1900,19 +1977,19 @@ float growBasalArea( /** * EMP121. Function that returns the basal area growth calculated using the empirical model. - * - * @param speciesBasalAreaProportions the proportion by basal area of each of the polygon's species - * @param baStart basal area of primary layer - * @param pspYabhStart primary species years at breast height or more - * @param pspDhStart primary species dominant height - * @param baYieldStart basal area yield at start of period - * @param baYieldEnd basal area yield at end of period - * + * + * @param speciesBasalAreaProportions the proportion by basal area of each of the polygon's species + * @param baStart basal area of primary layer + * @param pspYabhStart primary species years at breast height or more + * @param pspDhStart primary species dominant height + * @param baYieldStart basal area yield at start of period + * @param baYieldEnd basal area yield at end of period + * * @return the change in primary layer basal area from start to start + 1 year */ private float calculateBasalAreaGrowthEmpirical( - float[] speciesBasalAreaProportions, float baStart, float pspYabhStart, - float pspDhStart, float baYieldStart, float baYieldEnd + float[] speciesBasalAreaProportions, float baStart, float pspYabhStart, float pspDhStart, + float baYieldStart, float baYieldEnd ) { pspYabhStart = Math.max(pspYabhStart, 1.0f); @@ -1967,7 +2044,7 @@ private float calculateBasalAreaGrowthEmpirical( float basalAreaDelta = term1 * (term2 + term3) + term4; - // An undocumented check to prevent negative growth that causes BA to go to + // An undocumented check to prevent negative growth that causes BA to go to // less than 1.0. It is doubtful that this condition will ever occur. if (basalAreaDelta < 0.0 && baStart + basalAreaDelta < 1.0f) { basalAreaDelta = -baStart + 1.0f; @@ -1989,8 +2066,7 @@ private float growBasalAreaUpperBound() { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); Region region = lps.getBecZone().getRegion(); int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); - return upperBoundsCoefficients - .get(region, lps.getBank().speciesNames[primarySpeciesIndex], 1); + return upperBoundsCoefficients.get(region, lps.getBank().speciesNames[primarySpeciesIndex], 1); } else { var primarySpeciesGroupNumber = lps.getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.BA_INDEX); @@ -2011,8 +2087,7 @@ private float growQuadraticMeanDiameterUpperBound() { var upperBoundsCoefficients = fps.fcm.getUpperBoundsCoefficients(); Region region = lps.getBecZone().getRegion(); int primarySpeciesIndex = lps.getPrimarySpeciesIndex(); - return upperBoundsCoefficients - .get(region, lps.getBank().speciesNames[primarySpeciesIndex], 2); + return upperBoundsCoefficients.get(region, lps.getBank().speciesNames[primarySpeciesIndex], 2); } else { var primarySpeciesGroupNumber = fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(); return fps.fcm.getUpperBounds().get(primarySpeciesGroupNumber).getCoe(UpperBoundsParser.DQ_INDEX); @@ -2020,20 +2095,19 @@ private float growQuadraticMeanDiameterUpperBound() { } /** - * HDGROW - calculate growth in dominant height from the current dominant height and the parameters - * needed to do the computation - * - * @param spDhStart dominant height at the start of the growth period - * @param siteCurveNumber site curve number, used to find the site index equation - * @param siStart + * HDGROW - calculate growth in dominant height from the current dominant height and the parameters needed to do the + * computation + * + * @param spDhStart dominant height at the start of the growth period + * @param siteCurveNumber site curve number, used to find the site index equation + * @param siStart * @param yearsToBreastHeight for the given species - * + * * @return the difference in dominant height from the beginning to the end of the growth period * @throws ProcessingException */ - float growDominantHeight( - float spDhStart, int siteCurveNumber, float siStart, float yearsToBreastHeight - ) throws ProcessingException { + float calculateDominantHeightDelta(float spDhStart, int siteCurveNumber, float siStart, float yearsToBreastHeight) + throws ProcessingException { SiteCurveAgeMaximum scAgeMaximums = fps.fcm.getMaximumAgeBySiteCurveNumber().get(siteCurveNumber); Region region = fps.getLayerProcessingState().getBank().getBecZone().getRegion(); @@ -2046,9 +2120,7 @@ float growDominantHeight( if (spDhStart <= 1.3) { throw new ProcessingException( - MessageFormat.format( - "(current) DominantHeight {0} is out of range (must be above 1.3)", spDhStart - ) + MessageFormat.format("(current) DominantHeight {0} is out of range (must be above 1.3)", spDhStart) ); } @@ -2060,13 +2132,13 @@ float growDominantHeight( double ageStart; try { - ageStart = SiteTool.heightAndSiteIndexToAge( - siteIndexEquation, dhStart_d, ageType, siStart_d, yearsToBreastHeight_d - ); + ageStart = SiteTool + .heightAndSiteIndexToAge(siteIndexEquation, dhStart_d, ageType, siStart_d, yearsToBreastHeight_d); } catch (CommonCalculatorException e) { throw new ProcessingException( MessageFormat.format( - "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3}, {4})", siteIndexEquation, dhStart_d, ageType, siStart_d, yearsToBreastHeight_d + "Encountered exception when calling heightAndSiteIndexToAge({0}, {1}, {2}, {3}, {4})", + siteIndexEquation, dhStart_d, ageType, siStart_d, yearsToBreastHeight_d ), e ); } @@ -2083,8 +2155,8 @@ float growDominantHeight( double ageEnd = ageStart + 1.0f; - // If we are past the total age limit for site curve, assign no growth. If we are almost there, go - // slightly past the limit (by .01 yr). Once there, we should stop growing. The TOTAL age limit was + // If we are past the total age limit for site curve, assign no growth. If we are almost there, go + // slightly past the limit (by .01 yr). Once there, we should stop growing. The TOTAL age limit was // stored so we must calculate a BH age limit first... float ageLimitInYears = scAgeMaximums.getAgeMaximum(region); @@ -2110,8 +2182,8 @@ float growDominantHeight( } } - // The above code to find ages allows errors up to .005 m. At high ages with some - // species this can correspond to a half year. Therefore, AGED1 can not be assumed to + // The above code to find ages allows errors up to .005 m. At high ages with some + // species this can correspond to a half year. Therefore, AGED1 can not be assumed to // correspond to HDD1. Find a new HDD1 to at least get the increment correct. double currentDominantHeight = ageAndSiteIndexToHeight( @@ -2129,7 +2201,8 @@ float growDominantHeight( } else { throw new ProcessingException( MessageFormat.format( - "New dominant height {0} is less than the current dominant height {1}", nextDominantHeight, currentDominantHeight + "New dominant height {0} is less than the current dominant height {1}", + nextDominantHeight, currentDominantHeight ) ); } @@ -2138,7 +2211,7 @@ float growDominantHeight( return (float) (nextDominantHeight - currentDominantHeight); } else { - // We are in a special extension of the curve. Derive the new curve form and then + // We are in a special extension of the curve. Derive the new curve form and then // compute the answer. double breastHeightAgeLimitInYears_d = breastHeightAgeLimitInYears; @@ -2161,13 +2234,13 @@ float growDominantHeight( float a = FloatMath.log(0.5f) / scAgeMaximums.getT1(); float y = (float) currentDominantHeight; // Model is: - // Y = y - rate/a * (1 - exp(a * t)) where t = AGE - BHAGELIM + // Y = y - rate/a * (1 - exp(a * t)) where t = AGE - BHAGELIM // Solve for t: - // 1 - exp(a * t) = (y - dominantHeight) * a/rate - // -exp(a * t) = (y - dominantHeight) * a/rate - 1 - // exp(a * t) = (dominantHeight - y) * a/rate + 1 - // a * t = ln(1 + (dominantHeight - y) * a/rate) - // t = ln(1 + (dominantHeight - y) * a/rate) / a + // 1 - exp(a * t) = (y - dominantHeight) * a/rate + // -exp(a * t) = (y - dominantHeight) * a/rate - 1 + // exp(a * t) = (dominantHeight - y) * a/rate + 1 + // a * t = ln(1 + (dominantHeight - y) * a/rate) + // t = ln(1 + (dominantHeight - y) * a/rate) / a float t; if (spDhStart > y) { float term = 1.0f + (spDhStart - y) * a / rate; @@ -2195,7 +2268,8 @@ private static double ageAndSiteIndexToHeight( if (!checkResultValidity.apply(r)) { throw new ProcessingException( MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) returned {5}", curve, age, ageType, siteIndex, years2BreastHeight, r + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) returned {5}", curve, age, + ageType, siteIndex, years2BreastHeight, r ) ); } @@ -2207,57 +2281,62 @@ private static double ageAndSiteIndexToHeight( SiteIndexEquation curve, double age, SiteIndexAgeType ageType, double siteIndex, double years2BreastHeight ) throws ProcessingException { try { - return SiteTool.ageAndSiteIndexToHeight( - curve, age, ageType, siteIndex, years2BreastHeight - ); + return SiteTool.ageAndSiteIndexToHeight(curve, age, ageType, siteIndex, years2BreastHeight); } catch (CommonCalculatorException e) { throw new ProcessingException( MessageFormat.format( - "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", curve, age, ageType, siteIndex, years2BreastHeight + "SiteTool.ageAndSiteIndexToHeight({0}, {1}, {2}, {3}, {4}) threw exception", curve, age, + ageType, siteIndex, years2BreastHeight ), e ); } } - private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, int endYear) + private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, int endYear) throws ProcessingException { try { outputWriter.ifPresent((o) -> { logger.info("Writing polygon {} for year {}", polygon, currentYear); - - int controlVariable4Value = fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.OUTPUT_FILES_4); - + + int controlVariable4Value = fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.OUTPUT_FILES_4); + switch (controlVariable4Value) { - case 0: { - /* never write output */ + case 0: { + /* never write output */ + return; + } + case 1: { + /* write only first growth period */ + if (currentYear != startYear) { return; } - case 1: { - /* write only first growth period */ - if (currentYear != startYear) { - return; - } - } - case 2: { - /* write only first and last growth periods */ - if (currentYear != startYear && currentYear != endYear) { - return; - } - } - case 4: { - /* write only the first, every tenth subsequent, and the last periods */ - if ((currentYear - startYear) % 10 != 0 && currentYear != endYear) { - return; - } + } + case 2: { + /* write only first and last growth periods */ + if (currentYear != startYear && currentYear != endYear) { + return; } - case 3: { - break; + } + case 4: { + /* write only the first, every tenth subsequent, and the last periods */ + if ( (currentYear - startYear) % 10 != 0 && currentYear != endYear) { + return; } - default: - throw new LambdaProcessingException(new ProcessingException(MessageFormat.format("Invalid value for control variable 4: {0}", controlVariable4Value))); } - + case 3: { + break; + } + default: + throw new LambdaProcessingException( + new ProcessingException( + MessageFormat + .format("Invalid value for control variable 4: {0}", controlVariable4Value) + ) + ); + } + try { o.setPolygonYear(currentYear); o.writePolygonWithSpeciesAndUtilization(polygon); @@ -2275,9 +2354,9 @@ private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, i private static final float B_BASE_MIN = 0.01f; /** - * CVSET1 - computes cvVolume, cvBasalArea, cvQuadraticMeanDiameter and cvSmall and assigns - * them to the current LayerProcessingState. - * + * CVSET1 - computes cvVolume, cvBasalArea, cvQuadraticMeanDiameter and cvSmall and assigns them to the current + * LayerProcessingState. + * * @throws ProcessingException */ @SuppressWarnings("unchecked") @@ -2355,8 +2434,9 @@ void setCompatibilityVariables() throws ProcessingException { // EMP094 fps.estimators.estimateNetDecayAndWasteVolume( - lps.getBecZone() - .getRegion(), uc, aAdjust, bank.speciesNames[s], spLoreyHeight_All, quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, closeUtilizationVolumesNetOfDecayAndWaste + lps.getBecZone().getRegion(), uc, aAdjust, bank.speciesNames[s], spLoreyHeight_All, + quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay, + closeUtilizationVolumesNetOfDecayAndWaste ); float actualVolume = bank.cuVolumesMinusDecayAndWastage[s][uc.ordinal()]; @@ -2376,8 +2456,9 @@ void setCompatibilityVariables() throws ProcessingException { // EMP093 int decayGroup = lps.decayEquationGroups[s]; fps.estimators.estimateNetDecayVolume( - bank.speciesNames[s], lps.getBecZone().getRegion(), uc, aAdjust, decayGroup, lps - .getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, closeUtilizationVolumesNetOfDecay + bank.speciesNames[s], lps.getBecZone().getRegion(), uc, aAdjust, decayGroup, + lps.getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, + closeUtilizationVolumesNetOfDecay ); float actualVolume = bank.cuVolumesMinusDecay[s][uc.ordinal()]; @@ -2396,7 +2477,8 @@ void setCompatibilityVariables() throws ProcessingException { // EMP092 int volumeGroup = lps.volumeEquationGroups[s]; fps.estimators.estimateCloseUtilizationVolume( - uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes + uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, + closeUtilizationVolumes ); float actualVolume = bank.closeUtilizationVolumes[s][uc.ordinal()]; @@ -2409,15 +2491,14 @@ void setCompatibilityVariables() throws ProcessingException { int primarySpeciesVolumeGroup = lps.volumeEquationGroups[s]; float primarySpeciesQMDAll = bank.quadMeanDiameters[s][UC_ALL_INDEX]; - var wholeStemVolume = bank.treesPerHectare[s][UC_ALL_INDEX] - * fps.estimators.estimateWholeStemVolumePerTree( - primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll - ); + var wholeStemVolume = bank.treesPerHectare[s][UC_ALL_INDEX] * fps.estimators + .estimateWholeStemVolumePerTree(primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll); wholeStemVolumes.setCoe(UC_ALL_INDEX, wholeStemVolume); fps.estimators.estimateWholeStemVolume( - UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, quadMeanDiameters, basalAreas, wholeStemVolumes + UtilizationClass.ALL, 0.0f, primarySpeciesVolumeGroup, spLoreyHeight_All, quadMeanDiameters, + basalAreas, wholeStemVolumes ); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { @@ -2432,21 +2513,17 @@ void setCompatibilityVariables() throws ProcessingException { cvVolume[s].put(uc, VolumeVariable.WHOLE_STEM_VOL, LayerType.PRIMARY, adjustment); } - fps.estimators.estimateQuadMeanDiameterByUtilization( - lps.getBecZone(), quadMeanDiameters, genusName - ); + fps.estimators.estimateQuadMeanDiameterByUtilization(lps.getBecZone(), quadMeanDiameters, genusName); - fps.estimators.estimateBaseAreaByUtilization( - lps.getBecZone(), quadMeanDiameters, basalAreas, genusName - ); + fps.estimators.estimateBaseAreaByUtilization(lps.getBecZone(), quadMeanDiameters, basalAreas, genusName); // Calculate trees-per-hectare per utilization treesPerHectare.setCoe(UtilizationClass.ALL.index, bank.treesPerHectare[s][UC_ALL_INDEX]); for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { treesPerHectare.setCoe( - uc.index, BaseAreaTreeDensityDiameter.treesPerHectare( - basalAreas.getCoe(uc.index), quadMeanDiameters.getCoe(uc.index) - ) + uc.index, + BaseAreaTreeDensityDiameter + .treesPerHectare(basalAreas.getCoe(uc.index), quadMeanDiameters.getCoe(uc.index)) ); } @@ -2480,10 +2557,9 @@ void setCompatibilityVariables() throws ProcessingException { } /** - * Function that calculates values for the small component compatibility variables and returns - * the result. - * - * @param speciesIndex the index of the species for which this operation is to be performed + * Function that calculates values for the small component compatibility variables and returns the result. + * + * @param speciesIndex the index of the species for which this operation is to be performed * @param forwardControlVariables the control variables for this run * * @throws ProcessingException @@ -2521,9 +2597,7 @@ void setCompatibilityVariables() throws ProcessingException { float qmdSmall = smallComponentQuadMeanDiameter(speciesName, spLoreyHeight_All); // DQSMsp // EMP085 - float lhSmall = smallComponentLoreyHeight( - speciesName, spLoreyHeight_All, qmdSmall, spQuadMeanDiameter_All - ); // HLSMsp + float lhSmall = smallComponentLoreyHeight(speciesName, spLoreyHeight_All, qmdSmall, spQuadMeanDiameter_All); // HLSMsp // EMP086 float meanVolumeSmall = meanVolumeSmall(speciesName, qmdSmall, lhSmall); // VMEANSMs @@ -2535,10 +2609,7 @@ void setCompatibilityVariables() throws ProcessingException { if (forwardControlVariables.allowCalculation(spInputBasalArea_Small, B_BASE_MIN, (l, r) -> l > r)) { float spInputQuadMeanDiameter_Small = bank.quadMeanDiameters[speciesIndex][UC_SMALL_INDEX]; - cvSmall.put( - UtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - - qmdSmall - ); + cvSmall.put(UtilizationClassVariable.QUAD_MEAN_DIAMETER, spInputQuadMeanDiameter_Small - qmdSmall); } else { cvSmall.put(UtilizationClassVariable.QUAD_MEAN_DIAMETER, 0.0f); } @@ -2569,18 +2640,15 @@ void setCompatibilityVariables() throws ProcessingException { } /** - * EMP080 - calculate the small component probability of the species with - * speciesAlias, the given Lorey height and in the given - * region. - * + * EMP080 - calculate the small component probability of the species with speciesAlias, the given Lorey + * height and in the given region. + * * @param speciesAlias the species' alias - * @param loreyHeight current Lorey height of the stand - * @param region the stand's region + * @param loreyHeight current Lorey height of the stand + * @param region the stand's region * @return as described */ - private float smallComponentProbability( - String speciesAlias, float loreyHeight, Region region - ) { + private float smallComponentProbability(String speciesAlias, float loreyHeight, Region region) { LayerProcessingState lps = fps.getLayerProcessingState(); Coefficients coe = fps.fcm.getSmallComponentProbabilityCoefficients().get(speciesAlias); @@ -2604,7 +2672,7 @@ private float smallComponentProbability( // EMP081 /** - * + * * @param speciesName * @param basalArea * @param loreyHeight @@ -2666,9 +2734,7 @@ private float smallComponentLoreyHeight( } // EMP086 - private float meanVolumeSmall( - String speciesName, float quadMeanDiameterSpecSmall, float loreyHeightSpecSmall - ) { + private float meanVolumeSmall(String speciesName, float quadMeanDiameterSpecSmall, float loreyHeightSpecSmall) { Coefficients coe = fps.fcm.getSmallComponentWholeStemVolumeCoefficients().get(speciesName); // EQN 1 in IPSJF119.doc @@ -2732,10 +2798,10 @@ private static float calculateWholeStemVolume(float actualVolume, float basalAre /** * VHDOM1 METH_H = 2, METH_A = 2, METH_SI = 2. - * - * @param lps layer processing state + * + * @param lps layer processing state * @param hl1Coefficients the configured dominant height recalculation coefficients - * + * * @throws ProcessingException */ static void calculateDominantHeightAgeSiteIndex( @@ -2754,7 +2820,8 @@ static void calculateDominantHeightAgeSiteIndex( if (Float.isNaN(loreyHeight)) { throw new ProcessingException( MessageFormat.format( - "Neither dominant nor lorey height[All] is available for primary species {}", bank.speciesNames[primarySpeciesIndex] + "Neither dominant nor lorey height[All] is available for primary species {}", + bank.speciesNames[primarySpeciesIndex] ), 2 ); } @@ -2783,8 +2850,7 @@ static void calculateDominantHeightAgeSiteIndex( if (Float.isNaN(primarySpeciesTotalAge)) { - if (lps.hasSecondarySpeciesIndex() - && !Float.isNaN(bank.ageTotals[lps.getSecondarySpeciesIndex()])) { + if (lps.hasSecondarySpeciesIndex() && !Float.isNaN(bank.ageTotals[lps.getSecondarySpeciesIndex()])) { activeIndex = Optional.of(lps.getSecondarySpeciesIndex()); } else { for (int i = 1; i <= lps.getNSpecies(); i++) { @@ -2812,8 +2878,7 @@ static void calculateDominantHeightAgeSiteIndex( float primarySpeciesSiteIndex = bank.siteIndices[primarySpeciesIndex]; if (Float.isNaN(primarySpeciesSiteIndex)) { - if (lps.hasSecondarySpeciesIndex() - && !Float.isNaN(bank.siteIndices[lps.getSecondarySpeciesIndex()])) { + if (lps.hasSecondarySpeciesIndex() && !Float.isNaN(bank.siteIndices[lps.getSecondarySpeciesIndex()])) { activeIndex = Optional.of(lps.getSecondarySpeciesIndex()); } else { if (activeIndex.isEmpty() || Float.isNaN(bank.siteIndices[activeIndex.get()])) { @@ -2890,14 +2955,12 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { // Note: this block will normally never be executed because of the logic in // the constructor of VdypLayerSpecies that computes missing values when the // other two measurement values are present. - if (!Float.isNaN(bank.yearsAtBreastHeight[i]) - && bank.ageTotals[i] > bank.yearsAtBreastHeight[i]) { + if (!Float.isNaN(bank.yearsAtBreastHeight[i]) && bank.ageTotals[i] > bank.yearsAtBreastHeight[i]) { bank.yearsToBreastHeight[i] = bank.ageTotals[i] - bank.yearsAtBreastHeight[i]; continue; } - float siteIndex = !Float.isNaN(bank.siteIndices[i]) ? bank.siteIndices[i] - : defaultSiteIndex; + float siteIndex = !Float.isNaN(bank.siteIndices[i]) ? bank.siteIndices[i] : defaultSiteIndex; try { SiteIndexEquation curve = SiteIndexEquation.getByIndex(lps.getSiteCurveNumber(i)); double yearsToBreastHeight = SiteTool.yearsToBreastHeight(curve, siteIndex); @@ -2912,8 +2975,8 @@ static void estimateMissingYearsToBreastHeightValues(LayerProcessingState lps) { * SITEADD *

    * (1) If the site index of the primary species has not been set, calculate it as the average of the site indices of - * the other species that -do- have one, after converting each between the site curve of the other species and that of - * the primary species. + * the other species that -do- have one, after converting each between the site curve of the other species and that + * of the primary species. *

    * (2) If the site index of the primary species has (now) been set, calculate that of the other species whose site * index has not been set from the primary site index after converting it between the site curve of the other @@ -2958,14 +3021,16 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi logger.warn( MessageFormat.format( "there is no conversion from curves {0} to {1}. Excluding species {2}" - + " from the estimation of the site index of {3}", spSiteCurve, pspSiteCurve, - bank.speciesNames[spIndex], bank.speciesNames[pspIndex] + + " from the estimation of the site index of {3}", + spSiteCurve, pspSiteCurve, bank.speciesNames[spIndex], + bank.speciesNames[pspIndex] ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", spSiteCurve, spSiteIndex, pspSiteCurve + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", spSiteCurve, + spSiteIndex, pspSiteCurve ), e ); } @@ -2999,14 +3064,15 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } catch (NoAnswerException e) { logger.warn( MessageFormat.format( - "there is no conversion between curves {0} and {1}. Not calculating site index for species {2}", + "there is no conversion between curves {0} and {1}. Not calculating site index for species {2}", pspSiteCurve, spSiteCurve, bank.speciesNames[spIndex] ) ); } catch (CurveErrorException | SpeciesErrorException e) { throw new ProcessingException( MessageFormat.format( - "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", pspSiteCurve, pspSiteIndex, spSiteCurve + "convertSiteIndexBetweenCurves on {0}, {1} and {2} failed", pspSiteCurve, + pspSiteIndex, spSiteCurve ), e ); } @@ -3019,8 +3085,8 @@ static void estimateMissingSiteIndices(LayerProcessingState lps) throws Processi } /** - * VPRIME1, method == 1: calculate the percentage of forested land covered by each species - * by dividing the basal area of each given species with the basal area of the polygon covered by forest. + * VPRIME1, method == 1: calculate the percentage of forested land covered by each species by dividing the basal + * area of each given species with the basal area of the polygon covered by forest. * * @param state the bank in which the calculations are performed */ @@ -3033,12 +3099,11 @@ static void calculateCoverages(LayerProcessingState lps) { ); for (int i : lps.getIndices()) { - bank.percentagesOfForestedLand[i] = bank.basalAreas[i][UC_ALL_INDEX] - / bank.basalAreas[0][UC_ALL_INDEX] * 100.0f; + bank.percentagesOfForestedLand[i] = bank.basalAreas[i][UC_ALL_INDEX] / bank.basalAreas[0][UC_ALL_INDEX] + * 100.0f; - logger.atDebug().addArgument(i).addArgument(bank.speciesIndices[i]) - .addArgument(bank.speciesNames[i]).addArgument(bank.basalAreas[i][0]) - .addArgument(bank.percentagesOfForestedLand[i]) + logger.atDebug().addArgument(i).addArgument(bank.speciesIndices[i]).addArgument(bank.speciesNames[i]) + .addArgument(bank.basalAreas[i][0]).addArgument(bank.percentagesOfForestedLand[i]) .log("Species {}: SP0 {}, Name {}, Species 7.5cm+ BA {}, Calculated Percent {}"); } } @@ -3111,8 +3176,8 @@ private static void validatePolygon(VdypPolygon polygon) throws ProcessingExcept throw new ProcessingException( MessageFormat.format( - "Polygon {0}''s year value {1} is < 1900", polygon.getPolygonIdentifier().getName(), polygon - .getPolygonIdentifier().getYear() + "Polygon {0}''s year value {1} is < 1900", polygon.getPolygonIdentifier().getName(), + polygon.getPolygonIdentifier().getYear() ) ); } @@ -3130,8 +3195,8 @@ private static void stopIfNoWork(LayerProcessingState lps) throws ProcessingExce if (lps.getNSpecies() == 0) { throw new ProcessingException( MessageFormat.format( - "Polygon {0} layer 0 has no species with basal area above {1}", lps.getPolygon() - .getPolygonIdentifier().toStringCompact(), MIN_BASAL_AREA + "Polygon {0} layer 0 has no species with basal area above {1}", + lps.getPolygon().getPolygonIdentifier().toStringCompact(), MIN_BASAL_AREA ) ); } @@ -3163,8 +3228,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { throw new IllegalArgumentException("Can not find primary species as there are no species"); } - float[] percentages = Arrays - .copyOf(bank.percentagesOfForestedLand, bank.percentagesOfForestedLand.length); + float[] percentages = Arrays.copyOf(bank.percentagesOfForestedLand, bank.percentagesOfForestedLand.length); for (var speciesPair : speciesToCombine) { combinePercentages(bank.speciesNames, speciesPair, percentages); @@ -3198,8 +3262,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { String primaryGenusName = bank.speciesNames[highestPercentageIndex]; Optional secondaryGenusName = secondHighestPercentageIndex != -1 - ? Optional.of(bank.speciesNames[secondHighestPercentageIndex]) - : Optional.empty(); + ? Optional.of(bank.speciesNames[secondHighestPercentageIndex]) : Optional.empty(); try { int inventoryTypeGroup = findInventoryTypeGroup(primaryGenusName, secondaryGenusName, highestPercentage); @@ -3230,9 +3293,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { highestPercentageIndex, secondHighestPercentageIndex != -1 ? Optional.of(secondHighestPercentageIndex) : Optional.empty(), - inventoryTypeGroup, - basalAreaGroup1, - basalAreaGroup3 + inventoryTypeGroup, basalAreaGroup1, basalAreaGroup3 ) ); } catch (ProcessingException e) { @@ -3268,7 +3329,8 @@ static void combinePercentages(String[] speciesNames, List combinationGr if (speciesNames.length != percentages.length) { throw new IllegalArgumentException( MessageFormat.format( - "the length of speciesNames ({}) must match that of percentages ({}) but it doesn't", speciesNames.length, percentages.length + "the length of speciesNames ({}) must match that of percentages ({}) but it doesn't", + speciesNames.length, percentages.length ) ); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java index 8a11e64f3..a8fe49679 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingState.java @@ -24,16 +24,15 @@ class ForwardProcessingState { /** The active state */ private LayerProcessingState lps; - - public ForwardProcessingState(Map controlMap) - throws ProcessingException { + + public ForwardProcessingState(Map controlMap) throws ProcessingException { this.fcm = new ForwardResolvedControlMapImpl(controlMap); this.estimators = new EstimationMethods(this.fcm); this.computers = new ComputationMethods(estimators, VdypApplicationIdentifier.VDYP_FORWARD); } public void setPolygonLayer(VdypPolygon polygon, LayerType subjectLayer) throws ProcessingException { - + lps = new LayerProcessingState(this, polygon, subjectLayer); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java index 294da2695..37c173399 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessor.java @@ -62,8 +62,10 @@ public class ForwardProcessor { * @throws ResourceParseException * @throws ProcessingException */ - void run(FileResolver inputFileResolver, FileResolver outputFileResolver, List controlFileNames, Set vdypPassSet) - throws IOException, ResourceParseException, ProcessingException { + void run( + FileResolver inputFileResolver, FileResolver outputFileResolver, List controlFileNames, + Set vdypPassSet + ) throws IOException, ResourceParseException, ProcessingException { logger.info("VDYPPASS: {}", vdypPassSet); logger.debug("VDYPPASS(1): Perform Initiation activities?"); @@ -94,11 +96,14 @@ void run(FileResolver inputFileResolver, FileResolver outputFileResolver, List vdypPassSet, Map controlMap, Optional outputFileResolver) throws ProcessingException { + public void process( + Set vdypPassSet, Map controlMap, Optional outputFileResolver + ) throws ProcessingException { logger.info("Beginning processing with given configuration"); @@ -120,7 +125,7 @@ public void process(Set vdypPassSet, Map controlMap if (vdypPassSet.contains(ForwardPass.PASS_3)) { Optional outputWriter = Optional.empty(); - + if (outputFileResolver.isPresent()) { try { outputWriter = Optional.of(new VdypOutputWriter(controlMap, outputFileResolver.get())); @@ -128,7 +133,7 @@ public void process(Set vdypPassSet, Map controlMap throw new ProcessingException(e); } } - + var fpe = new ForwardProcessingEngine(controlMap, outputWriter); var forwardDataStreamReader = new ForwardDataStreamReader(fpe.fps.fcm); @@ -148,14 +153,14 @@ public void process(Set vdypPassSet, Map controlMap if (polygonHolder.isEmpty()) { break; } - + var polygon = polygonHolder.get(); - + fpe.processPolygon(polygon); nPolygonsProcessed += 1; } - + outputWriter.ifPresent(ow -> { try { ow.close(); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java index 4b43c0665..1271cc27c 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java @@ -9,9 +9,9 @@ public class LambdaProcessingException extends RuntimeException { public LambdaProcessingException(ProcessingException e) { super(e); } - + @Override public ProcessingException getCause() { - return (ProcessingException)super.getCause(); + return (ProcessingException) super.getCause(); } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index aeaabbb0f..8db8ac0d5 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -44,18 +44,18 @@ class LayerProcessingState { /** The containing polygon of the layer on which the Processor is operating */ private final VdypPolygon polygon; - + /** The type of Layer being processed */ private final LayerType layerType; // L1COM1, L1COM4 and L1COM5 - these common blocks mirror BANK1, BANK2 and BANK3 and are initialized // when copied to "active" in ForwardProcessingEngine. - - /** + + /** * State of the layer during processing. */ private Bank bank; - + // L1COM2 - equation groups. From the configuration, narrowed to the // polygon's BEC zone. @@ -115,18 +115,20 @@ class LayerProcessingState { // MNSP - MSPL1, MSPLV // TODO - public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, LayerType subjectLayerType) throws ProcessingException { + public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, LayerType subjectLayerType) + throws ProcessingException { this.fps = fps; this.polygon = polygon; this.layerType = subjectLayerType; - + BecDefinition becZone = polygon.getBiogeoclimaticZone(); - + this.bank = new Bank( polygon.getLayers().get(subjectLayerType), becZone, - s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= ForwardProcessingEngine.MIN_BASAL_AREA); - + s -> s.getBaseAreaByUtilization().get(UtilizationClass.ALL) >= ForwardProcessingEngine.MIN_BASAL_AREA + ); + var volumeEquationGroupMatrix = this.fps.fcm.getVolumeEquationGroups(); var decayEquationGroupMatrix = this.fps.fcm.getDecayEquationGroups(); var breakageEquationGroupMatrix = this.fps.fcm.getBreakageEquationGroups(); @@ -151,11 +153,11 @@ public LayerProcessingState(ForwardProcessingState fps, VdypPolygon polygon, Lay this.breakageEquationGroups[i] = breakageEquationGroupMatrix.get(speciesName, becZoneAlias); } } - + public VdypPolygon getPolygon() { return polygon; } - + public LayerType getLayerType() { return layerType; } @@ -178,7 +180,7 @@ public int getPrimarySpeciesIndex() { } return primarySpeciesIndex; } - + public String getPrimarySpeciesAlias() { if (!areRankingDetailsSet) { throw new IllegalStateException("unset primarySpeciesIndex"); @@ -288,7 +290,7 @@ public int getPrimarySpeciesStratumNumber() { public int[] getSiteCurveNumbers() { return siteCurveNumbers; } - + public MatrixMap3[] getCvVolume() { return cvVolume; } @@ -305,7 +307,7 @@ public Map[] getCvPrimaryLayerSmall() { return cvPrimaryLayerSmall; } - /** + /** * @param n index of species for whom the site curve number is to be returned. * @return the site curve number of the given species. */ @@ -383,10 +385,11 @@ public void setSiteCurveNumbers(int[] siteCurveNumbers) { } public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { - - // Normally, these values may only be set only once. However, during grow(), if the + + // Normally, these values may only be set only once. However, during grow(), if the // control variable UPDATE_DURING_GROWTH_6 has value "1" then updates are allowed. - if (this.arePrimarySpeciesDetailsSet && fps.fcm.getForwardControlVariables().getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) != 1) { + if (this.arePrimarySpeciesDetailsSet && fps.fcm.getForwardControlVariables() + .getControlVariable(ControlVariable.UPDATE_DURING_GROWTH_6) != 1) { throw new IllegalStateException(PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY); } @@ -415,21 +418,20 @@ public void setPrimarySpeciesDetails(PrimarySpeciesDetails details) { this.arePrimarySpeciesDetailsSet = true; } - - /** - * Update the cached primary species details after growth. These changes are made to - * the cached values only at this time. Later, if Control Variable 6 is > 0, - * setPrimarySpeciesDetails will be called before the next growth - * period is run and the bank values will be updated, too. - * + + /** + * Update the cached primary species details after growth. These changes are made to the cached values only at this + * time. Later, if Control Variable 6 is > 0, setPrimarySpeciesDetails will be called before the next + * growth period is run and the bank values will be updated, too. + * * @param newPrimarySpeciesDominantHeight */ public void updatePrimarySpeciesDetailsAfterGrowth(float newPrimarySpeciesDominantHeight) { - + this.primarySpeciesDominantHeight = newPrimarySpeciesDominantHeight; this.primarySpeciesTotalAge += 1; this.primarySpeciesAgeAtBreastHeight += 1; - + // primarySpeciesSiteIndex - does this change? // primarySpeciesAgeToBreastHeight of course doesn't change. } @@ -456,22 +458,33 @@ public void setCompatibilityVariableDetails( * CVADJ1 - adjust the values of the compatibility variables after one year of growth. */ public void updateCompatibilityVariablesAfterGrowth() { - + var compVarAdjustments = fps.fcm.getCompVarAdjustments(); - - for (int i: getIndices()) { - for (UtilizationClassVariable sucv: UtilizationClassVariable.values()) { - cvPrimaryLayerSmall[i].put(sucv, cvPrimaryLayerSmall[i].get(sucv) * compVarAdjustments.getValue(UtilizationClass.SMALL, sucv)); + + for (int i : getIndices()) { + for (UtilizationClassVariable sucv : UtilizationClassVariable.values()) { + cvPrimaryLayerSmall[i].put( + sucv, + cvPrimaryLayerSmall[i].get(sucv) * compVarAdjustments.getValue(UtilizationClass.SMALL, sucv) + ); } - for (UtilizationClass uc: UtilizationClass.UTIL_CLASSES) { - cvBasalArea[i].put(uc, LayerType.PRIMARY, cvBasalArea[i].get(uc, LayerType.PRIMARY) - * compVarAdjustments.getValue(uc, UtilizationClassVariable.BASAL_AREA)); - cvQuadraticMeanDiameter[i].put(uc, LayerType.PRIMARY, cvQuadraticMeanDiameter[i].get(uc, LayerType.PRIMARY) - * compVarAdjustments.getValue(uc, UtilizationClassVariable.QUAD_MEAN_DIAMETER)); - - for (VolumeVariable vv: VolumeVariable.ALL) { - cvVolume[i].put(uc, vv, LayerType.PRIMARY, cvVolume[i].get(uc, vv, LayerType.PRIMARY) - * compVarAdjustments.getVolumeValue(uc, vv)); + for (UtilizationClass uc : UtilizationClass.UTIL_CLASSES) { + cvBasalArea[i].put( + uc, LayerType.PRIMARY, + cvBasalArea[i].get(uc, LayerType.PRIMARY) + * compVarAdjustments.getValue(uc, UtilizationClassVariable.BASAL_AREA) + ); + cvQuadraticMeanDiameter[i].put( + uc, LayerType.PRIMARY, + cvQuadraticMeanDiameter[i].get(uc, LayerType.PRIMARY) + * compVarAdjustments.getValue(uc, UtilizationClassVariable.QUAD_MEAN_DIAMETER) + ); + + for (VolumeVariable vv : VolumeVariable.ALL) { + cvVolume[i].put( + uc, vv, LayerType.PRIMARY, + cvVolume[i].get(uc, vv, LayerType.PRIMARY) * compVarAdjustments.getVolumeValue(uc, vv) + ); } } } @@ -511,15 +524,16 @@ public float getCVSmall(int speciesIndex, UtilizationClassVariable variable) { } public VdypLayer getLayer() { - + VdypLayer updatedLayer = bank.getLayer(); - + for (int i = 1; i < getNSpecies() + 1; i++) { VdypSpecies species = updatedLayer.getSpeciesBySp0(bank.speciesNames[i]); species.setCompatibilityVariables( - cvVolume[i], cvBasalArea[i], cvQuadraticMeanDiameter[i], cvPrimaryLayerSmall[i]); + cvVolume[i], cvBasalArea[i], cvQuadraticMeanDiameter[i], cvPrimaryLayerSmall[i] + ); } - + return updatedLayer; } } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java index 60788beb6..736ffd4f7 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/SpeciesRankingDetails.java @@ -3,7 +3,7 @@ import java.util.Optional; public record SpeciesRankingDetails( - int primarySpeciesIndex, Optional secondarySpeciesIndex, int inventoryTypeGroup, - int basalAreaGroup1, int basalAreaGroup3 + int primarySpeciesIndex, Optional secondarySpeciesIndex, int inventoryTypeGroup, int basalAreaGroup1, + int basalAreaGroup3 ) { } \ No newline at end of file diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java index b1782f3be..403c09ecf 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMap.java @@ -17,31 +17,31 @@ import ca.bc.gov.nrs.vdyp.model.Region; public interface ForwardResolvedControlMap extends ResolvedControlMap { - + /** 25 - SITE_CURVE_NUMBERS */ MatrixMap2 getSiteCurveMap(); - + /** 28 - PARAM_ADJUSTMENTS */ CompVarAdjustments getCompVarAdjustments(); - + /** 43 - UPPER_BA_BY_CI_S0_P */ MatrixMap3 getUpperBoundsCoefficients(); - + /** 50 - HL_PRIMARY_SP_EQN_P1 */ MatrixMap2 getLoreyHeightPrimarySpeciesEquationP1Coefficients(); - + /** 53 - HL_NONPRIMARY */ MatrixMap3> getLoreyHeightNonPrimaryCoefficients(); /** 101 - VTROL */ ForwardControlVariables getForwardControlVariables(); - + /** 106 - BA_YIELD */ MatrixMap2 getBasalAreaYieldCoefficients(); - + /** 107 - DQ_YIELD */ MatrixMap2 getQuadMeanDiameterYieldCoefficients(); - + /** 111 - BA_GROWTH_FIAT */ Map getBasalAreaGrowthFiatDetails(); @@ -50,25 +50,25 @@ public interface ForwardResolvedControlMap extends ResolvedControlMap { /** 121 - BA_GROWTH_EMPIRICAL */ MatrixMap2 getBasalAreaGrowthEmpiricalCoefficients(); - + /** 122 - DQ_GROWTH_EMPIRICAL */ Map getQuadMeanDiameterGrowthEmpiricalCoefficients(); - + /** 123 - DQ_GROWTH_EMPIRICAL_LIMITS */ Map getQuadMeanDiameterGrowthEmpiricalLimits(); - + /** 148 - PRIMARY_SP_BA_GROWTH */ Map getPrimarySpeciesBasalAreaGrowthCoefficients(); - + /** 149 - NON_PRIMARY_SP_BA_GROWTH */ MatrixMap2> getNonPrimarySpeciesBasalAreaGrowthCoefficients(); - + /** 150 - PRIMARY_SP_DQ_GROWTH */ Map getPrimarySpeciesQuadMeanDiameterGrowthCoefficients(); - + /** 151 - NON_PRIMARY_SP_DQ_GROWTH */ MatrixMap2> getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients(); - + /** 199 - DEBUG_SWITCHES */ ForwardDebugSettings getDebugSettings(); } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index abe43c41c..ff4c0872a 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -20,7 +20,7 @@ import ca.bc.gov.nrs.vdyp.model.Region; public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl implements ForwardResolvedControlMap { - + final ForwardDebugSettings debugSettings; final ForwardControlVariables forwardControlVariables; final MatrixMap2 siteCurveMap; @@ -43,7 +43,7 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl public ForwardResolvedControlMapImpl(Map controlMap) { super(controlMap); - + this.debugSettings = new ForwardDebugSettings(get(ControlKey.DEBUG_SWITCHES, DebugSettings.class)); this.forwardControlVariables = get(ControlKey.VTROL, ForwardControlVariables.class); this.siteCurveMap = Utils.expectParsedControl(controlMap, ControlKey.SITE_CURVE_NUMBERS, MatrixMap2.class); @@ -56,19 +56,22 @@ public ForwardResolvedControlMapImpl(Map controlMap) { this.quadMeanDiameterGrowthFiatDetails = this.get(ControlKey.DQ_GROWTH_FIAT, Map.class); this.quadMeanDiameterGrowthEmpiricalCoefficients = this.get(ControlKey.DQ_GROWTH_EMPIRICAL, Map.class); this.quadMeanDiameterGrowthEmpiricalLimits = this.get(ControlKey.DQ_GROWTH_EMPIRICAL_LIMITS, Map.class); - this.loreyHeightPrimarySpeciesEquationP1Coefficients = this.get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); + this.loreyHeightPrimarySpeciesEquationP1Coefficients = this + .get(ControlKey.HL_PRIMARY_SP_EQN_P1, MatrixMap2.class); this.loreyHeightNonPrimaryCoefficients = this.get(ControlKey.HL_NONPRIMARY, MatrixMap3.class); this.primarySpeciesBasalAreaGrowthCoefficients = this.get(ControlKey.PRIMARY_SP_BA_GROWTH, Map.class); - this.nonPrimarySpeciesBasalAreaGrowthCoefficients = this.get(ControlKey.NON_PRIMARY_SP_BA_GROWTH, MatrixMap2.class); + this.nonPrimarySpeciesBasalAreaGrowthCoefficients = this + .get(ControlKey.NON_PRIMARY_SP_BA_GROWTH, MatrixMap2.class); this.primaryQuadMeanDiameterGrowthCoefficients = this.get(ControlKey.PRIMARY_SP_DQ_GROWTH, Map.class); - this.nonPrimaryQuadMeanDiameterGrowthCoefficients = this.get(ControlKey.NON_PRIMARY_SP_DQ_GROWTH, MatrixMap2.class); + this.nonPrimaryQuadMeanDiameterGrowthCoefficients = this + .get(ControlKey.NON_PRIMARY_SP_DQ_GROWTH, MatrixMap2.class); } - + @Override public ForwardDebugSettings getDebugSettings() { return debugSettings; } - + @Override public ForwardControlVariables getForwardControlVariables() { return forwardControlVariables; @@ -83,12 +86,12 @@ public MatrixMap2 getSiteCurveMap() { public CompVarAdjustments getCompVarAdjustments() { return compVarAdjustments; } - + @Override public MatrixMap2 getBasalAreaYieldCoefficients() { return basalAreaYieldCoefficients; } - + @Override public MatrixMap2 getQuadMeanDiameterYieldCoefficients() { return quadMeanDiameterYieldCoefficients; @@ -108,7 +111,7 @@ public MatrixMap2 getBasalAreaGrowthEmpiricalCoeff public MatrixMap3 getUpperBoundsCoefficients() { return upperBoundCoefficients; } - + @Override public Map getQuadMeanDiameterGrowthFiatDetails() { return quadMeanDiameterGrowthFiatDetails; @@ -118,7 +121,7 @@ public Map getQuadMeanDiameterGrowthFiatDetails() { public Map getQuadMeanDiameterGrowthEmpiricalCoefficients() { return quadMeanDiameterGrowthEmpiricalCoefficients; } - + @Override public Map getQuadMeanDiameterGrowthEmpiricalLimits() { return quadMeanDiameterGrowthEmpiricalLimits; @@ -128,9 +131,10 @@ public Map getQuadMeanDiameterGrowthEmpiricalLimits() { public MatrixMap2 getLoreyHeightPrimarySpeciesEquationP1Coefficients() { return loreyHeightPrimarySpeciesEquationP1Coefficients; } - + @Override - public MatrixMap3> getLoreyHeightNonPrimaryCoefficients() { + public MatrixMap3> + getLoreyHeightNonPrimaryCoefficients() { return loreyHeightNonPrimaryCoefficients; } @@ -150,7 +154,8 @@ public Map getPrimarySpeciesQuadMeanDiameterGrowthCo } @Override - public MatrixMap2> getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() { + public MatrixMap2> + getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients() { return nonPrimaryQuadMeanDiameterGrowthCoefficients; } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java index a44bd3427..c16ae4d36 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ControlVariable.java @@ -1,15 +1,11 @@ package ca.bc.gov.nrs.vdyp.forward.model; public enum ControlVariable { - GROW_TARGET_1(1), - COMPAT_VAR_OUTPUT_2(2), - COMPAT_VAR_APPLICATION_3(3), - OUTPUT_FILES_4(4), - ALLOW_COMPAT_VAR_CALCS_5(5), - UPDATE_DURING_GROWTH_6(6); - + GROW_TARGET_1(1), COMPAT_VAR_OUTPUT_2(2), COMPAT_VAR_APPLICATION_3(3), OUTPUT_FILES_4(4), + ALLOW_COMPAT_VAR_CALCS_5(5), UPDATE_DURING_GROWTH_6(6); + public final int variableNumber; - + ControlVariable(int variableNumber) { this.variableNumber = variableNumber; } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java index 91ea8c25c..32d5fe31e 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardControlVariables.java @@ -64,14 +64,14 @@ public ForwardControlVariables(Integer[] controlVariableValues) throws ValuePars for (; index < MAX_CONTROL_VARIABLE_VALUES; index++) this.controlVariables[index] = DEFAULT_CONTROL_VARIABLE_VALUE; - + validate(); } - + private void validate() throws ValueParseException { // Validate the control variable values. - + var yearCounter = getControlVariable(ControlVariable.GROW_TARGET_1); if (yearCounter != -1 && (yearCounter < 0 || yearCounter > 400 && yearCounter < 1920 || yearCounter > 2400)) { throw new ValueParseException( @@ -84,15 +84,19 @@ private void validate() throws ValueParseException { if (compatibilityVariableOutputVariableValue < 0 || compatibilityVariableOutputVariableValue > 2) { throw new ValueParseException( Integer.toString(compatibilityVariableOutputVariableValue), - "VdypControlVariableParser: compatibility variable output value \"" + compatibilityVariableOutputVariableValue + "\" is out of range [0-2]" + "VdypControlVariableParser: compatibility variable output value \"" + + compatibilityVariableOutputVariableValue + "\" is out of range [0-2]" ); } - var compatibilityVariableApplicationVariableValue = getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3); + var compatibilityVariableApplicationVariableValue = getControlVariable( + ControlVariable.COMPAT_VAR_APPLICATION_3 + ); if (compatibilityVariableApplicationVariableValue < 0 || compatibilityVariableApplicationVariableValue > 2) { throw new ValueParseException( Integer.toString(compatibilityVariableApplicationVariableValue), - "VdypControlVariableParser: compatibility variable application value \"" + compatibilityVariableApplicationVariableValue + "\" is out of range [0-2]" + "VdypControlVariableParser: compatibility variable application value \"" + + compatibilityVariableApplicationVariableValue + "\" is out of range [0-2]" ); } @@ -100,15 +104,20 @@ private void validate() throws ValueParseException { if (outputFileDirectiveVariableValue < 0 || outputFileDirectiveVariableValue > 4) { throw new ValueParseException( Integer.toString(outputFileDirectiveVariableValue), - "VdypControlVariableParser: output file directive value \"" + outputFileDirectiveVariableValue + "\" is out of range [0-4]" + "VdypControlVariableParser: output file directive value \"" + outputFileDirectiveVariableValue + + "\" is out of range [0-4]" ); } - var allowCompatibilityVariableCalculationsVariableValue = getControlVariable(ControlVariable.ALLOW_COMPAT_VAR_CALCS_5); - if (allowCompatibilityVariableCalculationsVariableValue < 0 || allowCompatibilityVariableCalculationsVariableValue > 1) { + var allowCompatibilityVariableCalculationsVariableValue = getControlVariable( + ControlVariable.ALLOW_COMPAT_VAR_CALCS_5 + ); + if (allowCompatibilityVariableCalculationsVariableValue < 0 + || allowCompatibilityVariableCalculationsVariableValue > 1) { throw new ValueParseException( Integer.toString(allowCompatibilityVariableCalculationsVariableValue), - "VdypControlVariableParser: compatibility variable calculations allowed value \"" + allowCompatibilityVariableCalculationsVariableValue + "\" is out of range [0-1]" + "VdypControlVariableParser: compatibility variable calculations allowed value \"" + + allowCompatibilityVariableCalculationsVariableValue + "\" is out of range [0-1]" ); } @@ -116,7 +125,8 @@ private void validate() throws ValueParseException { if (updateDuringGrowthVariableValue < 0 || updateDuringGrowthVariableValue > 1) { throw new ValueParseException( Integer.toString(updateDuringGrowthVariableValue), - "VdypControlVariableParser: update site species and ITG during grow value \"" + updateDuringGrowthVariableValue + "\" is out of range [0-1]" + "VdypControlVariableParser: update site species and ITG during grow value \"" + + updateDuringGrowthVariableValue + "\" is out of range [0-1]" ); } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java index b42baf000..f15bbe75a 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/model/ForwardDebugSettings.java @@ -5,96 +5,94 @@ import ca.bc.gov.nrs.vdyp.model.DebugSettings; /** -(1) Species Dynamics -

      -
    • Value 0: Full species dynamics. Not recommended. -
    • Value 1: No species dynamics. Species percents in TPH and BA are constant. -
    • Value 2: Limited dynamics. Percents by BA are constant, but TPH %’s vary. -
    -(2) Maximum Breast Height Age -
      -
    • Value 0: No upper age for application of BA and DQ yield equations. -
    • Value n: Maximum BH age for application of BA and DQ yields is 100 * n (years). -
    -(3) Basal Area Growth Model -
      -
    • Value 0: BA growth comes from fiat model (approach to yield eqn’s). -
    • Value 1: BA growth from empirical model (older ages suspect). -
    • Value 2: Mixed fiat & empirical model. (See SEQ111 and IPSJF162). -
    -(4) Maximum Breast Height Per Species and Region -
      -
    • Value 0: Will default to (2). Controls upper bounds in some models. -
    • Value 1: Limits from SEQ108 on control file, categorized by GRPBA1. -
    • Value 2: Limits from SEQ043 on control file, Coast Interior & Leading species. -
    -(5) Messaging Level. See note (1), below -(6) Quadratic Mean Diameter growth model -
      -
    • Value 0: DQ growth comes from fiat model (approach to yield eqn’s). -
    • Value 1: DQ growth from empirical model (older ages suspect). -
    • Value 2: Mixed fiat & empirical model. (See SEQ117 and IPSJF178). -
    -(8) Lorey Height change strategy -
      -
    • Value 0: Normal changes in Lorey height (HL), all species. -
    • Value 1: Force change to zero for nonprimary species if change in HD is zero. -
    • Value 2: Force change to zero for all species if change in HD is zero. - (option 2 precludes changes in primary sp HL due solely to change in TPH). -
    -(9) Can limit BA if DQ has been limited (see Note 2, below.) -

    -(11-21) HD/Age/SI fill-in controls (see Note 3, and IPSJF174.doc). -

    -Note 1: for all programs the 5th debug switch should be zero except for program debugging. This will -prevent “SZERO” messages in the output and error messages produced by the MATH77 routines. Allowable -values: -

      -
    • Value 0: activates the MATH77 process to suppress messages AND furthermore totally deactivates the -messaging capability. -
    • Value 1: implements the MATH77 deactivation mechanism, but there will still be a few error messages. -
    • Value 2: allows for normal error messaging. -
    -The usual underlying cause of the messages is that in reconciling results for the different species, the -program has been forced to violate a DQ/HL limit for a species. -

    -Note 2: There has been a programming change to VDYP7 GROW, such that the behavior of the BA increment -may be altered subsequent to a projection having hit or exceeded a DQ limit. The configuration file -for VDYP7 GROW is affected, in that on sequence 199, Ndebug(9) is now defined. -

      -
    • Value 0: causes the program to operate as it always has to date (2009.03.24) -
    • Value 1: causes the indicated condition to be checked for, and may cause some predicted BA increments -to be smaller, or to be set to zero. -
    -An explanation of the change, and the reason for it, are given in a document JFmemo_20090311.doc. Detailed -notes for code developers and those with detailed knowledge of VDYP7 are in JFmemo_20090318.doc. -

    -Note 3: Valid values from Ndebug(11) through Ndebug(20): -

      -
    • 0: No action -
    • 1: Move SI from non-primary to primary using sitetools si conversions. Checks start with second high-BA - species, then ordered by ISP. If no conversions found, first attempted conversion redone 1:1. -
    • 2: Move SI from primary to non-primary using sitetools si conversions. -
    • 3: Complete (TOTAGE, BHAGE, YTBH) if 2 out of 3 present, all sp. -
    • 4: Move total age from non-primary to primary species (From second-most common species if present, else - 1st encountered). -
    • 5: Estimate dominant height of primary species from Lorey height. -
    • 6: Estimate dominant height of non-primary species from Lorey heights. -
    • 7: Estimate SI of primary species from HD and total age. (*) -
    • 8: Estimate SI of primary species from HD and BHAGE. (*) -
    • 9: Estimate SI of non-primary species from HD and total age. (*) -
    • 10: Estimate SI of non-primary species from HD and BHAGE. (*) -
    • 11: Estimate ages (total and BH and YTBH) of primary species from SI, HD -
    • 12: Estimate ages (total and BH and YTBH) of non-primary species from SI, HD. -
    • 13: Estimate YTBH of primary species from SI. -
    • 14: Estimate YTBH of non-primary species from SI. -
    • 15: Same as option 1, condition on total age (primary) < 30. -
    -*/ + * (1) Species Dynamics + *
      + *
    • Value 0: Full species dynamics. Not recommended. + *
    • Value 1: No species dynamics. Species percents in TPH and BA are constant. + *
    • Value 2: Limited dynamics. Percents by BA are constant, but TPH %’s vary. + *
    + * (2) Maximum Breast Height Age + *
      + *
    • Value 0: No upper age for application of BA and DQ yield equations. + *
    • Value n: Maximum BH age for application of BA and DQ yields is 100 * n (years). + *
    + * (3) Basal Area Growth Model + *
      + *
    • Value 0: BA growth comes from fiat model (approach to yield eqn’s). + *
    • Value 1: BA growth from empirical model (older ages suspect). + *
    • Value 2: Mixed fiat & empirical model. (See SEQ111 and IPSJF162). + *
    + * (4) Maximum Breast Height Per Species and Region + *
      + *
    • Value 0: Will default to (2). Controls upper bounds in some models. + *
    • Value 1: Limits from SEQ108 on control file, categorized by GRPBA1. + *
    • Value 2: Limits from SEQ043 on control file, Coast Interior & Leading species. + *
    + * (5) Messaging Level. See note (1), below (6) Quadratic Mean Diameter growth model + *
      + *
    • Value 0: DQ growth comes from fiat model (approach to yield eqn’s). + *
    • Value 1: DQ growth from empirical model (older ages suspect). + *
    • Value 2: Mixed fiat & empirical model. (See SEQ117 and IPSJF178). + *
    + * (8) Lorey Height change strategy + *
      + *
    • Value 0: Normal changes in Lorey height (HL), all species. + *
    • Value 1: Force change to zero for nonprimary species if change in HD is zero. + *
    • Value 2: Force change to zero for all species if change in HD is zero. (option 2 precludes changes in primary sp + * HL due solely to change in TPH). + *
    + * (9) Can limit BA if DQ has been limited (see Note 2, below.) + *

    + * (11-21) HD/Age/SI fill-in controls (see Note 3, and IPSJF174.doc). + *

    + * Note 1: for all programs the 5th debug switch should be zero except for program debugging. This will prevent + * “SZERO” messages in the output and error messages produced by the MATH77 routines. Allowable values: + *

      + *
    • Value 0: activates the MATH77 process to suppress messages AND furthermore totally deactivates the messaging + * capability. + *
    • Value 1: implements the MATH77 deactivation mechanism, but there will still be a few error messages. + *
    • Value 2: allows for normal error messaging. + *
    + * The usual underlying cause of the messages is that in reconciling results for the different species, the program has + * been forced to violate a DQ/HL limit for a species. + *

    + * Note 2: There has been a programming change to VDYP7 GROW, such that the behavior of the BA increment may be + * altered subsequent to a projection having hit or exceeded a DQ limit. The configuration file for VDYP7 GROW is + * affected, in that on sequence 199, Ndebug(9) is now defined. + *

      + *
    • Value 0: causes the program to operate as it always has to date (2009.03.24) + *
    • Value 1: causes the indicated condition to be checked for, and may cause some predicted BA increments to be + * smaller, or to be set to zero. + *
    + * An explanation of the change, and the reason for it, are given in a document JFmemo_20090311.doc. Detailed notes for + * code developers and those with detailed knowledge of VDYP7 are in JFmemo_20090318.doc. + *

    + * Note 3: Valid values from Ndebug(11) through Ndebug(20): + *

      + *
    • 0: No action + *
    • 1: Move SI from non-primary to primary using sitetools si conversions. Checks start with second high-BA species, + * then ordered by ISP. If no conversions found, first attempted conversion redone 1:1. + *
    • 2: Move SI from primary to non-primary using sitetools si conversions. + *
    • 3: Complete (TOTAGE, BHAGE, YTBH) if 2 out of 3 present, all sp. + *
    • 4: Move total age from non-primary to primary species (From second-most common species if present, else 1st + * encountered). + *
    • 5: Estimate dominant height of primary species from Lorey height. + *
    • 6: Estimate dominant height of non-primary species from Lorey heights. + *
    • 7: Estimate SI of primary species from HD and total age. (*) + *
    • 8: Estimate SI of primary species from HD and BHAGE. (*) + *
    • 9: Estimate SI of non-primary species from HD and total age. (*) + *
    • 10: Estimate SI of non-primary species from HD and BHAGE. (*) + *
    • 11: Estimate ages (total and BH and YTBH) of primary species from SI, HD + *
    • 12: Estimate ages (total and BH and YTBH) of non-primary species from SI, HD. + *
    • 13: Estimate YTBH of primary species from SI. + *
    • 14: Estimate YTBH of non-primary species from SI. + *
    • 15: Same as option 1, condition on total age (primary) < 30. + *
    + */ public class ForwardDebugSettings { public static final int MAX_FILL_INDEX_SETTINGS_INDEX = DebugSettings.MAX_DEBUG_SETTINGS; - + public enum Vars { /** *
  • Value 0: Full species dynamics. Not recommended. @@ -110,13 +108,13 @@ public enum Vars { /** *
  • Value 0: BA growth comes from fiat model (approach to yield eqn’s). *
  • Value 1: BA growth from empirical model (older ages suspect). - *
  • Value 2: Mixed fiat & empirical model. (See SEQ111 and IPSJF162). + *
  • Value 2: Mixed fiat & empirical model. (See SEQ111 and IPSJF162). */ BASAL_AREA_GROWTH_MODEL_3(3), /** *
  • Value 0: Will default to (2). Controls upper bounds in some models. *
  • Value 1: Limits from SEQ108 on control file, categorized by GRPBA1. - *
  • Value 2: Limits from SEQ043 on control file, Coast Interior & Leading species. + *
  • Value 2: Limits from SEQ043 on control file, Coast Interior & Leading species. */ PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4(4), /** Messaging Level */ @@ -124,14 +122,14 @@ public enum Vars { /** *
  • Value 0: DQ growth comes from fiat model (approach to yield eqn’s). *
  • Value 1: DQ growth from empirical model (older ages suspect). - *
  • Value 2: Mixed fiat & empirical model. (See SEQ117 and IPSJF178). + *
  • Value 2: Mixed fiat & empirical model. (See SEQ117 and IPSJF178). */ DQ_GROWTH_MODEL_6(6), /** *
  • Value 0: Normal changes in Lorey height (HL), all species. *
  • Value 1: Force change to zero for nonprimary species if change in HD is zero. - *
  • Value 2: Force change to zero for all species if change in HD is zero. - * (option 2 precludes changes in primary sp HL due solely to change in TPH). + *
  • Value 2: Force change to zero for all species if change in HD is zero. (option 2 precludes changes in + * primary sp HL due solely to change in TPH). */ LOREY_HEIGHT_CHANGE_STRATEGY_8(8), /** Limit BA if DQ has been limited */ @@ -153,16 +151,16 @@ public ForwardDebugSettings(DebugSettings debugSettings) { public int getValue(Vars v) { return debugSettings.getValue(v.settingNumber); } - + /** - * For testing purposes sometimes it's useful to change the value of a debug setting. - * It is not expected that this method would be used for any other purpose. - * - * @param v the variable to change + * For testing purposes sometimes it's useful to change the value of a debug setting. It is not expected that this + * method would be used for any other purpose. + * + * @param v the variable to change * @param value the new value the variable is to have */ public void setValue(Vars v, int value) { - + int[] currentSettings = debugSettings.getValues(); Integer[] updatedSettings = new Integer[currentSettings.length]; for (int i = 0; i < currentSettings.length; i++) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java index 4392d2089..b949f320a 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypPolygonParser.java @@ -103,14 +103,14 @@ protected VdypPolygon convert(Map entry) throws ResourceParseExc } final float percentAvailable = percentForestLand; - + return VdypPolygon.build(builder -> { - builder.polygonIdentifier(descriptionText); - builder.biogeoclimaticZone(bec); - builder.forestInventoryZone(fizId.toString()); - fipMode.ifPresentOrElse(m -> builder.mode(PolygonMode.getByCode(m)), () -> Optional.empty()); - builder.percentAvailable(percentAvailable); - builder.inventoryTypeGroup(inventoryTypeGroup); + builder.polygonIdentifier(descriptionText); + builder.biogeoclimaticZone(bec); + builder.forestInventoryZone(fizId.toString()); + fipMode.ifPresentOrElse(m -> builder.mode(PolygonMode.getByCode(m)), () -> Optional.empty()); + builder.percentAvailable(percentAvailable); + builder.inventoryTypeGroup(inventoryTypeGroup); }); } }; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java index 644fd0e24..357dca714 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypSpeciesParser.java @@ -125,7 +125,7 @@ protected ValueOrMarker, EndOfRecord> convert(MapoptSafe(entry.get(IS_PRIMARY_SPECIES)); var siteCurveNumber = Utils.optSafe(entry.get(SITE_CURVE_NUMBER)) .orElse(VdypEntity.MISSING_INTEGER_VALUE); - + var builder = new ValueOrMarker.Builder, EndOfRecord>(); return layerType.handle(l -> builder.value(l.map(lt -> { @@ -157,7 +157,7 @@ protected ValueOrMarker, EndOfRecord> convert(Map 0.0 && yearsToBreastHeight > 0.0) @@ -175,7 +175,7 @@ protected ValueOrMarker, EndOfRecord> convert(Map { siteBuilder.ageTotal(inferredTotalAge); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java index 8ec76395e..f1a45de0e 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/parsers/VdypUtilizationParser.java @@ -80,8 +80,8 @@ public ControlKey getControlKey() { ) { @SuppressWarnings("unchecked") @Override - protected ValueOrMarker, EndOfRecord> - convert(Map entry) throws ResourceParseException { + protected ValueOrMarker, EndOfRecord> convert(Map entry) + throws ResourceParseException { var polygonId = PolygonIdentifier.split((String) entry.get(DESCRIPTION)); var layerType = (ValueOrMarker, EndOfRecord>) entry.get(LAYER_TYPE); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java index 4c7cea74c..ccae75c66 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/AbstractForwardProcessingEngineTest.java @@ -78,8 +78,8 @@ protected void buildUtilizationParserForStream(String fileName, String... stream protected void buildUtilizationParserForStandardStream(String fileName) throws ResourceParseException, IOException { buildUtilizationParserForStream( - fileName, - // polygon year P? I N UC BasalArea TPH Lorey H WhSt Vol CUtl Vol CU-Decay CU-DWst CU-DWBrk QMDBH + fileName, + // polygon year P? I N UC BasalArea TPH Lorey H WhSt Vol CUtl Vol CU-Decay CU-DWst CU-DWBrk QMDBH "01002 S000001 00 1970 P 0 -1 0.01513 5.24 7.0166 0.0630 0.0000 0.0000 0.0000 0.0000 6.1", // "01002 S000001 00 1970 P 0 0 44.93259 595.32 30.9724 620.9775 592.2023 580.1681 577.6229 549.0159 31.0", // "01002 S000001 00 1970 P 0 1 0.53100 64.82 -9.0000 2.5979 0.3834 0.3794 0.3788 0.3623 10.2", // diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java index 71e1a8a88..f8b00d750 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java @@ -181,51 +181,59 @@ void testLayerUpdate() throws IOException, ResourceParseException, ProcessingExc Bank bank = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); VdypLayer currentLayer = bank.getLayer(); - + verifyBankMatchesLayer(bank, currentLayer); - + UtilizationVector uv = currentLayer.getBaseAreaByUtilization(); float newValue = uv.get(UtilizationClass.ALL) + 1.0f; uv.set(UtilizationClass.ALL, newValue); currentLayer.setBaseAreaByUtilization(uv); bank.refreshBank(currentLayer); - + verifyBankMatchesLayer(bank, currentLayer); } private void verifyBankMatchesLayer(Bank lps, VdypLayer layer) { - List sortedSpIndices = layer.getSpecies().values().stream().map(s -> s.getGenusIndex()).sorted().toList(); + List sortedSpIndices = layer.getSpecies().values().stream().map(s -> s.getGenusIndex()).sorted() + .toList(); int arrayIndex = 1; for (int i = 0; i < sortedSpIndices.size(); i++) { VdypSpecies genus = layer.getSpeciesByIndex(sortedSpIndices.get(i)); - + verifyBankSpeciesMatchesSpecies(lps, arrayIndex, genus); - verifyBankUtilizationsMatchesUtilizations( - lps, arrayIndex, genus - ); - + verifyBankUtilizationsMatchesUtilizations(lps, arrayIndex, genus); + arrayIndex += 1; } verifyBankUtilizationsMatchesUtilizations(lps, 0, layer); } - private void verifyBankUtilizationsMatchesUtilizations( - Bank lps, int spIndex, VdypUtilizationHolder u - ) { + private void verifyBankUtilizationsMatchesUtilizations(Bank lps, int spIndex, VdypUtilizationHolder u) { for (UtilizationClass uc : UtilizationClass.values()) { assertThat(lps.basalAreas[spIndex][uc.index + 1], is(u.getBaseAreaByUtilization().get(uc))); - assertThat(lps.closeUtilizationVolumes[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeByUtilization().get(uc))); - assertThat(lps.cuVolumesMinusDecay[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc))); - assertThat(lps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc))); + assertThat( + lps.closeUtilizationVolumes[spIndex][uc.index + 1], + is(u.getCloseUtilizationVolumeByUtilization().get(uc)) + ); + assertThat( + lps.cuVolumesMinusDecay[spIndex][uc.index + 1], + is(u.getCloseUtilizationVolumeNetOfDecayByUtilization().get(uc)) + ); + assertThat( + lps.cuVolumesMinusDecayAndWastage[spIndex][uc.index + 1], + is(u.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization().get(uc)) + ); if (uc.index <= 0) { assertThat(lps.loreyHeights[spIndex][uc.index + 1], is(u.getLoreyHeightByUtilization().get(uc))); } - assertThat(lps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc))); + assertThat( + lps.quadMeanDiameters[spIndex][uc.index + 1], is(u.getQuadraticMeanDiameterByUtilization().get(uc)) + ); assertThat(lps.treesPerHectare[spIndex][uc.index + 1], is(u.getTreesPerHectareByUtilization().get(uc))); assertThat(lps.wholeStemVolumes[spIndex][uc.index + 1], is(u.getWholeStemVolumeByUtilization().get(uc))); } @@ -235,7 +243,7 @@ private void verifyBankSpeciesMatchesSpecies(Bank bank, int index, VdypSpecies s assertThat(bank.sp64Distributions[index], is(species.getSp64DistributionSet())); assertThat(bank.speciesIndices[index], is(species.getGenusIndex())); assertThat(bank.speciesNames[index], is(species.getGenus())); - + species.getSite().ifPresentOrElse(site -> { assertThat(bank.yearsAtBreastHeight[index], is(site.getYearsAtBreastHeight().get())); assertThat(bank.ageTotals[index], is(site.getAgeTotal().get())); @@ -248,8 +256,7 @@ private void verifyBankSpeciesMatchesSpecies(Bank bank, int index, VdypSpecies s assertThat(bank.siteCurveNumbers[index], is(VdypEntity.MISSING_INTEGER_VALUE)); }); assertThat(bank.speciesNames[index], is(site.getSiteGenus())); - }, - () -> { + }, () -> { assertThat(bank.yearsAtBreastHeight[index], is(VdypEntity.MISSING_FLOAT_VALUE)); assertThat(bank.ageTotals[index], is(VdypEntity.MISSING_FLOAT_VALUE)); assertThat(bank.dominantHeights[index], is(VdypEntity.MISSING_FLOAT_VALUE)); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateBasalAreaDeltaTest.java similarity index 90% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateBasalAreaDeltaTest.java index 551bd70be..ab9e65ca7 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBasalAreaTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateBasalAreaDeltaTest.java @@ -23,9 +23,9 @@ import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; -class GrowBasalAreaTest { +class CalculateBasalAreaDeltaTest { - protected static final Logger logger = LoggerFactory.getLogger(GrowBasalAreaTest.class); + protected static final Logger logger = LoggerFactory.getLogger(CalculateBasalAreaDeltaTest.class); protected static ForwardControlParser parser; protected static Map controlMap; @@ -50,63 +50,63 @@ void beforeTest() throws IOException, ResourceParseException, ProcessingExceptio @Test void testStandardPath() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + float yabh = 54.0f; float hd = 35.2999992f; float ba = 45.3864441f; float growthInHd = 0.173380271f; - - float gba = fpe.growBasalArea(yabh, hd, ba, Optional.empty(), growthInHd); - + + float gba = fpe.calculateBasalAreaDelta(yabh, hd, ba, Optional.empty(), growthInHd); + assertThat(gba, is(0.35185286f)); } @Test void testYoungPath() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + float yabh = 30.0f; float hd = 10.0f; float ba = 200.0f; float growthInHd = 0.173380271f; - - float gba = fpe.growBasalArea(yabh, hd, ba, Optional.empty(), growthInHd); - + + float gba = fpe.calculateBasalAreaDelta(yabh, hd, ba, Optional.empty(), growthInHd); + assertThat(gba, is(0.0f)); } @Test void testDebugSettings3EqualsZeroPath() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + float yabh = 54.0f; float hd = 35.2999992f; float ba = 45.3864441f; float hdDelta = 0.173380271f; - + fpe.fps.fcm.getDebugSettings().setValue(Vars.BASAL_AREA_GROWTH_MODEL_3, 0); - - float gba = fpe.growBasalArea(yabh, hd, ba, Optional.empty(), hdDelta); - + + float gba = fpe.calculateBasalAreaDelta(yabh, hd, ba, Optional.empty(), hdDelta); + assertThat(gba, is(-0.10392746f)); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateDominantHeightDeltaTest.java similarity index 89% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateDominantHeightDeltaTest.java index 4595f0b17..239f6c542 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowDominantHeightTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateDominantHeightDeltaTest.java @@ -35,9 +35,9 @@ import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; -class GrowDominantHeightTest { +class CalculateDominantHeightDeltaTest { - protected static final Logger logger = LoggerFactory.getLogger(GrowDominantHeightTest.class); + protected static final Logger logger = LoggerFactory.getLogger(CalculateDominantHeightDeltaTest.class); protected static ForwardControlParser parser; protected static Map controlMap; @@ -62,9 +62,9 @@ void beforeTest() throws IOException, ResourceParseException, ProcessingExceptio @Test void testNormalCurve() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) fpe.fps.setPolygonLayer(forwardDataStreamReader.readNextPolygon().orElseThrow(), LayerType.PRIMARY); @@ -72,55 +72,55 @@ void testNormalCurve() throws ProcessingException { int sc = 13; float si = 35; float ytbh = 1.0f; - - float gdh = fpe.growDominantHeight(hd, sc, si, ytbh); - + + float gdh = fpe.calculateDominantHeightDelta(hd, sc, si, ytbh); + assertThat(gdh, is(0.173380271f)); } @Test void testCurveExtension1() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); // Select polygon 01003AS000001 00(1953) - triggers curve extension code VdypPolygon polygon; do { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - } while (! polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); - + } while (!polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); + fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); float hd = 29.5f; int sc = 11; float si = 14.8000002f; float ytbh = 10.8000002f; - - float gdh = fpe.growDominantHeight(hd, sc, si, ytbh); - + + float gdh = fpe.calculateDominantHeightDelta(hd, sc, si, ytbh); + assertThat(gdh, is(0.0f)); } @Test void testCurveExtension2() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); // Select polygon 01003AS000001 00(1953) - triggers curve extension code VdypPolygon polygon; do { polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - } while (! polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); - + } while (!polygon.getPolygonIdentifier().getName().equals("01003AS000001 00")); + fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); - + float hd = 26.5f; int sc = 11; float si = 14.8000002f; float ytbh = 5.8000002f; - - float gdh = fpe.growDominantHeight(hd, sc, si, ytbh); - + + float gdh = fpe.calculateDominantHeightDelta(hd, sc, si, ytbh); + assertThat(gdh, is(0.045883115f)); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateQuadMeanDiameterDeltaTest.java similarity index 89% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateQuadMeanDiameterDeltaTest.java index 1cff43563..2d7b6aea9 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowQuadMeanDiameterTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateQuadMeanDiameterDeltaTest.java @@ -26,9 +26,9 @@ import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; -class GrowQuadMeanDiameterTest { +class CalculateQuadMeanDiameterDeltaTest { - protected static final Logger logger = LoggerFactory.getLogger(GrowQuadMeanDiameterTest.class); + protected static final Logger logger = LoggerFactory.getLogger(CalculateQuadMeanDiameterDeltaTest.class); protected static ForwardControlParser parser; protected static Map controlMap; @@ -53,17 +53,17 @@ void beforeTest() throws IOException, ResourceParseException, ProcessingExceptio @Test void testMixedModel() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 2); - + float yabh = 54.0f; float hd = 35.2999992f; float ba = 45.3864441f; @@ -72,9 +72,11 @@ void testMixedModel() throws ProcessingException { Optional v_ba_start = Optional.empty(); Optional v_ba_end = Optional.empty(); Reference dqGrowthLimitApplied = new Reference<>(); - - float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); - + + float gba = fpe.calculateQuadMeanDiameterDelta( + yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied + ); + assertThat(gba, is(0.30947846f)); assertTrue(dqGrowthLimitApplied.isPresent()); assertThat(dqGrowthLimitApplied.get(), is(false)); @@ -82,17 +84,17 @@ void testMixedModel() throws ProcessingException { @Test void testFiatOnlyModel() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 0); /* this value will force the fiat only calculations. */ - + float yabh = 54.0f; float hd = 35.2999992f; float ba = 45.3864441f; @@ -101,9 +103,11 @@ void testFiatOnlyModel() throws ProcessingException { Optional v_ba_start = Optional.empty(); Optional v_ba_end = Optional.empty(); Reference dqGrowthLimitApplied = new Reference<>(); - - float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); - + + float gba = fpe.calculateQuadMeanDiameterDelta( + yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied + ); + assertThat(gba, is(0.3194551f)); assertTrue(dqGrowthLimitApplied.isPresent()); assertThat(dqGrowthLimitApplied.get(), is(false)); @@ -111,17 +115,17 @@ void testFiatOnlyModel() throws ProcessingException { @Test void testEmpiricalOnlyModel() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 1); /* this value will force the empirical only calculations. */ - + float yabh = 54.0f; float hd = 35.2999992f; float ba = 45.3864441f; @@ -130,9 +134,11 @@ void testEmpiricalOnlyModel() throws ProcessingException { Optional v_ba_start = Optional.empty(); Optional v_ba_end = Optional.empty(); Reference dqGrowthLimitApplied = new Reference<>(); - - float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); - + + float gba = fpe.calculateQuadMeanDiameterDelta( + yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied + ); + assertThat(gba, is(0.30947846f)); assertTrue(dqGrowthLimitApplied.isPresent()); assertThat(dqGrowthLimitApplied.get(), is(false)); @@ -140,17 +146,17 @@ void testEmpiricalOnlyModel() throws ProcessingException { @Test void testMixedModelWithInterpolation() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 2); - + float yabh = 104.0f; /* this value will force interpolation. */ float hd = 35.2999992f; float ba = 45.3864441f; @@ -159,9 +165,11 @@ void testMixedModelWithInterpolation() throws ProcessingException { Optional v_ba_start = Optional.empty(); Optional v_ba_end = Optional.empty(); Reference dqGrowthLimitApplied = new Reference<>(); - - float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); - + + float gba = fpe.calculateQuadMeanDiameterDelta( + yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied + ); + assertThat(gba, is(0.28309992f)); assertTrue(dqGrowthLimitApplied.isPresent()); assertThat(dqGrowthLimitApplied.get(), is(false)); @@ -169,17 +177,17 @@ void testMixedModelWithInterpolation() throws ProcessingException { @Test void testMinimumApplied() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 0); - + float yabh = 54.0f; float hd = 35.3f; float ba = 45.3864441f; @@ -188,9 +196,11 @@ void testMinimumApplied() throws ProcessingException { Optional v_ba_start = Optional.empty(); Optional v_ba_end = Optional.empty(); Reference dqGrowthLimitApplied = new Reference<>(); - - float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); - + + float gba = fpe.calculateQuadMeanDiameterDelta( + yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied + ); + assertThat(gba, is(4.6f)); assertTrue(dqGrowthLimitApplied.isPresent()); assertThat(dqGrowthLimitApplied.get(), is(false)); @@ -198,17 +208,17 @@ void testMinimumApplied() throws ProcessingException { @Test void testLimitApplied() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); - + ForwardDebugSettings debugSettings = fpe.fps.fcm.getDebugSettings(); debugSettings.setValue(Vars.DQ_GROWTH_MODEL_6, 0); - + float yabh = 54.0f; float hd = 35.3f; float ba = 45.3864441f; @@ -217,9 +227,11 @@ void testLimitApplied() throws ProcessingException { Optional v_ba_start = Optional.empty(); Optional v_ba_end = Optional.empty(); Reference dqGrowthLimitApplied = new Reference<>(); - - float gba = fpe.growQuadMeanDiameter(yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied); - + + float gba = fpe.calculateQuadMeanDiameterDelta( + yabh, ba, hd, dq, v_ba_start, v_ba_end, growthInHd, dqGrowthLimitApplied + ); + assertThat(gba, is(0.0f)); assertTrue(dqGrowthLimitApplied.isPresent()); assertThat(dqGrowthLimitApplied.get(), is(true)); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java index 280ab199f..33f5df4a4 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlParserTest.java @@ -285,16 +285,12 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 void testParseE061() throws Exception { var parser = new ForwardControlParser(); var result = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - assertThat( - result, - (Matcher) controlMapHasEntry(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, Matchers.anything()) - ); - - MatrixMap2 coastalSpeciesComponentSizeMap = Utils.expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); + assertThat(result, (Matcher) controlMapHasEntry(ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, Matchers.anything())); + + MatrixMap2 coastalSpeciesComponentSizeMap = Utils + .expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); var acCoastalSpeciesComponentSizeLimits = coastalSpeciesComponentSizeMap.get("AC", Region.COASTAL); - assertThat( - acCoastalSpeciesComponentSizeLimits, - Matchers.instanceOf(ComponentSizeLimits.class)); + assertThat(acCoastalSpeciesComponentSizeLimits, Matchers.instanceOf(ComponentSizeLimits.class)); assertThat(acCoastalSpeciesComponentSizeLimits.loreyHeightMaximum(), is(49.4f)); assertThat(acCoastalSpeciesComponentSizeLimits.maxQuadMeanDiameterLoreyHeightRatio(), is(3.647f)); assertThat(acCoastalSpeciesComponentSizeLimits.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java index 1d5879769..70fad6681 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardControlVariablesTest.java @@ -15,7 +15,7 @@ class ForwardControlVariablesTest { @Test void testNull() throws ValueParseException { ForwardControlVariables fcv = new ForwardControlVariables(null); - + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.GROW_TARGET_1), Matchers.equalTo(0)); MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2), Matchers.equalTo(0)); MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3), Matchers.equalTo(0)); @@ -27,7 +27,7 @@ void testNull() throws ValueParseException { @Test void testEmpty() throws ValueParseException { ForwardControlVariables fcv = new ForwardControlVariables(new Integer[0]); - + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.GROW_TARGET_1), Matchers.equalTo(0)); MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2), Matchers.equalTo(0)); MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3), Matchers.equalTo(0)); @@ -39,7 +39,7 @@ void testEmpty() throws ValueParseException { @Test void testSimple() throws ValueParseException { ForwardControlVariables fcv = new ForwardControlVariables(new Integer[] { 1, 1, 1, 1, 1, 1 }); - + MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.GROW_TARGET_1), Matchers.equalTo(1)); MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_OUTPUT_2), Matchers.equalTo(1)); MatcherAssert.assertThat(fcv.getControlVariable(ControlVariable.COMPAT_VAR_APPLICATION_3), Matchers.equalTo(1)); @@ -55,11 +55,17 @@ void testYearValues() throws ValueParseException { new ForwardControlVariables(new Integer[] { 0, 0, 0, 0, 0, 0 }); new ForwardControlVariables(new Integer[] { 1, 0, 0, 0, 0, 0 }); new ForwardControlVariables(new Integer[] { 400, 0, 0, 0, 0, 0 }); - assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 401, 0, 0, 0, 0, 0 })); - assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 1919, 0, 0, 0, 0, 0 })); + assertThrows( + ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 401, 0, 0, 0, 0, 0 }) + ); + assertThrows( + ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 1919, 0, 0, 0, 0, 0 }) + ); new ForwardControlVariables(new Integer[] { 1920, 0, 0, 0, 0, 0 }); new ForwardControlVariables(new Integer[] { 2400, 0, 0, 0, 0, 0 }); - assertThrows(ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 2401, 0, 0, 0, 0, 0 })); + assertThrows( + ValueParseException.class, () -> new ForwardControlVariables(new Integer[] { 2401, 0, 0, 0, 0, 0 }) + ); } @Test diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java index 964df58aa..f2b609f3e 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardDebugSettingsTest.java @@ -14,16 +14,17 @@ class ForwardDebugSettingsTest { void testNoSpecialActions() { DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }); ForwardDebugSettings fs = new ForwardDebugSettings(ds); - + MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.SPECIES_DYNAMICS_1), is(1)); MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MAX_BREAST_HEIGHT_AGE_2), is(2)); MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.BASAL_AREA_GROWTH_MODEL_3), is(3)); - MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); + MatcherAssert + .assertThat(fs.getValue(ForwardDebugSettings.Vars.PER_SPECIES_AND_REGION_MAX_BREAST_HEIGHT_4), is(4)); MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.MESSAGING_LEVEL_5), is(5)); MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DQ_GROWTH_MODEL_6), is(6)); MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8), is(8)); MatcherAssert.assertThat(fs.getValue(ForwardDebugSettings.Vars.DO_LIMIT_BA_WHEN_DQ_LIMITED_9), is(9)); - + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[0])); } @@ -31,23 +32,31 @@ void testNoSpecialActions() { void testOneSpecialAction() { DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 0 }); ForwardDebugSettings fs = new ForwardDebugSettings(ds); - + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 12 })); } @Test void testAllSpecialActions() { - DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }); + DebugSettings ds = new DebugSettings( + new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 111, 112, 113, 114 } + ); ForwardDebugSettings fs = new ForwardDebugSettings(ds); - - MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 })); + + MatcherAssert.assertThat( + fs.getFillInValues(), + is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114 }) + ); } - + @Test void testAllSomeActions() { - DebugSettings ds = new DebugSettings(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107 }); + DebugSettings ds = new DebugSettings( + new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 101, 102, 103, 104, 105, 106, 107 } + ); ForwardDebugSettings fs = new ForwardDebugSettings(ds); - + MatcherAssert.assertThat(fs.getFillInValues(), is(new Integer[] { 100, 101, 102, 103, 104, 105, 106, 107 })); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java index d16299021..3a783be97 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardGrowStepTests.java @@ -30,7 +30,7 @@ void testOnePolygon() throws IOException, ResourceParseException, ProcessingExce int nPolygonsProcessed = 0; var polygon = forwardDataStreamReader.readNextPolygon(); - + if (polygon.isPresent()) { fpe.processPolygon(polygon.get(), ExecutionStep.GROW); nPolygonsProcessed += 1; diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index a5ac3ca35..fb85de101 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -42,24 +42,24 @@ void test() throws IOException, ResourceParseException, ProcessingException { FileResolver inputFileResolver = TestUtils.fileResolver(TestUtils.class); var outputResolver = new ZipOutputFileResolver(); - + fp.run(inputFileResolver, outputResolver, List.of("VDYP.CTR"), vdypPassSet); - + Path resourceDirectory = Paths.get("src", "test", "resources", "output"); Files.createDirectories(resourceDirectory); - + Path zipFile = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); Files.deleteIfExists(zipFile); - + outputResolver.generate(zipFile); - + InputStream os = outputResolver.generateStream(); - byte[] zipFileBytes = Files.readAllBytes(zipFile); + byte[] zipFileBytes = Files.readAllBytes(zipFile); byte[] zipStreamBytes = os.readAllBytes(); - + assertTrue(zipFileBytes.length == zipStreamBytes.length); assertTrue(Arrays.equals(zipFileBytes, zipStreamBytes)); - + } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java index 173c7abe4..278d3e31c 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardReadPolygonTest.java @@ -64,23 +64,25 @@ void testReadPolygons() throws Exception { assertThat(polygon.getPolygonIdentifier().toStringCompact(), is("01002 S000001 00(1970)")); - for (VdypLayer layer: polygon.getLayers().values()) - { + for (VdypLayer layer : polygon.getLayers().values()) { assertThat(layer.getPolygonIdentifier().getName(), is(polygon.getPolygonIdentifier().getName())); assertThat(layer.getPolygonIdentifier().getYear(), is(polygon.getPolygonIdentifier().getYear())); assertThat(UtilizationClass.values().length, is(layer.getBaseAreaByUtilization().size())); var speciesMap = layer.getSpecies(); - for (VdypSpecies species: speciesMap.values()) { + for (VdypSpecies species : speciesMap.values()) { assertThat(species, hasProperty("layerType", is(layer.getLayerType()))); assertThat(species, hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier()))); - + species.getSite().ifPresent(site -> { - assertThat(site, allOf( - hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier())), - hasProperty("layerType", is(layer.getLayerType())) - )); + assertThat( + site, + allOf( + hasProperty("polygonIdentifier", is(polygon.getPolygonIdentifier())), + hasProperty("layerType", is(layer.getLayerType())) + ) + ); }); } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index 15e4a3886..f82d29558 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -50,7 +50,7 @@ void test() throws IOException, ResourceParseException, ProcessingException { int nPolygonsProcessed = 0; while (true) { var polygon = forwardDataStreamReader.readNextPolygon(); - + if (polygon.isPresent()) { fpe.processPolygon(polygon.get()); nPolygonsProcessed += 1; @@ -87,7 +87,8 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces fpe.fps.setPolygonLayer(polygon, LayerType.PRIMARY); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); - var speciesToCombine = Arrays.asList(Arrays.asList(lps.getBank().speciesNames[3], lps.getBank().speciesNames[4])); + var speciesToCombine = Arrays + .asList(Arrays.asList(lps.getBank().speciesNames[3], lps.getBank().speciesNames[4])); ForwardProcessingEngine.calculateCoverages(lps); fpe.determinePolygonRankings(speciesToCombine); @@ -105,19 +106,19 @@ void testFindPrimarySpecies() throws IOException, ResourceParseException, Proces @Test void testGroupAndStratumNumberSpecialCases() throws IOException, ResourceParseException, ProcessingException { - // We want the - // "equationModifierGroup.isPresent()" - // and the - // " Region.INTERIOR.equals(lps.wallet.getBecZone().getRegion()) - // && exceptedSpeciesIndicies.contains(primarySpeciesIndex)" + // We want the + // "equationModifierGroup.isPresent()" + // and the + // " Region.INTERIOR.equals(lps.wallet.getBecZone().getRegion()) + // && exceptedSpeciesIndicies.contains(primarySpeciesIndex)" // cases in determinePolygonRankings. - + buildPolygonParserForStream( "testPolygon.dat", // "01002 S000001 00 1970 IDF A 99 37 1 1", // "" ); - + buildSpeciesParserForStream( "testSpecies.dat", // "01002 S000001 00 1970 P 4 C C 100.0 0.0 0.0 0.0 -9.00 -9.00 -9.0 253.9 11.1 0 -9", // @@ -137,7 +138,7 @@ void testGroupAndStratumNumberSpecialCases() throws IOException, ResourceParseEx assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesGroupNumber(), is(35)); assertThat(fpe.fps.getLayerProcessingState().getPrimarySpeciesStratumNumber(), is(24)); } - + @Test void testCombinePercentages() { @@ -377,9 +378,9 @@ void testEstimateMissingSiteIndicesStep1() throws ProcessingException, IOExcepti fpe.processPolygon(polygon, ForwardProcessingEngine.ExecutionStep.ESTIMATE_MISSING_SITE_INDICES); // Despite 13.40 being in the data stream, the change (2024/8/29) to ignore site information - // for all species of the layer except the primary means that method (1) will never be + // for all species of the layer except the primary means that method (1) will never be // successful, since none of the non-primary species will have a site index value. - + // var sourceSiteCurve = SiteIndexEquation.SI_CWC_KURUCZ; // var sourceSiteIndex = 13.4; // var targetSiteCurve = SiteIndexEquation.SI_HWC_WILEYAC; @@ -481,9 +482,12 @@ void testCalculateDominantHeightAgeSiteIndex() throws ProcessingException, IOExc // Since the change to ignore site information for all but non-primary species, there is // no way to successfully estimate age for a primary species from the non-primary species. ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - assertThrows(ProcessingException.class, () -> fpe.processPolygon(polygon, - ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX) - ); + assertThrows( + ProcessingException.class, + () -> fpe.processPolygon( + polygon, ForwardProcessingEngine.ExecutionStep.CALCULATE_DOMINANT_HEIGHT_AGE_SITE_INDEX + ) + ); } @Test diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java new file mode 100644 index 000000000..9ea2caf19 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java @@ -0,0 +1,186 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; + +import java.io.IOException; +import java.util.Map; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings.Vars; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; + +class GrowBaDqTphTest { + + protected static final Logger logger = LoggerFactory.getLogger(GrowBaDqTphTest.class); + + protected static ForwardControlParser parser; + protected static Map controlMap; + + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; + + protected static ForwardDataStreamReader forwardDataStreamReader; + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeTest() throws IOException, ResourceParseException, ProcessingException { + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + .get(ControlKey.FORWARD_INPUT_GROWTO.name()); + polygonDescriptionStream = polygonDescriptionStreamFactory.get(); + + forwardDataStreamReader = new ForwardDataStreamReader(controlMap); + } + + @Test + void testStandardPath() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); + + float baStart = 45.3864441f; + float baDelta = 0.351852179f; + float dqStart = 30.9988747f; + float dqDelta = 0.309478492f; + float tphStart = 601.373718f; + float[] lhAtStart = new float[] { 30.9723663f, 36.7552986f, 22.9584007f, 33.7439995f, 22.7703991f, + 32.0125008f }; + + fpe.growUsingPartialSpeciesDynamics(baStart, baDelta, dqStart, dqDelta, tphStart, lhAtStart); + + // Results are stored in bank.basalAreas[1..nSpecies] + + assertThat( + slice(lps.getBank().basalAreas, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(45.7382965f, 0.410145015f, 5.13646269f, 29.8279209f, 5.91424417f, 4.44952154f) + Matchers.arrayContaining(45.38645f, 0.41014494f, 5.1364512f, 29.827925f, 5.914243f, 4.449531f) + ); + assertThat( + slice(lps.getBank().treesPerHectare, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(594.113831f, 5.14728308f, 84.0494843f, 286.714783f, 167.523376f, 50.6789017f) + Matchers.arrayContaining(601.3333f, 5.150639f, 83.26706f, 287.04187f, 167.69823f, 50.955967f) + ); + assertThat( + slice(lps.getBank().quadMeanDiameters, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(31.3083534f, 31.8518562f, 27.8945656f, 36.3949814f, 21.201519f, 33.4347534f) + Matchers.arrayContaining(30.999918f, 31.841476f, 28.025286f, 36.374245f, 21.190462f, 33.34377f) + ); + } + + private Float[] slice(float[][] perSpeciesUcData, UtilizationClass uc) { + Float[] result = new Float[perSpeciesUcData.length]; + for (int i = 0; i < perSpeciesUcData.length; i++) { + result[i] = perSpeciesUcData[i][uc.ordinal()]; + } + return result; + } + + @Test + void testGrowUsingNoSpeciesDynamics() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); + + float baChangeRate = 0.00775236264f; + float tphChangeRate = 0.987927794f; + + fpe.fps.fcm.getDebugSettings().setValue(Vars.SPECIES_DYNAMICS_1, 1); + + fpe.growUsingNoSpeciesDynamics(baChangeRate, tphChangeRate); + + // Results are stored in bank.basalAreas[1..nSpecies] + + assertThat( + slice(lps.getBank().basalAreas, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(45.7382965f, 0.410145015f, 5.13646269f, 29.8279209f, 5.91424417f, 4.44952154f) + Matchers.arrayContaining(45.38645f, 0.410145f, 5.1364527f, 29.827932f, 5.914244f, 4.449532f) + ); + assertThat( + slice(lps.getBank().treesPerHectare, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(594.113831f, 5.15917826f, 83.2853012f, 287.107758f, 167.558533f, 51.0030174f) + Matchers.arrayContaining(601.3333f, 5.149199f, 83.2853f, 287.09778f, 167.54855f, 50.99304f) + ); + assertThat( + slice(lps.getBank().quadMeanDiameters, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(31.3083534f, 31.8151169f, 28.0222473f, 36.3700676f, 21.199295f, 33.3283463f) + Matchers.arrayContaining(30.999918f, 31.84593f, 28.022219f, 36.370705f, 21.199926f, 33.33165f) + ); + } + + @Test + void testGrowUsingFullSpeciesDynamics() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); + + float baStart = 45.3864441f; + float baDelta = 0.351852179f; + float dqStart = 30.9988747f; + float dqDelta = 0.309478492f; + float tphStart = 601.373718f; + float lhStart = 30.9723663f; + + + fpe.fps.fcm.getDebugSettings().setValue(Vars.SPECIES_DYNAMICS_1, 0); + + fpe.growUsingFullSpeciesDynamics(baStart, baDelta, dqStart, dqDelta, tphStart, lhStart); + + // Results are stored in bank.basalAreas[1..nSpecies] + + assertThat( + slice(lps.getBank().basalAreas, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(45.7382965f, 0.40808472f, 5.28018427f, 29.444725f, 6.11862803f, 4.48667192f) + Matchers.arrayContaining(45.38645f, 0.40808356f, 5.280174f, 29.444735f, 6.1186314f, 4.486681f) + ); + assertThat( + slice(lps.getBank().treesPerHectare, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(594.113831f, 5.07865763f, 82.9379883f, 288.292511f, 167.419479f, 50.3814774f) + Matchers.arrayContaining(601.3333f, 5.151279f, 84.45613f, 292.43683f, 171.47192f, 51.14954f) + ); + assertThat( + slice(lps.getBank().quadMeanDiameters, UtilizationClass.ALL), + // Results from VDYP7: + // Matchers.arrayContaining(31.3083534f, 31.985693f, 28.4710083f, 36.0613632f, 21.5714378f, 33.6729965f) + Matchers.arrayContaining(30.999918f, 31.759386f, 28.21393f, 35.80493f, 21.315018f, 33.41926f) + ); + } +} diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java index 6f13f5766..090b6e747 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java @@ -50,23 +50,23 @@ void beforeTest() throws IOException, ResourceParseException, ProcessingExceptio @Test void testStandardPath() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); - + float dhStart = 35.3f; float dhEnd = 35.473381f; float pspTphStart = 290.61615f; float pspTphEnd = 287.107788f; float pspLhStart = 33.7439995f; - + fpe.growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); - + // Results are stored in bank.loreyHeights[1..nSpecies] assertThat(lps.getIndices().length, is(5)); assertThat(lps.getBank().loreyHeights[1][UtilizationClass.ALL.ordinal()], is(36.9653244f)); @@ -78,25 +78,25 @@ void testStandardPath() throws ProcessingException { @Test void testDebug8Setting2Path() throws ProcessingException { - + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); - + // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); - + float dhStart = 35.3f; float dhEnd = 35.3f; float pspTphStart = 290.61615f; float pspTphEnd = 287.107788f; float pspLhStart = 33.7439995f; - + fpe.fps.fcm.getDebugSettings().setValue(ForwardDebugSettings.Vars.LOREY_HEIGHT_CHANGE_STRATEGY_8, 2); - + fpe.growLoreyHeights(lps, dhStart, dhEnd, pspTphStart, pspTphEnd, pspLhStart); - + // Results are stored in bank.loreyHeights[1..nSpecies] assertThat(lps.getIndices().length, is(5)); assertThat(lps.getBank().loreyHeights[1][UtilizationClass.ALL.ordinal()], is(36.7552986f)); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java index af71d3302..2cbcfce2c 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java @@ -53,12 +53,10 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, ); assertThat( - fpe.fps.getLayerProcessingState().getCVVolume(1, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), - is(0.0f) + fpe.fps.getLayerProcessingState().getCVVolume(1, U75TO125, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0f) ); assertThat( - fpe.fps.getLayerProcessingState().getCVVolume(1, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), - is(0.0f) + fpe.fps.getLayerProcessingState().getCVVolume(1, U125TO175, CLOSE_UTIL_VOL, LayerType.PRIMARY), is(0.0f) ); assertThat( fpe.fps.getLayerProcessingState().getCVVolume(1, U175TO225, CLOSE_UTIL_VOL, LayerType.PRIMARY), @@ -153,8 +151,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, is(-0.004629612f) ); assertThat( - fpe.fps.getLayerProcessingState() - .getCVVolume(1, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(1, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(1.3446808E-4f) ); @@ -174,8 +171,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, is(2.2292137E-4f) ); assertThat( - fpe.fps.getLayerProcessingState() - .getCVVolume(2, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(2, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-1.9311905E-5f) ); @@ -195,8 +191,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, is(7.638931E-4f) ); assertThat( - fpe.fps.getLayerProcessingState() - .getCVVolume(3, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(3, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-2.4795532E-5f) ); @@ -216,8 +211,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, is(-9.3603134E-4f) ); assertThat( - fpe.fps.getLayerProcessingState() - .getCVVolume(4, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(4, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-5.4836273E-5f) ); @@ -237,8 +231,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, is(-0.0014338493f) ); assertThat( - fpe.fps.getLayerProcessingState() - .getCVVolume(5, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), + fpe.fps.getLayerProcessingState().getCVVolume(5, OVER225, CLOSE_UTIL_VOL_LESS_DECAY, LayerType.PRIMARY), is(-2.9087067E-5f) ); @@ -348,8 +341,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, ); assertThat( - fpe.fps.getLayerProcessingState().getCVVolume(1, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), - is(0.0f) + fpe.fps.getLayerProcessingState().getCVVolume(1, U75TO125, WHOLE_STEM_VOL, LayerType.PRIMARY), is(0.0f) ); assertThat( fpe.fps.getLayerProcessingState().getCVVolume(1, U125TO175, WHOLE_STEM_VOL, LayerType.PRIMARY), @@ -432,9 +424,7 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, is(-1.2636185E-5f) ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(1, OVER225, LayerType.PRIMARY), is(-2.065301E-5f) - ); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(1, OVER225, LayerType.PRIMARY), is(-2.065301E-5f)); assertThat( fpe.fps.getLayerProcessingState().getCVBasalArea(1, U125TO175, LayerType.PRIMARY), is(1.0924414E-5f) ); @@ -445,22 +435,12 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, fpe.fps.getLayerProcessingState().getCVBasalArea(1, U75TO125, LayerType.PRIMARY), is(-3.9674342E-7f) ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(2, OVER225, LayerType.PRIMARY), is(-1.1444092E-5f) - ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(2, U125TO175, LayerType.PRIMARY), is(5.00679E-6f) - ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(2, U175TO225, LayerType.PRIMARY), is(9.596348E-6f) - ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(2, U75TO125, LayerType.PRIMARY), is(6.660819E-6f) - ); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(2, OVER225, LayerType.PRIMARY), is(-1.1444092E-5f)); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(2, U125TO175, LayerType.PRIMARY), is(5.00679E-6f)); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(2, U175TO225, LayerType.PRIMARY), is(9.596348E-6f)); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(2, U75TO125, LayerType.PRIMARY), is(6.660819E-6f)); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(3, OVER225, LayerType.PRIMARY), is(7.6293945E-6f) - ); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(3, OVER225, LayerType.PRIMARY), is(7.6293945E-6f)); assertThat( fpe.fps.getLayerProcessingState().getCVBasalArea(3, U125TO175, LayerType.PRIMARY), is(-3.7066638E-6f) ); @@ -478,22 +458,14 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, assertThat( fpe.fps.getLayerProcessingState().getCVBasalArea(4, U175TO225, LayerType.PRIMARY), is(-9.059906E-6f) ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(4, U75TO125, LayerType.PRIMARY), is(-8.106232E-6f) - ); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(4, U75TO125, LayerType.PRIMARY), is(-8.106232E-6f)); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(5, OVER225, LayerType.PRIMARY), is(-4.673004E-5f) - ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(5, U125TO175, LayerType.PRIMARY), is(8.821487E-6f) - ); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(5, OVER225, LayerType.PRIMARY), is(-4.673004E-5f)); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(5, U125TO175, LayerType.PRIMARY), is(8.821487E-6f)); assertThat( fpe.fps.getLayerProcessingState().getCVBasalArea(5, U175TO225, LayerType.PRIMARY), is(2.8401613E-5f) ); - assertThat( - fpe.fps.getLayerProcessingState().getCVBasalArea(5, U75TO125, LayerType.PRIMARY), is(-4.954636E-7f) - ); + assertThat(fpe.fps.getLayerProcessingState().getCVBasalArea(5, U75TO125, LayerType.PRIMARY), is(-4.954636E-7f)); assertThat( fpe.fps.getLayerProcessingState().getCVQuadraticMeanDiameter(1, OVER225, LayerType.PRIMARY), diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java index 6ade4871c..4a8a3c67f 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java @@ -58,7 +58,8 @@ protected List> inputFileParsers() { @Override protected List outputFileParsers() { return List.of( - ControlKey.VRI_OUTPUT_VDYP_POLYGON, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL + ControlKey.VRI_OUTPUT_VDYP_POLYGON, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES, + ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL ); } } diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java index 3aa3c9f29..b14d32888 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParser.java @@ -47,9 +47,10 @@ public ControlKey getControlKey() { .strippedString(25, VriPolygonParser.POLYGON_IDENTIFIER) // .space(1) // .value( - 1, LAYER, ValueParser.valueOrMarker( - ValueParser.LAYER, ValueParser - .optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) + 1, LAYER, + ValueParser.valueOrMarker( + ValueParser.LAYER, + ValueParser.optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) ) ) // .value(6, CROWN_CLOSURE, ValueParser.FLOAT) // diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java index 8cce4901d..818191336 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParser.java @@ -52,9 +52,10 @@ public ControlKey getControlKey() { .strippedString(25, VriPolygonParser.POLYGON_IDENTIFIER) // .space(1) // .value( - 1, VriLayerParser.LAYER, ValueParser.valueOrMarker( - ValueParser.LAYER, ValueParser - .optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) + 1, VriLayerParser.LAYER, + ValueParser.valueOrMarker( + ValueParser.LAYER, + ValueParser.optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) ) ) // .value(4, AGE_TOTAL, ValueParser.SAFE_POSITIVE_FLOAT) // @@ -111,12 +112,10 @@ protected ValueOrMarker, EndOfRecord> convert(Map=3. per VDYP7 Fortran, per memo JFmemo_20090329.doc - height.or( - () -> s.map(l -> l == LayerType.PRIMARY).orElse(false) && // - ageTotal.map(at -> FloatMath.abs(at - 1f) < 0.6).orElse(false) && // - siteIndex.map(si -> si >= 3f).orElse(false) // - ? Optional.of(0.05f) - : Optional.empty() + height.or(() -> s.map(l -> l == LayerType.PRIMARY).orElse(false) && // + ageTotal.map(at -> FloatMath.abs(at - 1f) < 0.6).orElse(false) && // + siteIndex.map(si -> si >= 3f).orElse(false) // + ? Optional.of(0.05f) : Optional.empty() ) ); siteBuilder.ageTotal(ageTotal); @@ -127,9 +126,8 @@ protected ValueOrMarker, EndOfRecord> convert(Map x != 0f || Utils.mapBoth( - ageTotal, yearsToBreastHeight, ( - at, ytbh - ) -> FloatMath.abs(at - ytbh) < 0.5 + ageTotal, yearsToBreastHeight, + (at, ytbh) -> FloatMath.abs(at - ytbh) < 0.5 ).orElse(false) ) ); diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java index f5f8657e0..f8d4e2e6e 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParser.java @@ -66,9 +66,10 @@ public boolean isIgnoredSegment(List entry) { .strippedString(25, VriPolygonParser.POLYGON_IDENTIFIER) // .space(1) // .value( - 1, VriLayerParser.LAYER, ValueParser.valueOrMarker( - ValueParser.LAYER, ValueParser - .optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) + 1, VriLayerParser.LAYER, + ValueParser.valueOrMarker( + ValueParser.LAYER, + ValueParser.optionalSingleton("Z"::equals, EndOfRecord.END_OF_RECORD) ) ) // .space(1) // diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index f68f0edc2..bf1515d90 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -200,14 +200,14 @@ VriPolygon getPolygon( // Validate that species belong to the correct polygon if (!specWithSite.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { throw validationError( - "Record in species file contains species for polygon %s when expecting one for %s.", specWithSite - .getPolygonIdentifier(), polygon.getPolygonIdentifier() + "Record in species file contains species for polygon %s when expecting one for %s.", + specWithSite.getPolygonIdentifier(), polygon.getPolygonIdentifier() ); } if (Objects.isNull(layerBuilder)) { throw validationError( - "Species entry references layer %s of polygon %s but it is not present.", specWithSite - .getLayerType(), polygon.getPolygonIdentifier() + "Species entry references layer %s of polygon %s but it is not present.", + specWithSite.getLayerType(), polygon.getPolygonIdentifier() ); } layerBuilder.addSpecies(specWithSite); @@ -216,8 +216,8 @@ VriPolygon getPolygon( var specNames = sites.stream().map(site -> site.getSiteGenus()).collect(Collectors.joining(", ")); var layerType = sites.iterator().next().getLayerType(); throw validationError( - "Site entries reference species %s of layer %s of polygon %s but they are not present.", specNames, layerType, polygon - .getPolygonIdentifier() + "Site entries reference species %s of layer %s of polygon %s but they are not present.", specNames, + layerType, polygon.getPolygonIdentifier() ); } @@ -227,8 +227,8 @@ VriPolygon getPolygon( for (var layer : layers.values()) { if (!layer.getPolygonIdentifier().equals(polygon.getPolygonIdentifier())) { throw validationError( - "Record in layer file contains layer for polygon %s when expecting one for %s.", layer - .getPolygonIdentifier(), polygon.getPolygonIdentifier() + "Record in layer file contains layer for polygon %s when expecting one for %s.", + layer.getPolygonIdentifier(), polygon.getPolygonIdentifier() ); } layer.setSpecies(new HashMap<>()); @@ -300,8 +300,8 @@ private void modifyVeteranLayerBuild( float crownClosure = builder.getCrownClosure().filter(x -> x > 0f).orElseThrow( () -> new RuntimeStandProcessingException( validationError( - "Expected a positive crown closure for veteran layer but was %s", Utils - .optNa(builder.getCrownClosure()) + "Expected a positive crown closure for veteran layer but was %s", + Utils.optNa(builder.getCrownClosure()) ) ) ); @@ -408,7 +408,8 @@ Optional processPolygon(int polygonsRead, VriPolygon polygon) throw estimateSmallComponents(polygon, resultPrimaryLayer); computeUtilizationComponentsPrimary( - bec, resultPrimaryLayer, VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC, CompatibilityVariableMode.NONE + bec, resultPrimaryLayer, VolumeComputeMode.BY_UTIL_WITH_WHOLE_STEM_BY_SPEC, + CompatibilityVariableMode.NONE ); if (resultVeteranLayer != null) { @@ -563,7 +564,8 @@ void getDqBySpecies(VdypLayer layer, Region region) throws ProcessingException { } findRootForQuadMeanDiameterFractionalError( - -0.6f, 0.5f, resultsPerSpecies, initialDqEstimate, baseAreaPerSpecies, minPerSpecies, maxPerSpecies, treeDensityTotal + -0.6f, 0.5f, resultsPerSpecies, initialDqEstimate, baseAreaPerSpecies, minPerSpecies, maxPerSpecies, + treeDensityTotal ); applyDqBySpecies(layer, baseAreaTotal, baseAreaPerSpecies, resultsPerSpecies); @@ -597,15 +599,19 @@ void getDqBySpeciesInitial( for (var spec : layer.getSpecies().values()) { // EMP060 float specDq = estimationMethods.estimateQuadMeanDiameterForSpecies( - spec, layer - .getSpecies(), region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, loreyHeightTotal + spec, layer.getSpecies(), region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, + loreyHeightTotal ); var limits = getLimitsForSpecies(spec, region); - float min = Math.max(7.6f, limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll()); + float min = Math.max( + 7.6f, limits.minQuadMeanDiameterLoreyHeightRatio() * spec.getLoreyHeightByUtilization().getAll() + ); float loreyHeightToUse = Math.max(spec.getLoreyHeightByUtilization().getAll(), 7.0f); - float max = Math.min(limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightToUse); + float max = Math.min( + limits.quadMeanDiameterMaximum(), limits.maxQuadMeanDiameterLoreyHeightRatio() * loreyHeightToUse + ); max = Math.max(7.75f, max); minPerSpecies.put(spec.getGenus(), min); @@ -654,7 +660,7 @@ private float processVeteranLayer(VriPolygon polygon, VdypLayer.Builder lBuilder lBuilder.layerType(LayerType.VETERAN); lBuilder.adapt(veteranLayer); - + var bec = polygon.getBiogeoclimaticZone(); var primarySite = veteranLayer.getPrimarySite(); @@ -863,8 +869,9 @@ protected PolygonMode checkPolygonForMode(VriPolygon polygon, BecDefinition bec) PolygonMode mode = polygon.getMode().orElseGet(() -> { try { return findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, primaryLayer - .getSpecies().values(), bec, primaryLayer.getEmpericalRelationshipParameterIndex() + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, + primaryLayer.getSpecies().values(), bec, + primaryLayer.getEmpericalRelationshipParameterIndex() ); } catch (StandProcessingException e) { throw new RuntimeStandProcessingException(e); @@ -872,8 +879,8 @@ protected PolygonMode checkPolygonForMode(VriPolygon polygon, BecDefinition bec) }); polygon.setMode(Optional.of(mode)); Optional primaryBreastHeightAge = Utils.mapBoth( - primaryLayer.getPrimarySite().flatMap(VriSite::getAgeTotal), primaryLayer.getPrimarySite() - .flatMap(VriSite::getYearsToBreastHeight), (at, ytbh) -> at - ytbh + primaryLayer.getPrimarySite().flatMap(VriSite::getAgeTotal), + primaryLayer.getPrimarySite().flatMap(VriSite::getYearsToBreastHeight), (at, ytbh) -> at - ytbh ); log.atDebug().setMessage("Polygon mode {} checks").addArgument(mode).log(); switch (mode) { @@ -923,8 +930,8 @@ void validateMinimum(String fieldName, float value, float minimum, boolean inclu throws StandProcessingException { if (value < minimum || (value == minimum && !inclusive)) throw validationError( - "%s %s should be %s %s", fieldName, value, inclusive ? "greater than or equal to" - : "greater than", minimum + "%s %s should be %s %s", fieldName, value, inclusive ? "greater than or equal to" : "greater than", + minimum ); } @@ -1218,7 +1225,8 @@ VriPolygon processYoung(VriPolygon poly) throws ProcessingException { float primaryHeight = primarySite.getHeight().orElseThrow(); // HT_L1 final Increase inc = findIncreaseForYoungMode( - bec, primaryLayer, siteCurve, primaryBreastHeightAge0, siteIndex, yeastToBreastHeight, baseAreaTarget, heightTarget, ageTarget, dominantHeight0, moreYears, primaryHeight + bec, primaryLayer, siteCurve, primaryBreastHeightAge0, siteIndex, yeastToBreastHeight, + baseAreaTarget, heightTarget, ageTarget, dominantHeight0, moreYears, primaryHeight ); return VriPolygon.build(pBuilder -> { @@ -1289,8 +1297,9 @@ private Increase findIncreaseForYoungMode( // check empirical BA assuming BAV = 0 float predictedBaseArea = estimateBaseAreaYield( - dominantHeight, primaryBreastHeightAge, Optional.empty(), false, primaryLayer.getSpecies() - .values(), bec, primaryLayer.getEmpericalRelationshipParameterIndex().orElseThrow() + dominantHeight, primaryBreastHeightAge, Optional.empty(), false, + primaryLayer.getSpecies().values(), bec, + primaryLayer.getEmpericalRelationshipParameterIndex().orElseThrow() ); // BAP // Calculate the full occupancy BA Hence the BA we will test is the Full @@ -1399,14 +1408,14 @@ VriPolygon processBatn(VriPolygon poly) throws ProcessingException { ); float primaryBaseAreaEstimated = estimateBaseAreaYield( - primaryHeight, primaryBreastHeightAge, veteranBaseArea, false, primaryLayer.getSpecies() - .values(), bec, primaryEmpericalRelationshipParameterIndex + primaryHeight, primaryBreastHeightAge, veteranBaseArea, false, primaryLayer.getSpecies().values(), bec, + primaryEmpericalRelationshipParameterIndex ); // EMP107 float normativeQuadMeanDiameter = estimateQuadMeanDiameterYield( - primaryHeight, primaryBreastHeightAge, veteranBaseArea, primaryLayer.getSpecies() - .values(), bec, primaryEmpericalRelationshipParameterIndex + primaryHeight, primaryBreastHeightAge, veteranBaseArea, primaryLayer.getSpecies().values(), bec, + primaryEmpericalRelationshipParameterIndex ); final float normativePercentAvailable = 85f; diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java index e9e7a8f32..b32256cbe 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java @@ -86,11 +86,10 @@ public Optional getEmpericalRelationshipParameterIndex() { return empericalRelationshipParameterIndex; } - public float getAgeIncrease() { return this.ageIncrease; }; - + /** * Accepts a configuration function that accepts a builder to configure. * @@ -116,9 +115,9 @@ public static VriLayer build(VriPolygon polygon, Consumer config) { public static class Builder extends BaseVdypLayer.Builder { - + private static final float DEFAULT_AGE_INCREASE = 0; - + protected Optional crownClosure = Optional.empty(); protected Optional baseArea = Optional.empty(); protected Optional treesPerHectare = Optional.empty(); @@ -204,7 +203,7 @@ public Builder secondaryGenus(Optional secondaryGenus) { public Builder secondaryGenus(String secondaryGenus) { return secondaryGenus(Optional.of(secondaryGenus)); } - + public Builder ageIncrease(float ageIncrease) { this.ageIncrease = Optional.of(ageIncrease); return this; diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java index 5a41c9fd1..b2bd66ddd 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriPolygon.java @@ -16,9 +16,8 @@ public class VriPolygon extends BaseVdypPolygon, VriSp public static final String FIZ = " "; public VriPolygon( - PolygonIdentifier polygonIdentifier, String fiz, BecDefinition bec, - Optional percentAvailable, Optional modeFip, Optional nonproductiveDescription, - float yieldFactor + PolygonIdentifier polygonIdentifier, String fiz, BecDefinition bec, Optional percentAvailable, + Optional modeFip, Optional nonproductiveDescription, float yieldFactor ) { super(polygonIdentifier, percentAvailable, fiz, bec, modeFip, Optional.empty()); this.nonproductiveDescription = nonproductiveDescription; diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java index b1cd0d895..2592c26e2 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java @@ -66,20 +66,20 @@ void setUp() throws IOException, ResourceParseException { resolver.addStream("DUMMY3", (OutputStream) new ByteArrayOutputStream()); controlMap.put( - ControlKey.BEC_DEF.name(), new BecDefinitionParser() - .parse(TestUtils.class, "coe/Becdef.dat", controlMap) + ControlKey.BEC_DEF.name(), + new BecDefinitionParser().parse(TestUtils.class, "coe/Becdef.dat", controlMap) ); controlMap.put( - ControlKey.SP0_DEF.name(), new GenusDefinitionParser() - .parse(TestUtils.class, "coe/SP0DEF_v0.dat", controlMap) + ControlKey.SP0_DEF.name(), + new GenusDefinitionParser().parse(TestUtils.class, "coe/SP0DEF_v0.dat", controlMap) ); controlMap.put( - ControlKey.DEFAULT_EQ_NUM.name(), new DefaultEquationNumberParser() - .parse(TestUtils.class, "coe/GRPBA1.DAT", controlMap) + ControlKey.DEFAULT_EQ_NUM.name(), + new DefaultEquationNumberParser().parse(TestUtils.class, "coe/GRPBA1.DAT", controlMap) ); controlMap.put( - ControlKey.EQN_MODIFIERS.name(), new EquationModifierParser() - .parse(TestUtils.class, "coe/GMODBA1.DAT", controlMap) + ControlKey.EQN_MODIFIERS.name(), + new EquationModifierParser().parse(TestUtils.class, "coe/GMODBA1.DAT", controlMap) ); TestUtils.populateControlMapBecReal(controlMap); } diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java index 05ff779d2..a4edcf823 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriControlParserTest.java @@ -58,10 +58,10 @@ void testParseBec() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.BEC_DEF, allOf( - instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class))) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.BEC_DEF, + allOf(instanceOf(BecLookup.class), hasBec("AT", present(instanceOf(BecDefinition.class)))) ) ); } @@ -78,7 +78,8 @@ void testParseVGRP() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VOLUME_EQN_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(7), "AT", "CDF")) ) ); @@ -89,7 +90,8 @@ void testParseDGRP() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.DECAY_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(5), "AT", "CDF")) ) ); @@ -100,7 +102,8 @@ void testParseBGRP() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BREAKAGE_GROUPS, allOf(isA(MatrixMap2.class), mmHasEntry(is(3), "AT", "CDF")) ) ); @@ -111,7 +114,8 @@ void testParseGRBA1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.DEFAULT_EQ_NUM, allOf(isA(MatrixMap2.class), mmHasEntry(is(11), "AT", "CDF")) ) ); @@ -174,8 +178,8 @@ void testParseE026Empty() throws Exception { // Map is empty but gives appropriate default values assertThat(result, (Matcher) controlMapHasEntry(ControlKey.SITE_CURVE_AGE_MAX, Matchers.anEmptyMap())); assertThat( - ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())) - .get(1), (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) + ((Map) result.get(ControlKey.SITE_CURVE_AGE_MAX.name())).get(1), + (Matcher) allOf(SiteCurveAgeMaximumParserTest.hasAge(Region.COASTAL, is(140.f))) ); } @@ -184,12 +188,16 @@ void testParseE040() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.COE_BA, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.COE_BA, + allOf( mmHasEntry( coe( - 0, contains( - 2.0028f, 0.2426f, 10.1668f, -0.9042f, -5.0012f, -0.0068f, -0.0095f, 1.1938f, -0.2749f, 0f + 0, + contains( + 2.0028f, 0.2426f, 10.1668f, -0.9042f, -5.0012f, -0.0068f, + -0.0095f, 1.1938f, -0.2749f, 0f ) ), "AT", "AC" ) @@ -203,12 +211,16 @@ void testParseE041() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.COE_DQ, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.COE_DQ, + allOf( mmHasEntry( coe( - 0, contains( - 6.6190f, -0.5579f, -1.9421f, -0.7092f, -5.2290f, 4.8473f, 0.2629f, -0.0062f, 0f, 0f + 0, + contains( + 6.6190f, -0.5579f, -1.9421f, -0.7092f, -5.2290f, 4.8473f, + 0.2629f, -0.0062f, 0f, 0f ) ), "AT", "AC" ) @@ -222,7 +234,8 @@ void testParseE043() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.UPPER_BA_BY_CI_S0_P, allOf(mmHasEntry(is(109.27f), Region.COASTAL, "AC", 1)) ) ); @@ -233,10 +246,10 @@ void testParseE050() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P1, allOf( - mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P1, + allOf(mmHasEntry(coe(1, contains(1.00160f, 0.20508f, -0.0013743f)), "AC", Region.COASTAL)) ) ); } @@ -246,10 +259,10 @@ void testParseE051() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P2, allOf( - mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P2, + allOf(mmHasEntry(coe(1, contains(0.49722f, 1.18403f)), "AC", Region.COASTAL)) ) ); } @@ -259,8 +272,10 @@ void testParseE052() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_PRIMARY_SP_EQN_P3, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_PRIMARY_SP_EQN_P3, + allOf( mmHasEntry( coe(1, contains(1.04422f, 0.93010f, -0.05745f, -2.50000f)), "AC", Region.COASTAL ) @@ -274,10 +289,10 @@ void testParseE053() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.HL_NONPRIMARY, allOf( - mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.HL_NONPRIMARY, + allOf(mmHasEntry(present(coe(1, 0.86323f, 1.00505f)), "AC", "AT", Region.COASTAL)) ) ); } @@ -287,7 +302,8 @@ void testParseE060() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162f)) ) ); @@ -296,21 +312,22 @@ ControlKey.BY_SPECIES_DQ, hasEntry(is("AT"), coe(0, -0.48275f, 0.19886f, 0.23162 @Test void testParseE061() throws Exception { BaseControlParser parser = new VriControlParser(); - var result = (Map)parse(parser, TestUtils.class, CONTROL_FILE); + var result = (Map) parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, - mmHasEntry(instanceOf(ComponentSizeLimits.class) - , "AC", Region.COASTAL - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, + mmHasEntry(instanceOf(ComponentSizeLimits.class), "AC", Region.COASTAL) ) ); - var mm = Utils.>expectParsedControl(result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class); - + var mm = Utils.>expectParsedControl( + result, ControlKey.SPECIES_COMPONENT_SIZE_LIMIT, MatrixMap2.class + ); + var csl = mm.get("AC", Region.COASTAL); - + assertThat(csl.loreyHeightMaximum(), is(49.4f)); assertThat(csl.quadMeanDiameterMaximum(), is(153.3f)); assertThat(csl.minQuadMeanDiameterLoreyHeightRatio(), is(0.726f)); @@ -322,10 +339,10 @@ void testParseUBA1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_BA, allOf( - mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH") - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.UTIL_COMP_BA, + allOf(mmHasEntry(coe(1, contains(-26.68771f, 14.38811f)), 1, "AT", "ICH")) ) ); } @@ -335,10 +352,10 @@ void testParseYVC1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.CLOSE_UTIL_VOLUME, allOf( - mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.CLOSE_UTIL_VOLUME, + allOf(mmHasEntry(present(coe(1, contains(-3.249f, 0.2426f, 0.04621f))), 2, 53)) ) ); } @@ -348,10 +365,10 @@ void testParseYVD1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY, allOf( - mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VOLUME_NET_DECAY, + allOf(mmHasEntry(present(coe(1, contains(12.7054f, 0.14984f, -1.73471f))), 2, 53)) ) ); } @@ -361,10 +378,10 @@ void testParseSBA1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_PROBABILITY, allOf( - hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_PROBABILITY, + allOf(hasEntry(is("AT"), contains(-1.76158f, 2.50045f, -0.030447f, -0.11746f))) ) ); } @@ -374,10 +391,10 @@ void testParseSBA2() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_BA, allOf( - hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_BA, + allOf(hasEntry(is("B"), contains(-1.3504f, 9.5806f, 3.35173f, -0.27311f))) ) ); } @@ -387,7 +404,8 @@ void testParseSDQ1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.SMALL_COMP_DQ, allOf(hasEntry(is("B"), contains(-0.33485f, 0.02029f))) ) ); @@ -398,7 +416,8 @@ void testParseSHL1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.SMALL_COMP_HL, allOf(hasEntry(is("B"), contains(-8.5269f, -0.20000f))) ) ); @@ -409,10 +428,10 @@ void testParseSVT1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.SMALL_COMP_WS_VOLUME, allOf( - hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.SMALL_COMP_WS_VOLUME, + allOf(hasEntry(is("B"), contains(-9.6020f, 1.09191f, 1.26171f, 0.10841f))) ) ); } @@ -422,11 +441,15 @@ void testParseYVT1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, allOf( + result, + (Matcher) controlMapHasEntry( + ControlKey.TOTAL_STAND_WHOLE_STEM_VOL, + allOf( hasEntry( - is(2), contains( - -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, 0.0000000f, 0.0000000f, 0.19884f + is(2), + contains( + -10.41832f, 1.94182f, 0.99414f, 0.000000f, 1.11329f, 0.000000f, + 0.0000000f, 0.0000000f, 0.19884f ) ) ) @@ -439,10 +462,10 @@ void testParseYVT2() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.UTIL_COMP_WS_VOLUME, allOf( - mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.UTIL_COMP_WS_VOLUME, + allOf(mmHasEntry(present(contains(-1.44375f, 1.20115f, 1.14639f, -1.17521f)), 2, 11)) ) ); } @@ -452,10 +475,10 @@ void testParseYVW1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VOLUME_NET_DECAY_WASTE, allOf( - hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VOLUME_NET_DECAY_WASTE, + allOf(hasEntry(is("B"), contains(-4.2025f, 11.2235f, -33.0270f, 0.1246f, -0.2318f, -0.1259f))) ) ); } @@ -465,7 +488,8 @@ void testParseE095() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.BREAKAGE, allOf(hasEntry(is(10), contains(-0.7153f, 2.0108f, 4.00f, 8.00f))) ) ); @@ -476,10 +500,10 @@ void testParseYVVET() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_VOLUME_ADJUST, allOf( - hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f)) - ) + result, + (Matcher) controlMapHasEntry( + ControlKey.VETERAN_LAYER_VOLUME_ADJUST, + allOf(hasEntry(is("B"), contains(0.10881f, -0.09818f, 0.00048f, -0.00295f))) ) ); } @@ -489,15 +513,14 @@ void testParseYDQV() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VETERAN_LAYER_DQ, allOf( - mmHasEntry( - coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL - ), mmHasEntry( - coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR - ), mmHasEntry( - coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL - ), mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) + result, + (Matcher) controlMapHasEntry( + ControlKey.VETERAN_LAYER_DQ, + allOf( + mmHasEntry(coe(1, contains(22.500f, 0.24855f, 1.46089f)), "B", Region.COASTAL), + mmHasEntry(coe(1, contains(19.417f, 0.04354f, 1.96395f)), "B", Region.INTERIOR), + mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.COASTAL), + mmHasEntry(coe(1, contains(22.500f, 0.80260f, 1.00000f)), "D", Region.INTERIOR) ) ) ); @@ -512,13 +535,10 @@ void testParseE098() throws Exception { ControlKey.VETERAN_BQ, // Includes modifiers from 198 allOf( - mmHasEntry( - contains(0.12874f * 0.311f, 8.00000f, 1.26982f), "B", Region.COASTAL - ), mmHasEntry( - contains(0.70932f * 0.374f, 7.63269f, 0.62545f), "B", Region.INTERIOR - ), mmHasEntry( - contains(0.07962f * 0.311f, 6.60231f, 1.37998f), "D", Region.COASTAL - ), mmHasEntry(contains(0.07962f * 0.374f, 6.60231f, 1.37998f), "D", Region.INTERIOR) + mmHasEntry(contains(0.12874f * 0.311f, 8.00000f, 1.26982f), "B", Region.COASTAL), + mmHasEntry(contains(0.70932f * 0.374f, 7.63269f, 0.62545f), "B", Region.INTERIOR), + mmHasEntry(contains(0.07962f * 0.311f, 6.60231f, 1.37998f), "D", Region.COASTAL), + mmHasEntry(contains(0.07962f * 0.374f, 6.60231f, 1.37998f), "D", Region.INTERIOR) ) ) ); @@ -533,11 +553,10 @@ void testParseMinima() throws Exception { ControlKey.MINIMA, // Includes modifiers from 198 allOf( - hasEntry(is(BaseControlParser.MINIMUM_HEIGHT), is(6.0f)), hasEntry( - is(BaseControlParser.MINIMUM_BASE_AREA), is(0.0f) - ), hasEntry( - is(BaseControlParser.MINIMUM_PREDICTED_BASE_AREA), is(2.0f) - ), hasEntry(is(BaseControlParser.MINIMUM_VETERAN_HEIGHT), is(10.0f)) + hasEntry(is(BaseControlParser.MINIMUM_HEIGHT), is(6.0f)), + hasEntry(is(BaseControlParser.MINIMUM_BASE_AREA), is(0.0f)), + hasEntry(is(BaseControlParser.MINIMUM_PREDICTED_BASE_AREA), is(2.0f)), + hasEntry(is(BaseControlParser.MINIMUM_VETERAN_HEIGHT), is(10.0f)) ) ) ); @@ -549,9 +568,8 @@ void testParseV7R_RIP1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VRI_INPUT_YIELD_POLY, instanceOf(StreamingParserFactory.class) - ) + result, + (Matcher) controlMapHasEntry(ControlKey.VRI_INPUT_YIELD_POLY, instanceOf(StreamingParserFactory.class)) ); } @@ -561,9 +579,8 @@ void testParseV7R_RIL1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( - ControlKey.VRI_INPUT_YIELD_LAYER, instanceOf(StreamingParserFactory.class) - ) + result, + (Matcher) controlMapHasEntry(ControlKey.VRI_INPUT_YIELD_LAYER, instanceOf(StreamingParserFactory.class)) ); } @@ -573,7 +590,8 @@ void testParseV7R_RIT1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VRI_INPUT_YIELD_HEIGHT_AGE_SI, instanceOf(StreamingParserFactory.class) ) ); @@ -585,7 +603,8 @@ void testParseV7R_RIS1() throws Exception { BaseControlParser parser = new VriControlParser(); var result = parse(parser, TestUtils.class, CONTROL_FILE); assertThat( - result, (Matcher) controlMapHasEntry( + result, + (Matcher) controlMapHasEntry( ControlKey.VRI_INPUT_YIELD_SPEC_DIST, instanceOf(StreamingParserFactory.class) ) ); diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java index e6ee0797a..3c5dcf9bf 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java @@ -1575,10 +1575,10 @@ void testCheckVeteranHeight() throws Exception { var ex = assertThrows(StandProcessingException.class, () -> app.checkPolygon(poly)); assertThat( - ex, hasProperty( - "message", is( - "Veteran layer primary species height 34.0 should be greater than or equal to 36.0" - ) + ex, + hasProperty( + "message", + is("Veteran layer primary species height 34.0 should be greater than or equal to 36.0") ) ); diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java index 7843918e5..525a02181 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriLayerParserTest.java @@ -86,8 +86,10 @@ void testParsePrimaryLayer() throws Exception { assertThat(layers, aMapWithSize(1)); assertThat( - layers, hasSpecificEntry( - LayerType.PRIMARY, VdypMatchers.builds( + layers, + hasSpecificEntry( + LayerType.PRIMARY, + VdypMatchers.builds( allOf( hasProperty("polygonIdentifier", isPolyId("082F074/0071", 2001)), // hasProperty("layerType", is(LayerType.PRIMARY)), // @@ -135,8 +137,10 @@ void testParseVeteranLayer() throws Exception { assertThat(layers, aMapWithSize(1)); assertThat( - layers, hasSpecificEntry( - LayerType.VETERAN, VdypMatchers.builds( + layers, + hasSpecificEntry( + LayerType.VETERAN, + VdypMatchers.builds( allOf( hasProperty("polygonIdentifier", isPolyId("082F074/0071", 2001)), // hasProperty("layerType", is(LayerType.VETERAN)), // @@ -186,8 +190,10 @@ void testParseTwoLayers() throws Exception { assertThat(layers, aMapWithSize(2)); assertThat( - layers, hasSpecificEntry( - LayerType.PRIMARY, VdypMatchers.builds( + layers, + hasSpecificEntry( + LayerType.PRIMARY, + VdypMatchers.builds( allOf( hasProperty("polygonIdentifier", isPolyId("082F074/0071", 2001)), // hasProperty("layerType", is(LayerType.PRIMARY)), // @@ -200,8 +206,10 @@ layers, hasSpecificEntry( ) ); assertThat( - layers, hasSpecificEntry( - LayerType.VETERAN, VdypMatchers.builds( + layers, + hasSpecificEntry( + LayerType.VETERAN, + VdypMatchers.builds( allOf( hasProperty("polygonIdentifier", isPolyId("082F074/0071", 2001)), // hasProperty("layerType", is(LayerType.VETERAN)), // diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java index 436508267..1a700587e 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriPolygonParserTest.java @@ -148,7 +148,7 @@ void testParseMultiple() throws Exception { "01004 S000002 00 1953 B CWH 1.00", // "01004 S000036 00 1957 B CWH 1.00", // "01004 S000037 00 1957 B CWH 1.00", // - "01004 S000038 00 1957 B CWH 1.00" // + "01004 S000038 00 1957 B CWH 1.00" // ) ); diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java index 844e5a324..274a60b25 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSiteParserTest.java @@ -68,8 +68,10 @@ void testParseOneSite() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -114,8 +116,11 @@ void testIgnoreIfNotPrimaryOrSecondary() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0071 2001 X 100 28.0 14.3 C CW 10.9 189.1 11", "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0071 2001 X 100 28.0 14.3 C CW 10.9 189.1 11", + "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -162,8 +167,11 @@ void testParseTwoSites() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", "082F074/0071 2001 P 200 32.0 14.6 H HW 9.7 190.3 37", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", + "082F074/0071 2001 P 200 32.0 14.6 H HW 9.7 190.3 37", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -191,7 +199,8 @@ sites, containsInAnyOrder( hasProperty("yearsToBreastHeight", present(closeTo(10.9f))), // hasProperty("breastHeightAge", present(closeTo(189.1f))), // hasProperty("siteCurveNumber", present(is(11))) - ), allOf( + ), + allOf( hasProperty("ageTotal", present(closeTo(200.0f))), // hasProperty("height", present(closeTo(32.0f))), // hasProperty("siteIndex", present(closeTo(14.6f))), // @@ -219,8 +228,11 @@ void testParseTwoLayers() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", "082F074/0071 2001 S 200 32.0 14.6 H HW 9.7 190.3 37", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0071 2001 P 200 28.0 14.3 C CW 10.9 189.1 11", + "082F074/0071 2001 S 200 32.0 14.6 H HW 9.7 190.3 37", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -249,7 +261,8 @@ sites, containsInAnyOrder( hasProperty("yearsToBreastHeight", present(closeTo(10.9f))), // hasProperty("breastHeightAge", present(closeTo(189.1f))), // hasProperty("siteCurveNumber", present(is(11))) - ), allOf( + ), + allOf( hasProperty("layerType", is(LayerType.SECONDARY)), // hasProperty("ageTotal", present(closeTo(200.0f))), // hasProperty("height", present(closeTo(32.0f))), // @@ -277,8 +290,12 @@ void testParseTwoPolygons() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0072 2002 P 200 28.0 14.3 C CW 10.9 189.1 11", "082F074/0072 2002 Z 0 0.0 0.0", "082F074/0071 2001 P 200 32.0 14.6 H HW 9.7 190.3 37", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0072 2002 P 200 28.0 14.3 C CW 10.9 189.1 11", + "082F074/0072 2002 Z 0 0.0 0.0", + "082F074/0071 2001 P 200 32.0 14.6 H HW 9.7 190.3 37", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -344,8 +361,10 @@ void testBreastHeightAgeZeroAndTotalEmpty() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0071 2001 P -9 28.0 14.3 C CW 10.9 0.0 11", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0071 2001 P -9 28.0 14.3 C CW 10.9 0.0 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -386,7 +405,8 @@ void testBreastHeightAgeZeroAndNotCloseToExpected() throws Exception { var fileResolver = TestUtils.fileResolver( "test.dat", TestUtils.makeInputStream( // YTBH differs from Age Total by more than 0.5 - "082F074/0071 2001 P 20 28.0 14.3 C CW 19.4 0.0 11", "082F074/0071 2001 Z 0 0.0 0.0" + "082F074/0071 2001 P 20 28.0 14.3 C CW 19.4 0.0 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -427,7 +447,8 @@ void testBreastHeightAgeZeroAndIsCloseToExpected() throws Exception { var fileResolver = TestUtils.fileResolver( "test.dat", TestUtils.makeInputStream( // YTBH differs from Age Total by less than 0.5 - "082F074/0071 2001 P 20 28.0 14.3 C CW 19.6 0.0 11", "082F074/0071 2001 Z 0 0.0 0.0" + "082F074/0071 2001 P 20 28.0 14.3 C CW 19.6 0.0 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -468,7 +489,8 @@ void testDefaultHeight() throws Exception { var fileResolver = TestUtils.fileResolver( "test.dat", TestUtils.makeInputStream( // height empty, ageTotal within 0.6 of 1, siteIndex >=3 - "082F074/0071 2001 P 1 -9.0 14.3 C CW 19.6 0.0 11", "082F074/0071 2001 Z 0 0.0 0.0" + "082F074/0071 2001 P 1 -9.0 14.3 C CW 19.6 0.0 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); @@ -510,8 +532,10 @@ void testNoDefaultHeight() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "082F074/0071 2001 P 1.7 -9.0 14.3 C CW 19.6 0.0 11", "082F074/0071 2001 Z 0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "082F074/0071 2001 P 1.7 -9.0 14.3 C CW 19.6 0.0 11", + "082F074/0071 2001 Z 0 0.0 0.0" ) ); diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java index 27985ae05..51a6f496f 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriSpeciesParserTest.java @@ -66,8 +66,10 @@ void testParseOneGenus() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( - "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" + "test.dat", + TestUtils.makeInputStream( + "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", + "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" ) ); @@ -93,13 +95,16 @@ void testParseOneGenus() throws Exception { hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -158,13 +163,16 @@ void testIgnore(String ignoredLine) throws Exception { hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -217,30 +225,37 @@ void testParseTwoGenera() throws Exception { hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(75.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) ) ) - ), allOf( + ), + allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000001 00", 1970)), // hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("C")), // hasProperty("percentGenus", is(25.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("C")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("C")), + hasProperty("percentage", is(100f)) ) ) ) @@ -265,7 +280,8 @@ void testParseTwoLayers() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 V B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0" // @@ -293,30 +309,37 @@ void testParseTwoLayers() throws Exception { hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) ) ) - ), allOf( + ), + allOf( hasProperty("polygonIdentifier", isPolyId("01002 S000001 00", 1970)), // hasProperty("layerType", is(LayerType.VETERAN)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -340,7 +363,8 @@ void testParseTwoPolygons() throws Exception { TestUtils.populateControlMapGenusReal(controlMap); var fileResolver = TestUtils.fileResolver( - "test.dat", TestUtils.makeInputStream( + "test.dat", + TestUtils.makeInputStream( "01002 S000001 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // "01002 S000001 00 1970 Z 0.0 0.0 0.0 0.0 0.0", // "01002 S000002 00 1970 1 B 100.0B 100.0 0.0 0.0 0.0", // @@ -369,13 +393,16 @@ void testParseTwoPolygons() throws Exception { hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -395,13 +422,16 @@ void testParseTwoPolygons() throws Exception { hasProperty("layerType", is(LayerType.PRIMARY)), hasProperty("genus", is("B")), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", is("B")), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B")), + hasProperty("percentage", is(100f)) ) ) ) @@ -455,31 +485,37 @@ void testParseMultipleSpecies() throws Exception { hasProperty("genusIndex", is(3)), // hasProperty("percentGenus", is(100.0f)), // hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(4), hasEntry( - is(1), allOf( - hasProperty( - "genusAlias", is("B1") - ), hasProperty("percentage", is(75f)) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(4), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", is("B1")), + hasProperty("percentage", is(75f)) ) - ), hasEntry( - is(2), allOf( - hasProperty( - "genusAlias", is("B2") - ), hasProperty("percentage", is(10f)) + ), + hasEntry( + is(2), + allOf( + hasProperty("genusAlias", is("B2")), + hasProperty("percentage", is(10f)) ) - ), hasEntry( - is(3), allOf( - hasProperty( - "genusAlias", is("B3") - ), hasProperty("percentage", is(8f)) + ), + hasEntry( + is(3), + allOf( + hasProperty("genusAlias", is("B3")), + hasProperty("percentage", is(8f)) ) - ), hasEntry( - is(4), allOf( - hasProperty( - "genusAlias", is("B4") - ), hasProperty("percentage", is(7f)) + ), + hasEntry( + is(4), + allOf( + hasProperty("genusAlias", is("B4")), + hasProperty("percentage", is(7f)) ) ) ) diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java index ed36b420c..2933e728e 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java @@ -211,7 +211,8 @@ void testGetCoefficients() throws StandProcessingException { Coefficients result = app.estimateBaseAreaYieldCoefficients(species, bec); assertThat( - result, VdypMatchers.coe( + result, + VdypMatchers.coe( 0, 7.29882717f, 0.934803009f, 7.22950029f, 0.478330702f, 0.00542420009f, 0f, -0.00899999961f ) ); @@ -265,8 +266,8 @@ void testLowBA() throws Exception { var bec = new BecDefinition("IDF", Region.INTERIOR, "Interior Douglas Fir"); var result = app.findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, Optional - .of(76) + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, + Optional.of(76) ); assertThat(result, is(PolygonMode.YOUNG)); @@ -318,8 +319,8 @@ void testLowHeight() throws Exception { var bec = new BecDefinition("IDF", Region.INTERIOR, "Interior Douglas Fir"); var result = app.findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, Optional - .of(76) + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, + Optional.of(76) ); assertThat(result, is(PolygonMode.YOUNG)); @@ -371,8 +372,8 @@ void testNoBA() throws Exception { var bec = new BecDefinition("IDF", Region.INTERIOR, "Interior Douglas Fir"); var result = app.findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, Optional - .of(76) + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, + Optional.of(76) ); assertThat(result, is(PolygonMode.YOUNG)); @@ -424,8 +425,8 @@ void testNoTPH() throws Exception { var bec = new BecDefinition("IDF", Region.INTERIOR, "Interior Douglas Fir"); var result = app.findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, Optional - .of(76) + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, + Optional.of(76) ); assertThat(result, is(PolygonMode.YOUNG)); @@ -477,8 +478,8 @@ void testLowRation() throws Exception { var bec = new BecDefinition("IDF", Region.INTERIOR, "Interior Douglas Fir"); var result = app.findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, Optional - .of(76) + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, + Optional.of(76) ); assertThat(result, is(PolygonMode.YOUNG)); @@ -530,8 +531,8 @@ void testStart() throws Exception { var bec = new BecDefinition("IDF", Region.INTERIOR, "Interior Douglas Fir"); var result = app.findDefaultPolygonMode( - ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, Optional - .of(76) + ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, species, bec, + Optional.of(76) ); assertThat(result, is(PolygonMode.START)); @@ -860,8 +861,8 @@ void testSimpleChange() throws StandProcessingException, IOException { var evaluated = result.evaluate(errorFunc); assertTrue( - evaluated.start() * evaluated.end() <= 0, () -> "F(" + result - + ") should have mixed signs but was " + evaluated + evaluated.start() * evaluated.end() <= 0, + () -> "F(" + result + ") should have mixed signs but was " + evaluated ); } @@ -882,8 +883,8 @@ void testDifficultChange(float a, float b) throws StandProcessingException, IOEx var evaluated = result.evaluate(errorFunc); assertTrue( - evaluated.start() * evaluated.end() <= 0, () -> "F(" + result - + ") should have mixed signs but was " + evaluated + evaluated.start() * evaluated.end() <= 0, + () -> "F(" + result + ") should have mixed signs but was " + evaluated ); } @@ -904,8 +905,8 @@ void testTwoRoots(float a) throws StandProcessingException, IOException { var evaluated = result.evaluate(errorFunc); assertTrue( - evaluated.start() * evaluated.end() <= 0, () -> "F(" + result - + ") should have mixed signs but was " + evaluated + evaluated.start() * evaluated.end() <= 0, + () -> "F(" + result + ") should have mixed signs but was " + evaluated ); } @@ -1057,7 +1058,8 @@ float quadMeanDiameterFractionalError( app.setDebugMode(1, 2); assertThrows( - StandProcessingException.class, () -> app.findRootForQuadMeanDiameterFractionalError( + StandProcessingException.class, + () -> app.findRootForQuadMeanDiameterFractionalError( x1, x2, resultPerSpecies, initialDqs, baseAreas, minDq, maxDq, tph ) ); @@ -1207,7 +1209,8 @@ void testTooManyEvaluationsStrictThrow() { app.setDebugMode(1, 2); assertThrows( - StandProcessingException.class, () -> app.findRootForQuadMeanDiameterFractionalError( + StandProcessingException.class, + () -> app.findRootForQuadMeanDiameterFractionalError( x1, x2, resultPerSpecies, initialDqs, baseAreas, minDq, maxDq, tph ) ); @@ -1277,12 +1280,13 @@ void testTooManyEvaluationsGuess() throws StandProcessingException { assertThat(result, closeTo((float) expectedX)); assertThat( - resultPerSpecies, allOf( - appliedX("B", expectedX, app, initialDqs, minDq, maxDq), appliedX( - "C", expectedX, app, initialDqs, minDq, maxDq - ), appliedX("F", expectedX, app, initialDqs, minDq, maxDq), appliedX( - "H", expectedX, app, initialDqs, minDq, maxDq - ), appliedX("S", expectedX, app, initialDqs, minDq, maxDq) + resultPerSpecies, + allOf( + appliedX("B", expectedX, app, initialDqs, minDq, maxDq), + appliedX("C", expectedX, app, initialDqs, minDq, maxDq), + appliedX("F", expectedX, app, initialDqs, minDq, maxDq), + appliedX("H", expectedX, app, initialDqs, minDq, maxDq), + appliedX("S", expectedX, app, initialDqs, minDq, maxDq) ) ); @@ -1347,7 +1351,8 @@ void testTooManyEvaluationsDiscontinuity() { app.setDebugMode(1, 0); assertThrows( - StandProcessingException.class, () -> app.findRootForQuadMeanDiameterFractionalError( + StandProcessingException.class, + () -> app.findRootForQuadMeanDiameterFractionalError( x1, x2, resultPerSpecies, initialDqs, baseAreas, minDq, maxDq, tph ) ); @@ -1358,7 +1363,8 @@ void testTooManyEvaluationsDiscontinuity() { Map minDq, Map maxDq ) { return hasEntry( - is(species), closeTo( + is(species), + closeTo( app.quadMeanDiameterSpeciesAdjust( expectedX, initialDqs.get(species), minDq.get(species), maxDq.get(species) ) @@ -1481,7 +1487,8 @@ void testCompute() throws ProcessingException { Map maxPerSpecies = new HashMap<>(5); app.getDqBySpeciesInitial( - layer, region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, loreyHeightTotal, initialDqs, baseAreaPerSpecies, minPerSpecies, maxPerSpecies + layer, region, quadMeanDiameterTotal, baseAreaTotal, treeDensityTotal, loreyHeightTotal, + initialDqs, baseAreaPerSpecies, minPerSpecies, maxPerSpecies ); assertThat( @@ -2084,97 +2091,100 @@ void testProcessPrimary() throws Exception { resultLayer, hasProperty("loreyHeightByUtilization", utilizationHeight(4.14067888f, 6.61390257f)) ); assertThat( - resultLayer, hasProperty( - "baseAreaByUtilization", utilization( + resultLayer, + hasProperty( + "baseAreaByUtilization", + utilization( 0.0679966733f, 6.34290648f, 4.24561071f, 1.01540196f, 0.571661115f, 0.510232806f ) ) ); assertThat( - resultLayer, hasProperty( - "quadraticMeanDiameterByUtilization", utilization( - 5.58983135f, 10.3879948f, 9.11466217f, 13.9179964f, 18.6690178f, 25.3685265f - ) + resultLayer, + hasProperty( + "quadraticMeanDiameterByUtilization", + utilization(5.58983135f, 10.3879948f, 9.11466217f, 13.9179964f, 18.6690178f, 25.3685265f) ) ); assertThat( - resultLayer, hasProperty( - "treesPerHectareByUtilization", utilization( - 27.707695f, 748.4021f, 650.682556f, 66.7413025f, 20.8836231f, 10.094574f - ) + resultLayer, + hasProperty( + "treesPerHectareByUtilization", + utilization(27.707695f, 748.4021f, 650.682556f, 66.7413025f, 20.8836231f, 10.094574f) ) ); assertThat( - resultLayer, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", utilization( - 0, 4.73118162f, 0.0503439531f, 1.59589052f, 1.62338901f, 1.46155834f - ) + resultLayer, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + utilization(0, 4.73118162f, 0.0503439531f, 1.59589052f, 1.62338901f, 1.46155834f) ) ); assertThat( - resultLayer.getSpecies(), allOf( - aMapWithSize(5), hasKey("B"), hasKey("C"), hasKey("F"), hasKey("H"), hasKey("S") - ) + resultLayer.getSpecies(), + allOf(aMapWithSize(5), hasKey("B"), hasKey("C"), hasKey("F"), hasKey("H"), hasKey("S")) ); VdypSpecies resultSpecB = TestUtils.assertHasSpecies(resultLayer, "B", "C", "F", "H", "S"); assertThat( - resultSpecB, hasProperty( - "baseAreaByUtilization", utilization( + resultSpecB, + hasProperty( + "baseAreaByUtilization", + utilization( 0.0116237309f, 0.634290636f, 0.239887208f, 0.196762085f, 0.102481194f, 0.095160149f ) ) ); assertThat( - resultSpecB, hasProperty( - "quadraticMeanDiameterByUtilization", utilization( - 5.61674118f, 12.9407434f, 9.93954372f, 14.3500404f, 19.1790199f, 27.5482502f - ) + resultSpecB, + hasProperty( + "quadraticMeanDiameterByUtilization", + utilization(5.61674118f, 12.9407434f, 9.93954372f, 14.3500404f, 19.1790199f, 27.5482502f) ) ); assertThat( - resultSpecB, hasProperty( - "treesPerHectareByUtilization", utilization( - 4.69123125f, 48.2258606f, 30.9160728f, 12.1659298f, 3.54732919f, 1.59653044f - ) + resultSpecB, + hasProperty( + "treesPerHectareByUtilization", + utilization(4.69123125f, 48.2258606f, 30.9160728f, 12.1659298f, 3.54732919f, 1.59653044f) ) ); assertThat( - resultSpecB, hasProperty( - "wholeStemVolumeByUtilization", utilization( - 0.0244281366f, 2.41518188f, 0.747900844f, 0.752810001f, 0.4540295f, 0.46044156f - ) + resultSpecB, + hasProperty( + "wholeStemVolumeByUtilization", + utilization(0.0244281366f, 2.41518188f, 0.747900844f, 0.752810001f, 0.4540295f, 0.46044156f) ) ); assertThat( - resultSpecB, hasProperty( - "closeUtilizationVolumeByUtilization", utilization( - 0, 1.28733742f, 0.0235678982f, 0.464995325f, 0.378819793f, 0.41995436f - ) + resultSpecB, + hasProperty( + "closeUtilizationVolumeByUtilization", + utilization(0, 1.28733742f, 0.0235678982f, 0.464995325f, 0.378819793f, 0.41995436f) ) ); assertThat( - resultSpecB, hasProperty( - "closeUtilizationVolumeNetOfDecayByUtilization", utilization( - 0, 1.24826729f, 0.0230324566f, 0.454239398f, 0.369579285f, 0.401416153f - ) + resultSpecB, + hasProperty( + "closeUtilizationVolumeNetOfDecayByUtilization", + utilization(0, 1.24826729f, 0.0230324566f, 0.454239398f, 0.369579285f, 0.401416153f) ) ); assertThat( - resultSpecB, hasProperty( - "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", utilization( - 0, 1.23482728f, 0.0228475146f, 0.450360179f, 0.366144955f, 0.395474672f - ) + resultSpecB, + hasProperty( + "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", + utilization(0, 1.23482728f, 0.0228475146f, 0.450360179f, 0.366144955f, 0.395474672f) ) ); assertThat( - resultSpecB, hasProperty( - "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", utilization( - 0, 1.20897281f, 0.0223761573f, 0.441060275f, 0.358547896f, 0.386988521f - ) + resultSpecB, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + utilization(0, 1.20897281f, 0.0223761573f, 0.441060275f, 0.358547896f, 0.386988521f) ) ); @@ -2616,24 +2626,24 @@ resultPrimaryLayer, hasProperty( "sites", allOf( aMapWithSize(5), // hasSite( - is("B"), is("BL"), forPrimeLayer - .and(hasProperty("siteCurveNumber", notPresent())) + is("B"), is("BL"), + forPrimeLayer.and(hasProperty("siteCurveNumber", notPresent())) ), // hasSite( - is("C"), is("CW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(11)))) + is("C"), is("CW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(11)))) ), // hasSite( - is("F"), is("FD"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(23)))) + is("F"), is("FD"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(23)))) ), // hasSite( - is("H"), is("HW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(37)))) + is("H"), is("HW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(37)))) ), // hasSite( - is("S"), is("S"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(71)))) + is("S"), is("S"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(71)))) ) ) ) @@ -2804,24 +2814,24 @@ resultPrimaryLayer, hasProperty( "sites", allOf( aMapWithSize(5), // hasSite( - is("B"), is("BL"), forPrimeLayer - .and(hasProperty("siteCurveNumber", notPresent())) + is("B"), is("BL"), + forPrimeLayer.and(hasProperty("siteCurveNumber", notPresent())) ), // hasSite( - is("C"), is("CW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(11)))) + is("C"), is("CW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(11)))) ), // hasSite( - is("F"), is("FD"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(23)))) + is("F"), is("FD"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(23)))) ), // hasSite( - is("H"), is("HW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(37)))) + is("H"), is("HW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(37)))) ), // hasSite( - is("S"), is("S"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(71)))) + is("S"), is("S"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(71)))) ) ) ) @@ -2990,24 +3000,24 @@ resultPrimaryLayer, hasProperty( "sites", allOf( aMapWithSize(5), // hasSite( - is("B"), is("BL"), forPrimeLayer - .and(hasProperty("siteCurveNumber", notPresent())) + is("B"), is("BL"), + forPrimeLayer.and(hasProperty("siteCurveNumber", notPresent())) ), // hasSite( - is("C"), is("CW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(11)))) + is("C"), is("CW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(11)))) ), // hasSite( - is("F"), is("FD"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(23)))) + is("F"), is("FD"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(23)))) ), // hasSite( - is("H"), is("HW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(37)))) + is("H"), is("HW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(37)))) ), // hasSite( - is("S"), is("S"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(71)))) + is("S"), is("S"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(71)))) ) ) ) @@ -3219,24 +3229,24 @@ resultPrimaryLayer, hasProperty( "sites", allOf( aMapWithSize(5), // hasSite( - is("B"), is("BL"), forPrimeLayer - .and(hasProperty("siteCurveNumber", notPresent())) + is("B"), is("BL"), + forPrimeLayer.and(hasProperty("siteCurveNumber", notPresent())) ), // hasSite( - is("C"), is("CW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(11)))) + is("C"), is("CW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(11)))) ), // hasSite( - is("F"), is("FD"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(23)))) + is("F"), is("FD"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(23)))) ), // hasSite( - is("H"), is("HW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(37)))) + is("H"), is("HW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(37)))) ), // hasSite( - is("S"), is("S"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(71)))) + is("S"), is("S"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(71)))) ) ) ) @@ -3463,11 +3473,12 @@ controlMap, new ModifierParser(VdypApplicationIdentifier.VRI_START), "mod19813.p assertThat(result, hasProperty("mode", present(is(PolygonMode.BATC)))); assertThat( - result, hasProperty( - "layers", allOf( - aMapWithSize(2), hasEntry(is(LayerType.PRIMARY), anything()), hasEntry( - is(LayerType.VETERAN), anything() - ) + result, + hasProperty( + "layers", + allOf( + aMapWithSize(2), hasEntry(is(LayerType.PRIMARY), anything()), + hasEntry(is(LayerType.VETERAN), anything()) ) ) ); @@ -3649,24 +3660,24 @@ resultPrimaryLayer, hasProperty( "sites", allOf( aMapWithSize(5), // hasSite( - is("B"), is("BL"), forPrimeLayer - .and(hasProperty("siteCurveNumber", notPresent())) + is("B"), is("BL"), + forPrimeLayer.and(hasProperty("siteCurveNumber", notPresent())) ), // hasSite( - is("C"), is("CW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(11)))) + is("C"), is("CW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(11)))) ), // hasSite( - is("F"), is("FD"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(23)))) + is("F"), is("FD"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(23)))) ), // hasSite( - is("H"), is("HW"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(37)))) + is("H"), is("HW"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(37)))) ), // hasSite( - is("S"), is("S"), forPrimeLayer - .and(hasProperty("siteCurveNumber", present(is(71)))) + is("S"), is("S"), + forPrimeLayer.and(hasProperty("siteCurveNumber", present(is(71)))) ) ) ) @@ -3897,11 +3908,12 @@ controlMap, new ModifierParser(VdypApplicationIdentifier.VRI_START), "mod19813.p assertThat(result, hasProperty("mode", present(is(PolygonMode.BATN)))); assertThat( - result, hasProperty( - "layers", allOf( - aMapWithSize(2), hasEntry(is(LayerType.PRIMARY), anything()), hasEntry( - is(LayerType.VETERAN), anything() - ) + result, + hasProperty( + "layers", + allOf( + aMapWithSize(2), hasEntry(is(LayerType.PRIMARY), anything()), + hasEntry(is(LayerType.VETERAN), anything()) ) ) ); @@ -4049,8 +4061,8 @@ void testBreastHeightAgeLow(float breastHeightAge) throws StandProcessingExcepti var bec = Utils.expectParsedControl(controlMap, ControlKey.BEC_DEF, BecLookup.class).get("IDF").get(); var ex = assertThrows( - StandProcessingException.class, () -> app - .estimateQuadMeanDiameterYield(7.6f, breastHeightAge, Optional.empty(), species, bec, 61) + StandProcessingException.class, + () -> app.estimateQuadMeanDiameterYield(7.6f, breastHeightAge, Optional.empty(), species, bec, 61) ); assertThat(ex, hasProperty("message", endsWith(Float.toString(breastHeightAge)))); @@ -4074,24 +4086,25 @@ void testBreastHeightAgeLow(float breastHeightAge) throws StandProcessingExcepti ) { return hasEntry( genus, // - both(hasProperty("genus", genus)) - .and(hasProperty("percentGenus", percent)) + both(hasProperty("genus", genus)).and(hasProperty("percentGenus", percent)) .and( hasProperty( - "sp64DistributionSet", hasProperty( - "sp64DistributionMap", allOf( - aMapWithSize(1), hasEntry( - is(1), allOf( - hasProperty("genusAlias", species), hasProperty( - "percentage", is(100f) - ) + "sp64DistributionSet", + hasProperty( + "sp64DistributionMap", + allOf( + aMapWithSize(1), + hasEntry( + is(1), + allOf( + hasProperty("genusAlias", species), + hasProperty("percentage", is(100f)) ) ) ) ) ) - ) - .and((Matcher) additional) + ).and((Matcher) additional) ); } From 788fd7a5b1c28ce8331de7638cbe132a8135b167 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 4 Sep 2024 10:32:50 -0700 Subject: [PATCH 45/66] FipStartTest & ZipOutputFileResolverTest corrections --- .../vdyp/io/ZipOutputFileResolverTest.java | 11 +++-- .../ca/bc/gov/nrs/vdyp/fip/FipStartTest.java | 9 ++--- .../vdyp/forward/ForwardProcessingEngine.java | 40 +++++++++---------- .../gov/nrs/vdyp/forward/GrowBaDqTphTest.java | 16 +++++--- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index 99f0d0be1..af4a5da9c 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -26,19 +26,18 @@ void testZipOutputFileResolver() throws IOException { } Path zipFile = Files.createTempFile(this.getClass().getName(), ".zip"); - try - { + try { resolver.generate(zipFile); - + System.out.println("Output zip file written to " + zipFile.toString()); - + try (ZipFile zip = new ZipFile(zipFile.toFile())) { var entries = zip.entries(); - + byte[] buffer = new byte[16]; while (entries.hasMoreElements()) { ZipEntry e = entries.nextElement(); - + InputStream is = zip.getInputStream(e); int nBytesRead = is.read(buffer, 0, 10); assertTrue(nBytesRead == 1); diff --git a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java index e9b2d404c..759cde01e 100644 --- a/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java +++ b/vdyp-lib/vdyp-fip/src/test/java/ca/bc/gov/nrs/vdyp/fip/FipStartTest.java @@ -2315,18 +2315,15 @@ void testFindRootsForPrimaryLayerDiameterAndAreaOneSpecies() throws Exception { var spec = VdypSpecies.build(layer, builder -> { builder.genus("Y", controlMap); builder.percentGenus(100f); - builder.volumeGroup(-1); - builder.decayGroup(-1); - builder.breakageGroup(-1); + builder.volumeGroup(74); + builder.decayGroup(63); + builder.breakageGroup(31); builder.addSite(siteBuilder -> { siteBuilder.ageTotal(285f); siteBuilder.yearsToBreastHeight(11.3999996f); siteBuilder.height(24.3999996f); }); }); - spec.setVolumeGroup(74); - spec.setDecayGroup(63); - spec.setBreakageGroup(31); spec.getLoreyHeightByUtilization().setCoe(0, 19.9850883f); var fipLayer = this.getTestPrimaryLayer(polygonId, l -> { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index b50cf4766..c0c13210f 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -1187,8 +1187,8 @@ private ComponentSizeLimits getComponentSizeLimits(String genusAlias, Region reg } /** - * EMP150 - return the change in quad-mean-diameter over the growth period for the - * primary species of the Primary layer. Based on IPSJF150.doc (July, 1999). + * EMP150 - return the change in quad-mean-diameter over the growth period for the primary species of the Primary + * layer. Based on IPSJF150.doc (July, 1999). * * @param dqStart primary layer quad-mean-diameter at start of growth period * @param dqDelta change in quad-mean-diameter of primary layer during growth period @@ -1223,15 +1223,14 @@ private float calculateQuadMeanDiameterDeltaForPrimarySpecies( } /** - * EMP151 - calculate and return the quad-mean-diameter delta over the growth period for a - * non-primary species. - * + * EMP151 - calculate and return the quad-mean-diameter delta over the growth period for a non-primary species. + * * @param speciesIndex the index of the species (1..nSpecies) in the current bank - * @param dqStart layer quad-mean-diameter at start of growth period - * @param dqDelta layer quad-mean-diameter delta over growth period - * @param spDqStart species quad-mean-diameter at start of growth period - * @param lhStart layer Lorey height at start of growth period - * @param spLhStart species Lorey height at start of growth period + * @param dqStart layer quad-mean-diameter at start of growth period + * @param dqDelta layer quad-mean-diameter delta over growth period + * @param spDqStart species quad-mean-diameter at start of growth period + * @param lhStart layer Lorey height at start of growth period + * @param spLhStart species Lorey height at start of growth period * @return as described * @throws ProcessingException */ @@ -1261,18 +1260,19 @@ private float calculateQuadMeanDiameterDeltaForNonPrimarySpecies( ); } - return calculateQuadMeanDiameterDelta(modelCoefficientsOpt.get(), dqStart, dqDelta, spDqStart, lhStart, spLhStart); + return calculateQuadMeanDiameterDelta( + modelCoefficientsOpt.get(), dqStart, dqDelta, spDqStart, lhStart, spLhStart + ); } /** - * Calculate and return the quad-mean-diameter delta over the growth period for a - * non-primary species. - * - * @param mc coefficients to use for the calculation - * @param dqStart layer quad-mean-diameter at start of growth period - * @param dqDelta layer quad-mean-diameter delta over growth period + * Calculate and return the quad-mean-diameter delta over the growth period for a non-primary species. + * + * @param mc coefficients to use for the calculation + * @param dqStart layer quad-mean-diameter at start of growth period + * @param dqDelta layer quad-mean-diameter delta over growth period * @param spDqStart species quad-mean-diameter at start of growth period - * @param lhStart layer Lorey height at start of growth period + * @param lhStart layer Lorey height at start of growth period * @param spLhStart species Lorey height at start of growth period * @return as described * @throws ProcessingException @@ -1335,7 +1335,7 @@ private float growBasalAreaForNonPrimarySpecies( int pspStratumNumber = lps.getPrimarySpeciesStratumNumber(); - var coe = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients(); + var coe = fps.fcm.getNonPrimarySpeciesBasalAreaGrowthCoefficients(); var modelCoefficientsOpt = coe.get(speciesName, pspStratumNumber); if (modelCoefficientsOpt.isEmpty()) { @@ -1390,7 +1390,7 @@ private float growBasalAreaForPrimarySpecies( LayerProcessingState lps = fps.getLayerProcessingState(); float pspBaDelta; - + float spToAllProportionStart = pspBaStart / baStart; if (spToAllProportionStart <= 0.999f) { var psStratumNumber = lps.getPrimarySpeciesStratumNumber(); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java index 9ea2caf19..fa66df22b 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java @@ -74,13 +74,15 @@ void testStandardPath() throws ProcessingException { assertThat( slice(lps.getBank().basalAreas, UtilizationClass.ALL), // Results from VDYP7: - // Matchers.arrayContaining(45.7382965f, 0.410145015f, 5.13646269f, 29.8279209f, 5.91424417f, 4.44952154f) + // Matchers.arrayContaining(45.7382965f, 0.410145015f, 5.13646269f, 29.8279209f, 5.91424417f, + // 4.44952154f) Matchers.arrayContaining(45.38645f, 0.41014494f, 5.1364512f, 29.827925f, 5.914243f, 4.449531f) ); assertThat( slice(lps.getBank().treesPerHectare, UtilizationClass.ALL), // Results from VDYP7: - // Matchers.arrayContaining(594.113831f, 5.14728308f, 84.0494843f, 286.714783f, 167.523376f, 50.6789017f) + // Matchers.arrayContaining(594.113831f, 5.14728308f, 84.0494843f, 286.714783f, 167.523376f, + // 50.6789017f) Matchers.arrayContaining(601.3333f, 5.150639f, 83.26706f, 287.04187f, 167.69823f, 50.955967f) ); assertThat( @@ -122,13 +124,15 @@ void testGrowUsingNoSpeciesDynamics() throws ProcessingException { assertThat( slice(lps.getBank().basalAreas, UtilizationClass.ALL), // Results from VDYP7: - // Matchers.arrayContaining(45.7382965f, 0.410145015f, 5.13646269f, 29.8279209f, 5.91424417f, 4.44952154f) + // Matchers.arrayContaining(45.7382965f, 0.410145015f, 5.13646269f, 29.8279209f, 5.91424417f, + // 4.44952154f) Matchers.arrayContaining(45.38645f, 0.410145f, 5.1364527f, 29.827932f, 5.914244f, 4.449532f) ); assertThat( slice(lps.getBank().treesPerHectare, UtilizationClass.ALL), // Results from VDYP7: - // Matchers.arrayContaining(594.113831f, 5.15917826f, 83.2853012f, 287.107758f, 167.558533f, 51.0030174f) + // Matchers.arrayContaining(594.113831f, 5.15917826f, 83.2853012f, 287.107758f, 167.558533f, + // 51.0030174f) Matchers.arrayContaining(601.3333f, 5.149199f, 83.2853f, 287.09778f, 167.54855f, 50.99304f) ); assertThat( @@ -157,7 +161,6 @@ void testGrowUsingFullSpeciesDynamics() throws ProcessingException { float tphStart = 601.373718f; float lhStart = 30.9723663f; - fpe.fps.fcm.getDebugSettings().setValue(Vars.SPECIES_DYNAMICS_1, 0); fpe.growUsingFullSpeciesDynamics(baStart, baDelta, dqStart, dqDelta, tphStart, lhStart); @@ -173,7 +176,8 @@ void testGrowUsingFullSpeciesDynamics() throws ProcessingException { assertThat( slice(lps.getBank().treesPerHectare, UtilizationClass.ALL), // Results from VDYP7: - // Matchers.arrayContaining(594.113831f, 5.07865763f, 82.9379883f, 288.292511f, 167.419479f, 50.3814774f) + // Matchers.arrayContaining(594.113831f, 5.07865763f, 82.9379883f, 288.292511f, 167.419479f, + // 50.3814774f) Matchers.arrayContaining(601.3333f, 5.151279f, 84.45613f, 292.43683f, 171.47192f, 51.14954f) ); assertThat( From f3ddda11492e9ef62755d31eab9bcde63336c3f0 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 4 Sep 2024 11:16:02 -0700 Subject: [PATCH 46/66] Add test for Grow, step 6 --- .../vdyp/forward/ForwardProcessingEngine.java | 12 ++++ ...=> CalculateLoreyHeightEstimatesTest.java} | 8 +-- .../vdyp/forward/ForwardProcessorTest.java | 17 +++-- ...Test.java => Grow5SpeciesBaDqTphTest.java} | 10 +-- .../forward/Grow6TreesPerHectareTest.java | 67 +++++++++++++++++++ 5 files changed, 98 insertions(+), 16 deletions(-) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{GrowLoreyHeightsTest.java => CalculateLoreyHeightEstimatesTest.java} (94%) rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/{GrowBaDqTphTest.java => Grow5SpeciesBaDqTphTest.java} (96%) create mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index c0c13210f..3a8848263 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -114,6 +114,7 @@ public enum ExecutionStep { GROW_2_LAYER_BADELTA, // GROW_3_LAYER_DQDELTA, // GROW_4_LAYER_BA_AND_DQTPH_EST, // + GROW_5A_LH_EST, // GROW_5_SPECIES_BADQTPH, // GROW_6_LAYER_TPH2, // GROW_7_LAYER_DQ2, // @@ -453,6 +454,9 @@ private void grow( bank.loreyHeights[0][UC_ALL_INDEX] = sum1 / sum2; + if (ExecutionStep.GROW_5A_LH_EST.eq(lastStepInclusive)) + return; + // Now do the actual per-species updates of ba, qmd and tph, based in part // on both the starting Lorey Heights and the estimated Lorey Heights at the // end of the growth period. @@ -493,6 +497,14 @@ private void grow( tphEndSum += bank.treesPerHectare[i][UC_ALL_INDEX]; } } + + if (tphEndSum < 0.0f) { + throw new ProcessingException( + MessageFormat.format( + "During processing of {0}, trees-per-hectare was calculated to be negative ({1})", + lps.getPolygon().getLayers().get(LayerType.PRIMARY), tphEndSum)); + } + bank.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; if (ExecutionStep.GROW_6_LAYER_TPH2.eq(lastStepInclusive)) diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateLoreyHeightEstimatesTest.java similarity index 94% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateLoreyHeightEstimatesTest.java index 090b6e747..9069c2ab9 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowLoreyHeightsTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/CalculateLoreyHeightEstimatesTest.java @@ -23,9 +23,9 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; -class GrowLoreyHeightsTest { +class CalculateLoreyHeightEstimatesTest { - protected static final Logger logger = LoggerFactory.getLogger(GrowLoreyHeightsTest.class); + protected static final Logger logger = LoggerFactory.getLogger(CalculateLoreyHeightEstimatesTest.class); protected static ForwardControlParser parser; protected static Map controlMap; @@ -56,7 +56,7 @@ void testStandardPath() throws ProcessingException { // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + fpe.processPolygon(polygon, ExecutionStep.GROW_5A_LH_EST.predecessor()); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); float dhStart = 35.3f; @@ -84,7 +84,7 @@ void testDebug8Setting2Path() throws ProcessingException { // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - fpe.processPolygon(polygon, ExecutionStep.GROW.predecessor()); + fpe.processPolygon(polygon, ExecutionStep.GROW_5A_LH_EST.predecessor()); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); float dhStart = 35.3f; diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index fb85de101..3b0762380 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -51,15 +51,18 @@ void test() throws IOException, ResourceParseException, ProcessingException { Path zipFile = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); Files.deleteIfExists(zipFile); - outputResolver.generate(zipFile); + try { + outputResolver.generate(zipFile); - InputStream os = outputResolver.generateStream(); + InputStream os = outputResolver.generateStream(); - byte[] zipFileBytes = Files.readAllBytes(zipFile); - byte[] zipStreamBytes = os.readAllBytes(); - - assertTrue(zipFileBytes.length == zipStreamBytes.length); - assertTrue(Arrays.equals(zipFileBytes, zipStreamBytes)); + byte[] zipFileBytes = Files.readAllBytes(zipFile); + byte[] zipStreamBytes = os.readAllBytes(); + assertTrue(zipFileBytes.length == zipStreamBytes.length); + assertTrue(Arrays.equals(zipFileBytes, zipStreamBytes)); + } finally { + Files.delete(zipFile); + } } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow5SpeciesBaDqTphTest.java similarity index 96% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow5SpeciesBaDqTphTest.java index fa66df22b..078dbfecc 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GrowBaDqTphTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow5SpeciesBaDqTphTest.java @@ -23,9 +23,9 @@ import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.VdypPolygon; -class GrowBaDqTphTest { +class Grow5SpeciesBaDqTphTest { - protected static final Logger logger = LoggerFactory.getLogger(GrowBaDqTphTest.class); + protected static final Logger logger = LoggerFactory.getLogger(Grow5SpeciesBaDqTphTest.class); protected static ForwardControlParser parser; protected static Map controlMap; @@ -56,7 +56,7 @@ void testStandardPath() throws ProcessingException { // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + fpe.processPolygon(polygon, ExecutionStep.GROW_5A_LH_EST); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); float baStart = 45.3864441f; @@ -109,7 +109,7 @@ void testGrowUsingNoSpeciesDynamics() throws ProcessingException { // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + fpe.processPolygon(polygon, ExecutionStep.GROW_4_LAYER_BA_AND_DQTPH_EST); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); float baChangeRate = 0.00775236264f; @@ -151,7 +151,7 @@ void testGrowUsingFullSpeciesDynamics() throws ProcessingException { // Select the first polygon - 01002 S000001 00(1970) VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); - fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + fpe.processPolygon(polygon, ExecutionStep.GROW_4_LAYER_BA_AND_DQTPH_EST); LayerProcessingState lps = fpe.fps.getLayerProcessingState(); float baStart = 45.3864441f; diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java new file mode 100644 index 000000000..63a61db99 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java @@ -0,0 +1,67 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.common.ControlKey; +import ca.bc.gov.nrs.vdyp.forward.ForwardProcessingEngine.ExecutionStep; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; +import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; +import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.VdypPolygon; + +class Grow6TreesPerHectareTest { + + protected static final Logger logger = LoggerFactory.getLogger(Grow6TreesPerHectareTest.class); + + protected static ForwardControlParser parser; + protected static Map controlMap; + + protected static StreamingParserFactory polygonDescriptionStreamFactory; + protected static StreamingParser polygonDescriptionStream; + + protected static ForwardDataStreamReader forwardDataStreamReader; + + @SuppressWarnings("unchecked") + @BeforeEach + void beforeTest() throws IOException, ResourceParseException, ProcessingException { + parser = new ForwardControlParser(); + controlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + + polygonDescriptionStreamFactory = (StreamingParserFactory) controlMap + .get(ControlKey.FORWARD_INPUT_GROWTO.name()); + polygonDescriptionStream = polygonDescriptionStreamFactory.get(); + + forwardDataStreamReader = new ForwardDataStreamReader(controlMap); + } + + @Test + void testStandardPath() throws ProcessingException { + + ForwardProcessingEngine fpe = new ForwardProcessingEngine(controlMap); + + // Select the first polygon - 01002 S000001 00(1970) + VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); + + fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); + + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); + + var calculatedLayerTph = lps.getBank().treesPerHectare[0][UtilizationClass.ALL.ordinal()]; + + // VDYP7 value is 594.113811 + assertThat(calculatedLayerTph, is(601.3333f)); + } +} From 1085140a0340093b81550ecea502a882ef135723 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Wed, 4 Sep 2024 11:43:47 -0700 Subject: [PATCH 47/66] Sonarcube quality checks --- .../ca/bc/gov/nrs/vdyp/common/ComputationMethods.java | 10 ++++++---- .../ca/bc/gov/nrs/vdyp/common/EstimationMethods.java | 2 +- .../java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 5 +++++ .../java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java | 5 +++++ .../java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java | 5 +++++ .../java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java | 5 +++++ .../gov/nrs/vdyp/forward/ForwardProcessingEngine.java | 2 +- .../nrs/vdyp/forward/LambdaProcessingException.java | 2 +- 8 files changed, 29 insertions(+), 7 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java index 886521dc5..012ed46d6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java @@ -180,10 +180,12 @@ public void computeUtilizationComponentsPrimary( ); } - float baMult = basalAreaUtil.get(UtilizationClass.ALL) / basalAreaSumForSpecies; - - for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { - basalAreaUtil.set(uc, basalAreaUtil.get(uc) * baMult); + if (basalAreaSumForSpecies > 0.0f) { + float baMult = basalAreaUtil.get(UtilizationClass.ALL) / basalAreaSumForSpecies; + + for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { + basalAreaUtil.set(uc, basalAreaUtil.get(uc) * baMult); + } } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index 488912381..781e4c01f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -829,7 +829,7 @@ public float estimateBaseAreaYield( float ageToUse = breastHeightAge; if (controlVariable2Setting > 0) { - ageToUse = Math.min(ageToUse, controlVariable2Setting * 100); + ageToUse = Math.min(ageToUse, controlVariable2Setting * 100f); } if (ageToUse <= 0f) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index 408abf02f..77f1bffb3 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -95,6 +95,11 @@ public boolean equals(Object other) { } } + @Override + public int hashCode() { + return polygonIdentifier.hashCode() * 17 + layerType.hashCode(); + } + public abstract static class Builder, S extends BaseVdypSpecies, I extends BaseVdypSite, SB extends BaseVdypSpecies.Builder, IB extends BaseVdypSite.Builder> extends ModelClassBuilder { protected Optional polygonIdentifier = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java index 01e9a6431..08fe959c8 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java @@ -130,6 +130,11 @@ public boolean equals(Object other) { } } + @Override + public int hashCode() { + return polygonIdentifier.hashCode(); + } + protected abstract static class Builder< // T extends BaseVdypPolygon, // L extends BaseVdypLayer, // diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java index f59d507e3..b24d86e0b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java @@ -88,6 +88,11 @@ public boolean equals(Object other) { } } + @Override + public int hashCode() { + return (polygonIdentifier.hashCode() * 17 + layerType.hashCode()) * 17 + siteGenus.hashCode(); + } + public abstract static class Builder extends ModelClassBuilder { protected Optional polygonIdentifier = Optional.empty(); protected Optional layerType = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 613695604..5069d4500 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -104,6 +104,11 @@ public boolean equals(Object other) { } } + @Override + public int hashCode() { + return (polygonIdentifier.hashCode() * 17 + layerType.hashCode()) * 17 + genus.hashCode(); + } + /** * Construct the species sp64DistributionSet from the given list of species percentages. The maxIndex of the Set is * taken to be the size of the map, and the index of each sp64Distribution is set to be its position in the list diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 3a8848263..e3fc8f471 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -91,7 +91,7 @@ public class ForwardProcessingEngine { public ForwardProcessingEngine(Map controlMap, Optional outputWriter) throws ProcessingException { this.fps = new ForwardProcessingState(controlMap); - this.outputWriter = outputWriter == null ? Optional.empty() : outputWriter; + this.outputWriter = outputWriter; } public ForwardProcessingEngine(Map controlMap) throws ProcessingException { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java index 1271cc27c..8dc32f437 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java @@ -11,7 +11,7 @@ public LambdaProcessingException(ProcessingException e) { } @Override - public ProcessingException getCause() { + public synchronized ProcessingException getCause() { return (ProcessingException) super.getCause(); } } From 562afd71635ca4773757be8b45ce81901ad8b34b Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 13:20:40 -0700 Subject: [PATCH 48/66] Added tests of UtilizationOperations and ForwardControlMapTest class --- .../CachingResolvedControlMapImpl.java | 4 - .../vdyp/controlmap/ResolvedControlMap.java | 2 +- .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 23 +-- .../gov/nrs/vdyp/model/BaseVdypPolygon.java | 42 ++--- .../bc/gov/nrs/vdyp/model/BaseVdypSite.java | 24 +-- .../gov/nrs/vdyp/model/BaseVdypSpecies.java | 36 ++-- .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 74 +++++++- .../ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 8 +- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 86 +++++++-- .../bc/gov/nrs/vdyp/common/ReferenceTest.java | 24 +++ .../bc/gov/nrs/vdyp/model/VdypSiteTest.java | 63 +++++-- .../gov/nrs/vdyp/model/VdypSpeciesTest.java | 60 +++++-- .../vdyp/forward/ForwardDataStreamReader.java | 1 - .../vdyp/forward}/UtilizationOperations.java | 13 +- .../ForwardResolvedControlMapImpl.java | 36 ++-- .../forward/UtilizationOperationsTest.java | 166 ++++++++++++++++++ .../controlmap/ForwardControlMapTest.java | 130 ++++++++++++++ 17 files changed, 658 insertions(+), 134 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java rename vdyp-lib/{vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common => vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward}/UtilizationOperations.java (96%) create mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java create mode 100644 vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index 1dd9ee223..e3f9249b5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -221,10 +221,6 @@ public MatrixMap3> ge return hlNonPrimaryCoefficients; } - public Map getBreakageMap() { - return breakageMap; - } - @Override public MatrixMap2 getComponentSizeLimits() { return componentSizeLimitCoefficients; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index 54a8d29be..a884a6efb 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -88,7 +88,7 @@ public interface ResolvedControlMap { /** 92 - CLOSE_UTIL_VOLUME */ MatrixMap2> getCloseUtilizationCoeMap(); - + /** 93 - VOLUME_NET_DECAY */ MatrixMap2> getNetDecayCoeMap(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index 77f1bffb3..b956221f9 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -17,9 +17,10 @@ public abstract class BaseVdypLayer, I extends Base private final PolygonIdentifier polygonIdentifier; private final LayerType layerType; + private Optional inventoryTypeGroup = Optional.empty(); + private LinkedHashMap speciesBySp0 = new LinkedHashMap<>(); private HashMap speciesByIndex = new HashMap<>(); - private Optional inventoryTypeGroup = Optional.empty(); protected BaseVdypLayer( PolygonIdentifier polygonIdentifier, LayerType layerType, Optional inventoryTypeGroup @@ -159,21 +160,21 @@ public Builder inventoryTypeGroup(Optional inventoryTy return this; } - public Builder adapt(BaseVdypLayer toCopy) { - polygonIdentifier(toCopy.getPolygonIdentifier()); - layerType(toCopy.getLayerType()); - inventoryTypeGroup(toCopy.getInventoryTypeGroup()); + public Builder adapt(BaseVdypLayer source) { + polygonIdentifier(source.getPolygonIdentifier()); + layerType(source.getLayerType()); + inventoryTypeGroup(source.getInventoryTypeGroup()); return this; } - public Builder copy(T toCopy) { - adapt(toCopy); + public Builder copy(T source) { + adapt(source); return this; } public , I2 extends BaseVdypSite> Builder - adaptSpecies(BaseVdypLayer toCopy, BiConsumer config) { - toCopy.getSpecies().values().forEach(speciesToCopy -> { + adaptSpecies(BaseVdypLayer source, BiConsumer config) { + source.getSpecies().values().forEach(speciesToCopy -> { this.addSpecies(builder -> { builder.adapt(speciesToCopy); builder.polygonIdentifier = Optional.empty(); @@ -184,8 +185,8 @@ public Builder copy(T toCopy) { return this; } - public Builder copySpecies(T toCopy, BiConsumer config) { - toCopy.getSpecies().values().forEach(speciesToCopy -> { + public Builder copySpecies(T source, BiConsumer config) { + source.getSpecies().values().forEach(speciesToCopy -> { this.addSpecies(builder -> { builder.copy(speciesToCopy); builder.polygonIdentifier = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java index 08fe959c8..82623075f 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypPolygon.java @@ -41,16 +41,16 @@ protected BaseVdypPolygon( * * @param Type of the polygon to copy * @param Type of percent available in the other polygon - * @param toCopy The polygon to copy + * @param source The polygon to copy * @param convertPercentAvailable Function to convert */ protected , U> BaseVdypPolygon( - O toCopy, Function convertPercentAvailable + O source, Function convertPercentAvailable ) { this( - toCopy.getPolygonIdentifier(), convertPercentAvailable.apply(toCopy.getPercentAvailable()), - toCopy.getForestInventoryZone(), toCopy.getBiogeoclimaticZone(), toCopy.getMode(), - toCopy.getInventoryTypeGroup() + source.getPolygonIdentifier(), convertPercentAvailable.apply(source.getPercentAvailable()), + source.getForestInventoryZone(), source.getBiogeoclimaticZone(), source.getMode(), + source.getInventoryTypeGroup() ); } @@ -229,27 +229,27 @@ protected L buildLayer(Consumer specConfig) { protected abstract LB getLayerBuilder(); public Builder - adapt(BaseVdypPolygon toCopy, Function paConvert) { - polygonIdentifier(toCopy.getPolygonIdentifier()); - percentAvailable(paConvert.apply(toCopy.getPercentAvailable())); - biogeoclimaticZone(toCopy.getBiogeoclimaticZone()); - forestInventoryZone(toCopy.getForestInventoryZone()); - mode(toCopy.getMode()); + adapt(BaseVdypPolygon source, Function paConvert) { + polygonIdentifier(source.getPolygonIdentifier()); + percentAvailable(paConvert.apply(source.getPercentAvailable())); + biogeoclimaticZone(source.getBiogeoclimaticZone()); + forestInventoryZone(source.getForestInventoryZone()); + mode(source.getMode()); return this; } - public Builder copy(T toCopy) { - polygonIdentifier(toCopy.getPolygonIdentifier()); - percentAvailable(toCopy.getPercentAvailable()); - biogeoclimaticZone(toCopy.getBiogeoclimaticZone()); - forestInventoryZone(toCopy.getForestInventoryZone()); - mode(toCopy.getMode()); + public Builder copy(T source) { + polygonIdentifier(source.getPolygonIdentifier()); + percentAvailable(source.getPercentAvailable()); + biogeoclimaticZone(source.getBiogeoclimaticZone()); + forestInventoryZone(source.getForestInventoryZone()); + mode(source.getMode()); return this; } public > Builder - adaptLayers(BaseVdypPolygon toCopy, BiConsumer layerConfig) { - toCopy.getLayers().values().forEach(layer -> { + adaptLayers(BaseVdypPolygon source, BiConsumer layerConfig) { + source.getLayers().values().forEach(layer -> { this.addLayer(lBuilder -> { lBuilder.adapt(layer); lBuilder.polygonIdentifier = Optional.empty(); @@ -259,8 +259,8 @@ public Builder copy(T toCopy) { return this; } - public Builder copyLayers(T toCopy, BiConsumer layerConfig) { - toCopy.getLayers().values().forEach(layer -> { + public Builder copyLayers(T source, BiConsumer layerConfig) { + source.getLayers().values().forEach(layer -> { this.addLayer(lBuilder -> { lBuilder.copy(layer); lBuilder.polygonIdentifier = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java index b24d86e0b..d32ba6e87 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSite.java @@ -74,7 +74,7 @@ public Optional getYearsAtBreastHeight() { @Override public String toString() { - return polygonIdentifier.toStringCompact() + "-" + layerType + "-" + siteGenus; + return MessageFormat.format("{0}-{1}-{2}", polygonIdentifier.toStringCompact(), layerType, siteGenus); } @Override @@ -180,20 +180,20 @@ public Builder yearsToBreastHeight(float yearsToBreastHeight) { return yearsToBreastHeight(Optional.of(yearsToBreastHeight)); } - public Builder adapt(BaseVdypSite toCopy) { - polygonIdentifier(toCopy.getPolygonIdentifier()); - layerType(toCopy.getLayerType()); - ageTotal(toCopy.getAgeTotal()); - yearsToBreastHeight(toCopy.getYearsToBreastHeight()); - height(toCopy.getHeight()); - siteIndex(toCopy.getSiteIndex()); - siteCurveNumber(toCopy.getSiteCurveNumber()); - siteGenus(toCopy.getSiteGenus()); + public Builder adapt(BaseVdypSite source) { + polygonIdentifier(source.getPolygonIdentifier()); + layerType(source.getLayerType()); + ageTotal(source.getAgeTotal()); + yearsToBreastHeight(source.getYearsToBreastHeight()); + height(source.getHeight()); + siteIndex(source.getSiteIndex()); + siteCurveNumber(source.getSiteCurveNumber()); + siteGenus(source.getSiteGenus()); return this; } - public Builder copy(T toCopy) { - return adapt(toCopy); + public Builder copy(T source) { + return adapt(source); } @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java index 5069d4500..57df2b904 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypSpecies.java @@ -90,7 +90,7 @@ public Sp64DistributionSet getSp64DistributionSet() { @Override public String toString() { - return MessageFormat.format("{0} {1} {2}", polygonIdentifier, layerType, genus); + return MessageFormat.format("{0}-{1}-{2}", polygonIdentifier.toStringCompact(), layerType, genus); } @Override @@ -235,8 +235,8 @@ public Builder sp64DistributionSet(Sp64DistributionSet sp64Distributio return this; } - public Builder copy(T toCopy) { - return this.adapt(toCopy); + public Builder copy(T source) { + return this.adapt(source); } public Builder addSite(Consumer config) { @@ -296,48 +296,48 @@ protected String getBuilderId() { ); } - public Builder adapt(BaseVdypSpecies toCopy) { - polygonIdentifier(toCopy.getPolygonIdentifier()); - layerType(toCopy.getLayerType()); - genus(toCopy.getGenus(), toCopy.getGenusIndex()); - percentGenus(toCopy.getPercentGenus()); + public Builder adapt(BaseVdypSpecies source) { + polygonIdentifier(source.getPolygonIdentifier()); + layerType(source.getLayerType()); + genus(source.getGenus(), source.getGenusIndex()); + percentGenus(source.getPercentGenus()); - fractionGenus(toCopy.getFractionGenus()); + fractionGenus(source.getFractionGenus()); - sp64DistributionList(toCopy.getSp64DistributionSet().getSp64DistributionList()); + sp64DistributionList(source.getSp64DistributionSet().getSp64DistributionList()); return this; } - public Builder adaptSite(I2 toCopy, BiConsumer config) { + public Builder adaptSite(I2 source, BiConsumer config) { this.addSite(builder -> { - builder.adapt(toCopy); + builder.adapt(source); builder.polygonIdentifier = Optional.empty(); builder.layerType = Optional.empty(); - config.accept(builder, toCopy); + config.accept(builder, source); }); return this; } public , I2 extends BaseVdypSite> Builder adaptSiteFrom(S2 specToCopy, BiConsumer config) { - specToCopy.getSite().ifPresent(toCopy -> this.adaptSite(toCopy, config)); + specToCopy.getSite().ifPresent(source -> this.adaptSite(source, config)); return this; } - public Builder copySite(I toCopy, BiConsumer config) { + public Builder copySite(I source, BiConsumer config) { this.addSite(builder -> { - builder.copy(toCopy); + builder.copy(source); builder.siteGenus = Optional.empty(); builder.polygonIdentifier = Optional.empty(); builder.layerType = Optional.empty(); - config.accept(builder, toCopy); + config.accept(builder, source); }); return this; } public Builder copySiteFrom(T specToCopy, BiConsumer config) { - specToCopy.getSite().ifPresent(toCopy -> this.copySite(toCopy, config)); + specToCopy.getSite().ifPresent(source -> this.copySite(source, config)); return this; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 23037c039..22e4968fd 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -231,8 +231,8 @@ public void treesPerHectare(float height) { protected UtilizationVector quadMeanDiameter = VdypUtilizationHolder.emptyUtilization(); - public void quadMeanDiameter(float small, float u1, float u2, float u3, float u4) { - this.quadMeanDiameter = Utils.utilizationVector(small, u1, u2, u3, u4); + public void quadMeanDiameter(float small, float uAll, float u1, float u2, float u3, float u4) { + this.quadMeanDiameter = Utils.utilizationVector(small, uAll, u1, u2, u3, u4); } public void quadMeanDiameter(float height) { @@ -249,14 +249,78 @@ public void wholeStemVolume(float volume) { this.wholeStemVolume = Utils.utilizationVector(volume); } + protected UtilizationVector closeUtilizationVolumeByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeByUtilization(float volume) { + this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(volume); + } + + protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeNetOfDecayByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeNetOfDecayByUtilization(float volume) { + this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(volume); + } + + protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float volume) { + this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(volume); + } + + protected UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float volume) { + this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(volume); + } + + @Override + public VdypLayer.Builder adapt(BaseVdypLayer baseSource) { + super.adapt(baseSource); + + if (baseSource instanceof VdypLayer source) { + loreyHeight = new UtilizationVector(source.loreyHeightByUtilization); + baseArea = new UtilizationVector(source.baseAreaByUtilization); + treesPerHectare = new UtilizationVector(source.treesPerHectareByUtilization); + quadMeanDiameter = new UtilizationVector(source.quadraticMeanDiameterByUtilization); + wholeStemVolume = new UtilizationVector(source.wholeStemVolumeByUtilization); + closeUtilizationVolumeByUtilization = new UtilizationVector(source.closeUtilizationVolumeByUtilization); + closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayByUtilization); + closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayAndWasteByUtilization); + closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization); + } + + return this; + } + @Override protected void postProcess(VdypLayer layer) { super.postProcess(layer); + layer.setLoreyHeightByUtilization(loreyHeight); layer.setBaseAreaByUtilization(baseArea); layer.setTreesPerHectareByUtilization(treesPerHectare); layer.setQuadraticMeanDiameterByUtilization(quadMeanDiameter); layer.setWholeStemVolumeByUtilization(wholeStemVolume); + layer.setCloseUtilizationVolumeByUtilization(closeUtilizationVolumeByUtilization); + layer.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationNetVolumeOfDecayByUtilization); + layer.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(closeUtilizationVolumeNetOfDecayAndWasteByUtilization); + layer.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization);; } @Override @@ -277,11 +341,5 @@ protected VdypSpecies buildSpecies(Consumer config) { builder.layerType(this.layerType.get()); }); } - - public void baseAreaByUtilization(UtilizationVector utilizationVector) { - // TODO Auto-generated method stub - - } - } } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index 0df19ce8d..c6e8d387c 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -30,14 +30,14 @@ public VdypPolygon( * * @param Type of the polygon to copy * @param Type of percent available in the other polygon - * @param toCopy The polygon to copy + * @param source The polygon to copy * @param convertPercentAvailable Function to convert */ public , U> VdypPolygon( - O toCopy, Function convertPercentAvailable + O source, Function convertPercentAvailable ) { - super(toCopy, convertPercentAvailable); - if (toCopy instanceof VdypPolygon vdypPolygonToCopy) { + super(source, convertPercentAvailable); + if (source instanceof VdypPolygon vdypPolygonToCopy) { this.targetYear = vdypPolygonToCopy.getTargetYear(); } else { this.targetYear = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index 343bbbab1..b15a47ead 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -19,7 +19,7 @@ public class VdypSpecies extends BaseVdypSpecies implements VdypUtiliz private UtilizationVector wholeStemVolumeByUtilization = Utils.utilizationVector(); // LVCOM/VOLWS private UtilizationVector closeUtilizationVolumeByUtilization = Utils.utilizationVector(); // LVCOM/VOLCU - private UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(); // LVCOM/VOL_D + private UtilizationVector closeUtilizationVolumeNetOfDecayByUtilization = Utils.utilizationVector(); // LVCOM/VOL_D private UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(); // LVCOM/VOL_DW private UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(); // LVCOM/VOL_DWB @@ -163,14 +163,14 @@ public void setCloseUtilizationVolumeByUtilization(UtilizationVector closeUtiliz @Override public UtilizationVector getCloseUtilizationVolumeNetOfDecayByUtilization() { - return closeUtilizationNetVolumeOfDecayByUtilization; + return closeUtilizationVolumeNetOfDecayByUtilization; } @Override public void setCloseUtilizationVolumeNetOfDecayByUtilization( UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization ) { - this.closeUtilizationNetVolumeOfDecayByUtilization = closeUtilizationNetVolumeOfDecayByUtilization; + this.closeUtilizationVolumeNetOfDecayByUtilization = closeUtilizationNetVolumeOfDecayByUtilization; } @Override @@ -317,8 +317,8 @@ public void treesPerHectare(float height) { protected UtilizationVector quadMeanDiameter = VdypUtilizationHolder.emptyUtilization(); - public void quadMeanDiameter(float small, float u1, float u2, float u3, float u4) { - this.quadMeanDiameter = Utils.utilizationVector(small, u1, u2, u3, u4); + public void quadMeanDiameter(float small, float uAll, float u1, float u2, float u3, float u4) { + this.quadMeanDiameter = Utils.utilizationVector(small, uAll, u1, u2, u3, u4); } public void quadMeanDiameter(float height) { @@ -335,28 +335,94 @@ public void wholeStemVolume(float volume) { this.wholeStemVolume = Utils.utilizationVector(volume); } + protected UtilizationVector closeUtilizationVolumeByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeByUtilization(float volume) { + this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(volume); + } + + protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeNetOfDecayByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeNetOfDecayByUtilization(float volume) { + this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(volume); + } + + protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float volume) { + this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(volume); + } + + protected UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = VdypUtilizationHolder.emptyUtilization(); + + public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float small, float u1, float u2, float u3, float u4) { + this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + } + + public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float volume) { + this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(volume); + } + @Override protected void check(Collection errors) { super.check(errors); } @Override - public Builder copy(VdypSpecies toCopy) { - super.copy(toCopy); - volumeGroup(toCopy.getVolumeGroup()); - decayGroup(toCopy.getDecayGroup()); - breakageGroup(toCopy.getBreakageGroup()); + public VdypSpecies.Builder adapt(BaseVdypSpecies baseSource) { + super.adapt(baseSource); + + if (baseSource instanceof VdypSpecies source) { + loreyHeight = new UtilizationVector(source.loreyHeightByUtilization); + baseArea = new UtilizationVector(source.baseAreaByUtilization); + treesPerHectare = new UtilizationVector(source.treesPerHectareByUtilization); + quadMeanDiameter = new UtilizationVector(source.quadraticMeanDiameterByUtilization); + wholeStemVolume = new UtilizationVector(source.wholeStemVolumeByUtilization); + closeUtilizationVolumeByUtilization = new UtilizationVector(source.closeUtilizationVolumeByUtilization); + closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayByUtilization); + closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayAndWasteByUtilization); + closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization); + } + + return this; + } + + @Override + public Builder copy(VdypSpecies source) { + super.copy(source); + + source.volumeGroup.ifPresent(vg -> volumeGroup(vg)); + source.decayGroup.ifPresent(dg -> decayGroup(dg)); + source.breakageGroup.ifPresent(bg -> breakageGroup(bg)); + return this; } @Override protected void postProcess(VdypSpecies spec) { super.postProcess(spec); + spec.setLoreyHeightByUtilization(loreyHeight); spec.setBaseAreaByUtilization(baseArea); spec.setTreesPerHectareByUtilization(treesPerHectare); spec.setQuadraticMeanDiameterByUtilization(quadMeanDiameter); spec.setWholeStemVolumeByUtilization(wholeStemVolume); + spec.setCloseUtilizationVolumeByUtilization(closeUtilizationVolumeByUtilization); + spec.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationNetVolumeOfDecayByUtilization); + spec.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(closeUtilizationVolumeNetOfDecayAndWasteByUtilization); + spec.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization);; } @Override diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java new file mode 100644 index 000000000..72425e1e1 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java @@ -0,0 +1,24 @@ +package ca.bc.gov.nrs.vdyp.common; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +public class ReferenceTest { + + @Test + void testReference() { + + var reference = new Reference(3); + assertThat(reference.get(), Matchers.is(Integer.valueOf(3))); + assertThat(reference.isPresent(), Matchers.is(true)); + reference.set(4); + assertThat(reference.get(), Matchers.is(Integer.valueOf(4))); + + var reference2 = new Reference(); + assertThat(reference2.isPresent(), Matchers.is(false)); + assertThrows(IllegalStateException.class, () -> reference2.get()); + } +} diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java index 7a6b8ca8a..81ea13a39 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java @@ -16,7 +16,7 @@ class VdypSiteTest { @Test void build() throws Exception { - var result = VdypSite.build(builder -> { + var site1 = VdypSite.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); builder.ageTotal(35.0f); @@ -26,15 +26,58 @@ void build() throws Exception { builder.siteIndex(42.5f); builder.yearsToBreastHeight(5.0f); }); - assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); - assertThat(result, hasProperty("layerType", is(LayerType.PRIMARY))); - assertThat(result, hasProperty("ageTotal", is(Optional.of(35.0f)))); - assertThat(result, hasProperty("height", is(Optional.of(53.0f)))); - assertThat(result, hasProperty("siteCurveNumber", is(Optional.of(22)))); - assertThat(result, hasProperty("siteGenus", is("B"))); - assertThat(result, hasProperty("siteIndex", is(Optional.of(42.5f)))); - assertThat(result, hasProperty("yearsToBreastHeight", is(Optional.of(5.0f)))); - assertThat(result, hasProperty("yearsAtBreastHeight", is(Optional.of(30.0f)))); + assertThat(site1, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(site1, hasProperty("layerType", is(LayerType.PRIMARY))); + assertThat(site1, hasProperty("ageTotal", is(Optional.of(35.0f)))); + assertThat(site1, hasProperty("height", is(Optional.of(53.0f)))); + assertThat(site1, hasProperty("siteCurveNumber", is(Optional.of(22)))); + assertThat(site1, hasProperty("siteGenus", is("B"))); + assertThat(site1, hasProperty("siteIndex", is(Optional.of(42.5f)))); + assertThat(site1, hasProperty("yearsToBreastHeight", is(Optional.of(5.0f)))); + assertThat(site1, hasProperty("yearsAtBreastHeight", is(Optional.of(30.0f)))); + + assertThat(site1.toString(), is("Test(2024)-PRIMARY-B")); + assertThat(site1.hashCode(), is(1134087689)); + assertThat(site1.equals(site1), is(true)); + + var site2 = VdypSite.build(builder -> { + builder.polygonIdentifier("Test2", 2024); + builder.layerType(LayerType.PRIMARY); + builder.ageTotal(35.0f); + builder.height(53.0f); + builder.siteCurveNumber(22); + builder.siteGenus("B"); + builder.siteIndex(42.5f); + builder.yearsToBreastHeight(5.0f); + }); + + assertThat(site1.equals(site2), is(false)); + + var site3 = VdypSite.build(builder -> { + builder.polygonIdentifier("Test", 2024); + builder.layerType(LayerType.PRIMARY); + builder.ageTotal(35.0f); + builder.height(53.0f); + builder.siteCurveNumber(22); + builder.siteGenus("C"); + builder.siteIndex(42.5f); + builder.yearsToBreastHeight(5.0f); + }); + + assertThat(site1.equals(site3), is(false)); + + var site4 = VdypSite.build(builder -> { + builder.polygonIdentifier("Test", 2024); + builder.layerType(LayerType.VETERAN); + builder.ageTotal(35.0f); + builder.height(53.0f); + builder.siteCurveNumber(22); + builder.siteGenus("B"); + builder.siteIndex(42.5f); + builder.yearsToBreastHeight(5.0f); + }); + + assertThat(site1.equals(site4), is(false)); } @Test diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java index 08799f176..618ddafbd 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java @@ -17,7 +17,7 @@ class VdypSpeciesTest { @Test void build() throws Exception { - var result = VdypSpecies.build(builder -> { + var species1 = VdypSpecies.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); builder.genus("B", 3); @@ -26,15 +26,55 @@ void build() throws Exception { builder.decayGroup(2); builder.breakageGroup(3); }); - assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); - assertThat(result, hasProperty("layerType", is(LayerType.PRIMARY))); - assertThat(result, hasProperty("genus", is("B"))); - assertThat(result, hasProperty("percentGenus", is(50f))); - assertThat(result, hasProperty("volumeGroup", is(1))); - assertThat(result, hasProperty("decayGroup", is(2))); - assertThat(result, hasProperty("breakageGroup", is(3))); - assertThat(result, hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", anEmptyMap()))); - } + assertThat(species1, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(species1, hasProperty("layerType", is(LayerType.PRIMARY))); + assertThat(species1, hasProperty("genus", is("B"))); + assertThat(species1, hasProperty("percentGenus", is(50f))); + assertThat(species1, hasProperty("volumeGroup", is(1))); + assertThat(species1, hasProperty("decayGroup", is(2))); + assertThat(species1, hasProperty("breakageGroup", is(3))); + assertThat(species1, hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", anEmptyMap()))); + + assertThat(species1.toString(), is("Test(2024)-PRIMARY-B")); + assertThat(species1.hashCode(), is(-1947684965)); + assertThat(species1.equals(species1), is(true)); + + var species2 = VdypSpecies.build(builder -> { + builder.polygonIdentifier("Test2", 2024); + builder.layerType(LayerType.PRIMARY); + builder.genus("B", 3); + builder.percentGenus(50f); + builder.volumeGroup(1); + builder.decayGroup(2); + builder.breakageGroup(3); + }); + + assertThat(species1.equals(species2), is(false)); + + var species3 = VdypSpecies.build(builder -> { + builder.polygonIdentifier("Test", 2024); + builder.layerType(LayerType.PRIMARY); + builder.genus("D", 5); + builder.percentGenus(50f); + builder.volumeGroup(1); + builder.decayGroup(2); + builder.breakageGroup(3); + }); + + assertThat(species1.equals(species3), is(false)); + + var species4 = VdypSpecies.build(builder -> { + builder.polygonIdentifier("Test", 2024); + builder.layerType(LayerType.VETERAN); + builder.genus("B", 3); + builder.percentGenus(50f); + builder.volumeGroup(1); + builder.decayGroup(2); + builder.breakageGroup(3); + }); + + assertThat(species1.equals(species4), is(false)); + }; @Test void buildNoProperties() throws Exception { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java index 7bdac239d..8e66189cf 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardDataStreamReader.java @@ -13,7 +13,6 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.common.UtilizationOperations; import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMap; import ca.bc.gov.nrs.vdyp.forward.controlmap.ForwardResolvedControlMapImpl; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java similarity index 96% rename from vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java rename to vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java index f51172ead..911396d61 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/UtilizationOperations.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java @@ -1,4 +1,4 @@ -package ca.bc.gov.nrs.vdyp.common; +package ca.bc.gov.nrs.vdyp.forward; import java.text.MessageFormat; import java.util.ArrayList; @@ -66,7 +66,7 @@ public static void doPostCreateAdjustments(VdypPolygon polygon) throws Processin * * @param scalingFactor the factor by which the uh is to be scaled */ - public static void scale(VdypUtilizationHolder uh, float scalingFactor) { + private static void scale(VdypUtilizationHolder uh, float scalingFactor) { for (UtilizationClass uc : UtilizationClass.values()) { float basalArea = uh.getBaseAreaByUtilization().get(uc); @@ -77,8 +77,9 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { if (treesPerHectare > 0) { uh.getTreesPerHectareByUtilization().set(uc, treesPerHectare * scalingFactor); } - // lorey height is not a per-hectare value and therefore - // is excluded from scaling. + + // lorey height is not a per-hectare value and therefore is excluded from scaling. + float wholeStemVolume = uh.getWholeStemVolumeByUtilization().get(uc); if (wholeStemVolume > 0) { uh.getWholeStemVolumeByUtilization().set(uc, wholeStemVolume * scalingFactor); @@ -102,8 +103,8 @@ public static void scale(VdypUtilizationHolder uh, float scalingFactor) { uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() .set(uc, cuVolumeMinusDecayWastageBreakage * scalingFactor); } - // quadratic mean diameter is not a per-hectare value and - // therefore not scaled. + + // quadratic mean diameter is not a per-hectare value and therefore not scaled. } } diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java index ff4c0872a..752587436 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapImpl.java @@ -21,24 +21,24 @@ public class ForwardResolvedControlMapImpl extends CachingResolvedControlMapImpl implements ForwardResolvedControlMap { - final ForwardDebugSettings debugSettings; - final ForwardControlVariables forwardControlVariables; - final MatrixMap2 siteCurveMap; - final CompVarAdjustments compVarAdjustments; - final MatrixMap2 basalAreaYieldCoefficients; - final Map basalAreaGrowthFiatDetails; - final MatrixMap2 basalAreaGrowthEmpiricalCoefficients; - final MatrixMap3 upperBoundCoefficients; - final MatrixMap2 quadMeanDiameterYieldCoefficients; - final Map quadMeanDiameterGrowthFiatDetails; - final Map quadMeanDiameterGrowthEmpiricalCoefficients; - final Map quadMeanDiameterGrowthEmpiricalLimits; - final MatrixMap2 loreyHeightPrimarySpeciesEquationP1Coefficients; - final MatrixMap3> loreyHeightNonPrimaryCoefficients; - final Map primarySpeciesBasalAreaGrowthCoefficients; - final MatrixMap2> nonPrimarySpeciesBasalAreaGrowthCoefficients; - final Map primaryQuadMeanDiameterGrowthCoefficients; - final MatrixMap2> nonPrimaryQuadMeanDiameterGrowthCoefficients; + private final ForwardDebugSettings debugSettings; + private final ForwardControlVariables forwardControlVariables; + private final MatrixMap2 siteCurveMap; + private final CompVarAdjustments compVarAdjustments; + private final MatrixMap2 basalAreaYieldCoefficients; + private final Map basalAreaGrowthFiatDetails; + private final MatrixMap2 basalAreaGrowthEmpiricalCoefficients; + private final MatrixMap3 upperBoundCoefficients; + private final MatrixMap2 quadMeanDiameterYieldCoefficients; + private final Map quadMeanDiameterGrowthFiatDetails; + private final Map quadMeanDiameterGrowthEmpiricalCoefficients; + private final Map quadMeanDiameterGrowthEmpiricalLimits; + private final MatrixMap2 loreyHeightPrimarySpeciesEquationP1Coefficients; + private final MatrixMap3> loreyHeightNonPrimaryCoefficients; + private final Map primarySpeciesBasalAreaGrowthCoefficients; + private final MatrixMap2> nonPrimarySpeciesBasalAreaGrowthCoefficients; + private final Map primaryQuadMeanDiameterGrowthCoefficients; + private final MatrixMap2> nonPrimaryQuadMeanDiameterGrowthCoefficients; public ForwardResolvedControlMapImpl(Map controlMap) { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java new file mode 100644 index 000000000..922d11a37 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java @@ -0,0 +1,166 @@ +package ca.bc.gov.nrs.vdyp.forward; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.model.BecDefinition; +import ca.bc.gov.nrs.vdyp.model.LayerType; +import ca.bc.gov.nrs.vdyp.model.PolygonMode; +import ca.bc.gov.nrs.vdyp.model.Region; +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.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; +import ca.bc.gov.nrs.vdyp.test.TestUtils; + +class UtilizationOperationsTest { + + @Test + void testUtilizationOperations() throws Exception { + + var polyId = "TestPolygon1 2024"; + var species1Id = "D"; + var species2Id = "B"; + var forestInventoryZone = "A"; + + var coveringPercentage = 80.0f; + var scalingFactor = 100.0f / coveringPercentage; + + var polygon = VdypPolygon.build(pb -> { + pb.polygonIdentifier(polyId); + pb.biogeoclimaticZone(new BecDefinition("CWH", Region.COASTAL, "Coastal Western Hemlock")); + pb.forestInventoryZone(forestInventoryZone); + pb.inventoryTypeGroup(37); + pb.mode(PolygonMode.START); + pb.percentAvailable(coveringPercentage); + + pb.addLayer(VdypLayer.build(lb -> { + lb.polygonIdentifier(polyId); + lb.layerType(LayerType.PRIMARY); + lb.inventoryTypeGroup(1); + + lb.baseArea(0.01513f, 0.53100f, 1.27855f, 2.33020f, 40.79285f); + lb.treesPerHectare(5.24f, 64.82f, 71.93f, 73.60f, 384.98f); + lb.loreyHeight(7.0166f, 30.9724f); + lb.wholeStemVolume(0.0630f, 2.5979f, 9.1057f, 22.4019f, 586.8720f); + lb.quadMeanDiameter(6.1f, 31.0f, 10.2f, 15.0f, 20.1f, 36.7f); + lb.closeUtilizationVolumeByUtilization(0.0630f, 2.5979f, 9.1057f, 22.4019f, 586.8720f); + lb.closeUtilizationVolumeNetOfDecayByUtilization(0.0000f, 0.3794f, 6.8469f, 19.8884f, 553.0534f); + lb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(0.0000f, 0.3788f, 6.8324f, 19.8375f, 550.5741f); + lb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(0.0000f, 0.3623f, 6.5384f, 18.9555f, 523.1597f); + + lb.addSpecies(VdypSpecies.build(sb -> { + sb.polygonIdentifier(polyId); + sb.layerType(LayerType.PRIMARY); + sb.percentGenus(100.0f); + sb.genus(species1Id, 5); + sb.baseArea(0.00155f, 0.01412f, 0.05128f, 0.45736f, 28.77972f); + sb.treesPerHectare(0.47f, 1.64f, 2.69f, 13.82f, 269.56f); + sb.loreyHeight(10.6033f, 33.7440f); + sb.wholeStemVolume(0.0078f, 0.1091f, 0.5602f, 6.0129f, 452.8412f); + sb.quadMeanDiameter(6.5f, 36.0f, 10.5f, 15.6f, 20.5f, 36.9f); + sb.closeUtilizationVolumeByUtilization(0.0078f, 0.1091f, 0.5602f, 6.0129f, 452.8412f); + sb.closeUtilizationVolumeNetOfDecayByUtilization(0.0000f, 0.0571f, 0.5048f, 5.6414f, 437.8810f); + sb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(0.0000f, 0.0566f, 0.5007f, 5.5975f, 430.3732f); + sb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(0.0000f, 0.0565f, 0.5005f, 5.5948f, 429.1300f); + + sb.addSite(VdypSite.build(tb -> { + tb.siteIndex(35.0f); + tb.height(35.3f); + tb.ageTotal(55.0f); + tb.yearsToBreastHeight(1.0f); + tb.siteCurveNumber(13); + tb.layerType(LayerType.PRIMARY); + tb.polygonIdentifier(polyId); + tb.siteGenus(species1Id); + })); + })); + + lb.addSpecies(VdypSpecies.build(sb -> { + sb.polygonIdentifier(polyId); + sb.layerType(LayerType.PRIMARY); + sb.percentGenus(100.0f); + sb.genus(species2Id, 3); + sb.baseArea(0.00000f, 0.00502f, 0.01063f /* <-- too small; this will be replaced by the minimum */, 0.02284f, 0.36143f); + sb.treesPerHectare(0.00f, 0.76f, 0.93f, 0.88f, 2.60f); + sb.wholeStemVolume(0.0001f /* <-- to be cleared */, 0.0185f, 0.0757f, 0.1748f, 5.9408f); + + // These aren't to be cleared. + sb.loreyHeight(8.0272f, 36.7553f); + sb.quadMeanDiameter(6.1f, 31.5f, 7.4999f /* <-- too small; this will be replaced by the minimum */, 13.7f, 18.2f, 42.1f); + })); + })); + }); + + var layer = polygon.getLayers().get(LayerType.PRIMARY); + + VdypLayer originalLayer = VdypLayer.build(lb -> lb.copy(layer)); + + var species1 = layer.getSpeciesBySp0(species1Id); + + VdypSpecies originalSpecies1 = VdypSpecies.build(sb -> sb.copy(species1)); + + var species2 = layer.getSpeciesBySp0(species2Id); + + UtilizationOperations.doPostCreateAdjustments(polygon); + + // Scaling + testScaling(layer, originalLayer, scalingFactor); + testScaling(species1, originalSpecies1, scalingFactor); + + // (Partial) reset on missing basal area values + assertThat(species2.getWholeStemVolumeByUtilization().get(UtilizationClass.SMALL), is(0.0f)); + assertThat(species2.getLoreyHeightByUtilization().get(UtilizationClass.SMALL), is(8.0272f)); + assertThat(species2.getQuadraticMeanDiameterByUtilization().get(UtilizationClass.SMALL), is(6.1f)); + + // Adjust Basal Area to match trees per hectare + assertThat(species2.getBaseAreaByUtilization().get(UtilizationClass.U125TO175), is(0.014277437f)); + } + + private void testScaling(VdypUtilizationHolder post, VdypUtilizationHolder pre, float scalingFactor) { + testScalingWasPerformed(post.getBaseAreaByUtilization(), pre.getBaseAreaByUtilization(), scalingFactor); + testScalingWasPerformed(post.getCloseUtilizationVolumeByUtilization(), pre.getCloseUtilizationVolumeByUtilization(), scalingFactor); + testScalingWasPerformed(post.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), pre.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), scalingFactor); + testScalingWasPerformed(post.getCloseUtilizationVolumeNetOfDecayByUtilization(), pre.getCloseUtilizationVolumeNetOfDecayByUtilization(), scalingFactor); + testScalingWasPerformed(post.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), pre.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), scalingFactor); + testScalingWasNotPerformed(post.getLoreyHeightByUtilization(), pre.getLoreyHeightByUtilization(), scalingFactor); + testScalingWasNotPerformed(post.getQuadraticMeanDiameterByUtilization(), pre.getQuadraticMeanDiameterByUtilization(), scalingFactor); + testScalingWasPerformed(post.getTreesPerHectareByUtilization(), pre.getTreesPerHectareByUtilization(), scalingFactor); + testScalingWasPerformed(post.getWholeStemVolumeByUtilization(), pre.getWholeStemVolumeByUtilization(), scalingFactor); + } + + private void testScalingWasPerformed(UtilizationVector post, UtilizationVector pre, float scalingFactor) { + for (int i = UtilizationClass.SMALL.index, j = 0; j < post.size(); i++, j++) { + UtilizationClass uc = UtilizationClass.getByIndex(i); + assertThat(post.get(uc), is(pre.get(uc) * scalingFactor)); + } + } + + private void testScalingWasNotPerformed(UtilizationVector post, UtilizationVector pre, float scalingFactor) { + for (int i = UtilizationClass.SMALL.index, j = 0; j < post.size(); i++, j++) { + UtilizationClass uc = UtilizationClass.getByIndex(i); + assertThat(post.get(uc), not(pre.get(uc) * scalingFactor)); + } + } + + Map parse(ForwardControlParser parser, String resourceName) + throws IOException, ResourceParseException { + + Class klazz = TestUtils.class; + try (var is = klazz.getResourceAsStream(resourceName)) { + + return parser.parse(is, TestUtils.fileResolver(klazz), new HashMap<>()); + } + } +} diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java new file mode 100644 index 000000000..1a29f54e9 --- /dev/null +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java @@ -0,0 +1,130 @@ +package ca.bc.gov.nrs.vdyp.forward.controlmap; + +import java.io.IOException; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.instanceOf; +import org.junit.jupiter.api.Test; + +import ca.bc.gov.nrs.vdyp.forward.ForwardControlParser; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; +import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; +import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; + +public class ForwardControlMapTest { + + @Test + void testForwardResolvedControlMap() throws IOException, ResourceParseException { + var parser = new ForwardControlParser(); + var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + var forwardControlMap = new ForwardResolvedControlMapImpl(rawControlMap); + + assertThat(forwardControlMap.getControlMap(), is(rawControlMap)); + + Object e; + e = forwardControlMap.getDebugSettings(); + assertThat(e, instanceOf(ForwardDebugSettings.class)); + e = forwardControlMap.getForwardControlVariables(); + assertThat(e, instanceOf(ForwardControlVariables.class)); + e = forwardControlMap.getSiteCurveMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getCompVarAdjustments(); + assertThat(e, instanceOf(CompVarAdjustments.class)); + e = forwardControlMap.getBasalAreaYieldCoefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getQuadMeanDiameterYieldCoefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getBasalAreaGrowthFiatDetails(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getBasalAreaGrowthEmpiricalCoefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getUpperBoundsCoefficients(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getQuadMeanDiameterGrowthFiatDetails(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getQuadMeanDiameterGrowthEmpiricalCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getQuadMeanDiameterGrowthEmpiricalLimits(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getLoreyHeightPrimarySpeciesEquationP1Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getLoreyHeightNonPrimaryCoefficients(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getPrimarySpeciesBasalAreaGrowthCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getNonPrimarySpeciesBasalAreaGrowthCoefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getPrimarySpeciesQuadMeanDiameterGrowthCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getNonPrimarySpeciesQuadMeanDiameterGrowthCoefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getBecLookup(); + assertThat(e, instanceOf(BecLookup.class)); + e = forwardControlMap.getGenusDefinitionMap(); + assertThat(e, instanceOf(GenusDefinitionMap.class)); + e = forwardControlMap.getNetDecayWasteCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getNetDecayCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getWasteModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getDecayModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getCloseUtilizationCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getTotalStandWholeStepVolumeCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getWholeStemUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getQuadMeanDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getBasalAreaDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getSmallComponentWholeStemVolumeCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentLoreyHeightCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentQuadMeanDiameterCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentBasalAreaCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentProbabilityCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getMaximumAgeBySiteCurveNumber(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getUpperBounds(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getDefaultEquationGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getEquationModifierGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHl1Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHl2Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHl3Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHlNonPrimaryCoefficients(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getComponentSizeLimits(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getNetBreakageMap(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getVolumeEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getDecayEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getBreakageEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getQuadMeanDiameterBySpeciesCoefficients(); + assertThat(e, instanceOf(Map.class)); + } +} From 053589a737cdd5f9e09d3ea684f0d0ce405a6f5b Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 13:23:20 -0700 Subject: [PATCH 49/66] Two test corrections, reformatting. --- .../nrs/vdyp/common/ComputationMethods.java | 2 +- .../vdyp/controlmap/ResolvedControlMap.java | 2 +- .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 2 +- .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 47 +++++++--- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 51 +++++++---- .../bc/gov/nrs/vdyp/common/ReferenceTest.java | 4 +- .../bc/gov/nrs/vdyp/model/VdypSiteTest.java | 7 +- .../gov/nrs/vdyp/model/VdypSpeciesTest.java | 9 +- .../vdyp/forward/ForwardProcessingEngine.java | 4 +- .../vdyp/forward/UtilizationOperations.java | 6 +- .../forward/Grow6TreesPerHectareTest.java | 4 +- .../forward/UtilizationOperationsTest.java | 86 +++++++++++++------ .../controlmap/ForwardControlMapTest.java | 4 +- 13 files changed, 150 insertions(+), 78 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java index 012ed46d6..1f7f72caf 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java @@ -182,7 +182,7 @@ public void computeUtilizationComponentsPrimary( if (basalAreaSumForSpecies > 0.0f) { float baMult = basalAreaUtil.get(UtilizationClass.ALL) / basalAreaSumForSpecies; - + for (UtilizationClass uc : UtilizationClass.ALL_CLASSES) { basalAreaUtil.set(uc, basalAreaUtil.get(uc) * baMult); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java index a884a6efb..54a8d29be 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/ResolvedControlMap.java @@ -88,7 +88,7 @@ public interface ResolvedControlMap { /** 92 - CLOSE_UTIL_VOLUME */ MatrixMap2> getCloseUtilizationCoeMap(); - + /** 93 - VOLUME_NET_DECAY */ MatrixMap2> getNetDecayCoeMap(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index b956221f9..eece9caf7 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -100,7 +100,7 @@ public boolean equals(Object other) { public int hashCode() { return polygonIdentifier.hashCode() * 17 + layerType.hashCode(); } - + public abstract static class Builder, S extends BaseVdypSpecies, I extends BaseVdypSite, SB extends BaseVdypSpecies.Builder, IB extends BaseVdypSite.Builder> extends ModelClassBuilder { protected Optional polygonIdentifier = Optional.empty(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 22e4968fd..53e6b637d 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -259,7 +259,8 @@ public void closeUtilizationVolumeByUtilization(float volume) { this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder + .emptyUtilization(); public void closeUtilizationVolumeNetOfDecayByUtilization(float small, float u1, float u2, float u3, float u4) { this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); @@ -269,9 +270,12 @@ public void closeUtilizationVolumeNetOfDecayByUtilization(float volume) { this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder + .emptyUtilization(); - public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float small, float u1, float u2, float u3, float u4) { + public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization( + float small, float u1, float u2, float u3, float u4 + ) { this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); } @@ -279,10 +283,14 @@ public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float volume) this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = VdypUtilizationHolder + .emptyUtilization(); - public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float small, float u1, float u2, float u3, float u4) { - this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + float small, float u1, float u2, float u3, float u4 + ) { + this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils + .utilizationVector(small, u1, u2, u3, u4); } public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float volume) { @@ -292,7 +300,7 @@ public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float @Override public VdypLayer.Builder adapt(BaseVdypLayer baseSource) { super.adapt(baseSource); - + if (baseSource instanceof VdypLayer source) { loreyHeight = new UtilizationVector(source.loreyHeightByUtilization); baseArea = new UtilizationVector(source.baseAreaByUtilization); @@ -300,18 +308,24 @@ public VdypLayer.Builder adapt(BaseVdypLayer baseSource) { quadMeanDiameter = new UtilizationVector(source.quadraticMeanDiameterByUtilization); wholeStemVolume = new UtilizationVector(source.wholeStemVolumeByUtilization); closeUtilizationVolumeByUtilization = new UtilizationVector(source.closeUtilizationVolumeByUtilization); - closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayByUtilization); - closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayAndWasteByUtilization); - closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization); + closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector( + source.closeUtilizationVolumeNetOfDecayByUtilization + ); + closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector( + source.closeUtilizationVolumeNetOfDecayAndWasteByUtilization + ); + closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = new UtilizationVector( + source.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization + ); } - + return this; } @Override protected void postProcess(VdypLayer layer) { super.postProcess(layer); - + layer.setLoreyHeightByUtilization(loreyHeight); layer.setBaseAreaByUtilization(baseArea); layer.setTreesPerHectareByUtilization(treesPerHectare); @@ -319,8 +333,13 @@ protected void postProcess(VdypLayer layer) { layer.setWholeStemVolumeByUtilization(wholeStemVolume); layer.setCloseUtilizationVolumeByUtilization(closeUtilizationVolumeByUtilization); layer.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationNetVolumeOfDecayByUtilization); - layer.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(closeUtilizationVolumeNetOfDecayAndWasteByUtilization); - layer.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization);; + layer.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization( + closeUtilizationVolumeNetOfDecayAndWasteByUtilization + ); + layer.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization + ); + ; } @Override diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index b15a47ead..e534672e5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -345,7 +345,8 @@ public void closeUtilizationVolumeByUtilization(float volume) { this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder + .emptyUtilization(); public void closeUtilizationVolumeNetOfDecayByUtilization(float small, float u1, float u2, float u3, float u4) { this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); @@ -355,9 +356,12 @@ public void closeUtilizationVolumeNetOfDecayByUtilization(float volume) { this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder + .emptyUtilization(); - public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float small, float u1, float u2, float u3, float u4) { + public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization( + float small, float u1, float u2, float u3, float u4 + ) { this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); } @@ -365,10 +369,14 @@ public void closeUtilizationVolumeNetOfDecayAndWasteByUtilization(float volume) this.closeUtilizationVolumeNetOfDecayAndWasteByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = VdypUtilizationHolder + .emptyUtilization(); - public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float small, float u1, float u2, float u3, float u4) { - this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + float small, float u1, float u2, float u3, float u4 + ) { + this.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = Utils + .utilizationVector(small, u1, u2, u3, u4); } public void closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(float volume) { @@ -383,7 +391,7 @@ protected void check(Collection errors) { @Override public VdypSpecies.Builder adapt(BaseVdypSpecies baseSource) { super.adapt(baseSource); - + if (baseSource instanceof VdypSpecies source) { loreyHeight = new UtilizationVector(source.loreyHeightByUtilization); baseArea = new UtilizationVector(source.baseAreaByUtilization); @@ -391,29 +399,35 @@ public VdypSpecies.Builder adapt(BaseVdypSpecies baseSource) { quadMeanDiameter = new UtilizationVector(source.quadraticMeanDiameterByUtilization); wholeStemVolume = new UtilizationVector(source.wholeStemVolumeByUtilization); closeUtilizationVolumeByUtilization = new UtilizationVector(source.closeUtilizationVolumeByUtilization); - closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayByUtilization); - closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayAndWasteByUtilization); - closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = new UtilizationVector(source.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization); + closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector( + source.closeUtilizationVolumeNetOfDecayByUtilization + ); + closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector( + source.closeUtilizationVolumeNetOfDecayAndWasteByUtilization + ); + closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = new UtilizationVector( + source.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization + ); } - + return this; } @Override public Builder copy(VdypSpecies source) { super.copy(source); - + source.volumeGroup.ifPresent(vg -> volumeGroup(vg)); source.decayGroup.ifPresent(dg -> decayGroup(dg)); source.breakageGroup.ifPresent(bg -> breakageGroup(bg)); - + return this; } @Override protected void postProcess(VdypSpecies spec) { super.postProcess(spec); - + spec.setLoreyHeightByUtilization(loreyHeight); spec.setBaseAreaByUtilization(baseArea); spec.setTreesPerHectareByUtilization(treesPerHectare); @@ -421,8 +435,13 @@ protected void postProcess(VdypSpecies spec) { spec.setWholeStemVolumeByUtilization(wholeStemVolume); spec.setCloseUtilizationVolumeByUtilization(closeUtilizationVolumeByUtilization); spec.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationNetVolumeOfDecayByUtilization); - spec.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(closeUtilizationVolumeNetOfDecayAndWasteByUtilization); - spec.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization);; + spec.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization( + closeUtilizationVolumeNetOfDecayAndWasteByUtilization + ); + spec.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization + ); + ; } @Override diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java index 72425e1e1..6d2a16b0d 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/ReferenceTest.java @@ -10,13 +10,13 @@ public class ReferenceTest { @Test void testReference() { - + var reference = new Reference(3); assertThat(reference.get(), Matchers.is(Integer.valueOf(3))); assertThat(reference.isPresent(), Matchers.is(true)); reference.set(4); assertThat(reference.get(), Matchers.is(Integer.valueOf(4))); - + var reference2 = new Reference(); assertThat(reference2.isPresent(), Matchers.is(false)); assertThrows(IllegalStateException.class, () -> reference2.get()); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java index 81ea13a39..7d9d4ab31 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSiteTest.java @@ -37,7 +37,6 @@ void build() throws Exception { assertThat(site1, hasProperty("yearsAtBreastHeight", is(Optional.of(30.0f)))); assertThat(site1.toString(), is("Test(2024)-PRIMARY-B")); - assertThat(site1.hashCode(), is(1134087689)); assertThat(site1.equals(site1), is(true)); var site2 = VdypSite.build(builder -> { @@ -50,7 +49,7 @@ void build() throws Exception { builder.siteIndex(42.5f); builder.yearsToBreastHeight(5.0f); }); - + assertThat(site1.equals(site2), is(false)); var site3 = VdypSite.build(builder -> { @@ -63,7 +62,7 @@ void build() throws Exception { builder.siteIndex(42.5f); builder.yearsToBreastHeight(5.0f); }); - + assertThat(site1.equals(site3), is(false)); var site4 = VdypSite.build(builder -> { @@ -76,7 +75,7 @@ void build() throws Exception { builder.siteIndex(42.5f); builder.yearsToBreastHeight(5.0f); }); - + assertThat(site1.equals(site4), is(false)); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java index 618ddafbd..9d0b73e48 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java @@ -34,11 +34,10 @@ void build() throws Exception { assertThat(species1, hasProperty("decayGroup", is(2))); assertThat(species1, hasProperty("breakageGroup", is(3))); assertThat(species1, hasProperty("sp64DistributionSet", hasProperty("sp64DistributionMap", anEmptyMap()))); - + assertThat(species1.toString(), is("Test(2024)-PRIMARY-B")); - assertThat(species1.hashCode(), is(-1947684965)); assertThat(species1.equals(species1), is(true)); - + var species2 = VdypSpecies.build(builder -> { builder.polygonIdentifier("Test2", 2024); builder.layerType(LayerType.PRIMARY); @@ -50,7 +49,7 @@ void build() throws Exception { }); assertThat(species1.equals(species2), is(false)); - + var species3 = VdypSpecies.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.PRIMARY); @@ -62,7 +61,7 @@ void build() throws Exception { }); assertThat(species1.equals(species3), is(false)); - + var species4 = VdypSpecies.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.layerType(LayerType.VETERAN); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index e3fc8f471..2102796b2 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -502,7 +502,9 @@ private void grow( throw new ProcessingException( MessageFormat.format( "During processing of {0}, trees-per-hectare was calculated to be negative ({1})", - lps.getPolygon().getLayers().get(LayerType.PRIMARY), tphEndSum)); + lps.getPolygon().getLayers().get(LayerType.PRIMARY), tphEndSum + ) + ); } bank.treesPerHectare[0][UC_ALL_INDEX] = tphEndSum; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java index 911396d61..28c3bd13b 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java @@ -77,9 +77,9 @@ private static void scale(VdypUtilizationHolder uh, float scalingFactor) { if (treesPerHectare > 0) { uh.getTreesPerHectareByUtilization().set(uc, treesPerHectare * scalingFactor); } - + // lorey height is not a per-hectare value and therefore is excluded from scaling. - + float wholeStemVolume = uh.getWholeStemVolumeByUtilization().get(uc); if (wholeStemVolume > 0) { uh.getWholeStemVolumeByUtilization().set(uc, wholeStemVolume * scalingFactor); @@ -103,7 +103,7 @@ private static void scale(VdypUtilizationHolder uh, float scalingFactor) { uh.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization() .set(uc, cuVolumeMinusDecayWastageBreakage * scalingFactor); } - + // quadratic mean diameter is not a per-hectare value and therefore not scaled. } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java index 63a61db99..9b998d37a 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/Grow6TreesPerHectareTest.java @@ -56,11 +56,11 @@ void testStandardPath() throws ProcessingException { VdypPolygon polygon = forwardDataStreamReader.readNextPolygon().orElseThrow(); fpe.processPolygon(polygon, ExecutionStep.GROW_6_LAYER_TPH2); - + LayerProcessingState lps = fpe.fps.getLayerProcessingState(); var calculatedLayerTph = lps.getBank().treesPerHectare[0][UtilizationClass.ALL.ordinal()]; - + // VDYP7 value is 594.113811 assertThat(calculatedLayerTph, is(601.3333f)); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java index 922d11a37..8d9ad30f1 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java @@ -33,10 +33,10 @@ void testUtilizationOperations() throws Exception { var species1Id = "D"; var species2Id = "B"; var forestInventoryZone = "A"; - + var coveringPercentage = 80.0f; var scalingFactor = 100.0f / coveringPercentage; - + var polygon = VdypPolygon.build(pb -> { pb.polygonIdentifier(polyId); pb.biogeoclimaticZone(new BecDefinition("CWH", Region.COASTAL, "Coastal Western Hemlock")); @@ -44,12 +44,12 @@ void testUtilizationOperations() throws Exception { pb.inventoryTypeGroup(37); pb.mode(PolygonMode.START); pb.percentAvailable(coveringPercentage); - + pb.addLayer(VdypLayer.build(lb -> { lb.polygonIdentifier(polyId); lb.layerType(LayerType.PRIMARY); lb.inventoryTypeGroup(1); - + lb.baseArea(0.01513f, 0.53100f, 1.27855f, 2.33020f, 40.79285f); lb.treesPerHectare(5.24f, 64.82f, 71.93f, 73.60f, 384.98f); lb.loreyHeight(7.0166f, 30.9724f); @@ -57,9 +57,13 @@ void testUtilizationOperations() throws Exception { lb.quadMeanDiameter(6.1f, 31.0f, 10.2f, 15.0f, 20.1f, 36.7f); lb.closeUtilizationVolumeByUtilization(0.0630f, 2.5979f, 9.1057f, 22.4019f, 586.8720f); lb.closeUtilizationVolumeNetOfDecayByUtilization(0.0000f, 0.3794f, 6.8469f, 19.8884f, 553.0534f); - lb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(0.0000f, 0.3788f, 6.8324f, 19.8375f, 550.5741f); - lb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(0.0000f, 0.3623f, 6.5384f, 18.9555f, 523.1597f); - + lb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization( + 0.0000f, 0.3788f, 6.8324f, 19.8375f, 550.5741f + ); + lb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + 0.0000f, 0.3623f, 6.5384f, 18.9555f, 523.1597f + ); + lb.addSpecies(VdypSpecies.build(sb -> { sb.polygonIdentifier(polyId); sb.layerType(LayerType.PRIMARY); @@ -72,9 +76,13 @@ void testUtilizationOperations() throws Exception { sb.quadMeanDiameter(6.5f, 36.0f, 10.5f, 15.6f, 20.5f, 36.9f); sb.closeUtilizationVolumeByUtilization(0.0078f, 0.1091f, 0.5602f, 6.0129f, 452.8412f); sb.closeUtilizationVolumeNetOfDecayByUtilization(0.0000f, 0.0571f, 0.5048f, 5.6414f, 437.8810f); - sb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(0.0000f, 0.0566f, 0.5007f, 5.5975f, 430.3732f); - sb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(0.0000f, 0.0565f, 0.5005f, 5.5948f, 429.1300f); - + sb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization( + 0.0000f, 0.0566f, 0.5007f, 5.5975f, 430.3732f + ); + sb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + 0.0000f, 0.0565f, 0.5005f, 5.5948f, 429.1300f + ); + sb.addSite(VdypSite.build(tb -> { tb.siteIndex(35.0f); tb.height(35.3f); @@ -86,23 +94,29 @@ void testUtilizationOperations() throws Exception { tb.siteGenus(species1Id); })); })); - + lb.addSpecies(VdypSpecies.build(sb -> { sb.polygonIdentifier(polyId); sb.layerType(LayerType.PRIMARY); sb.percentGenus(100.0f); sb.genus(species2Id, 3); - sb.baseArea(0.00000f, 0.00502f, 0.01063f /* <-- too small; this will be replaced by the minimum */, 0.02284f, 0.36143f); + sb.baseArea( + 0.00000f, 0.00502f, 0.01063f /* <-- too small; this will be replaced by the minimum */, + 0.02284f, 0.36143f + ); sb.treesPerHectare(0.00f, 0.76f, 0.93f, 0.88f, 2.60f); sb.wholeStemVolume(0.0001f /* <-- to be cleared */, 0.0185f, 0.0757f, 0.1748f, 5.9408f); // These aren't to be cleared. sb.loreyHeight(8.0272f, 36.7553f); - sb.quadMeanDiameter(6.1f, 31.5f, 7.4999f /* <-- too small; this will be replaced by the minimum */, 13.7f, 18.2f, 42.1f); + sb.quadMeanDiameter( + 6.1f, 31.5f, 7.4999f /* <-- too small; this will be replaced by the minimum */, 13.7f, + 18.2f, 42.1f + ); })); })); }); - + var layer = polygon.getLayers().get(LayerType.PRIMARY); VdypLayer originalLayer = VdypLayer.build(lb -> lb.copy(layer)); @@ -112,32 +126,52 @@ void testUtilizationOperations() throws Exception { VdypSpecies originalSpecies1 = VdypSpecies.build(sb -> sb.copy(species1)); var species2 = layer.getSpeciesBySp0(species2Id); - + UtilizationOperations.doPostCreateAdjustments(polygon); - + // Scaling testScaling(layer, originalLayer, scalingFactor); testScaling(species1, originalSpecies1, scalingFactor); - + // (Partial) reset on missing basal area values assertThat(species2.getWholeStemVolumeByUtilization().get(UtilizationClass.SMALL), is(0.0f)); assertThat(species2.getLoreyHeightByUtilization().get(UtilizationClass.SMALL), is(8.0272f)); assertThat(species2.getQuadraticMeanDiameterByUtilization().get(UtilizationClass.SMALL), is(6.1f)); - + // Adjust Basal Area to match trees per hectare assertThat(species2.getBaseAreaByUtilization().get(UtilizationClass.U125TO175), is(0.014277437f)); } private void testScaling(VdypUtilizationHolder post, VdypUtilizationHolder pre, float scalingFactor) { testScalingWasPerformed(post.getBaseAreaByUtilization(), pre.getBaseAreaByUtilization(), scalingFactor); - testScalingWasPerformed(post.getCloseUtilizationVolumeByUtilization(), pre.getCloseUtilizationVolumeByUtilization(), scalingFactor); - testScalingWasPerformed(post.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), pre.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), scalingFactor); - testScalingWasPerformed(post.getCloseUtilizationVolumeNetOfDecayByUtilization(), pre.getCloseUtilizationVolumeNetOfDecayByUtilization(), scalingFactor); - testScalingWasPerformed(post.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), pre.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), scalingFactor); - testScalingWasNotPerformed(post.getLoreyHeightByUtilization(), pre.getLoreyHeightByUtilization(), scalingFactor); - testScalingWasNotPerformed(post.getQuadraticMeanDiameterByUtilization(), pre.getQuadraticMeanDiameterByUtilization(), scalingFactor); - testScalingWasPerformed(post.getTreesPerHectareByUtilization(), pre.getTreesPerHectareByUtilization(), scalingFactor); - testScalingWasPerformed(post.getWholeStemVolumeByUtilization(), pre.getWholeStemVolumeByUtilization(), scalingFactor); + testScalingWasPerformed( + post.getCloseUtilizationVolumeByUtilization(), pre.getCloseUtilizationVolumeByUtilization(), + scalingFactor + ); + testScalingWasPerformed( + post.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), + pre.getCloseUtilizationVolumeNetOfDecayAndWasteByUtilization(), scalingFactor + ); + testScalingWasPerformed( + post.getCloseUtilizationVolumeNetOfDecayByUtilization(), + pre.getCloseUtilizationVolumeNetOfDecayByUtilization(), scalingFactor + ); + testScalingWasPerformed( + post.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), + pre.getCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(), scalingFactor + ); + testScalingWasNotPerformed( + post.getLoreyHeightByUtilization(), pre.getLoreyHeightByUtilization(), scalingFactor + ); + testScalingWasNotPerformed( + post.getQuadraticMeanDiameterByUtilization(), pre.getQuadraticMeanDiameterByUtilization(), scalingFactor + ); + testScalingWasPerformed( + post.getTreesPerHectareByUtilization(), pre.getTreesPerHectareByUtilization(), scalingFactor + ); + testScalingWasPerformed( + post.getWholeStemVolumeByUtilization(), pre.getWholeStemVolumeByUtilization(), scalingFactor + ); } private void testScalingWasPerformed(UtilizationVector post, UtilizationVector pre, float scalingFactor) { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java index 1a29f54e9..a893f450e 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java @@ -26,9 +26,9 @@ void testForwardResolvedControlMap() throws IOException, ResourceParseException var parser = new ForwardControlParser(); var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); var forwardControlMap = new ForwardResolvedControlMapImpl(rawControlMap); - + assertThat(forwardControlMap.getControlMap(), is(rawControlMap)); - + Object e; e = forwardControlMap.getDebugSettings(); assertThat(e, instanceOf(ForwardDebugSettings.class)); From be301f957e95c3f558e71680d299f9df0cfbfec1 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 14:57:38 -0700 Subject: [PATCH 50/66] And one more test... --- .../CachingResolvedControlMapImpl.java | 60 +++++++++---------- .../gov/nrs/vdyp/model/VdypUtilization.java | 7 +++ .../nrs/vdyp/model/VdypUtilizationTest.java | 49 +++++++++++++++ ...ava => ForwardResolvedControlMapTest.java} | 2 +- 4 files changed, 87 insertions(+), 31 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java rename vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/{ForwardControlMapTest.java => ForwardResolvedControlMapTest.java} (99%) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java index e3f9249b5..e64d6180b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/controlmap/CachingResolvedControlMapImpl.java @@ -19,36 +19,36 @@ public class CachingResolvedControlMapImpl implements ResolvedControlMap { - final BecLookup becLookup; - final GenusDefinitionMap genusDefinitionMap; - final Map netDecayWasteCoeMap; - final MatrixMap2> netDecayCoeMap; - final MatrixMap2 wasteModifierMap; - final MatrixMap2 decayModifierMap; - final MatrixMap2> closeUtilizationCoeMap; - final Map totalStandWholeStepVolumeCoeMap; - final MatrixMap2> wholeStemUtilizationComponentMap; - final MatrixMap3 quadMeanDiameterUtilizationComponentMap; - final MatrixMap3 basalAreaDiameterUtilizationComponentMap; - final Map smallComponentWholeStemVolumeCoefficients; - final Map smallComponentLoreyHeightCoefficients; - final Map smallComponentQuadMeanDiameterCoefficients; - final Map smallComponentBasalAreaCoefficients; - final Map smallComponentProbabilityCoefficients; - final Map maximumAgeBySiteCurveNumber; - final Map upperBounds; - final MatrixMap2 defaultEquationGroup; - final MatrixMap2> equationModifierGroup; - final MatrixMap2 hl1Coefficients; - final MatrixMap2 hl2Coefficients; - final MatrixMap2 hl3Coefficients; - final MatrixMap3> hlNonPrimaryCoefficients; - final MatrixMap2 componentSizeLimitCoefficients; - final Map breakageMap; - final MatrixMap2 volumeEquationGroups; - final MatrixMap2 decayEquationGroups; - final MatrixMap2 breakageEquationGroups; - final Map quadMeanDiameterBySpeciesCoefficients; + private final BecLookup becLookup; + private final GenusDefinitionMap genusDefinitionMap; + private final Map netDecayWasteCoeMap; + private final MatrixMap2> netDecayCoeMap; + private final MatrixMap2 wasteModifierMap; + private final MatrixMap2 decayModifierMap; + private final MatrixMap2> closeUtilizationCoeMap; + private final Map totalStandWholeStepVolumeCoeMap; + private final MatrixMap2> wholeStemUtilizationComponentMap; + private final MatrixMap3 quadMeanDiameterUtilizationComponentMap; + private final MatrixMap3 basalAreaDiameterUtilizationComponentMap; + private final Map smallComponentWholeStemVolumeCoefficients; + private final Map smallComponentLoreyHeightCoefficients; + private final Map smallComponentQuadMeanDiameterCoefficients; + private final Map smallComponentBasalAreaCoefficients; + private final Map smallComponentProbabilityCoefficients; + private final Map maximumAgeBySiteCurveNumber; + private final Map upperBounds; + private final MatrixMap2 defaultEquationGroup; + private final MatrixMap2> equationModifierGroup; + private final MatrixMap2 hl1Coefficients; + private final MatrixMap2 hl2Coefficients; + private final MatrixMap2 hl3Coefficients; + private final MatrixMap3> hlNonPrimaryCoefficients; + private final MatrixMap2 componentSizeLimitCoefficients; + private final Map breakageMap; + private final MatrixMap2 volumeEquationGroups; + private final MatrixMap2 decayEquationGroups; + private final MatrixMap2 breakageEquationGroups; + private final Map quadMeanDiameterBySpeciesCoefficients; private final Map controlMap; diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java index 6bd32dd78..e0617d2ac 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java @@ -2,6 +2,13 @@ import java.util.Optional; +/** + * Instance of this class are parsed out of the Utilization input files supplied to + * Forward and other applications. They are used to solely for the purpose of + * transporting this information into code that builds the UtilizationHolders + * (that is, VdypLayer and VdypSpecies) from sets of them (each set will contain + * one entry per UtilizationClass.) + */ public class VdypUtilization implements VdypEntity { // See IPSJF155.doc diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java new file mode 100644 index 000000000..46b853790 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java @@ -0,0 +1,49 @@ +package ca.bc.gov.nrs.vdyp.model; + +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import org.hamcrest.Matchers; +import static org.hamcrest.Matchers.is; +import org.junit.jupiter.api.Test; + +class VdypUtilizationTest { + + @Test + void build() throws Exception { + var polygonId = new PolygonIdentifier("Polygon1", 2024); + var layerType = LayerType.PRIMARY; + var genusIndex = Integer.valueOf(3); + var genus = Optional.of("B"); + var ucIndex = UtilizationClass.ALL; + var basalArea = 35.0f; + var liveTreesPerHectare = 500.0f; + var loreyHeight = 45.0f; + var wholeStemVolume = 4.3f; + var closeUtilizationVolume = 4.1f; + var quadraticMeanDiameterAtBH = 0.95f; + var cuVolumeMinusDecay = 3.9f; + var cuVolumeMinusDecayWastage = 3.7f; + var cuVolumeMinusDecayWastageBreakage = 3.5f; + + VdypUtilization u = new VdypUtilization(polygonId, layerType, genusIndex, genus, ucIndex, + basalArea, liveTreesPerHectare, loreyHeight, wholeStemVolume, closeUtilizationVolume, + cuVolumeMinusDecay, cuVolumeMinusDecayWastage, cuVolumeMinusDecayWastageBreakage, + quadraticMeanDiameterAtBH); + + assertThat(u.getPolygonId(), is(new PolygonIdentifier("Polygon1", 2024))); + assertThat(u.getLayerType(), is(LayerType.PRIMARY)); + assertThat(u.getGenusIndex(), is(Integer.valueOf(3))); + assertThat(u.getGenus(), is(Optional.of("B"))); + assertThat(u.getUcIndex(), is(UtilizationClass.ALL)); + assertThat(u.getBasalArea(), is(35.0f)); + assertThat(u.getLiveTreesPerHectare(), is(500.0f)); + assertThat(u.getLoreyHeight(), is(45.0f)); + assertThat(u.getWholeStemVolume(), is(4.3f)); + assertThat(u.getCloseUtilizationVolume(), is(4.1f)); + assertThat(u.getQuadraticMeanDiameterAtBH(), is(0.95f)); + assertThat(u.getCuVolumeMinusDecay(), is(3.9f)); + assertThat(u.getCuVolumeMinusDecayWastage(), is(3.7f)); + assertThat(u.getCuVolumeMinusDecayWastageBreakage(), is(3.5f)); + } +} diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java similarity index 99% rename from vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java rename to vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java index a893f450e..5a2ebf840 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardControlMapTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java @@ -19,7 +19,7 @@ import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.MatrixMap3; -public class ForwardControlMapTest { +public class ForwardResolvedControlMapTest { @Test void testForwardResolvedControlMap() throws IOException, ResourceParseException { From 7450b4a515b65bac6f8d068a81df034c3fc5d93c Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 15:18:38 -0700 Subject: [PATCH 51/66] Explicitly test CachingResolvedControlMap --- .../ForwardResolvedControlMapTest.java | 79 ++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java index 5a2ebf840..738695dd5 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java @@ -1,13 +1,15 @@ package ca.bc.gov.nrs.vdyp.forward.controlmap; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; + import java.io.IOException; import java.util.Map; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.instanceOf; import org.junit.jupiter.api.Test; +import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.forward.ForwardControlParser; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; @@ -127,4 +129,75 @@ void testForwardResolvedControlMap() throws IOException, ResourceParseException e = forwardControlMap.getQuadMeanDiameterBySpeciesCoefficients(); assertThat(e, instanceOf(Map.class)); } + + @Test + void testCachingResolvedControlMap() throws IOException, ResourceParseException { + var parser = new ForwardControlParser(); + var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); + var forwardControlMap = new CachingResolvedControlMapImpl(rawControlMap); + + assertThat(forwardControlMap.getControlMap(), is(rawControlMap)); + + Object e; + e = forwardControlMap.getBecLookup(); + assertThat(e, instanceOf(BecLookup.class)); + e = forwardControlMap.getGenusDefinitionMap(); + assertThat(e, instanceOf(GenusDefinitionMap.class)); + e = forwardControlMap.getNetDecayWasteCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getNetDecayCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getWasteModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getDecayModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getCloseUtilizationCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getTotalStandWholeStepVolumeCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getWholeStemUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getQuadMeanDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getBasalAreaDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getSmallComponentWholeStemVolumeCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentLoreyHeightCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentQuadMeanDiameterCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentBasalAreaCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getSmallComponentProbabilityCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getMaximumAgeBySiteCurveNumber(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getUpperBounds(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getDefaultEquationGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getEquationModifierGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHl1Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHl2Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHl3Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getHlNonPrimaryCoefficients(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = forwardControlMap.getComponentSizeLimits(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getNetBreakageMap(); + assertThat(e, instanceOf(Map.class)); + e = forwardControlMap.getVolumeEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getDecayEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getBreakageEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = forwardControlMap.getQuadMeanDiameterBySpeciesCoefficients(); + assertThat(e, instanceOf(Map.class)); + } } From 3308865c1bf69d6993f8bebc98b61c55baa0afed Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 15:34:55 -0700 Subject: [PATCH 52/66] Added logging to "uncovered" code to disprove this... --- .../ForwardResolvedControlMapTest.java | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java index 738695dd5..b3ff1ca5e 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java @@ -8,12 +8,15 @@ import java.util.Map; import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.forward.ForwardControlParser; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; +import ca.bc.gov.nrs.vdyp.io.parse.coe.DebugSettingsParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; @@ -23,8 +26,12 @@ public class ForwardResolvedControlMapTest { + private static final Logger logger = LoggerFactory.getLogger(ForwardResolvedControlMapTest.class); + @Test void testForwardResolvedControlMap() throws IOException, ResourceParseException { + logger.info(this.getClass().getName() + ":testForwardResolvedControlMap running..."); + var parser = new ForwardControlParser(); var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); var forwardControlMap = new ForwardResolvedControlMapImpl(rawControlMap); @@ -132,72 +139,74 @@ void testForwardResolvedControlMap() throws IOException, ResourceParseException @Test void testCachingResolvedControlMap() throws IOException, ResourceParseException { + logger.info(this.getClass().getName() + ":testCachingResolvedControlMap running..."); + var parser = new ForwardControlParser(); var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - var forwardControlMap = new CachingResolvedControlMapImpl(rawControlMap); + var cachingControlMap = new CachingResolvedControlMapImpl(rawControlMap); - assertThat(forwardControlMap.getControlMap(), is(rawControlMap)); + assertThat(cachingControlMap.getControlMap(), is(rawControlMap)); Object e; - e = forwardControlMap.getBecLookup(); + e = cachingControlMap.getBecLookup(); assertThat(e, instanceOf(BecLookup.class)); - e = forwardControlMap.getGenusDefinitionMap(); + e = cachingControlMap.getGenusDefinitionMap(); assertThat(e, instanceOf(GenusDefinitionMap.class)); - e = forwardControlMap.getNetDecayWasteCoeMap(); + e = cachingControlMap.getNetDecayWasteCoeMap(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getNetDecayCoeMap(); + e = cachingControlMap.getNetDecayCoeMap(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getWasteModifierMap(); + e = cachingControlMap.getWasteModifierMap(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getDecayModifierMap(); + e = cachingControlMap.getDecayModifierMap(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getCloseUtilizationCoeMap(); + e = cachingControlMap.getCloseUtilizationCoeMap(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getTotalStandWholeStepVolumeCoeMap(); + e = cachingControlMap.getTotalStandWholeStepVolumeCoeMap(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getWholeStemUtilizationComponentMap(); + e = cachingControlMap.getWholeStemUtilizationComponentMap(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getQuadMeanDiameterUtilizationComponentMap(); + e = cachingControlMap.getQuadMeanDiameterUtilizationComponentMap(); assertThat(e, instanceOf(MatrixMap3.class)); - e = forwardControlMap.getBasalAreaDiameterUtilizationComponentMap(); + e = cachingControlMap.getBasalAreaDiameterUtilizationComponentMap(); assertThat(e, instanceOf(MatrixMap3.class)); - e = forwardControlMap.getSmallComponentWholeStemVolumeCoefficients(); + e = cachingControlMap.getSmallComponentWholeStemVolumeCoefficients(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getSmallComponentLoreyHeightCoefficients(); + e = cachingControlMap.getSmallComponentLoreyHeightCoefficients(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getSmallComponentQuadMeanDiameterCoefficients(); + e = cachingControlMap.getSmallComponentQuadMeanDiameterCoefficients(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getSmallComponentBasalAreaCoefficients(); + e = cachingControlMap.getSmallComponentBasalAreaCoefficients(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getSmallComponentProbabilityCoefficients(); + e = cachingControlMap.getSmallComponentProbabilityCoefficients(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getMaximumAgeBySiteCurveNumber(); + e = cachingControlMap.getMaximumAgeBySiteCurveNumber(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getUpperBounds(); + e = cachingControlMap.getUpperBounds(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getDefaultEquationGroup(); + e = cachingControlMap.getDefaultEquationGroup(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getEquationModifierGroup(); + e = cachingControlMap.getEquationModifierGroup(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getHl1Coefficients(); + e = cachingControlMap.getHl1Coefficients(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getHl2Coefficients(); + e = cachingControlMap.getHl2Coefficients(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getHl3Coefficients(); + e = cachingControlMap.getHl3Coefficients(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getHlNonPrimaryCoefficients(); + e = cachingControlMap.getHlNonPrimaryCoefficients(); assertThat(e, instanceOf(MatrixMap3.class)); - e = forwardControlMap.getComponentSizeLimits(); + e = cachingControlMap.getComponentSizeLimits(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getNetBreakageMap(); + e = cachingControlMap.getNetBreakageMap(); assertThat(e, instanceOf(Map.class)); - e = forwardControlMap.getVolumeEquationGroups(); + e = cachingControlMap.getVolumeEquationGroups(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getDecayEquationGroups(); + e = cachingControlMap.getDecayEquationGroups(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getBreakageEquationGroups(); + e = cachingControlMap.getBreakageEquationGroups(); assertThat(e, instanceOf(MatrixMap2.class)); - e = forwardControlMap.getQuadMeanDiameterBySpeciesCoefficients(); + e = cachingControlMap.getQuadMeanDiameterBySpeciesCoefficients(); assertThat(e, instanceOf(Map.class)); } } From 80da1babdeeecf6434b01176055650ec6a768675 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 16:26:39 -0700 Subject: [PATCH 53/66] Run formatter (again) --- .../ca/bc/gov/nrs/vdyp/model/VdypUtilization.java | 8 +++----- .../bc/gov/nrs/vdyp/model/VdypUtilizationTest.java | 13 +++++++------ .../controlmap/ForwardResolvedControlMapTest.java | 4 ++-- .../java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java | 2 +- .../ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java | 2 +- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java index e0617d2ac..51ada34ba 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypUtilization.java @@ -3,11 +3,9 @@ import java.util.Optional; /** - * Instance of this class are parsed out of the Utilization input files supplied to - * Forward and other applications. They are used to solely for the purpose of - * transporting this information into code that builds the UtilizationHolders - * (that is, VdypLayer and VdypSpecies) from sets of them (each set will contain - * one entry per UtilizationClass.) + * Instance of this class are parsed out of the Utilization input files supplied to Forward and other applications. They + * are used to solely for the purpose of transporting this information into code that builds the UtilizationHolders + * (that is, VdypLayer and VdypSpecies) from sets of them (each set will contain one entry per UtilizationClass.) */ public class VdypUtilization implements VdypEntity { diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java index 46b853790..2f7d728a1 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java @@ -25,12 +25,13 @@ void build() throws Exception { var cuVolumeMinusDecay = 3.9f; var cuVolumeMinusDecayWastage = 3.7f; var cuVolumeMinusDecayWastageBreakage = 3.5f; - - VdypUtilization u = new VdypUtilization(polygonId, layerType, genusIndex, genus, ucIndex, - basalArea, liveTreesPerHectare, loreyHeight, wholeStemVolume, closeUtilizationVolume, - cuVolumeMinusDecay, cuVolumeMinusDecayWastage, cuVolumeMinusDecayWastageBreakage, - quadraticMeanDiameterAtBH); - + + VdypUtilization u = new VdypUtilization( + polygonId, layerType, genusIndex, genus, ucIndex, basalArea, liveTreesPerHectare, loreyHeight, + wholeStemVolume, closeUtilizationVolume, cuVolumeMinusDecay, cuVolumeMinusDecayWastage, + cuVolumeMinusDecayWastageBreakage, quadraticMeanDiameterAtBH + ); + assertThat(u.getPolygonId(), is(new PolygonIdentifier("Polygon1", 2024))); assertThat(u.getLayerType(), is(LayerType.PRIMARY)); assertThat(u.getGenusIndex(), is(Integer.valueOf(3))); diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java index b3ff1ca5e..015dbcb8b 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java @@ -31,7 +31,7 @@ public class ForwardResolvedControlMapTest { @Test void testForwardResolvedControlMap() throws IOException, ResourceParseException { logger.info(this.getClass().getName() + ":testForwardResolvedControlMap running..."); - + var parser = new ForwardControlParser(); var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); var forwardControlMap = new ForwardResolvedControlMapImpl(rawControlMap); @@ -136,7 +136,7 @@ void testForwardResolvedControlMap() throws IOException, ResourceParseException e = forwardControlMap.getQuadMeanDiameterBySpeciesCoefficients(); assertThat(e, instanceOf(Map.class)); } - + @Test void testCachingResolvedControlMap() throws IOException, ResourceParseException { logger.info(this.getClass().getName() + ":testCachingResolvedControlMap running..."); diff --git a/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java b/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java index c1250ed18..6f31c3b34 100644 --- a/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java +++ b/vdyp-lib/vdyp-sindex/src/main/java/ca/bc/gov/nrs/vdyp/sindex/Sindxdll.java @@ -1465,7 +1465,7 @@ public class Sindxdll { + "Engelmann Spruce Growth Intercept Models. For. Anal. Inv. Br., B.C." + "Min. For., Lands, Nat. Resour. Oper., Victoria, B.C. Tech. Rep. 084. ", "The growth intercept models were developed from 84 stem analysis plots " - + "located throughout the range of the Engelmann Spruce � Subalpine Fir " + + "located throughout the range of the Engelmann Spruce - Subalpine Fir " + "(ESSF) biogeoclimatic zone of British Columbia. Plots ranged in site " + "index from about 6 to 24 m. The models can be used to estimate site index " + "throughout the ESSF zone in British Columbia.", }, diff --git a/vdyp-lib/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java b/vdyp-lib/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java index 26aa01546..997c9214d 100644 --- a/vdyp-lib/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java +++ b/vdyp-lib/vdyp-sindex/src/test/java/ca/bc/gov/nrs/vdyp/sindex/SindxdllTest.java @@ -1108,7 +1108,7 @@ class SindxdllTest { + "Engelmann Spruce Growth Intercept Models. For. Anal. Inv. Br., B.C." + "Min. For., Lands, Nat. Resour. Oper., Victoria, B.C. Tech. Rep. 084. ", "The growth intercept models were developed from 84 stem analysis plots " - + "located throughout the range of the Engelmann Spruce � Subalpine Fir " + + "located throughout the range of the Engelmann Spruce - Subalpine Fir " + "(ESSF) biogeoclimatic zone of British Columbia. Plots ranged in site " + "index from about 6 to 24 m. The models can be used to estimate site index " + "throughout the ESSF zone in British Columbia.", }, From 47ad8d584f7620d053858d01f2ec1cb2e4b6505c Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 17:05:32 -0700 Subject: [PATCH 54/66] Improve test of ZipFileResolver to behave on multiple platforms. --- .../vdyp/forward/ForwardProcessorTest.java | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index 3b0762380..7a4083516 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -5,6 +5,7 @@ import static ca.bc.gov.nrs.vdyp.forward.ForwardPass.PASS_3; import static ca.bc.gov.nrs.vdyp.forward.ForwardPass.PASS_4; import static ca.bc.gov.nrs.vdyp.forward.ForwardPass.PASS_5; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; @@ -12,10 +13,12 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.text.MessageFormat; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.zip.ZipFile; import org.junit.jupiter.api.Test; import org.slf4j.Logger; @@ -48,21 +51,44 @@ void test() throws IOException, ResourceParseException, ProcessingException { Path resourceDirectory = Paths.get("src", "test", "resources", "output"); Files.createDirectories(resourceDirectory); - Path zipFile = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); - Files.deleteIfExists(zipFile); + Path zipFilePath = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); + Files.deleteIfExists(zipFilePath); try { - outputResolver.generate(zipFile); + outputResolver.generate(zipFilePath); - InputStream os = outputResolver.generateStream(); + InputStream is = outputResolver.generateStream(); - byte[] zipFileBytes = Files.readAllBytes(zipFile); - byte[] zipStreamBytes = os.readAllBytes(); + byte[] zipFileBytes = Files.readAllBytes(zipFilePath); + byte[] zipStreamBytes = is.readAllBytes(); assertTrue(zipFileBytes.length == zipStreamBytes.length); - assertTrue(Arrays.equals(zipFileBytes, zipStreamBytes)); + + Path zipFileFromStreamPath = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + "FromStream.zip"); + Files.write(zipFileFromStreamPath, zipStreamBytes); + + try (ZipFile zipFileFromStream = new ZipFile(zipFileFromStreamPath.toFile())) { + try (ZipFile zipFileFromFile = new ZipFile(zipFilePath.toFile())) { + + var streamEntries = zipFileFromStream.entries().asIterator(); + var fileEntries = zipFileFromFile.entries().asIterator(); + + while (streamEntries.hasNext()) { + assertTrue(fileEntries.hasNext()); + + var streamEntry = streamEntries.next(); + var fileEntry = fileEntries.next(); + + logger.info("Saw file entry {} and stream entry {}", fileEntry.getName(), streamEntry.getName()); + assertTrue(streamEntry.hashCode() == fileEntry.hashCode()); + assertTrue(streamEntry.getName().equals(fileEntry.getName())); + } + + assertFalse(fileEntries.hasNext()); + } + } } finally { - Files.delete(zipFile); + Files.delete(zipFilePath); } } } From 8b1baae8fe66106249d2fb56bdb540865e87fddc Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 17:09:11 -0700 Subject: [PATCH 55/66] Run formatter (again) --- .../vdyp/forward/ForwardProcessorTest.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index 7a4083516..3ae5d648e 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -54,41 +54,44 @@ void test() throws IOException, ResourceParseException, ProcessingException { Path zipFilePath = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); Files.deleteIfExists(zipFilePath); + Path zipFileFromStreamPath = Paths + .get(resourceDirectory.toString(), this.getClass().getSimpleName() + "FromStream.zip"); + try { outputResolver.generate(zipFilePath); + byte[] zipFileBytes = Files.readAllBytes(zipFilePath); InputStream is = outputResolver.generateStream(); - - byte[] zipFileBytes = Files.readAllBytes(zipFilePath); byte[] zipStreamBytes = is.readAllBytes(); + Files.write(zipFileFromStreamPath, zipStreamBytes); assertTrue(zipFileBytes.length == zipStreamBytes.length); - - Path zipFileFromStreamPath = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + "FromStream.zip"); - Files.write(zipFileFromStreamPath, zipStreamBytes); - + try (ZipFile zipFileFromStream = new ZipFile(zipFileFromStreamPath.toFile())) { try (ZipFile zipFileFromFile = new ZipFile(zipFilePath.toFile())) { - + var streamEntries = zipFileFromStream.entries().asIterator(); var fileEntries = zipFileFromFile.entries().asIterator(); - + while (streamEntries.hasNext()) { - assertTrue(fileEntries.hasNext()); - + assertTrue(fileEntries.hasNext()); + var streamEntry = streamEntries.next(); var fileEntry = fileEntries.next(); - - logger.info("Saw file entry {} and stream entry {}", fileEntry.getName(), streamEntry.getName()); + + logger.info( + "Saw file entry {} and stream entry {}", fileEntry.getName(), streamEntry.getName() + ); assertTrue(streamEntry.hashCode() == fileEntry.hashCode()); assertTrue(streamEntry.getName().equals(fileEntry.getName())); } - - assertFalse(fileEntries.hasNext()); + + assertFalse(fileEntries.hasNext()); } } } finally { Files.delete(zipFilePath); + Files.delete(zipFileFromStreamPath); } } } From 750f720ef94d3a16ee278381f089b5762361b92a Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Thu, 5 Sep 2024 17:54:23 -0700 Subject: [PATCH 56/66] Further VdypSpecies tests --- .../ca/bc/gov/nrs/vdyp/model/VdypSpecies.java | 6 +- .../gov/nrs/vdyp/model/VdypSpeciesTest.java | 58 +++++++++++++++++++ .../vdyp/forward/ForwardProcessorTest.java | 2 - 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java index e534672e5..87b38e2b6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypSpecies.java @@ -417,9 +417,9 @@ public VdypSpecies.Builder adapt(BaseVdypSpecies baseSource) { public Builder copy(VdypSpecies source) { super.copy(source); - source.volumeGroup.ifPresent(vg -> volumeGroup(vg)); - source.decayGroup.ifPresent(dg -> decayGroup(dg)); - source.breakageGroup.ifPresent(bg -> breakageGroup(bg)); + source.volumeGroup.ifPresent(this::volumeGroup); + source.decayGroup.ifPresent(this::decayGroup); + source.breakageGroup.ifPresent(this::breakageGroup); return this; } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java index 9d0b73e48..83204607f 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypSpeciesTest.java @@ -11,8 +11,15 @@ import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.NoSuchElementException; + import org.junit.jupiter.api.Test; +import ca.bc.gov.nrs.vdyp.application.InitializationIncompleteException; + class VdypSpeciesTest { @Test @@ -75,6 +82,57 @@ void build() throws Exception { assertThat(species1.equals(species4), is(false)); }; + @Test + void testAdditionalBuildMethods() { + VdypSpecies sp = VdypSpecies.build(sb -> { + sb.polygonIdentifier(new PolygonIdentifier("Poly1", 2024)); + sb.layerType(LayerType.PRIMARY); + sb.percentGenus(100.0f); + sb.genus("Species1", 5); + sb.baseArea(0.00155f, 0.01412f, 0.05128f, 0.45736f, 28.77972f); + sb.treesPerHectare(0.47f, 1.64f, 2.69f, 13.82f, 269.56f); + sb.loreyHeight(10.6033f, 33.7440f); + sb.wholeStemVolume(0.0078f, 0.1091f, 0.5602f, 6.0129f, 452.8412f); + sb.quadMeanDiameter(6.5f, 36.0f, 10.5f, 15.6f, 20.5f, 36.9f); + sb.closeUtilizationVolumeByUtilization(0.0078f, 0.1091f, 0.5602f, 6.0129f, 452.8412f); + sb.closeUtilizationVolumeNetOfDecayByUtilization(0.0000f, 0.0571f, 0.5048f, 5.6414f, 437.8810f); + sb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(0.0000f, 0.0566f, 0.5007f, 5.5975f, 430.3732f); + sb.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( + 0.0000f, 0.0565f, 0.5005f, 5.5948f, 429.1300f + ); + }); + + assertThrows(NoSuchElementException.class, () -> sp.getVolumeGroup()); + assertThrows(NoSuchElementException.class, () -> sp.getDecayGroup()); + assertThrows(NoSuchElementException.class, () -> sp.getBreakageGroup()); + + sp.setVolumeGroup(0); + sp.setDecayGroup(0); + sp.setBreakageGroup(0); + + assertThrows(IllegalStateException.class, () -> sp.setVolumeGroup(1)); + assertThrows(IllegalStateException.class, () -> sp.setDecayGroup(1)); + assertThrows(IllegalStateException.class, () -> sp.setBreakageGroup(1)); + + List ucs = Arrays.asList(UtilizationClass.values()); + List vvs = Arrays.asList(VolumeVariable.values()); + List lts = Arrays.asList(LayerType.values()); + + assertThrows(InitializationIncompleteException.class, () -> sp.getCvVolume(null, null, null)); + assertThrows(InitializationIncompleteException.class, () -> sp.getCvBasalArea(null, null)); + assertThrows(InitializationIncompleteException.class, () -> sp.getCvQuadraticMeanDiameter(null, null)); + assertThrows(InitializationIncompleteException.class, () -> sp.getCvPrimaryLayerSmall(null)); + + var cvVolume = new MatrixMap3Impl( + ucs, vvs, lts, (x, y, z) -> 1.0f + ); + var cvBasalArea = new MatrixMap2Impl(ucs, lts, (x, y) -> 1.0f); + var cvQuadraticMeanDiameter = new MatrixMap2Impl(ucs, lts, (x, y) -> 1.0f); + var cvPrimaryLayerSmall = new HashMap(); + + sp.setCompatibilityVariables(cvVolume, cvBasalArea, cvQuadraticMeanDiameter, cvPrimaryLayerSmall); + } + @Test void buildNoProperties() throws Exception { var ex = assertThrows(IllegalStateException.class, () -> VdypSpecies.build(builder -> { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index 3ae5d648e..c583c0760 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -13,7 +13,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.text.MessageFormat; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -32,7 +31,6 @@ class ForwardProcessorTest { - @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(ForwardProcessorTest.class); private static Set vdypPassSet = new HashSet<>(Arrays.asList(PASS_1, PASS_2, PASS_3, PASS_4, PASS_5)); From 29265ed219a58e08da4d5384f4d6dfe9463cbf43 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 09:40:40 -0700 Subject: [PATCH 57/66] Moved CachedResolvedControlMapTest to vdyp-common --- .../CachingResolvedControlMapTest.java | 99 +++++++++++++++++++ .../ca/bc/gov/nrs/vdyp/test/TestUtils.java | 7 +- .../ForwardResolvedControlMapTest.java | 75 -------------- 3 files changed, 104 insertions(+), 77 deletions(-) create mode 100644 vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/CachingResolvedControlMapTest.java diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/CachingResolvedControlMapTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/CachingResolvedControlMapTest.java new file mode 100644 index 000000000..e77fee265 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/CachingResolvedControlMapTest.java @@ -0,0 +1,99 @@ +package ca.bc.gov.nrs.vdyp.common.controlmap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.test.TestUtils; + +public class CachingResolvedControlMapTest { + + private static final Logger logger = LoggerFactory.getLogger(CachingResolvedControlMapTest.class); + + @Test + void testCachingResolvedControlMap() throws IOException, ResourceParseException { + logger.info(this.getClass().getName() + ":testCachingResolvedControlMap running..."); + + var rawControlMap = TestUtils.loadControlMap(Path.of("VDYP.CTR")); + + var cachingControlMap = new CachingResolvedControlMapImpl(rawControlMap); + + assertThat(cachingControlMap.getControlMap(), is(rawControlMap)); + + Object e; + e = cachingControlMap.getBecLookup(); + assertThat(e, instanceOf(BecLookup.class)); + e = cachingControlMap.getGenusDefinitionMap(); + assertThat(e, instanceOf(GenusDefinitionMap.class)); + e = cachingControlMap.getNetDecayWasteCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getNetDecayCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getWasteModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getDecayModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getCloseUtilizationCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getTotalStandWholeStepVolumeCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getWholeStemUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getQuadMeanDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = cachingControlMap.getBasalAreaDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = cachingControlMap.getSmallComponentWholeStemVolumeCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentLoreyHeightCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentQuadMeanDiameterCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentBasalAreaCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentProbabilityCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getMaximumAgeBySiteCurveNumber(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getUpperBounds(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getDefaultEquationGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getEquationModifierGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHl1Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHl2Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHl3Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHlNonPrimaryCoefficients(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = cachingControlMap.getComponentSizeLimits(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getNetBreakageMap(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getVolumeEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getDecayEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getBreakageEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getQuadMeanDiameterBySpeciesCoefficients(); + assertThat(e, instanceOf(Map.class)); + } +} diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java index 1a87fa688..11491ef43 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/test/TestUtils.java @@ -422,14 +422,17 @@ public static Map loadControlMap(BaseControlParser parser, Class } public static Map loadControlMap() { + return loadControlMap(Path.of("VRISTART.CTR")); + } + + public static Map loadControlMap(Path controlMapPath) { BaseControlParser parser = new TestNonFipControlParser(); try { - return TestUtils.loadControlMap(parser, TestUtils.class, "VRISTART.CTR"); + return TestUtils.loadControlMap(parser, TestUtils.class, controlMapPath.toString()); } catch (IOException | ResourceParseException ex) { fail(ex); return null; } - } public static PolygonIdentifier polygonId(String name, int year) { diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java index 015dbcb8b..bcb0541d3 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/controlmap/ForwardResolvedControlMapTest.java @@ -11,12 +11,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; import ca.bc.gov.nrs.vdyp.forward.ForwardControlParser; import ca.bc.gov.nrs.vdyp.forward.model.ForwardControlVariables; import ca.bc.gov.nrs.vdyp.forward.model.ForwardDebugSettings; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; -import ca.bc.gov.nrs.vdyp.io.parse.coe.DebugSettingsParser; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.BecLookup; import ca.bc.gov.nrs.vdyp.model.CompVarAdjustments; @@ -136,77 +134,4 @@ void testForwardResolvedControlMap() throws IOException, ResourceParseException e = forwardControlMap.getQuadMeanDiameterBySpeciesCoefficients(); assertThat(e, instanceOf(Map.class)); } - - @Test - void testCachingResolvedControlMap() throws IOException, ResourceParseException { - logger.info(this.getClass().getName() + ":testCachingResolvedControlMap running..."); - - var parser = new ForwardControlParser(); - var rawControlMap = VdypForwardTestUtils.parse(parser, "VDYP.CTR"); - var cachingControlMap = new CachingResolvedControlMapImpl(rawControlMap); - - assertThat(cachingControlMap.getControlMap(), is(rawControlMap)); - - Object e; - e = cachingControlMap.getBecLookup(); - assertThat(e, instanceOf(BecLookup.class)); - e = cachingControlMap.getGenusDefinitionMap(); - assertThat(e, instanceOf(GenusDefinitionMap.class)); - e = cachingControlMap.getNetDecayWasteCoeMap(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getNetDecayCoeMap(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getWasteModifierMap(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getDecayModifierMap(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getCloseUtilizationCoeMap(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getTotalStandWholeStepVolumeCoeMap(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getWholeStemUtilizationComponentMap(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getQuadMeanDiameterUtilizationComponentMap(); - assertThat(e, instanceOf(MatrixMap3.class)); - e = cachingControlMap.getBasalAreaDiameterUtilizationComponentMap(); - assertThat(e, instanceOf(MatrixMap3.class)); - e = cachingControlMap.getSmallComponentWholeStemVolumeCoefficients(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getSmallComponentLoreyHeightCoefficients(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getSmallComponentQuadMeanDiameterCoefficients(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getSmallComponentBasalAreaCoefficients(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getSmallComponentProbabilityCoefficients(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getMaximumAgeBySiteCurveNumber(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getUpperBounds(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getDefaultEquationGroup(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getEquationModifierGroup(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getHl1Coefficients(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getHl2Coefficients(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getHl3Coefficients(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getHlNonPrimaryCoefficients(); - assertThat(e, instanceOf(MatrixMap3.class)); - e = cachingControlMap.getComponentSizeLimits(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getNetBreakageMap(); - assertThat(e, instanceOf(Map.class)); - e = cachingControlMap.getVolumeEquationGroups(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getDecayEquationGroups(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getBreakageEquationGroups(); - assertThat(e, instanceOf(MatrixMap2.class)); - e = cachingControlMap.getQuadMeanDiameterBySpeciesCoefficients(); - assertThat(e, instanceOf(Map.class)); - } } From 8870cc6ead46ce737301b88f72169d536315bef8 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 11:08:39 -0700 Subject: [PATCH 58/66] additional tests --- .../nrs/vdyp/io/ZipOutputFileResolver.java | 2 +- .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 86 +++++------ .../application/VdypStartApplicationTest.java | 10 +- .../ca/bc/gov/nrs/vdyp/common/UtilsTest.java | 2 +- .../vdyp/io/ZipOutputFileResolverTest.java | 44 +++++- .../bc/gov/nrs/vdyp/model/VdypLayerTest.java | 133 +++++++++++++++++- .../forward/UtilizationOperationsTest.java | 10 +- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 8 +- .../ca/bc/gov/nrs/vdyp/vri/VriStartTest.java | 8 +- 9 files changed, 231 insertions(+), 72 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java index b618e4c10..8c0367ee1 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolver.java @@ -15,7 +15,7 @@ public class ZipOutputFileResolver implements FileResolver { private record OutputStreamDetails(Path outputStreamLocation, OutputStream outputStream) { - }; + } private Map entryOutputStreams = new HashMap<>(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index 53e6b637d..19236acc3 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -110,9 +110,9 @@ public UtilizationVector getCloseUtilizationVolumeNetOfDecayByUtilization() { @Override public void setCloseUtilizationVolumeNetOfDecayByUtilization( - UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization + UtilizationVector closeUtilizationVolumeNetOfDecayByUtilization ) { - this.closeUtilizationVolumeNetOfDecayByUtilization = closeUtilizationNetVolumeOfDecayByUtilization; + this.closeUtilizationVolumeNetOfDecayByUtilization = closeUtilizationVolumeNetOfDecayByUtilization; } @Override @@ -199,54 +199,55 @@ public void empiricalRelationshipParameterIndex(int empiricalRelationshipParamet this.empiricalRelationshipParameterIndex(Optional.of(empiricalRelationshipParameterIndex)); } - UtilizationVector loreyHeight = VdypUtilizationHolder.emptyLoreyHeightUtilization(); + UtilizationVector loreyHeightByUtilization = VdypUtilizationHolder.emptyLoreyHeightUtilization(); - public void loreyHeight(float height) { - this.loreyHeight = Utils.heightVector(0, height); + public void loreyHeightByUtilization(float height) { + this.loreyHeightByUtilization = Utils.heightVector(0, height); } - public void loreyHeight(float small, float height) { - this.loreyHeight = Utils.heightVector(small, height); + public void loreyHeightByUtilization(float small, float height) { + this.loreyHeightByUtilization = Utils.heightVector(small, height); } - protected UtilizationVector baseArea = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector baseAreaByUtilization = VdypUtilizationHolder.emptyUtilization(); - public void baseArea(float small, float u1, float u2, float u3, float u4) { - this.baseArea = Utils.utilizationVector(small, u1, u2, u3, u4); + public void baseAreaByUtilization(float small, float u1, float u2, float u3, float u4) { + this.baseAreaByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); } - public void baseArea(float height) { - this.baseArea = Utils.utilizationVector(height); + public void baseAreaByUtilization(float height) { + this.baseAreaByUtilization = Utils.utilizationVector(height); } - protected UtilizationVector treesPerHectare = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector treesPerHectareByUtilization = VdypUtilizationHolder.emptyUtilization(); - public void treesPerHectare(float small, float u1, float u2, float u3, float u4) { - this.treesPerHectare = Utils.utilizationVector(small, u1, u2, u3, u4); + public void treesPerHectareByUtilization(float small, float u1, float u2, float u3, float u4) { + this.treesPerHectareByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); } - public void treesPerHectare(float height) { - this.treesPerHectare = Utils.utilizationVector(height); + public void treesPerHectareByUtilization(float height) { + this.treesPerHectareByUtilization = Utils.utilizationVector(height); } - protected UtilizationVector quadMeanDiameter = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector quadraticMeanDiameterByUtilization = VdypUtilizationHolder.emptyUtilization(); - public void quadMeanDiameter(float small, float uAll, float u1, float u2, float u3, float u4) { - this.quadMeanDiameter = Utils.utilizationVector(small, uAll, u1, u2, u3, u4); + public void + quadraticMeanDiameterByUtilization(float small, float uAll, float u1, float u2, float u3, float u4) { + this.quadraticMeanDiameterByUtilization = Utils.utilizationVector(small, uAll, u1, u2, u3, u4); } - public void quadMeanDiameter(float height) { - this.quadMeanDiameter = Utils.utilizationVector(height); + public void quadraticMeanDiameterByUtilization(float height) { + this.quadraticMeanDiameterByUtilization = Utils.utilizationVector(height); } - protected UtilizationVector wholeStemVolume = VdypUtilizationHolder.emptyUtilization(); + protected UtilizationVector wholeStemVolumeByUtilization = VdypUtilizationHolder.emptyUtilization(); - public void wholeStemVolume(float small, float u1, float u2, float u3, float u4) { - this.wholeStemVolume = Utils.utilizationVector(small, u1, u2, u3, u4); + public void wholeStemVolumeByUtilization(float small, float u1, float u2, float u3, float u4) { + this.wholeStemVolumeByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); } - public void wholeStemVolume(float volume) { - this.wholeStemVolume = Utils.utilizationVector(volume); + public void wholeStemVolumeByUtilization(float volume) { + this.wholeStemVolumeByUtilization = Utils.utilizationVector(volume); } protected UtilizationVector closeUtilizationVolumeByUtilization = VdypUtilizationHolder.emptyUtilization(); @@ -259,15 +260,15 @@ public void closeUtilizationVolumeByUtilization(float volume) { this.closeUtilizationVolumeByUtilization = Utils.utilizationVector(volume); } - protected UtilizationVector closeUtilizationNetVolumeOfDecayByUtilization = VdypUtilizationHolder + protected UtilizationVector closeUtilizationVolumeNetOfDecayByUtilization = VdypUtilizationHolder .emptyUtilization(); public void closeUtilizationVolumeNetOfDecayByUtilization(float small, float u1, float u2, float u3, float u4) { - this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); + this.closeUtilizationVolumeNetOfDecayByUtilization = Utils.utilizationVector(small, u1, u2, u3, u4); } public void closeUtilizationVolumeNetOfDecayByUtilization(float volume) { - this.closeUtilizationNetVolumeOfDecayByUtilization = Utils.utilizationVector(volume); + this.closeUtilizationVolumeNetOfDecayByUtilization = Utils.utilizationVector(volume); } protected UtilizationVector closeUtilizationVolumeNetOfDecayAndWasteByUtilization = VdypUtilizationHolder @@ -302,13 +303,13 @@ public VdypLayer.Builder adapt(BaseVdypLayer baseSource) { super.adapt(baseSource); if (baseSource instanceof VdypLayer source) { - loreyHeight = new UtilizationVector(source.loreyHeightByUtilization); - baseArea = new UtilizationVector(source.baseAreaByUtilization); - treesPerHectare = new UtilizationVector(source.treesPerHectareByUtilization); - quadMeanDiameter = new UtilizationVector(source.quadraticMeanDiameterByUtilization); - wholeStemVolume = new UtilizationVector(source.wholeStemVolumeByUtilization); + loreyHeightByUtilization = new UtilizationVector(source.loreyHeightByUtilization); + baseAreaByUtilization = new UtilizationVector(source.baseAreaByUtilization); + treesPerHectareByUtilization = new UtilizationVector(source.treesPerHectareByUtilization); + quadraticMeanDiameterByUtilization = new UtilizationVector(source.quadraticMeanDiameterByUtilization); + wholeStemVolumeByUtilization = new UtilizationVector(source.wholeStemVolumeByUtilization); closeUtilizationVolumeByUtilization = new UtilizationVector(source.closeUtilizationVolumeByUtilization); - closeUtilizationNetVolumeOfDecayByUtilization = new UtilizationVector( + closeUtilizationVolumeNetOfDecayByUtilization = new UtilizationVector( source.closeUtilizationVolumeNetOfDecayByUtilization ); closeUtilizationVolumeNetOfDecayAndWasteByUtilization = new UtilizationVector( @@ -326,20 +327,19 @@ public VdypLayer.Builder adapt(BaseVdypLayer baseSource) { protected void postProcess(VdypLayer layer) { super.postProcess(layer); - layer.setLoreyHeightByUtilization(loreyHeight); - layer.setBaseAreaByUtilization(baseArea); - layer.setTreesPerHectareByUtilization(treesPerHectare); - layer.setQuadraticMeanDiameterByUtilization(quadMeanDiameter); - layer.setWholeStemVolumeByUtilization(wholeStemVolume); + layer.setLoreyHeightByUtilization(loreyHeightByUtilization); + layer.setBaseAreaByUtilization(baseAreaByUtilization); + layer.setTreesPerHectareByUtilization(treesPerHectareByUtilization); + layer.setQuadraticMeanDiameterByUtilization(quadraticMeanDiameterByUtilization); + layer.setWholeStemVolumeByUtilization(wholeStemVolumeByUtilization); layer.setCloseUtilizationVolumeByUtilization(closeUtilizationVolumeByUtilization); - layer.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationNetVolumeOfDecayByUtilization); + layer.setCloseUtilizationVolumeNetOfDecayByUtilization(closeUtilizationVolumeNetOfDecayByUtilization); layer.setCloseUtilizationVolumeNetOfDecayAndWasteByUtilization( closeUtilizationVolumeNetOfDecayAndWasteByUtilization ); layer.setCloseUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization( closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization ); - ; } @Override diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index 20afd4e3f..992a2704b 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -1276,11 +1276,11 @@ void testEstimate() throws ProcessingException, IOException { sb.wholeStemVolume(57.2091446f); }); - lb.loreyHeight(31.3307209f); - lb.baseArea(44.6249847f); - lb.treesPerHectare(620.484802f); - lb.quadMeanDiameter(30.2606697f); - lb.wholeStemVolume(635.659668f); + lb.loreyHeightByUtilization(31.3307209f); + lb.baseAreaByUtilization(44.6249847f); + lb.treesPerHectareByUtilization(620.484802f); + lb.quadraticMeanDiameterByUtilization(30.2606697f); + lb.wholeStemVolumeByUtilization(635.659668f); }); app.estimateSmallComponents(fPoly, layer); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java index e47390913..e4a8c7d87 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/UtilsTest.java @@ -142,7 +142,7 @@ void testFromSingleValue() { lb.polygonIdentifier("Test", 2024); lb.layerType(LayerType.PRIMARY); - lb.baseArea(0.7f, 0.9f, 1.1f, 1.3f, 1.5f); + lb.baseAreaByUtilization(0.7f, 0.9f, 1.1f, 1.3f, 1.5f); lb.addSpecies(sb -> { sb.genus("B", 3); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index af4a5da9c..1f9a30f82 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -1,5 +1,6 @@ package ca.bc.gov.nrs.vdyp.io; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; @@ -11,6 +12,8 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; public class ZipOutputFileResolverTest { @@ -20,18 +23,48 @@ void testZipOutputFileResolver() throws IOException { ZipOutputFileResolver resolver = new ZipOutputFileResolver(); + MatcherAssert.assertThat( + resolver.toPath("file").toString(), + Matchers.is("/Users/mjunkin/source/vdyp-ssh/vdyp-lib/vdyp-common/file") + ); + + assertThrows(UnsupportedOperationException.class, () -> resolver.resolveForInput("file")); + + MatcherAssert.assertThat( + resolver.toString("file"), Matchers.is("zip:/Users/mjunkin/source/vdyp-ssh/vdyp-lib/vdyp-common/file") + ); + for (int i = 0; i < 5; i++) { OutputStream os = resolver.resolveForOutput("file" + i); os.write(String.format("%d", i).getBytes()); } - Path zipFile = Files.createTempFile(this.getClass().getName(), ".zip"); + Path zipFileFromFile = Files.createTempFile(this.getClass().getName(), ".zip"); + Path zipFileFromStream = Files.createTempFile(this.getClass().getName(), "-from-stream.zip"); try { - resolver.generate(zipFile); + resolver.generate(zipFileFromFile); + + System.out.println("Output zip file written to " + zipFileFromFile.toString()); + + try (ZipFile zip = new ZipFile(zipFileFromFile.toFile())) { + var entries = zip.entries(); + + byte[] buffer = new byte[16]; + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); + + InputStream is = zip.getInputStream(e); + int nBytesRead = is.read(buffer, 0, 10); + assertTrue(nBytesRead == 1); + String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); + assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); + } + } - System.out.println("Output zip file written to " + zipFile.toString()); + InputStream zipByteStream = resolver.generateStream(); + Files.write(zipFileFromStream, zipByteStream.readAllBytes()); - try (ZipFile zip = new ZipFile(zipFile.toFile())) { + try (ZipFile zip = new ZipFile(zipFileFromStream.toFile())) { var entries = zip.entries(); byte[] buffer = new byte[16]; @@ -46,7 +79,8 @@ void testZipOutputFileResolver() throws IOException { } } } finally { - Files.delete(zipFile); + Files.delete(zipFileFromFile); + Files.delete(zipFileFromStream); } } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java index 8c4ab7810..299a9b1b2 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypLayerTest.java @@ -24,6 +24,7 @@ import ca.bc.gov.nrs.vdyp.common.Utils; import ca.bc.gov.nrs.vdyp.test.TestUtils; +import ca.bc.gov.nrs.vdyp.test.VdypMatchers; class VdypLayerTest { @@ -46,8 +47,8 @@ void build() throws Exception { siteBuilder.siteCurveNumber(0); }); }); - }); + assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); assertThat(result, hasProperty("layerType", is(LayerType.PRIMARY))); assertThat(result, hasProperty("ageTotal", present(is(42f)))); @@ -92,7 +93,6 @@ void buildForPolygon() throws Exception { siteBuilder.siteCurveNumber(0); }); }); - }); assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); @@ -163,7 +163,6 @@ void buildAdapt() throws Exception { assertThat(result, hasProperty("inventoryTypeGroup", present(is(12)))); control.verify(); - } @Test @@ -223,7 +222,6 @@ void buildAdaptSpecies() throws Exception { ); control.verify(); - } @Test @@ -292,4 +290,131 @@ void buildCopySpecies() throws Exception { ); } + @Test + void testAdditionalBuildMethods() { + Map controlMap = new HashMap<>(); + TestUtils.populateControlMapBecReal(controlMap); + + var poly = VdypPolygon.build(builder -> { + builder.polygonIdentifier("Test", 2024); + builder.percentAvailable(50f); + + builder.forestInventoryZone("?"); + builder.biogeoclimaticZone(Utils.getBec("IDF", controlMap)); + }); + + var layer1 = VdypLayer.build(poly, builder -> { + builder.inventoryTypeGroup(1); + builder.empiricalRelationshipParameterIndex(1); + builder.layerType(LayerType.PRIMARY); + + builder.closeUtilizationVolumeByUtilization(1.0f); + builder.closeUtilizationVolumeNetOfDecayByUtilization(1.0f); + builder.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(1.0f); + builder.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(1.0f); + builder.wholeStemVolumeByUtilization(1.0f); + builder.baseAreaByUtilization(1.0f); + builder.loreyHeightByUtilization(1.0f, 1.0f); + builder.quadraticMeanDiameterByUtilization(1.0f); + builder.treesPerHectareByUtilization(1.0f); + }); + + assertThat(poly.getLayers(), hasEntry(LayerType.PRIMARY, layer1)); + + assertThat(layer1, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(layer1, hasProperty("layerType", is(LayerType.PRIMARY))); + assertThat(layer1, hasProperty("species", aMapWithSize(0))); + assertThat(layer1, hasProperty("empiricalRelationshipParameterIndex", VdypMatchers.present(is(1)))); + assertThat(layer1, hasProperty("inventoryTypeGroup", VdypMatchers.present(is(1)))); + assertThat(layer1, hasProperty("closeUtilizationVolumeByUtilization", is(Utils.utilizationVector(1.0f)))); + assertThat( + layer1, hasProperty("closeUtilizationVolumeNetOfDecayByUtilization", is(Utils.utilizationVector(1.0f))) + ); + assertThat( + layer1, + hasProperty("closeUtilizationVolumeNetOfDecayAndWasteByUtilization", is(Utils.utilizationVector(1.0f))) + ); + assertThat( + layer1, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + is(Utils.utilizationVector(1.0f)) + ) + ); + assertThat(layer1, hasProperty("wholeStemVolumeByUtilization", is(Utils.utilizationVector(1.0f)))); + assertThat(layer1, hasProperty("baseAreaByUtilization", is(Utils.utilizationVector(1.0f)))); + assertThat(layer1, hasProperty("loreyHeightByUtilization", is(new UtilizationVector(1.0f, 1.0f)))); + assertThat(layer1, hasProperty("quadraticMeanDiameterByUtilization", is(Utils.utilizationVector(1.0f)))); + assertThat(layer1, hasProperty("treesPerHectareByUtilization", is(Utils.utilizationVector(1.0f)))); + + var layer2 = VdypLayer.build(poly, builder -> { + builder.inventoryTypeGroup(2); + builder.empiricalRelationshipParameterIndex(2); + builder.layerType(LayerType.PRIMARY); + + builder.closeUtilizationVolumeByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.closeUtilizationVolumeNetOfDecayByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.closeUtilizationVolumeNetOfDecayAndWasteByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.wholeStemVolumeByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.baseAreaByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.loreyHeightByUtilization(2.0f, 2.0f); + builder.quadraticMeanDiameterByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + builder.treesPerHectareByUtilization(2.0f, 2.0f, 2.0f, 2.0f, 2.0f); + }); + + assertThat(poly.getLayers(), hasEntry(LayerType.PRIMARY, layer2)); + + assertThat(layer2, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(layer2, hasProperty("layerType", is(LayerType.PRIMARY))); + assertThat(layer2, hasProperty("species", aMapWithSize(0))); + assertThat(layer2, hasProperty("empiricalRelationshipParameterIndex", VdypMatchers.present(is(2)))); + assertThat(layer2, hasProperty("inventoryTypeGroup", VdypMatchers.present(is(2)))); + assertThat( + layer2, + hasProperty( + "closeUtilizationVolumeByUtilization", is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f)) + ) + ); + assertThat( + layer2, + hasProperty( + "closeUtilizationVolumeNetOfDecayByUtilization", + is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f)) + ) + ); + assertThat( + layer2, + hasProperty( + "closeUtilizationVolumeNetOfDecayAndWasteByUtilization", + is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f)) + ) + ); + assertThat( + layer2, + hasProperty( + "closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization", + is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f)) + ) + ); + assertThat( + layer2, + hasProperty("wholeStemVolumeByUtilization", is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f))) + ); + assertThat( + layer2, hasProperty("baseAreaByUtilization", is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f))) + ); + assertThat(layer2, hasProperty("loreyHeightByUtilization", is(new UtilizationVector(2.0f, 2.0f)))); + assertThat( + layer2, + hasProperty( + "quadraticMeanDiameterByUtilization", + is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f)) + ) + ); + assertThat( + layer2, + hasProperty("treesPerHectareByUtilization", is(Utils.utilizationVector(2.0f, 2.0f, 2.0f, 2.0f, 2.0f))) + ); + } } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java index 8d9ad30f1..fa89923b4 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperationsTest.java @@ -50,11 +50,11 @@ void testUtilizationOperations() throws Exception { lb.layerType(LayerType.PRIMARY); lb.inventoryTypeGroup(1); - lb.baseArea(0.01513f, 0.53100f, 1.27855f, 2.33020f, 40.79285f); - lb.treesPerHectare(5.24f, 64.82f, 71.93f, 73.60f, 384.98f); - lb.loreyHeight(7.0166f, 30.9724f); - lb.wholeStemVolume(0.0630f, 2.5979f, 9.1057f, 22.4019f, 586.8720f); - lb.quadMeanDiameter(6.1f, 31.0f, 10.2f, 15.0f, 20.1f, 36.7f); + lb.baseAreaByUtilization(0.01513f, 0.53100f, 1.27855f, 2.33020f, 40.79285f); + lb.treesPerHectareByUtilization(5.24f, 64.82f, 71.93f, 73.60f, 384.98f); + lb.loreyHeightByUtilization(7.0166f, 30.9724f); + lb.wholeStemVolumeByUtilization(0.0630f, 2.5979f, 9.1057f, 22.4019f, 586.8720f); + lb.quadraticMeanDiameterByUtilization(6.1f, 31.0f, 10.2f, 15.0f, 20.1f, 36.7f); lb.closeUtilizationVolumeByUtilization(0.0630f, 2.5979f, 9.1057f, 22.4019f, 586.8720f); lb.closeUtilizationVolumeNetOfDecayByUtilization(0.0000f, 0.3794f, 6.8469f, 19.8884f, 553.0534f); lb.closeUtilizationVolumeNetOfDecayAndWasteByUtilization( diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index bf1515d90..6af5e5b08 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -458,9 +458,9 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws ); float layerQuadMeanDiameter = quadMeanDiameter(primaryBaseArea, primaryLayerDensity); - lBuilder.quadMeanDiameter(layerQuadMeanDiameter); - lBuilder.baseArea(primaryBaseArea); - lBuilder.treesPerHectare(primaryLayerDensity); + lBuilder.quadraticMeanDiameterByUtilization(layerQuadMeanDiameter); + lBuilder.baseAreaByUtilization(primaryBaseArea); + lBuilder.treesPerHectareByUtilization(primaryLayerDensity); lBuilder.empiricalRelationshipParameterIndex(primaryLayer.getEmpericalRelationshipParameterIndex()); lBuilder.adaptSpecies(primaryLayer, (sBuilder, vriSpec) -> { @@ -523,7 +523,7 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws } } - lBuilder.loreyHeight(sumBaseAreaLoreyHeight / primaryBaseArea); + lBuilder.loreyHeightByUtilization(sumBaseAreaLoreyHeight / primaryBaseArea); } diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java index 2933e728e..386c796a8 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java @@ -1633,10 +1633,10 @@ void testCompute() throws ProcessingException { VdypLayer layer = VdypLayer.build((lb) -> { lb.polygonIdentifier("Test", 2024); lb.layerType(LayerType.PRIMARY); - lb.baseArea(6.34290648f); - lb.treesPerHectare(748.402222f); - lb.quadMeanDiameter(10.3879938f); - lb.loreyHeight(6.61390257f); + lb.baseAreaByUtilization(6.34290648f); + lb.treesPerHectareByUtilization(748.402222f); + lb.quadraticMeanDiameterByUtilization(10.3879938f); + lb.loreyHeightByUtilization(6.61390257f); lb.addSpecies(sb -> { sb.genus("B", controlMap); sb.percentGenus(10); From cda811e052906e33e5917486b9a564f0b1f5e8e1 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 11:20:43 -0700 Subject: [PATCH 59/66] more tests --- .../controlmap/ResolvedControlMapTest.java | 99 +++++++++++++++++++ .../vdyp/io/ZipOutputFileResolverTest.java | 2 +- 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/ResolvedControlMapTest.java diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/ResolvedControlMapTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/ResolvedControlMapTest.java new file mode 100644 index 000000000..729d664f2 --- /dev/null +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/common/controlmap/ResolvedControlMapTest.java @@ -0,0 +1,99 @@ +package ca.bc.gov.nrs.vdyp.common.controlmap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.bc.gov.nrs.vdyp.controlmap.CachingResolvedControlMapImpl; +import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; +import ca.bc.gov.nrs.vdyp.model.BecLookup; +import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; +import ca.bc.gov.nrs.vdyp.model.MatrixMap2; +import ca.bc.gov.nrs.vdyp.model.MatrixMap3; +import ca.bc.gov.nrs.vdyp.test.TestUtils; + +public class ResolvedControlMapTest { + + private static final Logger logger = LoggerFactory.getLogger(ResolvedControlMapTest.class); + + @Test + void testCachingResolvedControlMap() throws IOException, ResourceParseException { + logger.info(this.getClass().getName() + ":testCachingResolvedControlMap running..."); + + var rawControlMap = TestUtils.loadControlMap(Path.of("VDYP.CTR")); + + var cachingControlMap = new CachingResolvedControlMapImpl(rawControlMap); + + assertThat(cachingControlMap.getControlMap(), is(rawControlMap)); + + Object e; + e = cachingControlMap.getBecLookup(); + assertThat(e, instanceOf(BecLookup.class)); + e = cachingControlMap.getGenusDefinitionMap(); + assertThat(e, instanceOf(GenusDefinitionMap.class)); + e = cachingControlMap.getNetDecayWasteCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getNetDecayCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getWasteModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getDecayModifierMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getCloseUtilizationCoeMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getTotalStandWholeStepVolumeCoeMap(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getWholeStemUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getQuadMeanDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = cachingControlMap.getBasalAreaDiameterUtilizationComponentMap(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = cachingControlMap.getSmallComponentWholeStemVolumeCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentLoreyHeightCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentQuadMeanDiameterCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentBasalAreaCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getSmallComponentProbabilityCoefficients(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getMaximumAgeBySiteCurveNumber(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getUpperBounds(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getDefaultEquationGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getEquationModifierGroup(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHl1Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHl2Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHl3Coefficients(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getHlNonPrimaryCoefficients(); + assertThat(e, instanceOf(MatrixMap3.class)); + e = cachingControlMap.getComponentSizeLimits(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getNetBreakageMap(); + assertThat(e, instanceOf(Map.class)); + e = cachingControlMap.getVolumeEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getDecayEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getBreakageEquationGroups(); + assertThat(e, instanceOf(MatrixMap2.class)); + e = cachingControlMap.getQuadMeanDiameterBySpeciesCoefficients(); + assertThat(e, instanceOf(Map.class)); + } +} diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index 1f9a30f82..6bacb5b4c 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -31,7 +31,7 @@ void testZipOutputFileResolver() throws IOException { assertThrows(UnsupportedOperationException.class, () -> resolver.resolveForInput("file")); MatcherAssert.assertThat( - resolver.toString("file"), Matchers.is("zip:/Users/mjunkin/source/vdyp-ssh/vdyp-lib/vdyp-common/file") + resolver.toString("file"), Matchers.endsWith("vdyp-lib/vdyp-common/file") ); for (int i = 0; i < 5; i++) { From d5522104bb125344a7d3010fb119041f6756683d Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 11:35:21 -0700 Subject: [PATCH 60/66] more tests --- .../vdyp/io/ZipOutputFileResolverTest.java | 4 +- .../java/ca/bc/gov/nrs/vdyp/forward/Bank.java | 78 ++++--------------- .../vdyp/forward/ForwardProcessingEngine.java | 6 +- .../vdyp/forward/LayerProcessingState.java | 54 +------------ .../ca/bc/gov/nrs/vdyp/forward/BankTest.java | 3 +- .../GeneralForwardProcessingEngineTest.java | 6 +- ...yVariablesForwardProcessingEngineTest.java | 6 +- 7 files changed, 31 insertions(+), 126 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index 6bacb5b4c..35cf9eab0 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -30,9 +30,7 @@ void testZipOutputFileResolver() throws IOException { assertThrows(UnsupportedOperationException.class, () -> resolver.resolveForInput("file")); - MatcherAssert.assertThat( - resolver.toString("file"), Matchers.endsWith("vdyp-lib/vdyp-common/file") - ); + MatcherAssert.assertThat(resolver.toString("file"), Matchers.endsWith("vdyp-lib/vdyp-common/file")); for (int i = 0; i < 5; i++) { OutputStream os = resolver.resolveForOutput("file" + i); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java index 884510e5e..2d807186c 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/Bank.java @@ -21,10 +21,6 @@ class Bank { - enum CopyMode { - CopyAll, CopyStructure - }; - @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(Bank.class); @@ -108,7 +104,7 @@ public Bank(VdypLayer layer, BecDefinition becZone, Predicate retai } } - public Bank(Bank source, CopyMode copyMode) { + public Bank(Bank source) { this.becZone = source.becZone; this.layer = source.layer; @@ -121,60 +117,21 @@ public Bank(Bank source, CopyMode copyMode) { this.siteCurveNumbers = copy(source.siteCurveNumbers); this.sp64Distributions = copy(source.sp64Distributions); - if (copyMode == CopyMode.CopyAll) { - 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); - } else { - this.ageTotals = buildShell(nSpecies); - this.dominantHeights = buildShell(nSpecies); - this.percentagesOfForestedLand = buildShell(nSpecies); - this.siteIndices = buildShell(nSpecies); - this.yearsAtBreastHeight = buildShell(nSpecies); - this.yearsToBreastHeight = buildShell(nSpecies); - - int nUtilizationClasses = UtilizationClass.values().length; - this.basalAreas = buildShell(nSpecies, nUtilizationClasses); - this.closeUtilizationVolumes = buildShell(nSpecies, nUtilizationClasses); - this.cuVolumesMinusDecay = buildShell(nSpecies, nUtilizationClasses); - this.cuVolumesMinusDecayAndWastage = buildShell(nSpecies, nUtilizationClasses); - this.loreyHeights = buildShell(nSpecies, nUtilizationClasses); - this.quadMeanDiameters = buildShell(nSpecies, nUtilizationClasses); - this.treesPerHectare = buildShell(nSpecies, nUtilizationClasses); - this.wholeStemVolumes = buildShell(nSpecies, nUtilizationClasses); - } - } - - private float[] buildShell(int n) { - - float[] result = new float[nSpecies + 1]; - Arrays.fill(result, Float.NaN); - return result; - } - - private float[][] buildShell(int n, int m) { - - float[][] result = new float[nSpecies + 1][]; - - for (int i = 0; i <= n; i++) { - float[] row = new float[m]; - Arrays.fill(row, Float.NaN); - result[i] = row; - } - - return result; + 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() { @@ -326,8 +283,7 @@ private void transferUtilizationsFromBank(int index, VdypUtilizationHolder uh) { } public Bank copy() { - return new Bank(this, CopyMode.CopyAll); - + return new Bank(this); } private String[] copy(String[] a) { diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 2102796b2..195a95800 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -2468,7 +2468,7 @@ void setCompatibilityVariables() throws ProcessingException { if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP093 - int decayGroup = lps.decayEquationGroups[s]; + int decayGroup = lps.getDecayEquationGroups()[s]; fps.estimators.estimateNetDecayVolume( bank.speciesNames[s], lps.getBecZone().getRegion(), uc, aAdjust, decayGroup, lps.getPrimarySpeciesAgeAtBreastHeight(), quadMeanDiameters, closeUtilizationVolumes, @@ -2489,7 +2489,7 @@ void setCompatibilityVariables() throws ProcessingException { if (growthDetails.allowCalculation(baseVolume, V_BASE_MIN, (l, r) -> l > r)) { // EMP092 - int volumeGroup = lps.volumeEquationGroups[s]; + int volumeGroup = lps.getVolumeEquationGroups()[s]; fps.estimators.estimateCloseUtilizationVolume( uc, aAdjust, volumeGroup, spLoreyHeight_All, quadMeanDiameters, wholeStemVolumes, closeUtilizationVolumes @@ -2503,7 +2503,7 @@ void setCompatibilityVariables() throws ProcessingException { cvVolume[s].put(uc, VolumeVariable.CLOSE_UTIL_VOL, LayerType.PRIMARY, adjustment); } - int primarySpeciesVolumeGroup = lps.volumeEquationGroups[s]; + int primarySpeciesVolumeGroup = lps.getVolumeEquationGroups()[s]; float primarySpeciesQMDAll = bank.quadMeanDiameters[s][UC_ALL_INDEX]; var wholeStemVolume = bank.treesPerHectare[s][UC_ALL_INDEX] * fps.estimators .estimateWholeStemVolumePerTree(primarySpeciesVolumeGroup, spLoreyHeight_All, primarySpeciesQMDAll); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java index 8db8ac0d5..594b48d19 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LayerProcessingState.java @@ -59,9 +59,9 @@ class LayerProcessingState { // L1COM2 - equation groups. From the configuration, narrowed to the // polygon's BEC zone. - int[] volumeEquationGroups; - int[] decayEquationGroups; - int[] breakageEquationGroups; + private int[] volumeEquationGroups; + private int[] decayEquationGroups; + private int[] breakageEquationGroups; // L1COM3 - just shadows of fields of L1COM5 // AGETOTL1 = wallet.ageTotals[primarySpeciesIndex] @@ -203,54 +203,6 @@ public int getInventoryTypeGroup() { return inventoryTypeGroup; } - public static String getCompatibilityVariablesSetCanBeSetOnceOnly() { - return COMPATIBILITY_VARIABLES_SET_CAN_BE_SET_ONCE_ONLY; - } - - public static String getPrimarySpeciesDetailsCanBeSetOnceOnly() { - return PRIMARY_SPECIES_DETAILS_CAN_BE_SET_ONCE_ONLY; - } - - public static String getSiteCurveNumbersCanBeSetOnceOnly() { - return SITE_CURVE_NUMBERS_CAN_BE_SET_ONCE_ONLY; - } - - public static String getSpeciesRankingDetailsCanBeSetOnceOnly() { - return SPECIES_RANKING_DETAILS_CAN_BE_SET_ONCE_ONLY; - } - - public static String getUnsetPrimarySpeciesAgeToBreastHeight() { - return UNSET_PRIMARY_SPECIES_AGE_TO_BREAST_HEIGHT; - } - - public static String getUnsetPrimarySpeciesAgeAtBreastHeight() { - return UNSET_PRIMARY_SPECIES_AGE_AT_BREAST_HEIGHT; - } - - public static String getUnsetPrimarySpeciesDominantHeight() { - return UNSET_PRIMARY_SPECIES_DOMINANT_HEIGHT; - } - - public static String getUnsetCvVolumes() { - return UNSET_CV_VOLUMES; - } - - public static String getUnsetCvBasalAreas() { - return UNSET_CV_BASAL_AREAS; - } - - public static String getUnsetRankingDetails() { - return UNSET_RANKING_DETAILS; - } - - public static String getUnsetSiteCurveNumbers() { - return UNSET_SITE_CURVE_NUMBERS; - } - - public static String getUnsetInventoryTypeGroup() { - return UNSET_INVENTORY_TYPE_GROUP; - } - public static Logger getLogger() { return logger; } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java index f8b00d750..345a124e4 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/BankTest.java @@ -16,7 +16,6 @@ import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; -import ca.bc.gov.nrs.vdyp.forward.Bank.CopyMode; import ca.bc.gov.nrs.vdyp.forward.test.VdypForwardTestUtils; import ca.bc.gov.nrs.vdyp.io.parse.common.ResourceParseException; import ca.bc.gov.nrs.vdyp.model.GenusDefinitionMap; @@ -163,7 +162,7 @@ void testCopyConstructor() throws IOException, ResourceParseException, Processin Bank bank = new Bank(pLayer, polygon.getBiogeoclimaticZone(), s -> true); - Bank bankCopy = new Bank(bank, CopyMode.CopyAll); + Bank bankCopy = new Bank(bank); verifyBankMatchesLayer(bankCopy, pLayer); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java index f82d29558..8fd8ef72f 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/GeneralForwardProcessingEngineTest.java @@ -500,15 +500,15 @@ void testSetEquationGroups() throws ResourceParseException, IOException, Process fps.setPolygonLayer(polygon, LayerType.PRIMARY); assertThat( - fps.getLayerProcessingState().volumeEquationGroups, + fps.getLayerProcessingState().getVolumeEquationGroups(), Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 12, 20, 25, 37, 66 }) ); assertThat( - fps.getLayerProcessingState().decayEquationGroups, + fps.getLayerProcessingState().getDecayEquationGroups(), Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 7, 14, 19, 31, 54 }) ); assertThat( - fps.getLayerProcessingState().breakageEquationGroups, + fps.getLayerProcessingState().getBreakageEquationGroups(), Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 5, 6, 12, 17, 28 }) ); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java index 2cbcfce2c..95aa0ed7c 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/SetCompatibilityVariablesForwardProcessingEngineTest.java @@ -40,15 +40,15 @@ void testSetCompatibilityVariables() throws ResourceParseException, IOException, // platform-specific differences. assertThat( - fpe.fps.getLayerProcessingState().volumeEquationGroups, + fpe.fps.getLayerProcessingState().getVolumeEquationGroups(), Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 12, 20, 25, 37, 66 }) ); assertThat( - fpe.fps.getLayerProcessingState().decayEquationGroups, + fpe.fps.getLayerProcessingState().getDecayEquationGroups(), Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 7, 14, 19, 31, 54 }) ); assertThat( - fpe.fps.getLayerProcessingState().breakageEquationGroups, + fpe.fps.getLayerProcessingState().getBreakageEquationGroups(), Matchers.is(new int[] { VdypEntity.MISSING_INTEGER_VALUE, 5, 6, 12, 17, 28 }) ); From 8d623573cff4cd57947a128bcf51d6ceff83b0d7 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 12:36:36 -0700 Subject: [PATCH 61/66] unti test correction --- .../ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index 35cf9eab0..d1ef85027 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -23,10 +23,7 @@ void testZipOutputFileResolver() throws IOException { ZipOutputFileResolver resolver = new ZipOutputFileResolver(); - MatcherAssert.assertThat( - resolver.toPath("file").toString(), - Matchers.is("/Users/mjunkin/source/vdyp-ssh/vdyp-lib/vdyp-common/file") - ); + MatcherAssert.assertThat(resolver.toPath("file").toString(), Matchers.endsWith("vdyp-lib/vdyp-common/file")); assertThrows(UnsupportedOperationException.class, () -> resolver.resolveForInput("file")); From d673ca89956f81e5a615ef30426f15a484118839 Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 13:01:16 -0700 Subject: [PATCH 62/66] More tests... --- .../ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 5 ++ .../gov/nrs/vdyp/model/VdypPolygonTest.java | 56 +++++++++++++++++-- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index c6e8d387c..276f81547 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -49,6 +49,11 @@ public String toString() { return super.getPolygonIdentifier().toString(); } + @Override + public boolean equals(Object other) { + return super.equals(other); + } + public Optional getTargetYear() { return targetYear; } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java index d73c700e8..6704728e0 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypPolygonTest.java @@ -30,18 +30,62 @@ void build() throws Exception { Map controlMap = new HashMap<>(); TestUtils.populateControlMapBecReal(controlMap); - var result = VdypPolygon.build(builder -> { + var poly1 = VdypPolygon.build(builder -> { builder.polygonIdentifier("Test", 2024); builder.percentAvailable(90f); - builder.forestInventoryZone("?"); builder.biogeoclimaticZone(Utils.getBec("IDF", controlMap)); builder.targetYear(Optional.of(2024)); }); - assertThat(result, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); - assertThat(result, hasProperty("percentAvailable", is(90f))); - assertThat(result, hasProperty("layers", anEmptyMap())); - assertThat(result.getTargetYear(), present(is(2024))); + assertThat(poly1, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(poly1, hasProperty("percentAvailable", is(90f))); + assertThat(poly1, hasProperty("forestInventoryZone", is("?"))); + assertThat(poly1, hasProperty("biogeoclimaticZone", is(Utils.getBec("IDF", controlMap)))); + + assertThat(poly1, hasProperty("layers", anEmptyMap())); + + assertThat(poly1, hasProperty("targetYear", present(is(2024)))); + + var poly2 = new VdypPolygon(poly1, x -> x); + assertThat(poly2, hasProperty("targetYear", present(is(2024)))); + + assertThat(poly1.toString(), is("Test 2024")); + + assertThrows(IllegalArgumentException.class, () -> poly1.setTargetYear(2025)); + } + + @Test + void construct() throws Exception { + Map controlMap = new HashMap<>(); + TestUtils.populateControlMapBecReal(controlMap); + + var poly1 = new VdypPolygon( + new PolygonIdentifier("Test", 2024), 90f, "?", Utils.getBec("IDF", controlMap), + Optional.of(PolygonMode.START), Optional.of(1) + ); + + assertThat(poly1, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(poly1, hasProperty("percentAvailable", is(90f))); + assertThat(poly1, hasProperty("targetYear", notPresent())); + assertThat(poly1, hasProperty("forestInventoryZone", is("?"))); + assertThat(poly1, hasProperty("biogeoclimaticZone", is(Utils.getBec("IDF", controlMap)))); + assertThat(poly1, hasProperty("mode", present(is(PolygonMode.START)))); + assertThat(poly1, hasProperty("inventoryTypeGroup", present(is(1)))); + assertThat(poly1, hasProperty("layers", anEmptyMap())); + + var poly2 = new VdypPolygon(poly1, x -> x); + assertThat(poly2, hasProperty("polygonIdentifier", isPolyId("Test", 2024))); + assertThat(poly2, hasProperty("percentAvailable", is(90f))); + assertThat(poly2, hasProperty("targetYear", notPresent())); + assertThat(poly2, hasProperty("forestInventoryZone", is("?"))); + assertThat(poly2, hasProperty("biogeoclimaticZone", is(Utils.getBec("IDF", controlMap)))); + assertThat(poly2, hasProperty("mode", present(is(PolygonMode.START)))); + assertThat(poly2, hasProperty("inventoryTypeGroup", present(is(1)))); + assertThat(poly2, hasProperty("layers", anEmptyMap())); + + poly1.setTargetYear(2025); + assertThat(poly1, hasProperty("targetYear", present(is(2025)))); + } @Test From 00fe5fa1f0a719c2b2750ddbbda8e80160cf88be Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Fri, 6 Sep 2024 13:07:41 -0700 Subject: [PATCH 63/66] correct code quality issue --- .../src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java index 276f81547..e59d9468d 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypPolygon.java @@ -54,6 +54,11 @@ public boolean equals(Object other) { return super.equals(other); } + @Override + public int hashCode() { + return super.hashCode(); + } + public Optional getTargetYear() { return targetYear; } From c60977fa2e68006f1c3cea60ea2ddb4242b7c1af Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Mon, 9 Sep 2024 17:58:30 -0700 Subject: [PATCH 64/66] Code review changes --- .../nrs/vdyp/common/ComputationMethods.java | 15 +---- .../nrs/vdyp/common/EstimationMethods.java | 39 +++++++---- .../nrs/vdyp/common/ReconcilationMethods.java | 18 ++++-- .../vdyp/io/ZipOutputFileResolverTest.java | 64 +++++++++---------- .../java/ca/bc/gov/nrs/vdyp/fip/FipStart.java | 10 +-- .../vdyp/forward/ForwardProcessingEngine.java | 35 +++++----- .../forward/LambdaProcessingException.java | 17 ----- .../vdyp/forward/UtilizationOperations.java | 27 +++----- .../vdyp/forward/ForwardProcessorTest.java | 56 ++++++++-------- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 18 ++++-- .../bc/gov/nrs/vdyp/vri/model/VriLayer.java | 3 +- 11 files changed, 145 insertions(+), 157 deletions(-) delete mode 100644 vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java index 1f7f72caf..0d56bc2d2 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ComputationMethods.java @@ -66,14 +66,6 @@ public class ComputationMethods { .filter(x -> !x.getName().contains("Volume")).toList(); } - private final static UtilizationVector quadMeanDiameterLowerBounds = new UtilizationVector( - 0f, 0f, 7.5f, 12.5f, 17.5f, 22.5f - ); - - private final static UtilizationVector quadMeanDiameterUpperBounds = new UtilizationVector( - 0f, 0f, 12.5f, 17.5f, 22.5f, 10000f - ); - private final EstimationMethods estimationMethods; private final VdypApplicationIdentifier context; @@ -172,12 +164,7 @@ public void computeUtilizationComponentsPrimary( float newDqValue = quadMeanDiameterUtil.get(uc) + spec.getCvQuadraticMeanDiameter(uc, spec.getLayerType()); - quadMeanDiameterUtil.set( - uc, - FloatMath.clamp( - newDqValue, quadMeanDiameterLowerBounds.get(uc), quadMeanDiameterUpperBounds.get(uc) - ) - ); + quadMeanDiameterUtil.set(uc, FloatMath.clamp(newDqValue, uc.lowBound, uc.highBound)); } if (basalAreaSumForSpecies > 0.0f) { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java index 781e4c01f..d3ca7ded8 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/EstimationMethods.java @@ -396,7 +396,8 @@ public void estimateBaseAreaByUtilization( logit = a0 + a1 * dq; } b.set(uc, b.get(uc.previous().get()) * exponentRatio(logit)); - if (uc == UtilizationClass.U75TO125 && quadMeanDiameterUtil.getAll() < 12.5f) { + if (uc == UtilizationClass.U75TO125 + && quadMeanDiameterUtil.getAll() < UtilizationClass.U125TO175.lowBound) { float ba12Max = (1f - pow( (quadMeanDiameterUtil.getCoe(1) - 7.4f) / (quadMeanDiameterUtil.getAll() - 7.4f), 2f)) * b.getCoe(0); @@ -421,8 +422,9 @@ public void estimateBaseAreaByUtilization( public void estimateQuadMeanDiameterByUtilization( BecDefinition bec, UtilizationVector quadMeanDiameterUtil, String genus ) throws ProcessingException { - log.atTrace().setMessage("Estimate DQ by utilization class for {} in BEC {}. DQ for all >7.5 is {}") - .addArgument(genus).addArgument(bec.getName()).addArgument(quadMeanDiameterUtil.getAll()); + log.atTrace().setMessage("Estimate DQ by utilization class for {} in BEC {}. DQ for all >{} is {}") + .addArgument(genus).addArgument(bec.getName()).addArgument(UtilizationClass.U75TO125.lowBound) + .addArgument(quadMeanDiameterUtil.getAll()); var coeMap = controlMap.getQuadMeanDiameterUtilizationComponentMap(); @@ -442,22 +444,29 @@ public void estimateQuadMeanDiameterByUtilization( switch (uc) { case U75TO125: - if (quadMeanDiameter07 < 7.5001f) { - quadMeanDiameterUtil.setAll(7.5f); + if (quadMeanDiameter07 < UtilizationClass.U75TO125.lowBound + 0.0001f) { + quadMeanDiameterUtil.setAll(UtilizationClass.U75TO125.lowBound); } else { - log.atDebug().setMessage("DQ = 7.5 + a0 * (1 - exp(a1 / a0*(DQ07 - 7.5) ))**a2' )"); - - logit = a1 / a0 * (quadMeanDiameter07 - 7.5f); - - quadMeanDiameterUtil - .setCoe(uc.index, min(7.5f + a0 * pow(1 - safeExponent(logit), a2), quadMeanDiameter07)); + log.atDebug().setMessage("DQ = {} + a0 * (1 - exp(a1 / a0*(DQ07 - {}) ))**a2' )") + .addArgument(UtilizationClass.U75TO125.lowBound) + .addArgument(UtilizationClass.U75TO125.lowBound); + + logit = a1 / a0 * (quadMeanDiameter07 - UtilizationClass.U75TO125.lowBound); + + quadMeanDiameterUtil.setCoe( + uc.index, + min( + UtilizationClass.U75TO125.lowBound + a0 * pow(1 - safeExponent(logit), a2), + quadMeanDiameter07 + ) + ); } break; case U125TO175, U175TO225: log.atDebug().setMessage( "LOGIT = a0 + a1*(SQ07 / 7.5)**a2, DQ = (12.5 or 17.5) + 5 * exp(LOGIT) / (1 + exp(LOGIT))" ); - logit = a0 + a1 * pow(quadMeanDiameter07 / 7.5f, a2); + logit = a0 + a1 * pow(quadMeanDiameter07 / UtilizationClass.U75TO125.lowBound, a2); quadMeanDiameterUtil.setCoe(uc.index, uc.lowBound + 5f * exponentRatio(logit)); break; @@ -470,8 +479,10 @@ public void estimateQuadMeanDiameterByUtilization( logit = a2 + a1 * pow(quadMeanDiameter07, a3); - quadMeanDiameterUtil - .setCoe(uc.index, max(22.5f, quadMeanDiameter07 + a0 * (1f - exponentRatio(logit)))); + quadMeanDiameterUtil.setCoe( + uc.index, + max(UtilizationClass.OVER225.lowBound, quadMeanDiameter07 + a0 * (1f - exponentRatio(logit))) + ); break; case ALL, SMALL: throw new IllegalStateException( diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java index 180459ace..387b0eaf6 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ReconcilationMethods.java @@ -3,12 +3,13 @@ import static ca.bc.gov.nrs.vdyp.math.FloatMath.abs; import static ca.bc.gov.nrs.vdyp.math.FloatMath.sqrt; +import java.text.MessageFormat; import java.util.List; import ca.bc.gov.nrs.vdyp.application.ProcessingException; import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; -import ca.bc.gov.nrs.vdyp.model.UtilizationVector; import ca.bc.gov.nrs.vdyp.model.UtilizationClass; +import ca.bc.gov.nrs.vdyp.model.UtilizationVector; public class ReconcilationMethods { @@ -47,14 +48,23 @@ public static void reconcileComponents( } if (abs(baSum - baseAreaUtil.getAll()) > 0.00003 * baSum) { - throw new ProcessingException("Computed base areas for 7.5+ components do not sum to expected total"); + throw new ProcessingException( + MessageFormat.format( + "Computed base areas for {}+ components do not sum to expected total", + UtilizationClass.U75TO125.lowBound + ) + ); } float dq0 = BaseAreaTreeDensityDiameter.quadMeanDiameter(baseAreaUtil.getAll(), treesPerHectareUtil.getAll()); - if (dq0 < 7.5f) { + if (dq0 < UtilizationClass.U75TO125.lowBound) { throw new ProcessingException( - "Quadratic mean diameter computed from total base area and trees per hectare is less than 7.5 cm" + MessageFormat.format( + "Quadratic mean diameter computed from total" + + " base area and trees per hectare is less than {0} cm", + UtilizationClass.U75TO125.lowBound + ) ); } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java index d1ef85027..f139bc394 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/ZipOutputFileResolverTest.java @@ -15,9 +15,13 @@ import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; public class ZipOutputFileResolverTest { + @TempDir + Path outputLocation; + @Test void testZipOutputFileResolver() throws IOException { @@ -34,48 +38,44 @@ void testZipOutputFileResolver() throws IOException { os.write(String.format("%d", i).getBytes()); } - Path zipFileFromFile = Files.createTempFile(this.getClass().getName(), ".zip"); - Path zipFileFromStream = Files.createTempFile(this.getClass().getName(), "-from-stream.zip"); - try { - resolver.generate(zipFileFromFile); + Path zipFileFromFile = outputLocation.resolve(this.getClass().getSimpleName() + ".zip"); + Path zipFileFromStream = outputLocation.resolve(this.getClass().getSimpleName() + "-from-stream.zip"); + + resolver.generate(zipFileFromFile); - System.out.println("Output zip file written to " + zipFileFromFile.toString()); + System.out.println("Output zip file written to " + zipFileFromFile.toString()); - try (ZipFile zip = new ZipFile(zipFileFromFile.toFile())) { - var entries = zip.entries(); + try (ZipFile zip = new ZipFile(zipFileFromFile.toFile())) { + var entries = zip.entries(); - byte[] buffer = new byte[16]; - while (entries.hasMoreElements()) { - ZipEntry e = entries.nextElement(); + byte[] buffer = new byte[16]; + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); - InputStream is = zip.getInputStream(e); - int nBytesRead = is.read(buffer, 0, 10); - assertTrue(nBytesRead == 1); - String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); - assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); - } + InputStream is = zip.getInputStream(e); + int nBytesRead = is.read(buffer, 0, 10); + assertTrue(nBytesRead == 1); + String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); + assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); } + } - InputStream zipByteStream = resolver.generateStream(); - Files.write(zipFileFromStream, zipByteStream.readAllBytes()); + InputStream zipByteStream = resolver.generateStream(); + Files.write(zipFileFromStream, zipByteStream.readAllBytes()); - try (ZipFile zip = new ZipFile(zipFileFromStream.toFile())) { - var entries = zip.entries(); + try (ZipFile zip = new ZipFile(zipFileFromStream.toFile())) { + var entries = zip.entries(); - byte[] buffer = new byte[16]; - while (entries.hasMoreElements()) { - ZipEntry e = entries.nextElement(); + byte[] buffer = new byte[16]; + while (entries.hasMoreElements()) { + ZipEntry e = entries.nextElement(); - InputStream is = zip.getInputStream(e); - int nBytesRead = is.read(buffer, 0, 10); - assertTrue(nBytesRead == 1); - String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); - assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); - } + InputStream is = zip.getInputStream(e); + int nBytesRead = is.read(buffer, 0, 10); + assertTrue(nBytesRead == 1); + String fileNumber = e.getName().substring(e.getName().length() - 1, e.getName().length()); + assertTrue(new String(Arrays.copyOf(buffer, nBytesRead)).equals(fileNumber)); } - } finally { - Files.delete(zipFileFromFile); - Files.delete(zipFileFromStream); } } } diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java index c69aa47d2..0b4af4435 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipStart.java @@ -526,7 +526,8 @@ void findRootsForDiameterAndBaseArea(VdypLayer result, FipLayerPrimary fipLayer, int i = 0; for (var spec : result.getSpecies().values()) { float dqBase = (float) quadMeanDiameterBase[i++]; - float dq = 7.5f + (dqBase - 7.5f) * exp((float) rootVec.getEntry(rootVec.getDimension() - 1) / 20f); + float dq = UtilizationClass.U75TO125.lowBound + (dqBase - UtilizationClass.U75TO125.lowBound) + * exp((float) rootVec.getEntry(rootVec.getDimension() - 1) / 20f); assert dq >= 0; float ba = baseAreaTotal * spec.getPercentGenus() / 100f; assert ba >= 0; @@ -661,7 +662,7 @@ VdypLayer processLayerAsVeteran(FipPolygon fipPolygon, FipLayer fipLayer) throws var a1 = coe.getCoe(2); var a2 = coe.getCoe(3); float hl = vSpec.getLoreyHeightByUtilization().getCoe(0); - float dq = max(a0 + a1 * pow(hl, a2), 22.5f); + float dq = max(a0 + a1 * pow(hl, a2), UtilizationClass.OVER225.lowBound); vSpec.getQuadraticMeanDiameterByUtilization().setLarge(dq); vSpec.getTreesPerHectareByUtilization().setLarge( BaseAreaTreeDensityDiameter.treesPerHectare(vSpec.getBaseAreaByUtilization().getLarge(), dq) @@ -913,8 +914,9 @@ public float estimateMeanVolume(int volumeGroup, float loreyHeight, float quadMe // These side effects are evil but that's how VDYP7 works. - final float quadMeanDiameter = (float) (7.5 - + (diameterBase[j] - 7.5) * FastMath.exp(point[point.length - 1] / 20d)); + final float quadMeanDiameter = (float) (UtilizationClass.U75TO125.lowBound + + (diameterBase[j] - UtilizationClass.U75TO125.lowBound) + * FastMath.exp(point[point.length - 1] / 20d)); spec.getQuadraticMeanDiameterByUtilization().setAll(quadMeanDiameter); final float baseArea = (float) (layerBa * percentL1[j] / 100d); diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java index 195a95800..709242dfa 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessingEngine.java @@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory; import ca.bc.gov.nrs.vdyp.application.ProcessingException; +import ca.bc.gov.nrs.vdyp.application.RuntimeProcessingException; import ca.bc.gov.nrs.vdyp.application.StandProcessingException; import ca.bc.gov.nrs.vdyp.common.ControlKey; import ca.bc.gov.nrs.vdyp.common.EstimationMethods; @@ -968,8 +969,8 @@ boolean growUsingPartialSpeciesDynamics( } /** - * Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth during the growth - * period. The result is stored in end, Utilization Class ALL. + * GRSPBT - Calculate the overall per-species basal area, trees-per-hectare and quad-mean-diameter growth during the + * growth period. The result is stored in end, Utilization Class ALL. * * @param baStart per-layer basal area at start of growth period * @param baDelta per-layer change in basal area during growth period @@ -1125,7 +1126,10 @@ void growUsingFullSpeciesDynamics( totalBasalAreaSkipped += bank.basalAreas[i][UC_ALL_INDEX]; } - float spDqMinimum = Math.max(7.6f, csl.minQuadMeanDiameterLoreyHeightRatio() * spLhAllStart); + float spDqMinimum = Math.max( + UtilizationClass.U75TO125.lowBound + 1.0f, + csl.minQuadMeanDiameterLoreyHeightRatio() * spLhAllStart + ); if (spDqStart + spDqDelta < spDqMinimum) { spDqDelta = spDqMinimum - spDqStart; @@ -1298,7 +1302,7 @@ private static float calculateQuadMeanDiameterDelta( float a1 = mc.getCoe(2); float a2 = mc.getCoe(3); - final float dqBase = 7.45f; + final float dqBase = UtilizationClass.U75TO125.lowBound - 0.05f; float dqRateStart = (spDqStart - dqBase) / (dqStart - dqBase); float logDqRateStart = FloatMath.log(dqRateStart); @@ -1306,8 +1310,8 @@ private static float calculateQuadMeanDiameterDelta( float dqRateEnd = FloatMath.exp(logDqRateStart + logDqRateDelta); float spDqEnd = dqRateEnd * (dqStart + dqDelta - dqBase) + dqBase; - if (spDqEnd < 7.51f) { - spDqEnd = 7.51f; + if (spDqEnd < UtilizationClass.U75TO125.lowBound + 0.01f) { + spDqEnd = UtilizationClass.U75TO125.lowBound + 0.01f; } float spDqDelta = spDqEnd - spDqStart; @@ -1503,11 +1507,8 @@ private void calculateSmallComponentYields(LayerProcessingState lps) throws Proc spBaSmall = 0.0f; } spDqSmall += lps.getCVSmall(speciesIndex, UtilizationClassVariable.QUAD_MEAN_DIAMETER); - if (spDqSmall < 4.01f) { - spDqSmall = 4.01f; - } else if (spDqSmall > 7.49) { - spDqSmall = 7.49f; - } + FloatMath.clamp(spDqSmall, 4.01f, 7.49f); + spLhSmall = 1.3f * (spLhSmall - 1.3f) * FloatMath.exp(lps.getCVSmall(speciesIndex, UtilizationClassVariable.LOREY_HEIGHT)); @@ -2343,7 +2344,7 @@ private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, i break; } default: - throw new LambdaProcessingException( + throw new RuntimeProcessingException( new ProcessingException( MessageFormat .format("Invalid value for control variable 4: {0}", controlVariable4Value) @@ -2355,10 +2356,10 @@ private void writePolygon(VdypPolygon polygon, int startYear, int currentYear, i o.setPolygonYear(currentYear); o.writePolygonWithSpeciesAndUtilization(polygon); } catch (IOException e) { - throw new LambdaProcessingException(new ProcessingException(e)); + throw new RuntimeProcessingException(new ProcessingException(e)); } }); - } catch (LambdaProcessingException e) { + } catch (RuntimeProcessingException e) { throw e.getCause(); } } @@ -3289,11 +3290,7 @@ void determinePolygonRankings(Collection> speciesToCombine) { int defaultEquationGroup = fps.fcm.getDefaultEquationGroup().get(primarySpeciesName, becZoneAlias); Optional equationModifierGroup = fps.fcm.getEquationModifierGroup() .get(defaultEquationGroup, inventoryTypeGroup); - if (equationModifierGroup.isPresent()) { - basalAreaGroup1 = equationModifierGroup.get(); - } else { - basalAreaGroup1 = defaultEquationGroup; - } + basalAreaGroup1 = equationModifierGroup.orElse(defaultEquationGroup); int primarySpeciesIndex = bank.speciesIndices[highestPercentageIndex]; int basalAreaGroup3 = defaultEquationGroups[primarySpeciesIndex]; diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java deleted file mode 100644 index 8dc32f437..000000000 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/LambdaProcessingException.java +++ /dev/null @@ -1,17 +0,0 @@ -package ca.bc.gov.nrs.vdyp.forward; - -import ca.bc.gov.nrs.vdyp.application.ProcessingException; - -public class LambdaProcessingException extends RuntimeException { - - private static final long serialVersionUID = 7768827464368942152L; - - public LambdaProcessingException(ProcessingException e) { - super(e); - } - - @Override - public synchronized ProcessingException getCause() { - return (ProcessingException) super.getCause(); - } -} diff --git a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java index 28c3bd13b..1320b2c23 100644 --- a/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java +++ b/vdyp-lib/vdyp-forward/src/main/java/ca/bc/gov/nrs/vdyp/forward/UtilizationOperations.java @@ -8,13 +8,14 @@ import ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter; import ca.bc.gov.nrs.vdyp.math.FloatMath; 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.VdypPolygon; import ca.bc.gov.nrs.vdyp.model.VdypUtilizationHolder; public class UtilizationOperations { + // TODO: Collect other generic UtilizationHolder operations here (some are in VdypStartApplication.) + /** * Perform the following operations on the UtilizationVectors of the given polygon. *
      @@ -109,12 +110,6 @@ private static void scale(VdypUtilizationHolder uh, float scalingFactor) { } private static final float MAX_ACCEPTABLE_BASAL_AREA_ERROR = 0.1f; - private static final UtilizationVector CLASS_LOWER_BOUNDS = new UtilizationVector( - 4.0f, 7.5f, 7.5f, 12.5f, 17.5f, 22.5f - ); - private static final UtilizationVector CLASS_UPPER_BOUNDS = new UtilizationVector( - 7.5f, 2000.0f, 12.5f, 17.5f, 22.5f, 2000.0f - ); private static final float DQ_EPS = 0.005f; /** @@ -146,10 +141,8 @@ private static void adjustBasalAreaToMatchTreesPerHectare(VdypUtilizationHolder for (UtilizationClass uc : UtilizationClass.values()) { float tph = uh.getTreesPerHectareByUtilization().get(uc); if (tph > 0.0f) { - float basalAreaLowerBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_LOWER_BOUNDS.get(uc) + DQ_EPS, tph); - float basalAreaUpperBound = BaseAreaTreeDensityDiameter - .basalArea(CLASS_UPPER_BOUNDS.get(uc) - DQ_EPS, tph); + float basalAreaLowerBound = BaseAreaTreeDensityDiameter.basalArea(uc.lowBound + DQ_EPS, tph); + float basalAreaUpperBound = BaseAreaTreeDensityDiameter.basalArea(uc.highBound - DQ_EPS, tph); float basalAreaError; float newBasalArea; @@ -199,23 +192,23 @@ private static void doCalculateQuadMeanDiameter(VdypUtilizationHolder uh) throws float tph = uh.getTreesPerHectareByUtilization().get(uc); float qmd = BaseAreaTreeDensityDiameter.quadMeanDiameter(basalArea, tph); - if (qmd < CLASS_LOWER_BOUNDS.get(uc)) { + if (qmd < uc.lowBound) { qmd = qmd + DQ_EPS; - if (qmd /* is still */ < CLASS_LOWER_BOUNDS.get(uc)) { + if (qmd /* is still */ < uc.lowBound) { throw new ProcessingException( MessageFormat.format( "{0}: Error 6: calculated quad-mean-diameter value {1} is below lower limit {2}", - uh, qmd, CLASS_LOWER_BOUNDS.get(uc) + uh, qmd, uc.lowBound ) ); } - } else if (qmd > CLASS_UPPER_BOUNDS.get(uc)) { + } else if (qmd > uc.highBound) { qmd = qmd - DQ_EPS; - if (qmd /* is still */ > CLASS_UPPER_BOUNDS.get(uc)) { + if (qmd /* is still */ > uc.highBound) { throw new ProcessingException( MessageFormat.format( "{0}: Error 6: calculated quad-mean-diameter value {1} is above upper limit {2}", - uh, qmd, CLASS_UPPER_BOUNDS.get(uc) + uh, qmd, uc.highBound ) ); } diff --git a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java index c583c0760..b2a8c97d6 100644 --- a/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java +++ b/vdyp-lib/vdyp-forward/src/test/java/ca/bc/gov/nrs/vdyp/forward/ForwardProcessorTest.java @@ -20,6 +20,7 @@ import java.util.zip.ZipFile; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +36,9 @@ class ForwardProcessorTest { private static Set vdypPassSet = new HashSet<>(Arrays.asList(PASS_1, PASS_2, PASS_3, PASS_4, PASS_5)); + @TempDir + Path outputFilesLocation; + @Test void test() throws IOException, ResourceParseException, ProcessingException { @@ -49,47 +53,39 @@ void test() throws IOException, ResourceParseException, ProcessingException { Path resourceDirectory = Paths.get("src", "test", "resources", "output"); Files.createDirectories(resourceDirectory); - Path zipFilePath = Paths.get(resourceDirectory.toString(), this.getClass().getSimpleName() + ".zip"); - Files.deleteIfExists(zipFilePath); - - Path zipFileFromStreamPath = Paths - .get(resourceDirectory.toString(), this.getClass().getSimpleName() + "FromStream.zip"); + Path zipFilePath = outputFilesLocation.resolve(this.getClass().getSimpleName() + ".zip"); + Path zipFileFromStreamPath = outputFilesLocation.resolve(this.getClass().getSimpleName() + "-fromtream.zip"); - try { - outputResolver.generate(zipFilePath); - byte[] zipFileBytes = Files.readAllBytes(zipFilePath); + System.out.println("Writing output to " + outputFilesLocation.toString()); - InputStream is = outputResolver.generateStream(); - byte[] zipStreamBytes = is.readAllBytes(); - Files.write(zipFileFromStreamPath, zipStreamBytes); + outputResolver.generate(zipFilePath); + byte[] zipFileBytes = Files.readAllBytes(zipFilePath); - assertTrue(zipFileBytes.length == zipStreamBytes.length); + InputStream is = outputResolver.generateStream(); + byte[] zipStreamBytes = is.readAllBytes(); + Files.write(zipFileFromStreamPath, zipStreamBytes); - try (ZipFile zipFileFromStream = new ZipFile(zipFileFromStreamPath.toFile())) { - try (ZipFile zipFileFromFile = new ZipFile(zipFilePath.toFile())) { + assertTrue(zipFileBytes.length == zipStreamBytes.length); - var streamEntries = zipFileFromStream.entries().asIterator(); - var fileEntries = zipFileFromFile.entries().asIterator(); + try (ZipFile zipFileFromStream = new ZipFile(zipFileFromStreamPath.toFile())) { + try (ZipFile zipFileFromFile = new ZipFile(zipFilePath.toFile())) { - while (streamEntries.hasNext()) { - assertTrue(fileEntries.hasNext()); + var streamEntries = zipFileFromStream.entries().asIterator(); + var fileEntries = zipFileFromFile.entries().asIterator(); - var streamEntry = streamEntries.next(); - var fileEntry = fileEntries.next(); + while (streamEntries.hasNext()) { + assertTrue(fileEntries.hasNext()); - logger.info( - "Saw file entry {} and stream entry {}", fileEntry.getName(), streamEntry.getName() - ); - assertTrue(streamEntry.hashCode() == fileEntry.hashCode()); - assertTrue(streamEntry.getName().equals(fileEntry.getName())); - } + var streamEntry = streamEntries.next(); + var fileEntry = fileEntries.next(); - assertFalse(fileEntries.hasNext()); + logger.info("Saw file entry {} and stream entry {}", fileEntry.getName(), streamEntry.getName()); + assertTrue(streamEntry.hashCode() == fileEntry.hashCode()); + assertTrue(streamEntry.getName().equals(fileEntry.getName())); } + + assertFalse(fileEntries.hasNext()); } - } finally { - Files.delete(zipFilePath); - Files.delete(zipFileFromStreamPath); } } } diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index 6af5e5b08..4207b81df 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -80,7 +80,8 @@ public class VriStart extends VdypStartApplication builder.getTreesPerHectare().map(tph -> quadMeanDiameter(ba, tph) < 7.5f)) - .orElse(false)) { + .flatMap( + ba -> builder.getTreesPerHectare() + .map(tph -> quadMeanDiameter(ba, tph) < UtilizationClass.U75TO125.lowBound) + ).orElse(false)) { builder.baseArea(Optional.empty()); builder.treesPerHectare(Optional.empty()); } @@ -481,7 +484,8 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws } else { float loreyHeight = vriSite.getHeight().filter((x) -> getDebugMode(2) != 1).map(height -> { - float speciesQuadMeanDiameter = Math.max(7.5f, height / leadHeight * layerQuadMeanDiameter); + float speciesQuadMeanDiameter = Math + .max(UtilizationClass.U75TO125.lowBound, height / leadHeight * layerQuadMeanDiameter); float speciesDensity = treesPerHectare(specBaseArea, speciesQuadMeanDiameter); // EMP050 Method 1 return estimationMethods.primaryHeightFromLeadHeight( @@ -652,7 +656,11 @@ float quadMeanDiameterFractionalError( } float quadMeanDiameterSpeciesAdjust(float x, float initialDq, float min, float max) { - return FloatMath.clamp(7.5f + (initialDq - 7.5f) * FloatMath.exp(x), min, max); + return FloatMath.clamp( + UtilizationClass.U75TO125.lowBound + + (initialDq - UtilizationClass.U75TO125.lowBound) * FloatMath.exp(x), + min, max + ); } private float processVeteranLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws StandProcessingException { diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java index b32256cbe..a98a045ce 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java @@ -9,6 +9,7 @@ import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; +import ca.bc.gov.nrs.vdyp.model.UtilizationClass; public class VriLayer extends BaseVdypLayer implements InputLayer { @@ -225,7 +226,7 @@ protected VriLayer doBuild() { crownClosure.get(), // baseArea.map(x -> x * multiplier), // treesPerHectare.map(x -> x * multiplier), // - Math.max(utilization.get(), 7.5f), // + Math.max(utilization.get(), UtilizationClass.U75TO125.lowBound), // primaryGenus, // secondaryGenus, // empericalRelationshipParameterIndex, // From b1b7d54d1a5f09876b2d2a0fa59389e66b0ba3da Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 10 Sep 2024 10:30:03 -0700 Subject: [PATCH 65/66] Further adjustments after merge --- .../nrs/vdyp/io/write/VdypOutputWriter.java | 24 +++---- .../vdyp/io/write/VriAdjustInputWriter.java | 19 ++++-- .../bc/gov/nrs/vdyp/model/BaseVdypLayer.java | 5 +- .../ca/bc/gov/nrs/vdyp/model/InputLayer.java | 1 - .../ca/bc/gov/nrs/vdyp/model/VdypLayer.java | 28 +++----- .../io/write/VriAdjustInputWriterTest.java | 4 +- .../nrs/vdyp/model/VdypUtilizationTest.java | 6 +- .../java/ca/bc/gov/nrs/vdyp/vri/VriStart.java | 68 +++++++++---------- .../bc/gov/nrs/vdyp/vri/model/VriLayer.java | 27 +++----- .../gov/nrs/vdyp/vri/ParsersTogetherTest.java | 2 +- 10 files changed, 86 insertions(+), 98 deletions(-) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java index b4c81c8bb..81641ae3a 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java @@ -21,6 +21,7 @@ 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; @@ -29,9 +30,9 @@ */ public class VdypOutputWriter implements Closeable { - private OutputStream polygonFile; - private OutputStream speciesFile; - private OutputStream utilizationFile; + protected final OutputStream polygonFile; + protected final OutputStream speciesFile; + protected final OutputStream utilizationFile; @SuppressWarnings("unused") private Optional compatibilityVariablesFile; @@ -175,7 +176,6 @@ void writeSpecies(VdypLayer layer, VdypSpecies spec) throws IOException { 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 - boolean isSiteSpec = layer.getSiteGenus().map(spec.getGenus()::equals).orElse(false); writeFormat( speciesFile, // SPEC_FORMAT, // @@ -195,15 +195,13 @@ void writeSpecies(VdypLayer layer, VdypSpecies spec) throws IOException { specDistributionEntries.get(3).getGenusAlias(), // specDistributionEntries.get(3).getPercentage(), // - layer.getSiteIndex().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getHeight().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getAgeTotal().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getBreastHeightAge().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getYearsToBreastHeight().filter(x -> isSiteSpec).orElse(EMPTY_FLOAT), // - layer.getSiteGenus().filter(x -> isSiteSpec).map(id -> id.equals(spec.getGenus())).orElse(false) ? 1 - : 0, // - layer.getSiteCurveNumber().filter(x -> isSiteSpec).orElse(EMPTY_INT) - + 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) // ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java index ed18c6f8b..d558f6b28 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java @@ -2,9 +2,15 @@ import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; 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.io.FileResolver; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.LayerType; @@ -68,6 +74,7 @@ static OutputStream getOutputStream(Map controlMap, FileResolver * @param polygon * @throws IOException */ + @Override void writePolygon(VdypPolygon polygon) throws IOException { writeFormat( polygonFile, // @@ -91,12 +98,13 @@ void writePolygon(VdypPolygon polygon) throws IOException { * @param spec * @throws IOException */ + @Override 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)) + 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( @@ -137,6 +145,7 @@ void writeSpecies(VdypLayer layer, VdypSpecies spec) throws IOException { * @param utils * @throws IOException */ + @Override // V7W_AIU Internalized loop over utilization classes void writeUtilization(VdypLayer layer, VdypUtilizationHolder utils) throws IOException { Optional specId = Optional.empty(); @@ -155,8 +164,8 @@ void writeUtilization(VdypLayer layer, VdypUtilizationHolder utils) throws IOExc if (utils.getBaseAreaByUtilization().getCoe(uc.index) > 0) { quadMeanDiameter = Optional.of( BaseAreaTreeDensityDiameter.quadMeanDiameter( - utils.getBaseAreaByUtilization().getCoe(uc.index), utils - .getTreesPerHectareByUtilization().getCoe(uc.index) + utils.getBaseAreaByUtilization().getCoe(uc.index), + utils.getTreesPerHectareByUtilization().getCoe(uc.index) ) ); } @@ -197,6 +206,7 @@ void writeUtilization(VdypLayer layer, VdypUtilizationHolder utils) throws IOExc * @throws IOException */ // VDYP_OUT when JPROGRAM = 1 (FIPSTART) or 3 (VRISTART) + @Override public void writePolygonWithSpeciesAndUtilization(VdypPolygon polygon) throws IOException { writePolygon(polygon); @@ -226,6 +236,7 @@ private void writeSpeciesEndRecord(VdypPolygon polygon) throws IOException { writeEndRecord(speciesFile, polygon); } + @Override void writeFormat(OutputStream os, String format, Object... params) throws IOException { os.write(String.format(format, params).getBytes()); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java index b992aabf7..a1268fc37 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/BaseVdypLayer.java @@ -47,9 +47,7 @@ public LinkedHashMap getSpecies() { } public void setSpecies(Map species) { - this.speciesBySp0.clear(); - this.speciesByIndex.clear(); - this.speciesBySp0.putAll(species); + setSpecies(species.values()); } public void setSpecies(Collection species) { @@ -93,6 +91,7 @@ public Optional getPrimarySpeciesRecord() { @Computed public Optional getPrimarySite() { return getPrimaryGenus().map(this.getSites()::get); + } @Override public String toString() { diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java index a1886a8bd..0db97341b 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/InputLayer.java @@ -1,6 +1,5 @@ package ca.bc.gov.nrs.vdyp.model; - public interface InputLayer { public float getCrownClosure(); diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java index f46cec8c1..518df5568 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/model/VdypLayer.java @@ -29,15 +29,15 @@ public class VdypLayer extends BaseVdypLayer implements V private UtilizationVector closeUtilizationVolumeNetOfDecayWasteAndBreakageByUtilization = // VdypUtilizationHolder.emptyUtilization(); // LVCOM/VOL_DWB species 0 - private Optional empericalRelationshipParameterIndex = Optional.empty(); // INXL1/GRPBA1 + private Optional empiricalRelationshipParameterIndex = Optional.empty(); // INXL1/GRPBA1 private Optional primarySp0; public VdypLayer( PolygonIdentifier polygonIdentifier, LayerType layer, Optional inventoryTypeGroup, - Optional empericalRelationshipParameterIndex, Optional primarySp0 + Optional empiricalRelationshipParameterIndex, Optional primarySp0 ) { super(polygonIdentifier, layer, inventoryTypeGroup); - this.empericalRelationshipParameterIndex = empericalRelationshipParameterIndex; + this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex; this.primarySp0 = primarySp0; } @@ -161,8 +161,8 @@ public Optional getEmpiricalRelationshipParameterIndex() { return empiricalRelationshipParameterIndex; } - public void setEmpericalRelationshipParameterIndex(Optional empericalRelationshipParameterIndex) { - this.empiricalRelationshipParameterIndex = empericalRelationshipParameterIndex; + public void setEmpiricalRelationshipParameterIndex(Optional empiricalRelationshipParameterIndex) { + this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex; } @Override @@ -233,7 +233,7 @@ public VdypLayer.Builder primaryGenus(String primarySp0) { return primaryGenus(Optional.of(primarySp0)); } - UtilizationVector loreyHeight = VdypUtilizationHolder.emptyLoreyHeightUtilization(); + UtilizationVector loreyHeightByUtilization = VdypUtilizationHolder.emptyLoreyHeightUtilization(); public void loreyHeightByUtilization(float height) { this.loreyHeightByUtilization = Utils.heightVector(0, height); @@ -382,7 +382,7 @@ protected VdypLayer doBuild() { polygonIdentifier.get(), // layerType.get(), // inventoryTypeGroup, // - empericalRelationshipParameterIndex, // + empiricalRelationshipParameterIndex, // primarySp0 ); } @@ -396,29 +396,19 @@ protected VdypSpecies buildSpecies(Consumer config) { }); } - public void baseAreaByUtilization(UtilizationVector utilizationVector) { - // TODO Auto-generated method stub - - } - @Override public , I2 extends BaseVdypSite> BaseVdypLayer.Builder - adaptSpecies( - BaseVdypLayer toCopy, BiConsumer config - ) { + adaptSpecies(BaseVdypLayer toCopy, BiConsumer config) { this.primaryGenus(toCopy.getPrimaryGenus()); return super.adaptSpecies(toCopy, config); } @Override public BaseVdypLayer.Builder - copySpecies( - VdypLayer toCopy, BiConsumer config - ) { + copySpecies(VdypLayer toCopy, BiConsumer config) { this.primaryGenus(toCopy.getPrimaryGenus()); return super.copySpecies(toCopy, config); } - } } diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java index a68ff6786..ce1475275 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java @@ -120,7 +120,7 @@ void testWritePolygon() throws IOException { }); // FIXME Add to builder - layer.setEmpericalRelationshipParameterIndex(Optional.of(119)); + layer.setEmpiricalRelationshipParameterIndex(Optional.of(119)); layer.setInventoryTypeGroup(Optional.of(28)); unit.writePolygon(polygon); @@ -369,7 +369,7 @@ void testWritePolygonWithChildren() throws IOException { var species = layer.getSpecies().get("PL"); // fixme add to builder - layer.setEmpericalRelationshipParameterIndex(Optional.of(119)); + layer.setEmpiricalRelationshipParameterIndex(Optional.of(119)); layer.setInventoryTypeGroup(Optional.of(28)); layer.setBaseAreaByUtilization( diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java index 2f7d728a1..8a1bbe855 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/model/VdypUtilizationTest.java @@ -1,10 +1,10 @@ package ca.bc.gov.nrs.vdyp.model; -import java.util.Optional; - import static org.hamcrest.MatcherAssert.assertThat; -import org.hamcrest.Matchers; import static org.hamcrest.Matchers.is; + +import java.util.Optional; + import org.junit.jupiter.api.Test; class VdypUtilizationTest { diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java index e7007eff1..e881b59e8 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriStart.java @@ -1,6 +1,7 @@ package ca.bc.gov.nrs.vdyp.vri; -import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.*; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.quadMeanDiameter; +import static ca.bc.gov.nrs.vdyp.common_calculators.BaseAreaTreeDensityDiameter.treesPerHectare; import static ca.bc.gov.nrs.vdyp.math.FloatMath.pow; import static java.lang.Math.max; @@ -46,7 +47,6 @@ import ca.bc.gov.nrs.vdyp.io.parse.control.BaseControlParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.math.FloatMath; -import ca.bc.gov.nrs.vdyp.model.UtilizationClass; import ca.bc.gov.nrs.vdyp.model.BaseVdypSite; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies; import ca.bc.gov.nrs.vdyp.model.BaseVdypSpecies.Builder; @@ -54,13 +54,13 @@ import ca.bc.gov.nrs.vdyp.model.Coefficients; import ca.bc.gov.nrs.vdyp.model.CompatibilityVariableMode; import ca.bc.gov.nrs.vdyp.model.ComponentSizeLimits; -import ca.bc.gov.nrs.vdyp.model.InputLayer; import ca.bc.gov.nrs.vdyp.model.LayerType; import ca.bc.gov.nrs.vdyp.model.MatrixMap2; import ca.bc.gov.nrs.vdyp.model.ModelClassBuilder; import ca.bc.gov.nrs.vdyp.model.PolygonIdentifier; import ca.bc.gov.nrs.vdyp.model.PolygonMode; import ca.bc.gov.nrs.vdyp.model.Region; +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.VdypSpecies; @@ -464,7 +464,7 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws lBuilder.quadraticMeanDiameterByUtilization(layerQuadMeanDiameter); lBuilder.baseAreaByUtilization(primaryBaseArea); lBuilder.treesPerHectareByUtilization(primaryLayerDensity); - lBuilder.empiricalRelationshipParameterIndex(primaryLayer.getEmpericalRelationshipParameterIndex()); + lBuilder.empiricalRelationshipParameterIndex(primaryLayer.getEmpiricalRelationshipParameterIndex()); lBuilder.adaptSpecies(primaryLayer, (sBuilder, vriSpec) -> { var vriSite = vriSpec.getSite(); @@ -478,43 +478,39 @@ void processPrimaryLayer(VriPolygon polygon, VdypLayer.Builder lBuilder) throws if (vriSite.map(site -> site == primarySiteIn).orElse(false)) { sBuilder.loreyHeight(primaryHeight); - sBuilder.adaptSite( - vriSite.get(), (iBuilder, vriSite2) -> { - vriSite2.getHeight().ifPresent(iBuilder::height); - } - ); + sBuilder.adaptSite(vriSite.get(), (iBuilder, vriSite2) -> { + vriSite2.getHeight().ifPresent(iBuilder::height); + }); } else { - var loreyHeight = vriSite.flatMap( - site -> site.getHeight().filter(x -> getDebugMode(2) != 1).map(height -> { - float speciesQuadMeanDiameter = Math.max(7.5f, height / leadHeight * layerQuadMeanDiameter); + var loreyHeight = vriSite + .flatMap(site -> site.getHeight().filter(x -> getDebugMode(2) != 1).map(height -> { + float speciesQuadMeanDiameter = Math.max( + UtilizationClass.U75TO125.lowBound, height / leadHeight * layerQuadMeanDiameter + ); float speciesDensity = treesPerHectare(specBaseArea, speciesQuadMeanDiameter); + // EMP050 return (float) estimationMethods.primaryHeightFromLeadHeight( site.getHeight().get(), site.getSiteGenus(), bec.getRegion(), speciesDensity ); - }) - ).orElseGet(() -> { - try { - // EMP053 - return estimationMethods.estimateNonPrimaryLoreyHeight( - vriSpec.getGenus(), primarySiteIn.getSiteGenus(), bec, leadHeight, primaryHeight - ); - } catch (ProcessingException e) { - throw new RuntimeProcessingException(e); - } - }); + })).orElseGet(() -> { + try { + // EMP053 + return estimationMethods.estimateNonPrimaryLoreyHeight( + vriSpec.getGenus(), primarySiteIn.getSiteGenus(), bec, leadHeight, primaryHeight + ); + } catch (ProcessingException e) { + throw new RuntimeProcessingException(e); + } + }); float maxHeight = estimationMethods.getLimitsForHeightAndDiameter(vriSpec.getGenus(), bec.getRegion()) .loreyHeightMaximum(); loreyHeight = Math.min(loreyHeight, maxHeight); sBuilder.loreyHeight(loreyHeight); } - vriSite.ifPresent( - site -> sBuilder.adaptSite( - site, (iBuilder, vriSite2) -> { - vriSite2.getHeight().ifPresent(iBuilder::height); - } - ) - ); + vriSite.ifPresent(site -> sBuilder.adaptSite(site, (iBuilder, vriSite2) -> { + vriSite2.getHeight().ifPresent(iBuilder::height); + })); this.applyGroups(bec, vriSpec.getGenus(), sBuilder); }); @@ -887,7 +883,7 @@ protected PolygonMode checkPolygonForMode(VriPolygon polygon, BecDefinition bec) return findDefaultPolygonMode( ageTotal, yearsToBreastHeight, height, baseArea, treesPerHectare, percentForest, primaryLayer.getSpecies().values(), bec, - primaryLayer.getEmpericalRelationshipParameterIndex() + primaryLayer.getEmpiricalRelationshipParameterIndex() ); } catch (StandProcessingException e) { throw new RuntimeStandProcessingException(e); @@ -1315,7 +1311,7 @@ private Increase findIncreaseForYoungMode( float predictedBaseArea = estimateBaseAreaYield( dominantHeight, primaryBreastHeightAge, Optional.empty(), false, primaryLayer.getSpecies().values(), bec, - primaryLayer.getEmpericalRelationshipParameterIndex().orElseThrow() + primaryLayer.getEmpiricalRelationshipParameterIndex().orElseThrow() ); // BAP // Calculate the full occupancy BA Hence the BA we will test is the Full @@ -1416,22 +1412,22 @@ VriPolygon processBatn(VriPolygon poly) throws ProcessingException { .orElseThrow(() -> new StandProcessingException("Primary site does not have a breast height age")); final Optional veteranBaseArea = veteranLayer.flatMap(VriLayer::getBaseArea); - final int primaryEmpericalRelationshipParameterIndex = primaryLayer.getEmpericalRelationshipParameterIndex() + final int primaryEmpiricalRelationshipParameterIndex = primaryLayer.getEmpiricalRelationshipParameterIndex() .orElseThrow( () -> new StandProcessingException( - "Primary layer does not have an emperical relationship parameter index" + "Primary layer does not have an empirical relationship parameter index" ) ); float primaryBaseAreaEstimated = estimateBaseAreaYield( primaryHeight, primaryBreastHeightAge, veteranBaseArea, false, primaryLayer.getSpecies().values(), bec, - primaryEmpericalRelationshipParameterIndex + primaryEmpiricalRelationshipParameterIndex ); // EMP107 float normativeQuadMeanDiameter = estimateQuadMeanDiameterYield( primaryHeight, primaryBreastHeightAge, veteranBaseArea, primaryLayer.getSpecies().values(), bec, - primaryEmpericalRelationshipParameterIndex + primaryEmpiricalRelationshipParameterIndex ); final float normativePercentAvailable = 85f; diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java index f2bdba0e8..1618021a1 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/model/VriLayer.java @@ -22,13 +22,13 @@ public class VriLayer extends BaseVdypLayer implements Inpu private final float utilization; // VRIL/UTLL public final Optional primaryGenus; // FIPL_1C/JPRIME_L1 ISPP private final Optional secondaryGenus; // FIPL_1C/JPRIME_L1 ISPS - private final Optional empericalRelationshipParameterIndex; // INXL1/GRPBA1 + private final Optional empiricalRelationshipParameterIndex; // INXL1/GRPBA1 private final float ageIncrease; // YOUNG1/AGE_INCR public VriLayer( PolygonIdentifier polygonIdentifier, LayerType layer, float crownClosure, Optional baseArea, Optional treesPerHectare, float utilization, Optional primaryGenus, - Optional secondaryGenus, Optional empericalRelationshipParameterIndex, float ageIncrease + Optional secondaryGenus, Optional empiricalRelationshipParameterIndex, float ageIncrease ) { super(polygonIdentifier, layer, Optional.empty()); this.crownClosure = crownClosure; @@ -37,7 +37,7 @@ public VriLayer( this.utilization = utilization; this.primaryGenus = primaryGenus; this.secondaryGenus = secondaryGenus; - this.empericalRelationshipParameterIndex = empericalRelationshipParameterIndex; + this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex; this.ageIncrease = ageIncrease; } @@ -77,8 +77,8 @@ public Optional getSecondarySite() { return secondaryGenus.map(this.getSites()::get); } - public Optional getEmpericalRelationshipParameterIndex() { - return empericalRelationshipParameterIndex; + public Optional getEmpiricalRelationshipParameterIndex() { + return empiricalRelationshipParameterIndex; } public float getAgeIncrease() { @@ -120,11 +120,11 @@ public static class Builder protected Optional percentAvailable = Optional.empty(); protected Optional primaryGenus = Optional.empty(); protected Optional secondaryGenus = Optional.empty(); - protected Optional empericalRelationshipParameterIndex = Optional.empty(); + protected Optional empiricalRelationshipParameterIndex = Optional.empty(); protected Optional ageIncrease = Optional.empty(); public Builder empiricalRelationshipParameterIndex(Optional empiricalRelationshipParameterIndex) { - this.empericalRelationshipParameterIndex = empiricalRelationshipParameterIndex; + this.empiricalRelationshipParameterIndex = empiricalRelationshipParameterIndex; return this; } @@ -223,7 +223,7 @@ protected VriLayer doBuild() { Math.max(utilization.get(), UtilizationClass.U75TO125.lowBound), // primaryGenus, // secondaryGenus, // - empericalRelationshipParameterIndex, // + empiricalRelationshipParameterIndex, // ageIncrease.orElse(DEFAULT_AGE_INCREASE) ); result.setInventoryTypeGroup(inventoryTypeGroup); @@ -247,26 +247,21 @@ public Builder copy(VriLayer toCopy) { this.utilization(toCopy.getUtilization()); this.primaryGenus(toCopy.getPrimaryGenus()); this.secondaryGenus(toCopy.getSecondaryGenus()); - this.empiricalRelationshipParameterIndex(toCopy.getEmpericalRelationshipParameterIndex()); + this.empiricalRelationshipParameterIndex(toCopy.getEmpiricalRelationshipParameterIndex()); return this; } @Override public , I2 extends BaseVdypSite> BaseVdypLayer.Builder - adaptSpecies( - BaseVdypLayer toCopy, - BiConsumer config - ) { + adaptSpecies(BaseVdypLayer toCopy, BiConsumer config) { this.primaryGenus(toCopy.getPrimaryGenus()); return super.adaptSpecies(toCopy, config); } @Override public BaseVdypLayer.Builder - copySpecies( - VriLayer toCopy, BiConsumer config - ) { + copySpecies(VriLayer toCopy, BiConsumer config) { this.primaryGenus(toCopy.getPrimaryGenus()); return super.copySpecies(toCopy, config); } diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java index 2592c26e2..2dcd84caf 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java @@ -530,7 +530,7 @@ void testFindsGRPBA1() throws IOException, StandProcessingException, ResourcePar assertThat(result, hasProperty("layers", Matchers.aMapWithSize(1))); var primaryResult = result.getLayers().get(LayerType.PRIMARY); var veteranResult = result.getLayers().get(LayerType.VETERAN); - assertThat(primaryResult, allOf(hasProperty("empericalRelationshipParameterIndex", present(is(27))))); + assertThat(primaryResult, allOf(hasProperty("empiricalRelationshipParameterIndex", present(is(27))))); assertThat(veteranResult, nullValue()); app.close(); From ff1731d571efa24aa1c0557c561826359bade40a Mon Sep 17 00:00:00 2001 From: Michael Junkin Date: Tue, 10 Sep 2024 11:10:18 -0700 Subject: [PATCH 66/66] Replace VriAdjustInputWriter with VdypOutputWriter and remove VRI_OUTPUT control keys (duplication) --- .../application/VdypStartApplication.java | 8 +- .../ca/bc/gov/nrs/vdyp/common/ControlKey.java | 4 +- .../nrs/vdyp/io/write/VdypOutputWriter.java | 4 +- .../vdyp/io/write/VriAdjustInputWriter.java | 250 ------------------ .../application/VdypStartApplicationTest.java | 6 +- ...terTest.java => VdypOutputWriterTest.java} | 23 +- .../bc/gov/nrs/vdyp/fip/FipControlParser.java | 4 +- .../bc/gov/nrs/vdyp/vri/VriControlParser.java | 4 +- .../gov/nrs/vdyp/vri/ParsersTogetherTest.java | 6 +- .../nrs/vdyp/vri/VriInputValidationTest.java | 6 +- .../ca/bc/gov/nrs/vdyp/vri/VriStartTest.java | 6 +- 11 files changed, 34 insertions(+), 287 deletions(-) delete mode 100644 vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java rename vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/{VriAdjustInputWriterTest.java => VdypOutputWriterTest.java} (95%) diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java index fefdceda9..6f84123f5 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplication.java @@ -48,7 +48,7 @@ import ca.bc.gov.nrs.vdyp.io.parse.control.BaseControlParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParser; import ca.bc.gov.nrs.vdyp.io.parse.streaming.StreamingParserFactory; -import ca.bc.gov.nrs.vdyp.io.write.VriAdjustInputWriter; +import ca.bc.gov.nrs.vdyp.io.write.VdypOutputWriter; import ca.bc.gov.nrs.vdyp.math.FloatMath; import ca.bc.gov.nrs.vdyp.model.BaseVdypLayer; import ca.bc.gov.nrs.vdyp.model.BaseVdypPolygon; @@ -165,7 +165,7 @@ protected static void doMain(VdypStartApplication app, final String. .filter(x -> !x.getName().contains("Volume")).toList(); } - protected VriAdjustInputWriter vriWriter; + protected VdypOutputWriter vriWriter; protected Map controlMap = new HashMap<>(); @@ -227,7 +227,7 @@ public void init(FileSystemFileResolver resolver, Map controlMap setControlMap(controlMap); closeVriWriter(); - vriWriter = new VriAdjustInputWriter(controlMap, resolver); + vriWriter = new VdypOutputWriter(controlMap, resolver); } protected abstract BaseControlParser getControlFileParser(); @@ -508,7 +508,7 @@ public int findEmpiricalRelationshipParameterIndex(String specAlias, BecDefiniti return group; } - protected VriAdjustInputWriter getVriWriter() { + protected VdypOutputWriter getVriWriter() { return vriWriter; } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java index 48ac00125..94b5182dc 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/common/ControlKey.java @@ -20,9 +20,7 @@ public enum ControlKey { FORWARD_INPUT_GROWTO(14), // FIP/VRI Outputs - VRI_OUTPUT_VDYP_POLYGON(15), VRI_OUTPUT_VDYP_LAYER_BY_SPECIES(16), VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL(18), - - // VDYP Forward Outputs + // VDYP Forward, Bank and Adjust Inputs and Outputs VDYP_OUTPUT_VDYP_POLYGON(15), VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES(16), VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL(18), VDYP_OUTPUT_COMPATIBILITY_VARIABLES(19), diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java index 81641ae3a..6a4b2936d 100644 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java +++ b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriter.java @@ -113,9 +113,9 @@ public VdypOutputWriter(Map controlMap, FileResolver resolver) t 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()), - Optional.of( + controlMap.containsKey(ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name()) ? Optional.of( getOutputStream(controlMap, resolver, ControlKey.VDYP_OUTPUT_COMPATIBILITY_VARIABLES.name()) - ) + ) : Optional.empty() ); } diff --git a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java b/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java deleted file mode 100644 index d558f6b28..000000000 --- a/vdyp-lib/vdyp-common/src/main/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriter.java +++ /dev/null @@ -1,250 +0,0 @@ -package ca.bc.gov.nrs.vdyp.io.write; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Stream; - -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.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. - */ -public class VriAdjustInputWriter extends VdypOutputWriter { - - /** - * Create a writer for VRI Adjust input files using provided OutputStreams. The Streams will be closed when the - * writer is closed. - * - * @param polygonFile - * @param speciesFile - * @param utilizationFile - * @param controlMap - */ - public VriAdjustInputWriter( - OutputStream polygonFile, OutputStream speciesFile, OutputStream utilizationFile, - Map controlMap - ) { - super(polygonFile, speciesFile, utilizationFile); - } - - /** - * Create a writer for VRI Adjust input files configured using the given control map. - * - * @param polygonFile - * @param speciesFile - * @param utilizationFile - * @param controlMap - */ - public VriAdjustInputWriter(Map controlMap, FileResolver resolver) throws IOException { - this( - getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_POLYGON.name()), - getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name()), - getOutputStream(controlMap, resolver, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name()), - controlMap - ); - } - - static OutputStream getOutputStream(Map 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 - */ - @Override - 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 - */ - @Override - 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 - */ - @Override - // V7W_AIU Internalized loop over utilization classes - void writeUtilization(VdypLayer layer, VdypUtilizationHolder utils) throws IOException { - Optional specId = Optional.empty(); - Optional specIndex = Optional.empty(); - if (utils instanceof VdypSpecies spec) { - specId = Optional.of(spec.getGenus()); - specIndex = Optional.of(spec.getGenusIndex()); - } - - for (var uc : UtilizationClass.values()) { - Optional height = Optional.empty(); - if (uc.index < 1) { - height = Optional.of(utils.getLoreyHeightByUtilization().getCoe(uc.index)).filter(x -> x > 0f); - } - Optional 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) - @Override - public void writePolygonWithSpeciesAndUtilization(VdypPolygon polygon) throws IOException { - - writePolygon(polygon); - for (var layer : polygon.getLayers().values()) { - writeUtilization(layer, layer); - List 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); - } - - @Override - 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(); - } -} diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java index 3385d4ffa..28049d64e 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/application/VdypStartApplicationTest.java @@ -111,9 +111,9 @@ void testInitNoControlFiles() throws IOException, ResourceParseException { } private MockFileResolver dummyIo() { - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); MockFileResolver resolver = new MockFileResolver("Test"); resolver.addStream("DUMMY1", (OutputStream) new ByteArrayOutputStream()); diff --git a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriterTest.java similarity index 95% rename from vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java rename to vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriterTest.java index ce1475275..fd7fcc09f 100644 --- a/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VriAdjustInputWriterTest.java +++ b/vdyp-lib/vdyp-common/src/test/java/ca/bc/gov/nrs/vdyp/io/write/VdypOutputWriterTest.java @@ -23,7 +23,7 @@ import ca.bc.gov.nrs.vdyp.test.TestUtils.MockOutputStream; import ca.bc.gov.nrs.vdyp.test.VdypMatchers; -class VriAdjustInputWriterTest { +class VdypOutputWriterTest { MockOutputStream polyStream; MockOutputStream specStream; @@ -43,21 +43,20 @@ void initStreams() { specStream = new TestUtils.MockOutputStream("species"); utilStream = new TestUtils.MockOutputStream("utilization"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_POLYGON.name(), "testPolygonFile"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "testSpeciesFile"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "testUtilizationFile"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name(), "testPolygonFile"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "testSpeciesFile"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "testUtilizationFile"); fileResolver = new MockFileResolver("TEST"); fileResolver.addStream("testPolygonFile", polyStream); fileResolver.addStream("testSpeciesFile", specStream); fileResolver.addStream("testUtilizationFile", utilStream); - } @Test void testClosesGivenStreams() throws IOException { - var unit = new VriAdjustInputWriter(polyStream, specStream, utilStream, controlMap); + var unit = new VdypOutputWriter(polyStream, specStream, utilStream); unit.close(); @@ -73,7 +72,7 @@ void testClosesGivenStreams() throws IOException { @Test void testClosesOpenedStreams() throws IOException { - var unit = new VriAdjustInputWriter(controlMap, fileResolver); + var unit = new VdypOutputWriter(controlMap, fileResolver); unit.close(); @@ -88,7 +87,7 @@ void testClosesOpenedStreams() throws IOException { @Test void testWritePolygon() throws IOException { - try (var unit = new VriAdjustInputWriter(controlMap, fileResolver);) { + try (var unit = new VdypOutputWriter(controlMap, fileResolver);) { VdypPolygon polygon = VdypPolygon.build(builder -> { @@ -133,7 +132,7 @@ void testWritePolygon() throws IOException { @Test void testWriteSpecies() throws IOException { - try (var unit = new VriAdjustInputWriter(controlMap, fileResolver);) { + try (var unit = new VdypOutputWriter(controlMap, fileResolver);) { var layer = VdypLayer.build(builder -> { builder.polygonIdentifier("082E004 615 1988"); @@ -172,7 +171,7 @@ void testWriteSpecies() throws IOException { @Test void testWriteUtilizationForLayer() throws IOException { - try (var unit = new VriAdjustInputWriter(controlMap, fileResolver);) { + try (var unit = new VdypOutputWriter(controlMap, fileResolver);) { var layer = VdypLayer.build(builder -> { builder.polygonIdentifier("082E004 615 1988"); @@ -252,7 +251,7 @@ void testWriteUtilizationForLayer() throws IOException { @Test void testWriteUtilizationZeroBaseArea() throws IOException { - try (var unit = new VriAdjustInputWriter(controlMap, fileResolver);) { + try (var unit = new VdypOutputWriter(controlMap, fileResolver);) { var layer = VdypLayer.build(builder -> { builder.polygonIdentifier("082E004 615 1988"); @@ -331,7 +330,7 @@ void testWriteUtilizationZeroBaseArea() throws IOException { @Test void testWritePolygonWithChildren() throws IOException { - try (var unit = new VriAdjustInputWriter(controlMap, fileResolver)) { + try (var unit = new VdypOutputWriter(controlMap, fileResolver)) { VdypPolygon polygon = VdypPolygon.build(builder -> { diff --git a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java index 98943158b..cc597523e 100644 --- a/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java +++ b/vdyp-lib/vdyp-fip/src/main/java/ca/bc/gov/nrs/vdyp/fip/FipControlParser.java @@ -125,8 +125,8 @@ protected List> inputFileParsers() { @Override protected List outputFileParsers() { return List.of( - ControlKey.VRI_OUTPUT_VDYP_POLYGON, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES, - ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL + ControlKey.VDYP_OUTPUT_VDYP_POLYGON, ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES, + ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL ); } diff --git a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java index 4a8a3c67f..b05ac6cbb 100644 --- a/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java +++ b/vdyp-lib/vdyp-vri/src/main/java/ca/bc/gov/nrs/vdyp/vri/VriControlParser.java @@ -58,8 +58,8 @@ protected List> inputFileParsers() { @Override protected List outputFileParsers() { return List.of( - ControlKey.VRI_OUTPUT_VDYP_POLYGON, ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES, - ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL + ControlKey.VDYP_OUTPUT_VDYP_POLYGON, ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES, + ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL ); } } diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java index 2dcd84caf..3b7e67312 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/ParsersTogetherTest.java @@ -55,9 +55,9 @@ class ParsersTogetherTest { @BeforeEach void setUp() throws IOException, ResourceParseException { - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); resolver = new MockFileResolver("Test"); diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java index 3c5dcf9bf..1a922b157 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriInputValidationTest.java @@ -309,9 +309,9 @@ void testFailIfMissingPrimary() throws Exception { } private MockFileResolver dummyInput() { - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); MockFileResolver resolver = new MockFileResolver("Test"); resolver.addStream("DUMMY1", (OutputStream) new ByteArrayOutputStream()); diff --git a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java index 06665f4f8..dd1aa6d70 100644 --- a/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java +++ b/vdyp-lib/vdyp-vri/src/test/java/ca/bc/gov/nrs/vdyp/vri/VriStartTest.java @@ -102,9 +102,9 @@ class VriStartTest { ByteArrayOutputStream utilOut; private MockFileResolver dummyInput() { - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); - controlMap.put(ControlKey.VRI_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_POLYGON.name(), "DUMMY1"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SPECIES.name(), "DUMMY2"); + controlMap.put(ControlKey.VDYP_OUTPUT_VDYP_LAYER_BY_SP0_BY_UTIL.name(), "DUMMY3"); TestUtils.populateControlMapGenusReal(controlMap); MockFileResolver resolver = new MockFileResolver("Test");