diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a5250fcb..37ef1d290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Enhance `WeatherSource` with method to retrieve all time keys after a given key [#572](https://github.com/ie3-institute/PowerSystemDataModel/issues/572) - Adding timeseries for voltage values [#1128](https://github.com/ie3-institute/PowerSystemDataModel/issues/1128) - Added Staudt to list of reviewers [#1190](https://github.com/ie3-institute/PowerSystemDataModel/issues/1190) +- Extend ValidationUtils for validating ThermalGrids [#1216](https://github.com/ie3-institute/PowerSystemDataModel/issues/1216) ### Fixed - Removing opened `SwitchInput` during connectivity check [#1221](https://github.com/ie3-institute/PowerSystemDataModel/issues/1221) diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalValidationUtils.java similarity index 86% rename from src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java rename to src/main/java/edu/ie3/datamodel/utils/validation/ThermalValidationUtils.java index 36c89c8a5..15cc20d2f 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalValidationUtils.java @@ -7,6 +7,7 @@ import edu.ie3.datamodel.exceptions.InvalidEntityException; import edu.ie3.datamodel.exceptions.ValidationException; +import edu.ie3.datamodel.models.input.container.ThermalGrid; import edu.ie3.datamodel.models.input.thermal.*; import edu.ie3.datamodel.utils.Try; import edu.ie3.datamodel.utils.Try.Failure; @@ -14,10 +15,10 @@ import java.util.List; import javax.measure.Quantity; -public class ThermalUnitValidationUtils extends ValidationUtils { +public class ThermalValidationUtils extends ValidationUtils { /** Private Constructor as this class is not meant to be instantiated */ - private ThermalUnitValidationUtils() { + private ThermalValidationUtils() { throw new IllegalStateException("Don't try and instantiate a Utility class."); } @@ -57,6 +58,42 @@ private ThermalUnitValidationUtils() { return exceptions; } + /** + * Validates a thermal grid if: + * + * + * + * A "distribution" method, that forwards the check request to specific implementations to fulfill + * the checking task, based on the class of the given object. + * + * @param thermalGrid ThermalGrid to validate + * @return a list of try objects either containing an {@link ValidationException} or an empty + * Success + */ + protected static List> check(ThermalGrid thermalGrid) { + Try isNull = checkNonNull(thermalGrid, "a thermal grid"); + + if (isNull.isFailure()) { + return List.of(isNull); + } + + List> exceptions = new ArrayList<>(); + + // Validate houses + for (ThermalHouseInput house : thermalGrid.houses()) { + exceptions.addAll(checkThermalHouse(house)); + } + + // Validate storages + for (ThermalStorageInput storage : thermalGrid.storages()) { + exceptions.addAll(check(storage)); + } + + return exceptions; + } + /** * Validates a thermalSinkInput if: * diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/ValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/ValidationUtils.java index cc04e8489..80006953b 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/ValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/ValidationUtils.java @@ -16,6 +16,7 @@ import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput; import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput; import edu.ie3.datamodel.models.input.container.GridContainer; +import edu.ie3.datamodel.models.input.container.ThermalGrid; import edu.ie3.datamodel.models.input.graphics.GraphicInput; import edu.ie3.datamodel.models.input.system.SystemParticipantInput; import edu.ie3.datamodel.models.input.system.type.SystemParticipantTypeInput; @@ -68,6 +69,8 @@ public static void check(Object obj) throws ValidationException { exceptions.addAll(GraphicValidationUtils.check((GraphicInput) obj)); } else if (AssetTypeInput.class.isAssignableFrom(obj.getClass())) { exceptions.addAll(checkAssetType((AssetTypeInput) obj)); + } else if (ThermalGrid.class.isAssignableFrom(obj.getClass())) { + exceptions.addAll(ThermalValidationUtils.check((ThermalGrid) obj)); } else { logNotImplemented(obj); } @@ -151,7 +154,9 @@ else if (SystemParticipantInput.class.isAssignableFrom(assetInput.getClass())) exceptions.addAll( SystemParticipantValidationUtils.check((SystemParticipantInput) assetInput)); else if (ThermalUnitInput.class.isAssignableFrom(assetInput.getClass())) - exceptions.addAll(ThermalUnitValidationUtils.check((ThermalUnitInput) assetInput)); + exceptions.addAll(ThermalValidationUtils.check((ThermalUnitInput) assetInput)); + else if (ThermalGrid.class.isAssignableFrom(assetInput.getClass())) + exceptions.addAll(ThermalValidationUtils.check((ThermalUnitInput) assetInput)); else { logNotImplemented(assetInput); } diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy similarity index 79% rename from src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtilsTest.groovy rename to src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy index 61c9bf571..aee73fe73 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy @@ -10,6 +10,7 @@ import edu.ie3.datamodel.exceptions.ValidationException import edu.ie3.datamodel.models.OperationTime import edu.ie3.datamodel.models.StandardUnits import edu.ie3.datamodel.models.input.OperatorInput +import edu.ie3.datamodel.models.input.container.ThermalGrid import edu.ie3.datamodel.models.input.thermal.CylindricalStorageInput import edu.ie3.datamodel.models.input.thermal.ThermalHouseInput import edu.ie3.datamodel.utils.Try @@ -26,7 +27,7 @@ import tech.units.indriya.quantity.Quantities import javax.measure.quantity.Temperature import javax.measure.quantity.Volume -class ThermalUnitValidationUtilsTest extends Specification { +class ThermalValidationUtilsTest extends Specification { // General data private static final UUID thermalUnitUuid = UUID.fromString("717af017-cc69-406f-b452-e022d7fb516a") @@ -44,7 +45,7 @@ class ThermalUnitValidationUtilsTest extends Specification { private static final ComparableQuantity UPPER_TEMPERATURE_LIMIT = Quantities.getQuantity(25, StandardUnits.TEMPERATURE) private static final ComparableQuantity LOWER_TEMPERATURE_LIMIT = Quantities.getQuantity(15, StandardUnits.TEMPERATURE) - // Specific data for thermal cylindric storage input + // Specific data for thermal cylindrical storage input private static final ComparableQuantity storageVolumeLvl = Quantities.getQuantity(100, StandardUnits.VOLUME) private static final ComparableQuantity inletTemp = Quantities.getQuantity(100, StandardUnits.TEMPERATURE) private static final ComparableQuantity returnTemp = Quantities.getQuantity(80, StandardUnits.TEMPERATURE) @@ -65,7 +66,7 @@ class ThermalUnitValidationUtilsTest extends Specification { def "ThermalUnitValidationUtils.checkThermalHouse() recognizes all potential errors for a thermal house"() { when: - List> exceptions = ThermalUnitValidationUtils.check(invalidThermalHouse).stream().filter { it -> it.failure }.toList() + List> exceptions = ThermalValidationUtils.check(invalidThermalHouse).stream().filter { it -> it.failure }.toList() then: exceptions.size() == expectedSize @@ -98,7 +99,7 @@ class ThermalUnitValidationUtilsTest extends Specification { def "ThermalUnitValidationUtils.checkCylindricalStorage() recognizes all potential errors for a thermal cylindrical storage"() { when: - List> exceptions = ThermalUnitValidationUtils.check(invalidCylindricalStorage).stream().filter { it -> it.failure }.toList() + List> exceptions = ThermalValidationUtils.check(invalidCylindricalStorage).stream().filter { it -> it.failure }.toList() then: exceptions.size() == expectedSize @@ -107,9 +108,34 @@ class ThermalUnitValidationUtilsTest extends Specification { ex.message == expectedException.message where: - invalidCylindricalStorage || expectedSize || expectedException - new CylindricalStorageInput(thermalUnitUuid, id, operator, operationTime, SystemParticipantTestData.thermalBus, storageVolumeLvl, Quantities.getQuantity(100, StandardUnits.TEMPERATURE), Quantities.getQuantity(200, StandardUnits.TEMPERATURE), c) || 1 || new InvalidEntityException("Inlet temperature of the cylindrical storage cannot be lower or equal than outlet temperature", invalidCylindricalStorage) - new CylindricalStorageInput(thermalUnitUuid, id, operator, operationTime, SystemParticipantTestData.thermalBus, storageVolumeLvl, Quantities.getQuantity(100, StandardUnits.TEMPERATURE), Quantities.getQuantity(100, StandardUnits.TEMPERATURE), c) || 1 || new InvalidEntityException("Inlet temperature of the cylindrical storage cannot be lower or equal than outlet temperature", invalidCylindricalStorage) + invalidCylindricalStorage || expectedSize || expectedException + new CylindricalStorageInput(thermalUnitUuid, id, operator, operationTime, SystemParticipantTestData.thermalBus, storageVolumeLvl, Quantities.getQuantity(100, StandardUnits.TEMPERATURE), Quantities.getQuantity(200, StandardUnits.TEMPERATURE), c) || 1 || new InvalidEntityException("Inlet temperature of the cylindrical storage cannot be lower or equal than outlet temperature", invalidCylindricalStorage) + new CylindricalStorageInput(thermalUnitUuid, id, operator, operationTime, SystemParticipantTestData.thermalBus, storageVolumeLvl, Quantities.getQuantity(100, StandardUnits.TEMPERATURE), Quantities.getQuantity(100, StandardUnits.TEMPERATURE), c) || 1 || new InvalidEntityException("Inlet temperature of the cylindrical storage cannot be lower or equal than outlet temperature", invalidCylindricalStorage) new CylindricalStorageInput(thermalUnitUuid, id, operator, operationTime, SystemParticipantTestData.thermalBus, Quantities.getQuantity(-100, StandardUnits.VOLUME), inletTemp, returnTemp, Quantities.getQuantity(-1.05, StandardUnits.SPECIFIC_HEAT_CAPACITY)) || 1 || new InvalidEntityException("The following quantities have to be positive: -100 ㎥, -1.05 kWh/K*m³", invalidCylindricalStorage) } + + def "ThermalUnitValidationUtils.check() works for complete ThermalGrid as well"() { + when: + def thermalBus = ThermalUnitInputTestData.thermalBus + def cylindricalStorageInput = [ + ThermalUnitInputTestData.cylindricStorageInput + ] + + + ThermalGrid thermalGrid = new ThermalGrid(thermalBus, [thermalHouse], cylindricalStorageInput) + + + List> exceptions = ThermalValidationUtils.check(thermalGrid).stream().filter { it -> it.failure }.toList() + + then: + exceptions.size() == expectedSize + Exception ex = exceptions.get(0).exception.get() + ex.class == expectedException.class + ex.message == expectedException.message + + + where: + thermalHouse || expectedSize || expectedException + new ThermalHouseInput(thermalUnitUuid, id, operator, operationTime, SystemParticipantTestData.thermalBus, thermalConductance, ethCapa, Quantities.getQuantity(0, StandardUnits.TEMPERATURE), UPPER_TEMPERATURE_LIMIT, LOWER_TEMPERATURE_LIMIT) || 1 || new InvalidEntityException("Target temperature must be higher than lower temperature limit and lower than upper temperature limit", thermalHouse) + } }