From 3f453f0414db4c6ad337b1d4afde13044d35ed94 Mon Sep 17 00:00:00 2001 From: Hilbrand Bouwkamp Date: Thu, 13 Nov 2025 12:03:06 +0100 Subject: [PATCH 1/2] AER-4109 Added lower bound to calculation options. The lower bound value is only put in the map (meaning ends up in the GML) but is not read as it will always use the value related with the type. - Refactored NCA/OWN2000 theme specific Metadata reading/writing to their own classes to keep things cleaner. - Replaced some of the old WNB wording. --- .../GMLCalculationSetOptionsReaderTest.java | 23 +- .../calculation/CalculationRoadOPS.java | 2 +- .../OwN2000CalculationOptions.java | 40 +++- .../calculation/PermitLowerBoundType.java | 45 ++++ .../aerius/util/NcaOptionsMetadataUtil.java | 212 +++++++++++++++++ .../aerius/util/OptionsMetadataUtil.java | 214 ++---------------- .../util/Own2000OptionsMetadataUtil.java | 110 +++++++++ ...t.java => NcaOptionsMetadataUtilTest.java} | 159 +------------ .../util/Own2000OptionsMetadataUtilTest.java | 193 ++++++++++++++++ 9 files changed, 639 insertions(+), 359 deletions(-) create mode 100644 source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/PermitLowerBoundType.java create mode 100644 source/imaer-util/src/main/java/nl/overheid/aerius/util/NcaOptionsMetadataUtil.java create mode 100644 source/imaer-util/src/main/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtil.java rename source/imaer-util/src/test/java/nl/overheid/aerius/util/{OptionsMetadataUtilTest.java => NcaOptionsMetadataUtilTest.java} (52%) create mode 100644 source/imaer-util/src/test/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtilTest.java 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..7ba3c86a 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..a4d820e7 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 used for permit calculations. + */ + public PermitLowerBoundType getPermitLowerBoundType() { + return permitLowerBoundType; + } + + /** + * Set the lower bound 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..cd623345 --- /dev/null +++ b/source/imaer-util/src/main/java/nl/overheid/aerius/util/NcaOptionsMetadataUtil.java @@ -0,0 +1,212 @@ +/* + * 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 static nl.overheid.aerius.util.OptionsMetadataUtil.LIST_OPTION_SEPARATOR; +import static nl.overheid.aerius.util.OptionsMetadataUtil.OPTION_KEY_SPLIT; +import static nl.overheid.aerius.util.OptionsMetadataUtil.addBooleanValue; +import static nl.overheid.aerius.util.OptionsMetadataUtil.addIntValue; +import static nl.overheid.aerius.util.OptionsMetadataUtil.addValue; +import static nl.overheid.aerius.util.OptionsMetadataUtil.getOrDefault; +import static nl.overheid.aerius.util.OptionsMetadataUtil.isOrDefault; +import static nl.overheid.aerius.util.OptionsMetadataUtil.parseListOption; + +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 { + + private NcaOptionsMetadataUtil() { + // Util class + } + + /** + * Reads the NCA specific {@link CalculationSetOptions} from a map. + * + * @param map The map t 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..dcdf9d92 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,15 +16,6 @@ */ 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; @@ -36,25 +27,17 @@ 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 = "-"; + static final String LIST_OPTION_SEPARATOR = ","; + static final String OPTION_KEY_SPLIT = "-"; public enum Option { // @formatter:off @@ -64,6 +47,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 +165,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,33 +178,15 @@ 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) { @@ -229,93 +196,16 @@ private static void addConnectSuppliedOptions(final ConnectSuppliedOptions conne } } - 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) { + 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) { + 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) { + 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); @@ -325,79 +215,11 @@ private static void parseListOption(final Option key, final Map } } - 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) { + 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) { + 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()); @@ -406,18 +228,18 @@ private static void addValue(final Map mapToAddTo, final String } } - private static void addIntValue(final Map mapToAddTo, final Option key, final int value, final boolean addDefaults) { + 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, + 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) { + 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..b8b69136 --- /dev/null +++ b/source/imaer-util/src/main/java/nl/overheid/aerius/util/Own2000OptionsMetadataUtil.java @@ -0,0 +1,110 @@ +/* + * 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 nl.overheid.aerius.util.OptionsMetadataUtil.addBooleanValue; +import static nl.overheid.aerius.util.OptionsMetadataUtil.addIntValue; +import static nl.overheid.aerius.util.OptionsMetadataUtil.addValue; + +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 { + + 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"); + } +} From 18ef4f30d0da68f36abf1d2f100774a1e91dd274 Mon Sep 17 00:00:00 2001 From: Hilbrand Bouwkamp Date: Thu, 13 Nov 2025 13:34:47 +0100 Subject: [PATCH 2/2] Review comments --- .../GMLCalculationSetOptionsReaderTest.java | 2 +- .../OwN2000CalculationOptions.java | 4 +- .../aerius/util/NcaOptionsMetadataUtil.java | 12 +-- .../aerius/util/OptionsMetadataUtil.java | 62 +------------ .../aerius/util/OptionsMetadataUtilBase.java | 87 +++++++++++++++++++ .../util/Own2000OptionsMetadataUtil.java | 6 +- 6 files changed, 94 insertions(+), 79 deletions(-) create mode 100644 source/imaer-util/src/main/java/nl/overheid/aerius/util/OptionsMetadataUtilBase.java 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 7ba3c86a..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 @@ -179,7 +179,7 @@ void testReadCalculationSetOptionsDuplicateOptions() { } @Test - void testOWN2000ReadCalculationSetOptions() { + void testOwN2000ReadCalculationSetOptions() { 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/OwN2000CalculationOptions.java b/source/imaer-shared/src/main/java/nl/overheid/aerius/shared/domain/calculation/OwN2000CalculationOptions.java index a4d820e7..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 @@ -44,14 +44,14 @@ public class OwN2000CalculationOptions implements Serializable { private int splitSubReceptorWorkDistance; /** - * @return Returns the lower bound used for permit calculations. + * @return Returns the lower bound type used for permit calculations. */ public PermitLowerBoundType getPermitLowerBoundType() { return permitLowerBoundType; } /** - * Set the lower bound used for permit calculations. + * Set the lower bound type used for permit calculations. */ public void setPermitLowerBoundType(final PermitLowerBoundType permitLowerBoundType) { this.permitLowerBoundType = permitLowerBoundType; 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 index cd623345..4b8ff759 100644 --- 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 @@ -24,14 +24,6 @@ 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 static nl.overheid.aerius.util.OptionsMetadataUtil.LIST_OPTION_SEPARATOR; -import static nl.overheid.aerius.util.OptionsMetadataUtil.OPTION_KEY_SPLIT; -import static nl.overheid.aerius.util.OptionsMetadataUtil.addBooleanValue; -import static nl.overheid.aerius.util.OptionsMetadataUtil.addIntValue; -import static nl.overheid.aerius.util.OptionsMetadataUtil.addValue; -import static nl.overheid.aerius.util.OptionsMetadataUtil.getOrDefault; -import static nl.overheid.aerius.util.OptionsMetadataUtil.isOrDefault; -import static nl.overheid.aerius.util.OptionsMetadataUtil.parseListOption; import java.util.List; import java.util.Map; @@ -48,7 +40,7 @@ /** * Util class to read/write NCA theme meta data options from/to a map into/from the CalculationSetOptions object. */ -final class NcaOptionsMetadataUtil { +final class NcaOptionsMetadataUtil extends OptionsMetadataUtilBase { private NcaOptionsMetadataUtil() { // Util class @@ -57,7 +49,7 @@ private NcaOptionsMetadataUtil() { /** * Reads the NCA specific {@link CalculationSetOptions} from a map. * - * @param map The map t read the options from + * @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 */ 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 dcdf9d92..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,15 +16,11 @@ */ package nl.overheid.aerius.util; -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.CalculationJobType; @@ -34,10 +30,7 @@ /** * Utility class to convert calculation options to metadata. */ -public final class OptionsMetadataUtil { - - static final String LIST_OPTION_SEPARATOR = ","; - static final String OPTION_KEY_SPLIT = "-"; +public final class OptionsMetadataUtil extends OptionsMetadataUtilBase { public enum Option { // @formatter:off @@ -186,8 +179,6 @@ public static Map optionsToMap(final Theme theme, final Calculat return mapToAddTo; } - - private static void addConnectSuppliedOptions(final ConnectSuppliedOptions connectSuppliedOptions, final Map mapToAddTo, final boolean addDefaults) { if (connectSuppliedOptions != null) { @@ -195,55 +186,4 @@ private static void addConnectSuppliedOptions(final ConnectSuppliedOptions conne addValue(mapToAddTo, Option.RECEPTOR_SET, connectSuppliedOptions.getReceptorSetName(), addDefaults); } } - - - 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/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 index b8b69136..e9957bf6 100644 --- 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 @@ -16,10 +16,6 @@ */ package nl.overheid.aerius.util; -import static nl.overheid.aerius.util.OptionsMetadataUtil.addBooleanValue; -import static nl.overheid.aerius.util.OptionsMetadataUtil.addIntValue; -import static nl.overheid.aerius.util.OptionsMetadataUtil.addValue; - import java.util.Map; import java.util.Optional; @@ -33,7 +29,7 @@ /** * Util class to read/write Own2000 theme meta data options from/to a map into/from the CalculationSetOptions object. */ -final class Own2000OptionsMetadataUtil { +final class Own2000OptionsMetadataUtil extends OptionsMetadataUtilBase { private Own2000OptionsMetadataUtil() { // Util class