Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AER-2978 Validation on building radius #283

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.io.input.ReaderInputStream;
import org.slf4j.Logger;
Expand Down Expand Up @@ -284,7 +283,7 @@ private static void addCalculationPoints(final ImportParcel result, final boolea
private static List<CalculationPointFeature> filterCalculationPoints(final List<CalculationPointFeature> points) {
return points.stream()
.filter(p -> p.getProperties() instanceof CustomCalculationPoint)
.collect(Collectors.toList());
.toList();
}

/**
Expand Down Expand Up @@ -341,12 +340,13 @@ private static void addCimlkCorrections(final GMLReader reader, final Set<Import
}
}

private static void addBuildings(final GMLReader reader, final Set<ImportOption> importOptions, final ImportParcel result,
private void addBuildings(final GMLReader reader, final Set<ImportOption> importOptions, final ImportParcel result,
final ScenarioSituation situation) {
if (ImportOption.INCLUDE_SOURCES.in(importOptions)) {
final List<BuildingFeature> buildings = reader.getBuildings();
if (ImportOption.VALIDATE_SOURCES.in(importOptions)) {
BuildingValidator.validateBuildings(buildings, result.getExceptions(), result.getWarnings());
BuildingValidator.validateBuildings(buildings, factory.createValidationHelper().buildingLimits(),
result.getExceptions(), result.getWarnings());
}
situation.getBuildingsList().addAll(buildings);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,8 @@ static GMLHelper mockGMLHelper(final CharacteristicsType ct) throws AeriusExcept
when(gmlHelper.getReceptorGridSettings()).thenReturn(RECEPTOR_GRID_SETTINGS);
mockEmissionSourceGeometryLimits(gmlHelper);
when(gmlHelper.getCharacteristicsType()).thenAnswer((i) -> currentCharacteristicsType);
final TestValidationAndEmissionHelper valiationAndEmissionHelper = new TestValidationAndEmissionHelper();
final TestValidationAndEmissionHelper valiationAndEmissionHelper = new TestValidationAndEmissionHelper(
() -> currentCharacteristicsType);
doAnswer(invocation -> {
final List<EmissionSourceFeature> arg1 = (List<EmissionSourceFeature>) invocation.getArgument(1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ class GMLRoundtripTest {
{"industry_with_calculated_heat_content", CharacteristicsType.OPS},
{"industry_with_default_emission_temperature", CharacteristicsType.OPS},
{"industry_with_building", CharacteristicsType.OPS},
{"industry_with_circular_building", CharacteristicsType.OPS},
{"industry_with_circular_building", CharacteristicsType.ADMS},
{"two_networks", CharacteristicsType.OPS},
{"road_srm1", CharacteristicsType.OPS},
{"nsl_full_example", CharacteristicsType.OPS},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import nl.overheid.aerius.gml.base.GMLLegacyCodeConverter.Conversion;
Expand All @@ -31,8 +32,12 @@
import nl.overheid.aerius.gml.base.conversion.PlanConversion;
import nl.overheid.aerius.shared.domain.Substance;
import nl.overheid.aerius.shared.domain.ops.DiurnalVariation;
import nl.overheid.aerius.shared.domain.ops.OPSLimits;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.characteristics.CharacteristicsType;
import nl.overheid.aerius.shared.domain.v2.characteristics.HeatContentType;
import nl.overheid.aerius.shared.domain.v2.characteristics.OPSSourceCharacteristics;
import nl.overheid.aerius.shared.domain.v2.characteristics.adms.ADMSLimits;
import nl.overheid.aerius.shared.domain.v2.geojson.Geometry;
import nl.overheid.aerius.shared.domain.v2.source.road.RoadStandardEmissionFactorsKey;
import nl.overheid.aerius.shared.domain.v2.source.road.RoadStandardsInterpolationValues;
Expand Down Expand Up @@ -544,6 +549,17 @@ public static Map<String, FarmLodgingConversion> legacyFarmLodgingConversions()
return conversions;
}

private final Supplier<CharacteristicsType> characteristicsType;

public TestValidationAndEmissionHelper(final Supplier<CharacteristicsType> characteristicsType) {
this.characteristicsType = characteristicsType;
}

@Override
public BuildingLimits buildingLimits() {
return characteristicsType.get() == CharacteristicsType.ADMS ? ADMSLimits.INSTANCE : OPSLimits.INSTANCE;
}

@Override
public FarmLodgingEmissionFactorSupplier farmLodging() {
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@
</imaer:identifier>
<imaer:label>Steenfabriek</imaer:label>
<imaer:emissionSourceCharacteristics>
<imaer:EmissionSourceCharacteristics>
<imaer:ADMSSourceCharacteristics>
<imaer:building xlink:href="#Building.1"/>
<imaer:heatContent>
<imaer:SpecifiedHeatContent>
<imaer:value>0.22</imaer:value>
</imaer:SpecifiedHeatContent>
</imaer:heatContent>
<imaer:emissionHeight>35.0</imaer:emissionHeight>
<imaer:height>35.0</imaer:height>
<imaer:specificHeatCapacity>342.12</imaer:specificHeatCapacity>
<imaer:sourceType>POINT</imaer:sourceType>
<imaer:diameter>4.3</imaer:diameter>
<imaer:buoyancyType>DENSITY</imaer:buoyancyType>
<imaer:density>58.23</imaer:density>
<imaer:effluxType>VELOCITY</imaer:effluxType>
<imaer:verticalVelocity>49.2</imaer:verticalVelocity>
<imaer:diurnalVariation>
<imaer:StandardDiurnalVariation>
<imaer:standardType>INDUSTRIAL_ACTIVITY</imaer:standardType>
<imaer:standardType>SOME_TYPE</imaer:standardType>
</imaer:StandardDiurnalVariation>
</imaer:diurnalVariation>
</imaer:EmissionSourceCharacteristics>
</imaer:ADMSSourceCharacteristics>
</imaer:emissionSourceCharacteristics>
<imaer:geometry>
<imaer:EmissionSourceGeometry>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@
</imaer:identifier>
<imaer:label>Steenfabriek</imaer:label>
<imaer:emissionSourceCharacteristics>
<imaer:EmissionSourceCharacteristics>
<imaer:ADMSSourceCharacteristics>
<imaer:building xlink:href="#Building.1"/>
<imaer:heatContent>
<imaer:SpecifiedHeatContent>
<imaer:value>0.22</imaer:value>
</imaer:SpecifiedHeatContent>
</imaer:heatContent>
<imaer:emissionHeight>35.0</imaer:emissionHeight>
<imaer:height>35.0</imaer:height>
<imaer:specificHeatCapacity>342.12</imaer:specificHeatCapacity>
<imaer:sourceType>POINT</imaer:sourceType>
<imaer:diameter>4.3</imaer:diameter>
<imaer:buoyancyType>DENSITY</imaer:buoyancyType>
<imaer:density>58.23</imaer:density>
<imaer:effluxType>VELOCITY</imaer:effluxType>
<imaer:verticalVelocity>49.2</imaer:verticalVelocity>
<imaer:diurnalVariation>
<imaer:StandardDiurnalVariation>
<imaer:standardType>INDUSTRIAL_ACTIVITY</imaer:standardType>
<imaer:standardType>SOME_TYPE</imaer:standardType>
</imaer:StandardDiurnalVariation>
</imaer:diurnalVariation>
</imaer:EmissionSourceCharacteristics>
</imaer:ADMSSourceCharacteristics>
</imaer:emissionSourceCharacteristics>
<imaer:geometry>
<imaer:EmissionSourceGeometry>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,22 @@
</imaer:identifier>
<imaer:label>Steenfabriek</imaer:label>
<imaer:emissionSourceCharacteristics>
<imaer:EmissionSourceCharacteristics>
<imaer:ADMSSourceCharacteristics>
<imaer:building xlink:href="#Building.1"/>
<imaer:heatContent>
<imaer:SpecifiedHeatContent>
<imaer:value>0.22</imaer:value>
</imaer:SpecifiedHeatContent>
</imaer:heatContent>
<imaer:emissionHeight>35.0</imaer:emissionHeight>
<imaer:timeVaryingProfile>
<imaer:height>35.0</imaer:height>
<imaer:specificHeatCapacity>342.12</imaer:specificHeatCapacity>
<imaer:sourceType>POINT</imaer:sourceType>
<imaer:diameter>4.3</imaer:diameter>
<imaer:buoyancyType>DENSITY</imaer:buoyancyType>
<imaer:density>58.23</imaer:density>
<imaer:effluxType>VELOCITY</imaer:effluxType>
<imaer:verticalVelocity>49.2</imaer:verticalVelocity>
<imaer:hourlyVariation>
<imaer:StandardTimeVaryingProfile>
<imaer:standardType>INDUSTRIAL_ACTIVITY</imaer:standardType>
<imaer:standardType>SOME_TYPE</imaer:standardType>
</imaer:StandardTimeVaryingProfile>
</imaer:timeVaryingProfile>
</imaer:EmissionSourceCharacteristics>
</imaer:hourlyVariation>
</imaer:ADMSSourceCharacteristics>
</imaer:emissionSourceCharacteristics>
<imaer:geometry>
<imaer:EmissionSourceGeometry>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -484,4 +484,15 @@ public double buildingLengthMinimum() {
public double buildingLengthMaximum() {
return SCOPE_BUILDING_LENGTH_MAXIMUM;
}

@Override
public double buildingDiameterMinimum() {
return 0;
}

@Override
public double buildingDiameterMaximum() {
return Double.MAX_VALUE;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,8 @@ default boolean isCircularBuildingSupported() {
double buildingLengthMinimum();

double buildingLengthMaximum();

double buildingDiameterMinimum();

double buildingDiameterMaximum();
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public final class ADMSLimits implements BuildingLimits {
public static final double BUILDING_LENGTH_MINIMUM = 0.001;
public static final double BUILDING_LENGTH_MAXIMUM = 1_000;

public static final double BUILDING_DIAMETER_MINIMUM = 0.001;
public static final double BUILDING_DIAMETER_MAXIMUM = 1_000;

public static final int ROAD_GRADIENT_MIN = -50;
public static final int ROAD_GRADIENT_MAX = 50;
public static final int ROAD_ELEVATION_MIN = 0;
Expand Down Expand Up @@ -180,4 +183,14 @@ public double buildingLengthMinimum() {
public double buildingLengthMaximum() {
return BUILDING_LENGTH_MAXIMUM;
}

@Override
public double buildingDiameterMinimum() {
return BUILDING_DIAMETER_MINIMUM;
}

@Override
public double buildingDiameterMaximum() {
return BUILDING_DIAMETER_MAXIMUM;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,9 @@ public enum ImaerExceptionReason implements Reason {
BUILDING_HEIGHT_ZERO(5241),

/**
* Buildingheight is < 0.
* Buildingheight is too low.
*
* @param 0 Label of the building that has height < 0.
* @param 0 Label of the building that has too low a height (model-dependent).
*/
BUILDING_HEIGHT_TOO_LOW(5242),

Expand All @@ -641,6 +641,13 @@ public enum ImaerExceptionReason implements Reason {
*/
CIRCULAR_BUILDING_INCORRECT_DIAMETER(5243),

/**
* Buildingheight is too high.
*
* @param 0 Label of the building that has too high a height (model-dependent).
*/
BUILDING_HEIGHT_TOO_HIGH(5244),

/**
* Value is <= 0.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@

import java.util.List;

import nl.overheid.aerius.shared.domain.ops.OPSLimits;
import nl.overheid.aerius.shared.domain.v2.building.Building;
import nl.overheid.aerius.shared.domain.v2.building.BuildingFeature;
import nl.overheid.aerius.shared.domain.v2.building.BuildingLimits;
import nl.overheid.aerius.shared.domain.v2.geojson.Point;
import nl.overheid.aerius.shared.domain.v2.geojson.Polygon;
import nl.overheid.aerius.shared.exception.AeriusException;
Expand All @@ -31,42 +33,58 @@ public final class BuildingValidator {
// Util class
}

/**
* @Deprecated Use the variant with a BuildingLimits parameter instead.
* This version uses OPS buildings limits as default.
*/
@Deprecated
public static void validateBuildings(final List<BuildingFeature> buildings, final List<AeriusException> errors,
final List<AeriusException> warnings) {
checkBuildingGeometry(buildings, errors);
checkBuildingHeight(buildings, errors, warnings);
checkBuildingDiameter(buildings, errors);
validateBuildings(buildings, OPSLimits.INSTANCE, errors, warnings);
}

private static void checkBuildingGeometry(final List<BuildingFeature> buildings, final List<AeriusException> errors) {
public static void validateBuildings(final List<BuildingFeature> buildings, final BuildingLimits buildingLimits,
final List<AeriusException> errors, final List<AeriusException> warnings) {
for (final BuildingFeature feature : buildings) {
// Only polygon and point geometries are supported.
if (!(feature.getGeometry() instanceof Polygon || feature.getGeometry() instanceof Point)) {
errors.add(new AeriusException(ImaerExceptionReason.GML_GEOMETRY_NOT_PERMITTED, feature.getProperties().getLabel()));
}
checkBuildingGeometry(feature, buildingLimits, errors);
checkBuildingHeight(feature, buildingLimits, errors, warnings);
checkBuildingDiameter(feature, buildingLimits, errors);
}
}

private static void checkBuildingHeight(final List<BuildingFeature> buildings, final List<AeriusException> errors,
final List<AeriusException> warnings) {
for (final BuildingFeature feature : buildings) {
final Building building = feature.getProperties();
if (building.getHeight() < 0) {
errors.add(new AeriusException(ImaerExceptionReason.BUILDING_HEIGHT_TOO_LOW, building.getLabel()));
} else if (building.getHeight() == 0) {
warnings.add(new AeriusException(ImaerExceptionReason.BUILDING_HEIGHT_ZERO, building.getLabel()));
}
private static void checkBuildingGeometry(final BuildingFeature feature, final BuildingLimits buildingLimits,
final List<AeriusException> errors) {
// Only polygon and point geometries are supported.
if (!(feature.getGeometry() instanceof Polygon
|| (buildingLimits.isCircularBuildingSupported() && feature.getGeometry() instanceof Point))) {
errors.add(new AeriusException(ImaerExceptionReason.GML_GEOMETRY_NOT_PERMITTED, feature.getProperties().getLabel()));
}
}

private static void checkBuildingDiameter(final List<BuildingFeature> buildings, final List<AeriusException> errors) {
for (final BuildingFeature feature : buildings) {
final Building building = feature.getProperties();
// When the geometry is a point, that indicates that a circular building is defined.
// A circular building consists of a point and a positive diameter.
if (feature.getGeometry() instanceof Point && building.getDiameter() <= 0) {
errors.add(new AeriusException(ImaerExceptionReason.CIRCULAR_BUILDING_INCORRECT_DIAMETER, building.getLabel()));
}
private static void checkBuildingHeight(final BuildingFeature feature, final BuildingLimits buildingLimits,
final List<AeriusException> errors, final List<AeriusException> warnings) {
final Building building = feature.getProperties();
if (building.getHeight() < buildingLimits.buildingHeightMinimum()) {
errors.add(new AeriusException(ImaerExceptionReason.BUILDING_HEIGHT_TOO_LOW, building.getLabel()));
} else if (building.getHeight() == 0) {
BertScholten marked this conversation as resolved.
Show resolved Hide resolved
// This warning only comes into play when the normal building height minimum is 0 or less.
// Some models have a higher minimum height, and in that case we don't want this warning to pop up.
// Other models do allow it, but modeling it that way would be a bit weird, hence the warning.
warnings.add(new AeriusException(ImaerExceptionReason.BUILDING_HEIGHT_ZERO, building.getLabel()));
} else if (building.getHeight() > buildingLimits.buildingHeightMaximum()) {
errors.add(new AeriusException(ImaerExceptionReason.BUILDING_HEIGHT_TOO_HIGH, building.getLabel()));
}
}

private static void checkBuildingDiameter(final BuildingFeature feature, final BuildingLimits buildingLimits,
final List<AeriusException> errors) {
final Building building = feature.getProperties();
// When the geometry is a point, that indicates that a circular building is defined.
// A circular building consists of a point and a positive diameter.
final double diameter = building.getDiameter();
if (feature.getGeometry() instanceof Point
BertScholten marked this conversation as resolved.
Show resolved Hide resolved
&& (diameter <= buildingLimits.buildingDiameterMinimum() || diameter > buildingLimits.buildingDiameterMaximum())) {
errors.add(new AeriusException(ImaerExceptionReason.CIRCULAR_BUILDING_INCORRECT_DIAMETER, building.getLabel()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private ScenarioSituationValidator() {
*/
public static void validateSituation(final ScenarioSituation situation, final ValidationHelper validationHelper) throws AeriusException {
validateSources(situation.getEmissionSourcesList(), validationHelper);
validateBuildings(situation.getBuildingsList());
validateBuildings(situation.getBuildingsList(), validationHelper);
validateCimlkMeasures(situation.getCimlkMeasuresList());
validateDefinitions(situation.getDefinitions());
}
Expand All @@ -57,9 +57,9 @@ public static void validateSources(final List<EmissionSourceFeature> sources, fi
}
}

public static void validateBuildings(final List<BuildingFeature> buildings) throws AeriusException {
public static void validateBuildings(final List<BuildingFeature> buildings, final ValidationHelper validationHelper) throws AeriusException {
final List<AeriusException> errors = new ArrayList<>();
BuildingValidator.validateBuildings(buildings, errors, new ArrayList<>());
BuildingValidator.validateBuildings(buildings, validationHelper.buildingLimits(), errors, new ArrayList<>());
if (!errors.isEmpty()) {
throw errors.get(0);
}
Expand Down
Loading
Loading