diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/GMLCalculationSetOptionsReaderTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/GMLCalculationSetOptionsReaderTest.java index b6637322..83e7c2d3 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/GMLCalculationSetOptionsReaderTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/GMLCalculationSetOptionsReaderTest.java @@ -20,6 +20,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; @@ -48,6 +49,7 @@ import nl.overheid.aerius.shared.domain.calculation.MetDatasetType; import nl.overheid.aerius.shared.domain.calculation.MetSurfaceCharacteristics; import nl.overheid.aerius.shared.domain.calculation.NCACalculationOptions; +import nl.overheid.aerius.shared.domain.calculation.PermitLowerBoundType; import nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits; /** @@ -176,6 +178,25 @@ void testReadCalculationSetOptionsDuplicateOptions() { assertEquals("somewhere else", options.getNcaCalculationOptions().getPermitArea(), "PermitArea"); } + @Test + void testOwN2000ReadCalculationSetOptions() { + final FeatureCollection featureCollection = mock(FeatureCollection.class); + final MetaData metaData = mock(MetaData.class); + final IsCalculationMetaData calculationMetaData = mock(IsCalculationMetaData.class); + final List> suppliedOptions = new ArrayList<>(); + + suppliedOptions.add(mockCalculationOption("permit_lower_bound", "policy")); + when(featureCollection.getMetaData()).thenReturn(metaData); + when(calculationMetaData.getOptions()).thenAnswer(a -> suppliedOptions); + when(metaData.getCalculation()).thenReturn(calculationMetaData); + final GMLCalculationSetOptionsReader reader = new GMLCalculationSetOptionsReader(featureCollection); + + final CalculationSetOptions options = reader.readCalculationSetOptions(Theme.OWN2000); + assertNotNull(options, "returned options shouldn't be null"); + assertSame(PermitLowerBoundType.POLICY, options.getOwN2000CalculationOptions().getPermitLowerBoundType(), + "Should have read the Permit Lower Bound."); + } + /** * @param spatiallyVaryingRoughness Test spatiallyVaryingRoughness. if null it should be true, else follow boolean value */ @@ -279,7 +300,7 @@ void testReadCalculationSetOptionsEmptyOptions() { } @Test - void testReadCalculationSetOptionsWnb() { + void testNCAReadCalculationSetOptions() { final FeatureCollection featureCollection = mock(FeatureCollection.class); final MetaData metaData = mock(MetaData.class); final IsCalculationMetaData calculationMetaData = mock(IsCalculationMetaData.class); diff --git a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/CalculationRoadOPS.java b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/CalculationRoadOPS.java index 70145868..1cc9018c 100644 --- a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/CalculationRoadOPS.java +++ b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/CalculationRoadOPS.java @@ -36,7 +36,7 @@ public enum CalculationRoadOPS { /** * Use OPS to calculate for the entire calculation. - * This gives results outside the scope of WNB. + * This gives results outside the scope of OWN2000. */ OPS_ALL } diff --git a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/OwN2000CalculationOptions.java b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/OwN2000CalculationOptions.java index 7cd529a2..650097d2 100644 --- a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/OwN2000CalculationOptions.java +++ b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/OwN2000CalculationOptions.java @@ -21,13 +21,15 @@ import nl.overheid.aerius.shared.domain.meteo.Meteo; /** - * Calculation options related to the WNB theme. + * Calculation options related to the OWN2000 theme. */ public class OwN2000CalculationOptions implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2L; private CalculationRoadOPS roadOPS = CalculationRoadOPS.DEFAULT; + private PermitLowerBoundType permitLowerBoundType; + private double permitLowerBoundValue; private boolean useMaxDistance; private boolean forceAggregation; private Meteo meteo; @@ -41,6 +43,34 @@ public class OwN2000CalculationOptions implements Serializable { private boolean splitSubReceptorWork; private int splitSubReceptorWorkDistance; + /** + * @return Returns the lower bound type used for permit calculations. + */ + public PermitLowerBoundType getPermitLowerBoundType() { + return permitLowerBoundType; + } + + /** + * Set the lower bound type used for permit calculations. + */ + public void setPermitLowerBoundType(final PermitLowerBoundType permitLowerBoundType) { + this.permitLowerBoundType = permitLowerBoundType; + } + + /** + * @return Returns the lower bound value used for permit calculations. + */ + public double getPermitLowerBoundValue() { + return permitLowerBoundValue; + } + + /** + * Set the lower bound value used for permit calculations. + */ + public void setPermitLowerBoundValue(final double permitLowerBoundValue) { + this.permitLowerBoundValue = permitLowerBoundValue; + } + /** * @return Returns true if OwN2000 maximum distance 25km calculation is to be applied. */ @@ -49,10 +79,10 @@ public boolean isUseMaxDistance() { } /** - * Set if the WNB 25km calculation distance limit should be applied. Default true for WNB. + * Set if the OWN2000 25km calculation distance limit should be applied. Default true for OWN2000. */ - public void setUseMaxDistance(final boolean uswWNBMaxDistance) { - this.useMaxDistance = uswWNBMaxDistance; + public void setUseMaxDistance(final boolean useMaxDistance) { + this.useMaxDistance = useMaxDistance; } /** diff --git a/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/PermitLowerBoundType.java b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/PermitLowerBoundType.java new file mode 100644 index 00000000..754eec1c --- /dev/null +++ b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/PermitLowerBoundType.java @@ -0,0 +1,45 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.shared.domain.calculation; + +import java.util.Locale; + +/** + * Enum for identifying calculation lower bounds for permit calculations. + */ +public enum PermitLowerBoundType { + /** + * Arithmetic limitations lower bound. + */ + ARITHMETIC, + /** + * Policy lower bound. + */ + POLICY; + + public String toDatabaseString() { + return name().toLowerCase(Locale.ROOT); + } + + public static PermitLowerBoundType safeValueOf(final String value) { + try { + return value == null ? null : valueOf(value.toUpperCase(Locale.ROOT)); + } catch (final IllegalArgumentException e) { + return null; + } + } +} diff --git a/source/imaer-util/src/main/java/nl/overheid/aerius/util/NcaOptionsMetadataUtil.java b/source/imaer-util/src/main/java/nl/overheid/aerius/util/NcaOptionsMetadataUtil.java new file mode 100644 index 00000000..4b8ff759 --- /dev/null +++ b/source/imaer-util/src/main/java/nl/overheid/aerius/util/NcaOptionsMetadataUtil.java @@ -0,0 +1,204 @@ +/* + * Crown copyright + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.util; + +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ADMS_COMPLEX_TERRAIN_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ADMS_PLUME_DEPLETION_NH3_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ADMS_PLUME_DEPLETION_NOX_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.MIN_MONIN_OBUKHOV_LENGTH_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.PRIESTLEY_TAYLOR_PARAMETER_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ROUGHNESS_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.SPATIALLY_VARYING_ROUGHNESS_DEFAULT; +import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.SURFACE_ALBEDO_DEFAULT; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import nl.overheid.aerius.shared.domain.calculation.ADMSOptions; +import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; +import nl.overheid.aerius.shared.domain.calculation.MetDatasetType; +import nl.overheid.aerius.shared.domain.calculation.MetSurfaceCharacteristics; +import nl.overheid.aerius.shared.domain.calculation.NCACalculationOptions; +import nl.overheid.aerius.shared.domain.calculation.RoadLocalFractionNO2Option; +import nl.overheid.aerius.util.OptionsMetadataUtil.Option; + +/** + * Util class to read/write NCA theme meta data options from/to a map into/from the CalculationSetOptions object. + */ +final class NcaOptionsMetadataUtil extends OptionsMetadataUtilBase { + + private NcaOptionsMetadataUtil() { + // Util class + } + + /** + * Reads the NCA specific {@link CalculationSetOptions} from a map. + * + * @param map The map to read the options from + * @param prefixedOptionsMap map of options that have a prefixed key + * @param options The object to set the options in + */ + static void ncaCalculationSetOptionsFromMap(final Map map, final Map> prefixedOptionsMap, + final CalculationSetOptions options) { + final NCACalculationOptions ncaCalculationOptions = options.getNcaCalculationOptions(); + + NcaOptionsMetadataUtil.ncaOptionsFromMap(ncaCalculationOptions, map, prefixedOptionsMap); + options.getCalculatedSnapshotValues().setDevelopmentPressureClassification(map.get(Option.DEVELOPMENT_PRESSURE_CLASSIFICATION)); + } + + private static void ncaOptionsFromMap(final NCACalculationOptions options, final Map map, + final Map> prefixedOptionsMap) { + options.setProjectCategory(map.get(Option.PROJECT_CATEGORY)); + options.setPermitArea(map.get(Option.PERMIT_AREA)); + parseListOption(Option.DEVELOPMENT_PRESSURE_SOURCE_IDS, map, options::setDevelopmentPressureSourceIds); + options.setRoadLocalFractionNO2ReceptorsOption(RoadLocalFractionNO2Option.safeValueOf(map.get(Option.ROAD_LOCAL_FRACTION_NO2_RECEPTORS_OPTION))); + options.setRoadLocalFractionNO2PointsOption(RoadLocalFractionNO2Option.safeValueOf(map.get(Option.ROAD_LOCAL_FRACTION_NO2_POINTS_OPTION))); + if (options.getRoadLocalFractionNO2ReceptorsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE + || options.getRoadLocalFractionNO2PointsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE) { + options.setRoadLocalFractionNO2( + Optional.ofNullable(map.get(Option.ROAD_LOCAL_FRACTION_NO2_CUSTOM_VALUE)).map(Double::parseDouble).orElse(null)); + } + + final ADMSOptions admsOptions = options.getAdmsOptions(); + admsOptions.setMinMoninObukhovLength(getOrDefault(map, Option.ADMS_MIN_MONIN_OBUKHOV_LENGTH, MIN_MONIN_OBUKHOV_LENGTH_DEFAULT)); + admsOptions.setSurfaceAlbedo(getOrDefault(map, Option.ADMS_SURFACE_ALBEDO, SURFACE_ALBEDO_DEFAULT)); + admsOptions.setPriestleyTaylorParameter(getOrDefault(map, Option.ADMS_PRIESTLEY_TAYLOR_PARAMETER, PRIESTLEY_TAYLOR_PARAMETER_DEFAULT)); + + if (map.get(Option.ADMS_MET_SITE_ID) != null) { + admsOptions.setMetSiteId(Integer.parseInt(map.get(Option.ADMS_MET_SITE_ID))); + admsOptions.setMetSiteLatitude(Optional.ofNullable(map.get(Option.ADMS_MET_SITE_LATITUDE)).map(Double::parseDouble).orElse(0.0)); + admsOptions.setMetDatasetType(MetDatasetType.safeValueOf(map.get(Option.ADMS_MET_DATASET_TYPE))); + parseListOption(Option.ADMS_MET_YEARS, map, admsOptions::setMetYears); + ncaMetSiteOptions(prefixedOptionsMap, admsOptions, map); + } + admsOptions.setPlumeDepletionNH3(isOrDefault(map, Option.ADMS_PLUME_DEPLETION_NH3, ADMS_PLUME_DEPLETION_NH3_DEFAULT)); + admsOptions.setPlumeDepletionNOX(isOrDefault(map, Option.ADMS_PLUME_DEPLETION_NOX, ADMS_PLUME_DEPLETION_NOX_DEFAULT)); + admsOptions.setSpatiallyVaryingRoughness(isOrDefault(map, Option.ADMS_SPATIALLY_VARYING_ROUGHNESS, SPATIALLY_VARYING_ROUGHNESS_DEFAULT)); + admsOptions.setComplexTerrain(isOrDefault(map, Option.ADMS_COMPLEX_TERRAIN, ADMS_COMPLEX_TERRAIN_DEFAULT)); + } + + /** + * Read Met Site data. If multiple met years are present the met site options key is expected to be prefixed with the met year. + * If only 1 year or no met year is present the options are not prefixed. + */ + private static void ncaMetSiteOptions(final Map> prefixedOptionsMap, final ADMSOptions admsOptions, + final Map map) { + if (admsOptions.getMetYears().size() > 1) { + for (final String metYear : admsOptions.getMetYears()) { + final Map prefixedMap = prefixedOptionsMap.get(metYear); + ncaPutMetSiteOptions(admsOptions, metYear, prefixedMap); + } + } else { + ncaPutMetSiteOptions(admsOptions, "", map); + } + } + + private static void ncaPutMetSiteOptions(final ADMSOptions admsOptions, final String metYear, final Map prefixedMap) { + final MetSurfaceCharacteristics msc = MetSurfaceCharacteristics.builder() + .roughness(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_ROUGHNESS, ROUGHNESS_DEFAULT)) + .minMoninObukhovLength(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_MIN_MONIN_OBUKHOV_LENGTH, + MIN_MONIN_OBUKHOV_LENGTH_DEFAULT)) + .surfaceAlbedo(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_SURFACE_ALBEDO, SURFACE_ALBEDO_DEFAULT)) + .priestleyTaylorParameter(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_PRIESTLEY_TAYLOR_PARAMETER, + PRIESTLEY_TAYLOR_PARAMETER_DEFAULT)) + .windInSectors(isOrDefault(prefixedMap, Option.ADMS_MET_SITE_WIND_IN_SECTORS, false)) + .build(); + admsOptions.putMetSiteCharacteristics(metYear, msc); + } + + /** + * Put NCA theme options into a map to be stored in the GML. + * + * @param options Object to get the options from + * @param mapToAddTo map to add the options to + * @param addDefaults flag if set to true will add default values when no value is present in the options object + */ + static void ncaCalculationSetOptionsToMap(final CalculationSetOptions options, final Map mapToAddTo, final boolean addDefaults) { + ncaOptionsToMap(mapToAddTo, options.getNcaCalculationOptions(), addDefaults); + addValue(mapToAddTo, Option.DEVELOPMENT_PRESSURE_CLASSIFICATION, options.getCalculatedSnapshotValues().getDevelopmentPressureClassification(), + addDefaults); + } + + private static void ncaOptionsToMap(final Map mapToAddTo, final NCACalculationOptions options, final boolean addDefaults) { + if (options != null) { + addValue(mapToAddTo, Option.ADMS_VERSION, options.getAdmsVersion(), addDefaults); + addValue(mapToAddTo, Option.PROJECT_CATEGORY, options.getProjectCategory(), addDefaults); + addValue(mapToAddTo, Option.PERMIT_AREA, options.getPermitArea(), addDefaults); + if (!options.getDevelopmentPressureSourceIds().isEmpty()) { + addValue(mapToAddTo, Option.DEVELOPMENT_PRESSURE_SOURCE_IDS, + String.join(LIST_OPTION_SEPARATOR, options.getDevelopmentPressureSourceIds()), addDefaults); + } + addValue(mapToAddTo, Option.ROAD_LOCAL_FRACTION_NO2_RECEPTORS_OPTION, options.getRoadLocalFractionNO2ReceptorsOption(), addDefaults); + addValue(mapToAddTo, Option.ROAD_LOCAL_FRACTION_NO2_POINTS_OPTION, options.getRoadLocalFractionNO2PointsOption(), addDefaults); + if (options.getRoadLocalFractionNO2ReceptorsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE + || options.getRoadLocalFractionNO2PointsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE) { + addValue(mapToAddTo, Option.ROAD_LOCAL_FRACTION_NO2_CUSTOM_VALUE, options.getRoadLocalFractionNO2(), addDefaults); + } + final ADMSOptions adms = options.getAdmsOptions(); + + if (adms != null) { + addValue(mapToAddTo, Option.ADMS_MIN_MONIN_OBUKHOV_LENGTH, adms.getMinMoninObukhovLength(), addDefaults); + addValue(mapToAddTo, Option.ADMS_SURFACE_ALBEDO, adms.getSurfaceAlbedo(), addDefaults); + addValue(mapToAddTo, Option.ADMS_PRIESTLEY_TAYLOR_PARAMETER, adms.getPriestleyTaylorParameter(), addDefaults); + addIntValue(mapToAddTo, Option.ADMS_MET_SITE_ID, adms.getMetSiteId(), addDefaults); + if (adms.getMetSiteLatitude() != 0.0) { + addValue(mapToAddTo, Option.ADMS_MET_SITE_LATITUDE, adms.getMetSiteLatitude(), addDefaults); + } + addValue(mapToAddTo, Option.ADMS_MET_DATASET_TYPE, adms.getMetDatasetType(), addDefaults); + ncaAddMetSite(mapToAddTo, addDefaults, adms); + // Always add the following fields to the GML as it also gives an indication if run in demo mode. + addBooleanValue(mapToAddTo, Option.ADMS_PLUME_DEPLETION_NH3, adms.isPlumeDepletionNH3(), true); + addBooleanValue(mapToAddTo, Option.ADMS_PLUME_DEPLETION_NOX, adms.isPlumeDepletionNOX(), true); + addBooleanValue(mapToAddTo, Option.ADMS_SPATIALLY_VARYING_ROUGHNESS, adms.isSpatiallyVaryingRoughness(), true); + addBooleanValue(mapToAddTo, Option.ADMS_COMPLEX_TERRAIN, adms.isComplexTerrain(), true); + } + } + } + + /** + * Add Met Site data. If multiple met years are present the met site options key is prefixed with the met year. + * If only 1 year or no met year is present the options are not prefixed. + */ + private static void ncaAddMetSite(final Map mapToAddTo, final boolean addDefaults, final ADMSOptions adms) { + final List metYears = adms.getMetYears(); + if (!metYears.isEmpty()) { + addValue(mapToAddTo, Option.ADMS_MET_YEARS, String.join(LIST_OPTION_SEPARATOR, metYears), addDefaults); + } + if (metYears.size() > 1) { + for (final String metYear : metYears) { + final String prefix = metYear + OPTION_KEY_SPLIT; + addADMSMetSiteOptions(mapToAddTo, addDefaults, adms.getMetSiteCharacteristics(metYear), prefix); + } + } else { + final String metYear = metYears.isEmpty() ? "" : metYears.get(0); + addADMSMetSiteOptions(mapToAddTo, addDefaults, adms.getMetSiteCharacteristics(metYear), ""); + } + } + + private static void addADMSMetSiteOptions(final Map mapToAddTo, final boolean addDefaults, final MetSurfaceCharacteristics msc, + final String prefix) { + + addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_ROUGHNESS.toKey(), msc.getRoughness(), addDefaults); + addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_MIN_MONIN_OBUKHOV_LENGTH.toKey(), msc.getMinMoninObukhovLength(), addDefaults); + addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_SURFACE_ALBEDO.toKey(), msc.getSurfaceAlbedo(), addDefaults); + addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_PRIESTLEY_TAYLOR_PARAMETER.toKey(), msc.getPriestleyTaylorParameter(), addDefaults); + if (msc.isWindInSectors()) { + addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_WIND_IN_SECTORS.toKey(), String.valueOf(msc.isWindInSectors()), addDefaults); + } + } +} diff --git a/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtil.java b/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtil.java index 18ecc814..2a57a7d6 100644 --- a/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtil.java +++ b/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtil.java @@ -16,45 +16,21 @@ */ package nl.overheid.aerius.util; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ADMS_COMPLEX_TERRAIN_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ADMS_PLUME_DEPLETION_NH3_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ADMS_PLUME_DEPLETION_NOX_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.MIN_MONIN_OBUKHOV_LENGTH_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.PRIESTLEY_TAYLOR_PARAMETER_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.ROUGHNESS_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.SPATIALLY_VARYING_ROUGHNESS_DEFAULT; -import static nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits.SURFACE_ALBEDO_DEFAULT; - -import java.util.Arrays; import java.util.EnumMap; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; import nl.overheid.aerius.shared.domain.Theme; -import nl.overheid.aerius.shared.domain.calculation.ADMSOptions; import nl.overheid.aerius.shared.domain.calculation.CalculationJobType; -import nl.overheid.aerius.shared.domain.calculation.CalculationRoadOPS; import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; import nl.overheid.aerius.shared.domain.calculation.ConnectSuppliedOptions; -import nl.overheid.aerius.shared.domain.calculation.MetDatasetType; -import nl.overheid.aerius.shared.domain.calculation.MetSurfaceCharacteristics; -import nl.overheid.aerius.shared.domain.calculation.NCACalculationOptions; -import nl.overheid.aerius.shared.domain.calculation.OPSOptions; -import nl.overheid.aerius.shared.domain.calculation.OwN2000CalculationOptions; -import nl.overheid.aerius.shared.domain.calculation.RoadLocalFractionNO2Option; /** * Utility class to convert calculation options to metadata. */ -public final class OptionsMetadataUtil { - - private static final String LIST_OPTION_SEPARATOR = ","; - private static final String OPTION_KEY_SPLIT = "-"; +public final class OptionsMetadataUtil extends OptionsMetadataUtilBase { public enum Option { // @formatter:off @@ -64,6 +40,8 @@ public enum Option { FORCED_AGGREGATION, USE_RECEPTOR_HEIGHT, MONITOR_SRM2_YEAR, + PERMIT_LOWER_BOUND, + PERMIT_LOWER_BOUND_VALUE, WITH_MAX_DISTANCE, SUB_RECEPTORS_MODE, SUB_RECEPTOR_ZOOM_LEVEL, @@ -180,9 +158,9 @@ private static void mapOptions(final Map optionsMap, final Map map, final Map> prefixedOptionsMap, final CalculationSetOptions options) { if (theme == Theme.NCA) { - final NCACalculationOptions ncaCalculationOptions = options.getNcaCalculationOptions(); - ncaOptionsFromMap(ncaCalculationOptions, map, prefixedOptionsMap); - options.getCalculatedSnapshotValues().setDevelopmentPressureClassification(map.get(Option.DEVELOPMENT_PRESSURE_CLASSIFICATION)); + NcaOptionsMetadataUtil.ncaCalculationSetOptionsFromMap(map, prefixedOptionsMap, options); + } else { + Own2000OptionsMetadataUtil.own2000CalculationSetOptionsFromMap(map, prefixedOptionsMap, options); } } @@ -193,34 +171,14 @@ public static Map optionsToMap(final Theme theme, final Calculat addBooleanValue(mapToAddTo, Option.USE_IN_COMBINATION_ARCHIVE, options.isUseInCombinationArchive(), addDefaults); } if (theme == null || theme == Theme.OWN2000 || theme == Theme.CIMLK) { - own2000OptionsToMap(mapToAddTo, options.getOwN2000CalculationOptions(), addDefaults); - addIntValue(mapToAddTo, Option.MONITOR_SRM2_YEAR, options.getRblCalculationOptions().getMonitorSrm2Year(), addDefaults); + Own2000OptionsMetadataUtil.own2000CalculationSetOptionsToMap(options, mapToAddTo, addDefaults); } else if (theme == Theme.NCA) { - ncaOptionsToMap(mapToAddTo, options.getNcaCalculationOptions(), addDefaults); - addValue(mapToAddTo, Option.DEVELOPMENT_PRESSURE_CLASSIFICATION, options.getCalculatedSnapshotValues().getDevelopmentPressureClassification(), - addDefaults); + NcaOptionsMetadataUtil.ncaCalculationSetOptionsToMap(options, mapToAddTo, addDefaults); } addConnectSuppliedOptions(options.getConnectSuppliedOptions(), mapToAddTo, addDefaults); return mapToAddTo; } - private static void own2000OptionsToMap(final Map mapToAddTo, final OwN2000CalculationOptions options, final boolean addDefaults) { - addValue(mapToAddTo, Option.METEO_YEAR, options.getMeteo(), addDefaults); - if (addDefaults || options.getRoadOPS() != CalculationRoadOPS.DEFAULT) { - mapToAddTo.put(Option.OPS_ROAD.toKey(), options.getRoadOPS().name()); - } - addBooleanValue(mapToAddTo, Option.FORCED_AGGREGATION, options.isForceAggregation(), addDefaults); - addBooleanValue(mapToAddTo, Option.USE_RECEPTOR_HEIGHT, options.isUseReceptorHeights(), addDefaults); - addBooleanValue(mapToAddTo, Option.WITH_MAX_DISTANCE, options.isUseMaxDistance(), addDefaults); - addValue(mapToAddTo, Option.SUB_RECEPTORS_MODE, options.getSubReceptorsMode(), addDefaults); - addValue(mapToAddTo, Option.SUB_RECEPTOR_ZOOM_LEVEL, options.getSubReceptorZoomLevel(), addDefaults); - addBooleanValue(mapToAddTo, Option.SPLIT_SUB_RECEPTOR_WORK, options.isSplitSubReceptorWork(), addDefaults); - if (options.isSplitSubReceptorWork()) { - addValue(mapToAddTo, Option.SPLIT_SUB_RECEPTOR_WORK_DISTANCE, options.getSplitSubReceptorWorkDistance(), addDefaults); - } - opsOptionsToMap(options.getOpsOptions(), mapToAddTo, addDefaults); - } - private static void addConnectSuppliedOptions(final ConnectSuppliedOptions connectSuppliedOptions, final Map mapToAddTo, final boolean addDefaults) { if (connectSuppliedOptions != null) { @@ -228,200 +186,4 @@ private static void addConnectSuppliedOptions(final ConnectSuppliedOptions conne addValue(mapToAddTo, Option.RECEPTOR_SET, connectSuppliedOptions.getReceptorSetName(), addDefaults); } } - - private static void opsOptionsToMap(final OPSOptions options, final Map mapToAddTo, final boolean addDefaults) { - if (options != null) { - addBooleanValue(mapToAddTo, Option.OPS_RAW_INPUT, options.isRawInput(), addDefaults); - addValue(mapToAddTo, Option.OPS_YEAR, options.getYear(), addDefaults); - addValue(mapToAddTo, Option.OPS_CHEMISTRY, Optional.ofNullable(options.getChemistry()).map(OPSOptions.Chemistry::name).orElse(null), - addDefaults); - addValue(mapToAddTo, Option.OPS_COMP_CODE, options.getCompCode(), addDefaults); - addValue(mapToAddTo, Option.OPS_MOL_WEIGHT, options.getMolWeight(), addDefaults); - addValue(mapToAddTo, Option.OPS_PHASE, options.getPhase(), addDefaults); - addValue(mapToAddTo, Option.OPS_LOSS, options.getLoss(), addDefaults); - addValue(mapToAddTo, Option.OPS_DIFF_COEFF, options.getDiffCoeff(), addDefaults); - addValue(mapToAddTo, Option.OPS_WASHOUT, options.getWashout(), addDefaults); - addValue(mapToAddTo, Option.OPS_CONV_RATE, options.getConvRate(), addDefaults); - addValue(mapToAddTo, Option.OPS_ROUGHNESS, options.getRoughness(), addDefaults); - addValue(mapToAddTo, Option.OPS_ROADS, options.getRoads(), addDefaults); - } - } - - private static void ncaOptionsFromMap(final NCACalculationOptions options, final Map map, - final Map> prefixedOptionsMap) { - options.setProjectCategory(map.get(Option.PROJECT_CATEGORY)); - options.setPermitArea(map.get(Option.PERMIT_AREA)); - parseListOption(Option.DEVELOPMENT_PRESSURE_SOURCE_IDS, map, options::setDevelopmentPressureSourceIds); - options.setRoadLocalFractionNO2ReceptorsOption(RoadLocalFractionNO2Option.safeValueOf(map.get(Option.ROAD_LOCAL_FRACTION_NO2_RECEPTORS_OPTION))); - options.setRoadLocalFractionNO2PointsOption(RoadLocalFractionNO2Option.safeValueOf(map.get(Option.ROAD_LOCAL_FRACTION_NO2_POINTS_OPTION))); - if (options.getRoadLocalFractionNO2ReceptorsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE - || options.getRoadLocalFractionNO2PointsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE) { - options.setRoadLocalFractionNO2( - Optional.ofNullable(map.get(Option.ROAD_LOCAL_FRACTION_NO2_CUSTOM_VALUE)).map(Double::parseDouble).orElse(null)); - } - - final ADMSOptions admsOptions = options.getAdmsOptions(); - admsOptions.setMinMoninObukhovLength(getOrDefault(map, Option.ADMS_MIN_MONIN_OBUKHOV_LENGTH, MIN_MONIN_OBUKHOV_LENGTH_DEFAULT)); - admsOptions.setSurfaceAlbedo(getOrDefault(map, Option.ADMS_SURFACE_ALBEDO, SURFACE_ALBEDO_DEFAULT)); - admsOptions.setPriestleyTaylorParameter(getOrDefault(map, Option.ADMS_PRIESTLEY_TAYLOR_PARAMETER, PRIESTLEY_TAYLOR_PARAMETER_DEFAULT)); - - if (map.get(Option.ADMS_MET_SITE_ID) != null) { - admsOptions.setMetSiteId(Integer.parseInt(map.get(Option.ADMS_MET_SITE_ID))); - admsOptions.setMetSiteLatitude(Optional.ofNullable(map.get(Option.ADMS_MET_SITE_LATITUDE)).map(Double::parseDouble).orElse(0.0)); - admsOptions.setMetDatasetType(MetDatasetType.safeValueOf(map.get(Option.ADMS_MET_DATASET_TYPE))); - parseListOption(Option.ADMS_MET_YEARS, map, admsOptions::setMetYears); - ncaMetSiteOptions(prefixedOptionsMap, admsOptions, map); - } - admsOptions.setPlumeDepletionNH3(isOrDefault(map, Option.ADMS_PLUME_DEPLETION_NH3, ADMS_PLUME_DEPLETION_NH3_DEFAULT)); - admsOptions.setPlumeDepletionNOX(isOrDefault(map, Option.ADMS_PLUME_DEPLETION_NOX, ADMS_PLUME_DEPLETION_NOX_DEFAULT)); - admsOptions.setSpatiallyVaryingRoughness(isOrDefault(map, Option.ADMS_SPATIALLY_VARYING_ROUGHNESS, SPATIALLY_VARYING_ROUGHNESS_DEFAULT)); - admsOptions.setComplexTerrain(isOrDefault(map, Option.ADMS_COMPLEX_TERRAIN, ADMS_COMPLEX_TERRAIN_DEFAULT)); - } - - /** - * Read Met Site data. If multiple met years are present the met site options key is expected to be prefixed with the met year. - * If only 1 year or no met year is present the options are not prefixed. - */ - private static void ncaMetSiteOptions(final Map> prefixedOptionsMap, final ADMSOptions admsOptions, - final Map map) { - if (admsOptions.getMetYears().size() > 1) { - for (final String metYear : admsOptions.getMetYears()) { - final Map prefixedMap = prefixedOptionsMap.get(metYear); - ncaPutMetSiteOptions(admsOptions, metYear, prefixedMap); - } - } else { - ncaPutMetSiteOptions(admsOptions, "", map); - } - } - - private static void ncaPutMetSiteOptions(final ADMSOptions admsOptions, final String metYear, final Map prefixedMap) { - final MetSurfaceCharacteristics msc = MetSurfaceCharacteristics.builder() - .roughness(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_ROUGHNESS, ROUGHNESS_DEFAULT)) - .minMoninObukhovLength(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_MIN_MONIN_OBUKHOV_LENGTH, - MIN_MONIN_OBUKHOV_LENGTH_DEFAULT)) - .surfaceAlbedo(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_SURFACE_ALBEDO, SURFACE_ALBEDO_DEFAULT)) - .priestleyTaylorParameter(getOrDefault(prefixedMap, Option.ADMS_MET_SITE_PRIESTLEY_TAYLOR_PARAMETER, - PRIESTLEY_TAYLOR_PARAMETER_DEFAULT)) - .windInSectors(isOrDefault(prefixedMap, Option.ADMS_MET_SITE_WIND_IN_SECTORS, false)) - .build(); - admsOptions.putMetSiteCharacteristics(metYear, msc); - } - - private static double getOrDefault(final Map map, final Option option, final double defaultValue) { - return Optional.ofNullable(map.get(option)).map(Double::parseDouble).orElse(defaultValue); - } - - private static boolean isOrDefault(final Map map, final Option option, final boolean defaultValue) { - return Optional.ofNullable(map.get(option)).map(Boolean::parseBoolean).orElse(defaultValue); - } - - private static void parseListOption(final Option key, final Map map, final Consumer> setter) { - final String value = map.get(key); - if (value != null && !value.isBlank()) { - final String[] splitOption = value.split(LIST_OPTION_SEPARATOR); - if (splitOption.length > 0) { - setter.accept(Arrays.asList(splitOption)); - } - } - } - - private static void ncaOptionsToMap(final Map mapToAddTo, final NCACalculationOptions options, final boolean addDefaults) { - if (options != null) { - addValue(mapToAddTo, Option.ADMS_VERSION, options.getAdmsVersion(), addDefaults); - addValue(mapToAddTo, Option.PROJECT_CATEGORY, options.getProjectCategory(), addDefaults); - addValue(mapToAddTo, Option.PERMIT_AREA, options.getPermitArea(), addDefaults); - if (!options.getDevelopmentPressureSourceIds().isEmpty()) { - addValue(mapToAddTo, Option.DEVELOPMENT_PRESSURE_SOURCE_IDS, - String.join(LIST_OPTION_SEPARATOR, options.getDevelopmentPressureSourceIds()), addDefaults); - } - addValue(mapToAddTo, Option.ROAD_LOCAL_FRACTION_NO2_RECEPTORS_OPTION, options.getRoadLocalFractionNO2ReceptorsOption(), addDefaults); - addValue(mapToAddTo, Option.ROAD_LOCAL_FRACTION_NO2_POINTS_OPTION, options.getRoadLocalFractionNO2PointsOption(), addDefaults); - if (options.getRoadLocalFractionNO2ReceptorsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE - || options.getRoadLocalFractionNO2PointsOption() == RoadLocalFractionNO2Option.ONE_CUSTOM_VALUE) { - addValue(mapToAddTo, Option.ROAD_LOCAL_FRACTION_NO2_CUSTOM_VALUE, options.getRoadLocalFractionNO2(), addDefaults); - } - final ADMSOptions adms = options.getAdmsOptions(); - - if (adms != null) { - addValue(mapToAddTo, Option.ADMS_MIN_MONIN_OBUKHOV_LENGTH, adms.getMinMoninObukhovLength(), addDefaults); - addValue(mapToAddTo, Option.ADMS_SURFACE_ALBEDO, adms.getSurfaceAlbedo(), addDefaults); - addValue(mapToAddTo, Option.ADMS_PRIESTLEY_TAYLOR_PARAMETER, adms.getPriestleyTaylorParameter(), addDefaults); - addIntValue(mapToAddTo, Option.ADMS_MET_SITE_ID, adms.getMetSiteId(), addDefaults); - if (adms.getMetSiteLatitude() != 0.0) { - addValue(mapToAddTo, Option.ADMS_MET_SITE_LATITUDE, adms.getMetSiteLatitude(), addDefaults); - } - addValue(mapToAddTo, Option.ADMS_MET_DATASET_TYPE, adms.getMetDatasetType(), addDefaults); - ncaAddMetSite(mapToAddTo, addDefaults, adms); - // Always add the following fields to the GML as it also gives an indication if run in demo mode. - addBooleanValue(mapToAddTo, Option.ADMS_PLUME_DEPLETION_NH3, adms.isPlumeDepletionNH3(), true); - addBooleanValue(mapToAddTo, Option.ADMS_PLUME_DEPLETION_NOX, adms.isPlumeDepletionNOX(), true); - addBooleanValue(mapToAddTo, Option.ADMS_SPATIALLY_VARYING_ROUGHNESS, adms.isSpatiallyVaryingRoughness(), true); - addBooleanValue(mapToAddTo, Option.ADMS_COMPLEX_TERRAIN, adms.isComplexTerrain(), true); - } - } - } - - /** - * Add Met Site data. If multiple met years are present the met site options key is prefixed with the met year. - * If only 1 year or no met year is present the options are not prefixed. - */ - private static void ncaAddMetSite(final Map mapToAddTo, final boolean addDefaults, final ADMSOptions adms) { - final List metYears = adms.getMetYears(); - if (!metYears.isEmpty()) { - addValue(mapToAddTo, Option.ADMS_MET_YEARS, String.join(LIST_OPTION_SEPARATOR, metYears), addDefaults); - } - if (metYears.size() > 1) { - for (final String metYear : metYears) { - final String prefix = metYear + OPTION_KEY_SPLIT; - addADMSMetSiteOptions(mapToAddTo, addDefaults, adms.getMetSiteCharacteristics(metYear), prefix); - } - } else { - final String metYear = metYears.isEmpty() ? "" : metYears.get(0); - addADMSMetSiteOptions(mapToAddTo, addDefaults, adms.getMetSiteCharacteristics(metYear), ""); - } - } - - private static void addADMSMetSiteOptions(final Map mapToAddTo, final boolean addDefaults, final MetSurfaceCharacteristics msc, - final String prefix) { - - addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_ROUGHNESS.toKey(), msc.getRoughness(), addDefaults); - addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_MIN_MONIN_OBUKHOV_LENGTH.toKey(), msc.getMinMoninObukhovLength(), addDefaults); - addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_SURFACE_ALBEDO.toKey(), msc.getSurfaceAlbedo(), addDefaults); - addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_PRIESTLEY_TAYLOR_PARAMETER.toKey(), msc.getPriestleyTaylorParameter(), addDefaults); - if (msc.isWindInSectors()) { - addValue(mapToAddTo, prefix + Option.ADMS_MET_SITE_WIND_IN_SECTORS.toKey(), String.valueOf(msc.isWindInSectors()), addDefaults); - } - } - - private static void addValue(final Map mapToAddTo, final Option key, final Object value, final boolean addDefaults) { - addValue(mapToAddTo, key.toKey(), value, addDefaults); - } - - private static void addValue(final Map mapToAddTo, final String key, final Object value, final boolean addDefaults) { - // false should be the default value, so only add if value is true, or if defaults should be added anyway. - if (value != null) { - mapToAddTo.put(key, value.toString()); - } else if (addDefaults) { - mapToAddTo.put(key, ""); - } - } - - private static void addIntValue(final Map mapToAddTo, final Option key, final int value, final boolean addDefaults) { - addIntValue(mapToAddTo, key, value, addDefaults, 0); - } - - private static void addIntValue(final Map mapToAddTo, final Option key, final int value, final boolean addDefaults, - final int defaultValue) { - if (addDefaults || value != defaultValue) { - mapToAddTo.put(key.toKey(), String.valueOf(value)); - } - } - - private static void addBooleanValue(final Map mapToAddTo, final Option key, final boolean value, final boolean addDefaults) { - // false should be the default value, so only add if value is true, or if defaults should be added anyway. - if (addDefaults || value) { - mapToAddTo.put(key.toKey(), String.valueOf(value)); - } - } - } diff --git a/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtilBase.java b/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtilBase.java new file mode 100644 index 00000000..830ff820 --- /dev/null +++ b/source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtilBase.java @@ -0,0 +1,87 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.util; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + +import nl.overheid.aerius.util.OptionsMetadataUtil.Option; + +/** + * Base class for Options Metadata Util classes with generic methods. + */ +class OptionsMetadataUtilBase { + + protected static final String LIST_OPTION_SEPARATOR = ","; + protected static final String OPTION_KEY_SPLIT = "-"; + + protected OptionsMetadataUtilBase() { + // Util class + } + + static double getOrDefault(final Map map, final Option option, final double defaultValue) { + return Optional.ofNullable(map.get(option)).map(Double::parseDouble).orElse(defaultValue); + } + + static boolean isOrDefault(final Map map, final Option option, final boolean defaultValue) { + return Optional.ofNullable(map.get(option)).map(Boolean::parseBoolean).orElse(defaultValue); + } + + static void parseListOption(final Option key, final Map map, final Consumer> setter) { + final String value = map.get(key); + if (value != null && !value.isBlank()) { + final String[] splitOption = value.split(LIST_OPTION_SEPARATOR); + if (splitOption.length > 0) { + setter.accept(Arrays.asList(splitOption)); + } + } + } + + static void addValue(final Map mapToAddTo, final Option key, final Object value, final boolean addDefaults) { + addValue(mapToAddTo, key.toKey(), value, addDefaults); + } + + static void addValue(final Map mapToAddTo, final String key, final Object value, final boolean addDefaults) { + // false should be the default value, so only add if value is true, or if defaults should be added anyway. + if (value != null) { + mapToAddTo.put(key, value.toString()); + } else if (addDefaults) { + mapToAddTo.put(key, ""); + } + } + + static void addIntValue(final Map mapToAddTo, final Option key, final int value, final boolean addDefaults) { + addIntValue(mapToAddTo, key, value, addDefaults, 0); + } + + static void addIntValue(final Map mapToAddTo, final Option key, final int value, final boolean addDefaults, + final int defaultValue) { + if (addDefaults || value != defaultValue) { + mapToAddTo.put(key.toKey(), String.valueOf(value)); + } + } + + static void addBooleanValue(final Map mapToAddTo, final Option key, final boolean value, final boolean addDefaults) { + // false should be the default value, so only add if value is true, or if defaults should be added anyway. + if (addDefaults || value) { + mapToAddTo.put(key.toKey(), String.valueOf(value)); + } + } +} diff --git a/source/imaer-util/src/main/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtil.java b/source/imaer-util/src/main/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtil.java new file mode 100644 index 00000000..e9957bf6 --- /dev/null +++ b/source/imaer-util/src/main/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtil.java @@ -0,0 +1,106 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.util; + +import java.util.Map; +import java.util.Optional; + +import nl.overheid.aerius.shared.domain.calculation.CalculationRoadOPS; +import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; +import nl.overheid.aerius.shared.domain.calculation.OPSOptions; +import nl.overheid.aerius.shared.domain.calculation.OwN2000CalculationOptions; +import nl.overheid.aerius.shared.domain.calculation.PermitLowerBoundType; +import nl.overheid.aerius.util.OptionsMetadataUtil.Option; + +/** + * Util class to read/write Own2000 theme meta data options from/to a map into/from the CalculationSetOptions object. + */ +final class Own2000OptionsMetadataUtil extends OptionsMetadataUtilBase { + + private Own2000OptionsMetadataUtil() { + // Util class + } + + /** + * Reads the Own2000 theme {@link CalculationSetOptions} from a map. + * + * @param map The map to read the options from + * @param prefixedOptionsMap map of options that have a prefixed key + * @param options The object to set the options in + */ + static void own2000CalculationSetOptionsFromMap(final Map map, final Map> prefixedOptionsMap, + final CalculationSetOptions options) { + final OwN2000CalculationOptions owN2000CalculationOptions = options.getOwN2000CalculationOptions(); + + owN2000CalculationOptions.setPermitLowerBoundType(PermitLowerBoundType.safeValueOf(map.get(Option.PERMIT_LOWER_BOUND))); + } + + /** + * Put OWN2000 theme options into a map to be stored in the GML. + * + * @param options Object to get the options from + * @param mapToAddTo map to add the options to + * @param addDefaults flag if set to true will add default values when no value is present in the options object + */ + static void own2000CalculationSetOptionsToMap(final CalculationSetOptions options, final Map mapToAddTo, final boolean addDefaults) { + own2000OptionsToMap(mapToAddTo, options.getOwN2000CalculationOptions(), addDefaults); + addIntValue(mapToAddTo, Option.MONITOR_SRM2_YEAR, options.getRblCalculationOptions().getMonitorSrm2Year(), addDefaults); + } + + private static void own2000OptionsToMap(final Map mapToAddTo, final OwN2000CalculationOptions options, final boolean addDefaults) { + addValue(mapToAddTo, Option.METEO_YEAR, options.getMeteo(), addDefaults); + if (addDefaults || options.getRoadOPS() != CalculationRoadOPS.DEFAULT) { + mapToAddTo.put(Option.OPS_ROAD.toKey(), options.getRoadOPS().name()); + } + addBooleanValue(mapToAddTo, Option.FORCED_AGGREGATION, options.isForceAggregation(), addDefaults); + addBooleanValue(mapToAddTo, Option.USE_RECEPTOR_HEIGHT, options.isUseReceptorHeights(), addDefaults); + addPermitLowerBound(mapToAddTo, options); + addBooleanValue(mapToAddTo, Option.WITH_MAX_DISTANCE, options.isUseMaxDistance(), addDefaults); + addValue(mapToAddTo, Option.SUB_RECEPTORS_MODE, options.getSubReceptorsMode(), addDefaults); + addValue(mapToAddTo, Option.SUB_RECEPTOR_ZOOM_LEVEL, options.getSubReceptorZoomLevel(), addDefaults); + addBooleanValue(mapToAddTo, Option.SPLIT_SUB_RECEPTOR_WORK, options.isSplitSubReceptorWork(), addDefaults); + if (options.isSplitSubReceptorWork()) { + addValue(mapToAddTo, Option.SPLIT_SUB_RECEPTOR_WORK_DISTANCE, options.getSplitSubReceptorWorkDistance(), addDefaults); + } + opsOptionsToMap(options.getOpsOptions(), mapToAddTo, addDefaults); + } + + private static void addPermitLowerBound(final Map mapToAddTo, final OwN2000CalculationOptions options) { + if (options.getPermitLowerBoundType() != null) { + addValue(mapToAddTo, Option.PERMIT_LOWER_BOUND, options.getPermitLowerBoundType().name(), false); + addValue(mapToAddTo, Option.PERMIT_LOWER_BOUND_VALUE, options.getPermitLowerBoundValue(), false); + } + } + + private static void opsOptionsToMap(final OPSOptions options, final Map mapToAddTo, final boolean addDefaults) { + if (options != null) { + addBooleanValue(mapToAddTo, Option.OPS_RAW_INPUT, options.isRawInput(), addDefaults); + addValue(mapToAddTo, Option.OPS_YEAR, options.getYear(), addDefaults); + addValue(mapToAddTo, Option.OPS_CHEMISTRY, Optional.ofNullable(options.getChemistry()).map(OPSOptions.Chemistry::name).orElse(null), + addDefaults); + addValue(mapToAddTo, Option.OPS_COMP_CODE, options.getCompCode(), addDefaults); + addValue(mapToAddTo, Option.OPS_MOL_WEIGHT, options.getMolWeight(), addDefaults); + addValue(mapToAddTo, Option.OPS_PHASE, options.getPhase(), addDefaults); + addValue(mapToAddTo, Option.OPS_LOSS, options.getLoss(), addDefaults); + addValue(mapToAddTo, Option.OPS_DIFF_COEFF, options.getDiffCoeff(), addDefaults); + addValue(mapToAddTo, Option.OPS_WASHOUT, options.getWashout(), addDefaults); + addValue(mapToAddTo, Option.OPS_CONV_RATE, options.getConvRate(), addDefaults); + addValue(mapToAddTo, Option.OPS_ROUGHNESS, options.getRoughness(), addDefaults); + addValue(mapToAddTo, Option.OPS_ROADS, options.getRoads(), addDefaults); + } + } +} diff --git a/source/imaer-util/src/test/java/nl/overheid/aerius/util/OptionsMetadataUtilTest.java b/source/imaer-util/src/test/java/nl/overheid/aerius/util/NcaOptionsMetadataUtilTest.java similarity index 52% rename from source/imaer-util/src/test/java/nl/overheid/aerius/util/OptionsMetadataUtilTest.java rename to source/imaer-util/src/test/java/nl/overheid/aerius/util/NcaOptionsMetadataUtilTest.java index 58c20e02..79ab3630 100644 --- a/source/imaer-util/src/test/java/nl/overheid/aerius/util/OptionsMetadataUtilTest.java +++ b/source/imaer-util/src/test/java/nl/overheid/aerius/util/NcaOptionsMetadataUtilTest.java @@ -1,5 +1,5 @@ /* - * Copyright the State of the Netherlands + * Crown copyright * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -18,7 +18,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; import java.util.Map; @@ -28,169 +27,17 @@ import nl.overheid.aerius.shared.domain.Theme; import nl.overheid.aerius.shared.domain.calculation.ADMSOptions; -import nl.overheid.aerius.shared.domain.calculation.CalculationMethod; -import nl.overheid.aerius.shared.domain.calculation.CalculationRoadOPS; import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; -import nl.overheid.aerius.shared.domain.calculation.ConnectSuppliedOptions; import nl.overheid.aerius.shared.domain.calculation.MetDatasetType; import nl.overheid.aerius.shared.domain.calculation.MetSurfaceCharacteristics; import nl.overheid.aerius.shared.domain.calculation.NCACalculationOptions; -import nl.overheid.aerius.shared.domain.calculation.OPSOptions; -import nl.overheid.aerius.shared.domain.calculation.OwN2000CalculationOptions; import nl.overheid.aerius.shared.domain.calculation.RoadLocalFractionNO2Option; -import nl.overheid.aerius.shared.domain.calculation.SubReceptorsMode; -import nl.overheid.aerius.shared.domain.meteo.Meteo; /** - * Test class for {@link OptionsMetadataUtil}. + * Test class for {@link NcaOptionsMetadataUtil}. */ -class OptionsMetadataUtilTest { +class NcaOptionsMetadataUtilTest { - private static final int BASIC_OPTIONS = 10; - private static final int CONNECT_OPTIONS = 2; - private static final int OPS_OPTIONS = 12; - - @Test - void testDefaultOptionsWithoutAddingDefaults() { - final CalculationSetOptions options = new CalculationSetOptions(); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, false); - - assertTrue(result.isEmpty(), "With default options and not adding defaults to map, the map should be empty"); - } - - @Test - void testDefaultOptionsWithAddingDefaults() { - final CalculationSetOptions options = new CalculationSetOptions(); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, true); - - assertEquals(BASIC_OPTIONS, result.size(), "Number of options with default options and when adding defaults to map"); - assertEquals("", result.get("meteo_year"), "meteo_year should be empty"); - assertEquals("false", result.get("without_source_stacking"), "without_source_stacking should be set"); - assertEquals("DEFAULT", result.get("ops_road"), "ops_road should be set"); - assertEquals("false", result.get("forced_aggregation"), "forced_aggregation should be set"); - assertEquals("false", result.get("use_receptor_height"), "use_receptor_height should be set"); - assertEquals("0", result.get("monitor_srm2_year"), "monitor_srm2 should be set"); - } - - @Test - void testNonDefaultOptions() { - final CalculationSetOptions cso = new CalculationSetOptions(); - final OwN2000CalculationOptions options = cso.getOwN2000CalculationOptions(); - options.setMeteo(new Meteo(2020)); - cso.setStacking(false); - // RoadOPS only applies with custom_points. - cso.setCalculationMethod(CalculationMethod.CUSTOM_POINTS); - options.setRoadOPS(CalculationRoadOPS.OPS_ROAD); - options.setForceAggregation(true); - options.setUseMaxDistance(true); - options.setUseReceptorHeights(true); - options.setSubReceptorsMode(SubReceptorsMode.ENABLED); - options.setSubReceptorZoomLevel(1); - options.setSplitSubReceptorWork(true); - options.setSplitSubReceptorWorkDistance(1000); - cso.getRblCalculationOptions().setMonitorSrm2Year(2023); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, cso, false); - // is BASIC_OPTIONS + 1 because SplitSubReceptorWorkDistance is by default not set when SplitSubReceptorWork is false - assertEquals(BASIC_OPTIONS + 1, result.size(), "Number of options when options are not default"); - assertEquals("2020", result.get("meteo_year"), "Invalid meteo year option"); - assertEquals("true", result.get("without_source_stacking"), "Invalid without_source_stacking option"); - assertEquals("OPS_ROAD", result.get("ops_road"), "Invalid ops_road option"); - assertEquals("true", result.get("forced_aggregation"), "Invalid forced_aggregation option"); - assertEquals("true", result.get("use_receptor_height"), "Invalid use_receptor_height option"); - assertEquals("ENABLED", result.get("sub_receptors_mode"), "Invalid sub_receptors_mode option"); - assertEquals("1", result.get("sub_receptor_zoom_level"), "Invalid sub_receptor_zoom_level option"); - assertEquals("2023", result.get("monitor_srm2_year"), "Invalid monitor_srm2 option"); - assertEquals("true", result.get("split_sub_receptor_work"), "Invalid split_sub_receptor_work option"); - assertEquals("1000", result.get("split_sub_receptor_work_distance"), "Invalid split_sub_receptor_work_distance option"); - } - - @Test - void testDefaultOptionsConnect() { - final CalculationSetOptions options = new CalculationSetOptions(); - final ConnectSuppliedOptions connectOptions = new ConnectSuppliedOptions(); - options.setConnectSuppliedOptions(connectOptions); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, true); - - assertEquals(BASIC_OPTIONS + CONNECT_OPTIONS, result.size(), "Number of options when connectOptions is supplied and when adding defaults to map"); - assertEquals("", result.get("calculation_year"), "calculation_year should be empty"); - assertEquals("", result.get("receptor_set"), "receptor_set should be empty"); - } - - @Test - void testNonDefaultOptionsConnect() { - final CalculationSetOptions options = new CalculationSetOptions(); - final ConnectSuppliedOptions connectOptions = new ConnectSuppliedOptions(); - connectOptions.setCalculationYear(1999); - connectOptions.setReceptorSetName("SomeRecept or name"); - options.setConnectSuppliedOptions(connectOptions); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, false); - - assertEquals(CONNECT_OPTIONS, result.size(), "Number of options when connectOptions is supplied with non default values"); - assertEquals("1999", result.get("calculation_year"), "Invalide calculation_year option"); - assertEquals("SomeRecept or name", result.get("receptor_set"), "Invalide receptor_set option"); - } - - @Test - void testDefaultOptionsOps() { - final CalculationSetOptions options = new CalculationSetOptions(); - final OPSOptions opsOptions = new OPSOptions(); - options.getOwN2000CalculationOptions().setOpsOptions(opsOptions); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, true); - - assertEquals(BASIC_OPTIONS + OPS_OPTIONS, result.size(), "Number of options when opsOptions is supplied and when adding defaults to map"); - assertEquals("false", result.get("ops_raw_input"), "ops_raw_input should be false"); - assertEquals("", result.get("ops_year"), "ops_year should be empty"); - assertEquals("", result.get("ops_comp_code"), "ops_comp_code should be empty"); - assertEquals("", result.get("ops_mol_weight"), "ops_mol_weight should be empty"); - assertEquals("", result.get("ops_phase"), "ops_phase should be empty"); - assertEquals("", result.get("ops_loss"), "ops_loss should be empty"); - assertEquals("", result.get("ops_diff_coeff"), "ops_diff_coeff should be empty"); - assertEquals("", result.get("ops_washout"), "ops_washout should be empty"); - assertEquals("", result.get("ops_conv_rate"), "ops_conv_rate should be empty"); - assertEquals("", result.get("ops_roughness"), "ops_roughness should be empty"); - assertEquals("", result.get("ops_chemistry"), "ops_chemistry should be empty"); - } - - @Test - void testNonDefaultOptionsOps() { - final CalculationSetOptions options = new CalculationSetOptions(); - final OPSOptions opsOptions = new OPSOptions(); - opsOptions.setRawInput(true); - opsOptions.setYear(1881); - opsOptions.setCompCode(20); - opsOptions.setMolWeight(23.12); - opsOptions.setPhase(4); - opsOptions.setLoss(9); - opsOptions.setDiffCoeff("noc lue"); - opsOptions.setWashout("reject"); - opsOptions.setConvRate("8 out of 10"); - opsOptions.setRoughness(8.19); - opsOptions.setChemistry(OPSOptions.Chemistry.PROGNOSIS); - opsOptions.setRoads("3030"); - options.getOwN2000CalculationOptions().setOpsOptions(opsOptions); - - final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, false); - - assertEquals(OPS_OPTIONS, result.size(), "Number of options when opsOptions is supplied with non default values"); - assertEquals("true", result.get("ops_raw_input"), "ops_raw_input should be true"); - assertEquals("1881", result.get("ops_year"), "ops_year should be set"); - assertEquals("20", result.get("ops_comp_code"), "ops_comp_code should be set"); - assertEquals("23.12", result.get("ops_mol_weight"), "ops_mol_weight should be set"); - assertEquals("4", result.get("ops_phase"), "ops_phase should be set"); - assertEquals("9", result.get("ops_loss"), "ops_loss should be set"); - assertEquals("noc lue", result.get("ops_diff_coeff"), "ops_diff_coeff should be set"); - assertEquals("reject", result.get("ops_washout"), "ops_washout should be set"); - assertEquals("8 out of 10", result.get("ops_conv_rate"), "ops_conv_rate should be set"); - assertEquals("8.19", result.get("ops_roughness"), "ops_roughness should be set"); - assertEquals("PROGNOSIS", result.get("ops_chemistry"), "ops_chemistry should be set"); - assertEquals("3030", result.get("ops_roads"), "ops_roads should be set"); - } @Test void testNcaOptions() { diff --git a/source/imaer-util/src/test/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtilTest.java b/source/imaer-util/src/test/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtilTest.java new file mode 100644 index 00000000..1680812b --- /dev/null +++ b/source/imaer-util/src/test/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtilTest.java @@ -0,0 +1,193 @@ +/* + * Copyright the State of the Netherlands + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package nl.overheid.aerius.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import nl.overheid.aerius.shared.domain.Theme; +import nl.overheid.aerius.shared.domain.calculation.CalculationMethod; +import nl.overheid.aerius.shared.domain.calculation.CalculationRoadOPS; +import nl.overheid.aerius.shared.domain.calculation.CalculationSetOptions; +import nl.overheid.aerius.shared.domain.calculation.ConnectSuppliedOptions; +import nl.overheid.aerius.shared.domain.calculation.OPSOptions; +import nl.overheid.aerius.shared.domain.calculation.OwN2000CalculationOptions; +import nl.overheid.aerius.shared.domain.calculation.PermitLowerBoundType; +import nl.overheid.aerius.shared.domain.calculation.SubReceptorsMode; +import nl.overheid.aerius.shared.domain.meteo.Meteo; + +/** + * Test class for {@link Own2000OptionsMetadataUtil}. + */ +class Own2000OptionsMetadataUtilTest { + + private static final int BASIC_OPTIONS = 10; + private static final int CONNECT_OPTIONS = 2; + private static final int OPS_OPTIONS = 12; + + @Test + void testDefaultOptionsWithoutAddingDefaults() { + final CalculationSetOptions options = new CalculationSetOptions(); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, false); + + assertTrue(result.isEmpty(), "With default options and not adding defaults to map, the map should be empty"); + } + + @Test + void testDefaultOptionsWithAddingDefaults() { + final CalculationSetOptions options = new CalculationSetOptions(); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, true); + + assertEquals(BASIC_OPTIONS, result.size(), "Number of options with default options and when adding defaults to map"); + assertEquals("", result.get("meteo_year"), "meteo_year should be empty"); + assertEquals("false", result.get("without_source_stacking"), "without_source_stacking should be set"); + assertEquals("DEFAULT", result.get("ops_road"), "ops_road should be set"); + assertEquals("false", result.get("forced_aggregation"), "forced_aggregation should be set"); + assertEquals("false", result.get("use_receptor_height"), "use_receptor_height should be set"); + assertEquals("0", result.get("monitor_srm2_year"), "monitor_srm2 should be set"); + } + + @Test + void testNonDefaultOptions() { + final CalculationSetOptions cso = new CalculationSetOptions(); + final OwN2000CalculationOptions options = cso.getOwN2000CalculationOptions(); + options.setMeteo(new Meteo(2020)); + cso.setStacking(false); + // RoadOPS only applies with custom_points. + cso.setCalculationMethod(CalculationMethod.CUSTOM_POINTS); + options.setRoadOPS(CalculationRoadOPS.OPS_ROAD); + options.setForceAggregation(true); + options.setPermitLowerBoundType(PermitLowerBoundType.POLICY); + options.setPermitLowerBoundValue(123); + options.setUseMaxDistance(true); + options.setUseReceptorHeights(true); + options.setSubReceptorsMode(SubReceptorsMode.ENABLED); + options.setSubReceptorZoomLevel(1); + options.setSplitSubReceptorWork(true); + options.setSplitSubReceptorWorkDistance(1000); + cso.getRblCalculationOptions().setMonitorSrm2Year(2023); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, cso, false); + // is BASIC_OPTIONS + 3 because SplitSubReceptorWorkDistance is by default not set when SplitSubReceptorWork is false + // Also PermitLowerBound options are optional. + assertEquals(BASIC_OPTIONS + 3, result.size(), "Number of options when options are not default"); + assertEquals("POLICY", result.get("permit_lower_bound"), "Permit Lower Bound invalid"); + assertEquals("123.0", result.get("permit_lower_bound_value"), "Permit Lower Bound valueinvalid"); + assertEquals("2020", result.get("meteo_year"), "Invalid meteo year option"); + assertEquals("true", result.get("without_source_stacking"), "Invalid without_source_stacking option"); + assertEquals("OPS_ROAD", result.get("ops_road"), "Invalid ops_road option"); + assertEquals("true", result.get("forced_aggregation"), "Invalid forced_aggregation option"); + assertEquals("true", result.get("use_receptor_height"), "Invalid use_receptor_height option"); + assertEquals("ENABLED", result.get("sub_receptors_mode"), "Invalid sub_receptors_mode option"); + assertEquals("1", result.get("sub_receptor_zoom_level"), "Invalid sub_receptor_zoom_level option"); + assertEquals("2023", result.get("monitor_srm2_year"), "Invalid monitor_srm2 option"); + assertEquals("true", result.get("split_sub_receptor_work"), "Invalid split_sub_receptor_work option"); + assertEquals("1000", result.get("split_sub_receptor_work_distance"), "Invalid split_sub_receptor_work_distance option"); + } + + @Test + void testDefaultOptionsConnect() { + final CalculationSetOptions options = new CalculationSetOptions(); + final ConnectSuppliedOptions connectOptions = new ConnectSuppliedOptions(); + options.setConnectSuppliedOptions(connectOptions); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, true); + + assertEquals(BASIC_OPTIONS + CONNECT_OPTIONS, result.size(), "Number of options when connectOptions is supplied and when adding defaults to map"); + assertEquals("", result.get("calculation_year"), "calculation_year should be empty"); + assertEquals("", result.get("receptor_set"), "receptor_set should be empty"); + } + + @Test + void testNonDefaultOptionsConnect() { + final CalculationSetOptions options = new CalculationSetOptions(); + final ConnectSuppliedOptions connectOptions = new ConnectSuppliedOptions(); + connectOptions.setCalculationYear(1999); + connectOptions.setReceptorSetName("SomeRecept or name"); + options.setConnectSuppliedOptions(connectOptions); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, false); + + assertEquals(CONNECT_OPTIONS, result.size(), "Number of options when connectOptions is supplied with non default values"); + assertEquals("1999", result.get("calculation_year"), "Invalide calculation_year option"); + assertEquals("SomeRecept or name", result.get("receptor_set"), "Invalide receptor_set option"); + } + + @Test + void testDefaultOptionsOps() { + final CalculationSetOptions options = new CalculationSetOptions(); + final OPSOptions opsOptions = new OPSOptions(); + options.getOwN2000CalculationOptions().setOpsOptions(opsOptions); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, true); + + assertEquals(BASIC_OPTIONS + OPS_OPTIONS, result.size(), "Number of options when opsOptions is supplied and when adding defaults to map"); + assertEquals("false", result.get("ops_raw_input"), "ops_raw_input should be false"); + assertEquals("", result.get("ops_year"), "ops_year should be empty"); + assertEquals("", result.get("ops_comp_code"), "ops_comp_code should be empty"); + assertEquals("", result.get("ops_mol_weight"), "ops_mol_weight should be empty"); + assertEquals("", result.get("ops_phase"), "ops_phase should be empty"); + assertEquals("", result.get("ops_loss"), "ops_loss should be empty"); + assertEquals("", result.get("ops_diff_coeff"), "ops_diff_coeff should be empty"); + assertEquals("", result.get("ops_washout"), "ops_washout should be empty"); + assertEquals("", result.get("ops_conv_rate"), "ops_conv_rate should be empty"); + assertEquals("", result.get("ops_roughness"), "ops_roughness should be empty"); + assertEquals("", result.get("ops_chemistry"), "ops_chemistry should be empty"); + } + + + @Test + void testNonDefaultOptionsOps() { + final CalculationSetOptions options = new CalculationSetOptions(); + final OPSOptions opsOptions = new OPSOptions(); + opsOptions.setRawInput(true); + opsOptions.setYear(1881); + opsOptions.setCompCode(20); + opsOptions.setMolWeight(23.12); + opsOptions.setPhase(4); + opsOptions.setLoss(9); + opsOptions.setDiffCoeff("noc lue"); + opsOptions.setWashout("reject"); + opsOptions.setConvRate("8 out of 10"); + opsOptions.setRoughness(8.19); + opsOptions.setChemistry(OPSOptions.Chemistry.PROGNOSIS); + opsOptions.setRoads("3030"); + options.getOwN2000CalculationOptions().setOpsOptions(opsOptions); + + final Map result = OptionsMetadataUtil.optionsToMap(Theme.OWN2000, options, false); + + assertEquals(OPS_OPTIONS, result.size(), "Number of options when opsOptions is supplied with non default values"); + assertEquals("true", result.get("ops_raw_input"), "ops_raw_input should be true"); + assertEquals("1881", result.get("ops_year"), "ops_year should be set"); + assertEquals("20", result.get("ops_comp_code"), "ops_comp_code should be set"); + assertEquals("23.12", result.get("ops_mol_weight"), "ops_mol_weight should be set"); + assertEquals("4", result.get("ops_phase"), "ops_phase should be set"); + assertEquals("9", result.get("ops_loss"), "ops_loss should be set"); + assertEquals("noc lue", result.get("ops_diff_coeff"), "ops_diff_coeff should be set"); + assertEquals("reject", result.get("ops_washout"), "ops_washout should be set"); + assertEquals("8 out of 10", result.get("ops_conv_rate"), "ops_conv_rate should be set"); + assertEquals("8.19", result.get("ops_roughness"), "ops_roughness should be set"); + assertEquals("PROGNOSIS", result.get("ops_chemistry"), "ops_chemistry should be set"); + assertEquals("3030", result.get("ops_roads"), "ops_roads should be set"); + } +}