From 957bf4990e6efe0ebc71bb480c3fcabbc50ce2ee Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 22 Jan 2025 17:24:47 +0100 Subject: [PATCH 1/5] Extend ValidationUtils for validating ThermalGrids --- CHANGELOG.md | 1 + .../ThermalUnitValidationUtils.java | 43 +++++++++++++++++++ .../utils/validation/ValidationUtils.java | 5 +++ .../ThermalUnitValidationUtilsTest.groovy | 28 ++++++++++++ 4 files changed, 77 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bd30cd83..2ea285c5c 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 diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java index 36c89c8a5..97fdbfbd5 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java @@ -7,11 +7,14 @@ 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; import java.util.ArrayList; import java.util.List; +import java.util.Set; +import java.util.stream.Stream; import javax.measure.Quantity; public class ThermalUnitValidationUtils extends ValidationUtils { @@ -57,6 +60,46 @@ 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 : + Stream.concat( + thermalGrid.heatStorages().stream(), + thermalGrid.domesticHotWaterStorages().stream()) + .toList()) { + 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..2859a8b8f 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(ThermalUnitValidationUtils.check((ThermalGrid) obj)); } else { logNotImplemented(obj); } @@ -152,6 +155,8 @@ else if (SystemParticipantInput.class.isAssignableFrom(assetInput.getClass())) SystemParticipantValidationUtils.check((SystemParticipantInput) assetInput)); else if (ThermalUnitInput.class.isAssignableFrom(assetInput.getClass())) exceptions.addAll(ThermalUnitValidationUtils.check((ThermalUnitInput) assetInput)); + else if (ThermalGrid.class.isAssignableFrom(assetInput.getClass())) + exceptions.addAll(ThermalUnitValidationUtils.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/ThermalUnitValidationUtilsTest.groovy index 61c9bf571..382a26821 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtilsTest.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 @@ -112,4 +113,31 @@ class ThermalUnitValidationUtilsTest extends Specification { 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 domesticHotWaterStorageInput = [ + ThermalUnitInputTestData.domesticHotWaterStorageInput + ] + def cylindricalStorageInput = [ + ThermalUnitInputTestData.cylindricalStorageInput + ] + + ThermalGrid thermalGrid = new ThermalGrid(thermalBus, [thermalHouse], cylindricalStorageInput, domesticHotWaterStorageInput) + + + List> exceptions = ThermalUnitValidationUtils.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, HOUSING_TYPE, NUMBER_INHABITANTS) || 1 || new InvalidEntityException("Target temperature must be higher than lower temperature limit and lower than upper temperature limit", thermalHouse) + } } From d761a9267042f51579f513f53a993a919e096f7d Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 23 Jan 2025 17:55:46 +0100 Subject: [PATCH 2/5] fix thermalStorages inside ThermalUnitValidationUtils --- .../utils/validation/ThermalUnitValidationUtils.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java index 97fdbfbd5..73d5a5a4a 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java @@ -89,11 +89,7 @@ private ThermalUnitValidationUtils() { } // Validate storages - for (ThermalStorageInput storage : - Stream.concat( - thermalGrid.heatStorages().stream(), - thermalGrid.domesticHotWaterStorages().stream()) - .toList()) { + for (ThermalStorageInput storage : thermalGrid.storages()) { exceptions.addAll(check(storage)); } From dd88d2fb64bb504bcca9badb5c9e90d00930c4cc Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 23 Jan 2025 17:56:41 +0100 Subject: [PATCH 3/5] rename ThermalUnitValidationUtils to ThermalValidationUtils --- ...itValidationUtils.java => ThermalValidationUtils.java} | 6 ++---- .../ie3/datamodel/utils/validation/ValidationUtils.java | 6 +++--- ...UtilsTest.groovy => ThermalValidationUtilsTest.groovy} | 8 ++++---- 3 files changed, 9 insertions(+), 11 deletions(-) rename src/main/java/edu/ie3/datamodel/utils/validation/{ThermalUnitValidationUtils.java => ThermalValidationUtils.java} (98%) rename src/test/groovy/edu/ie3/datamodel/utils/validation/{ThermalUnitValidationUtilsTest.groovy => ThermalValidationUtilsTest.groovy} (96%) 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 98% 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 73d5a5a4a..15cc20d2f 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/ThermalValidationUtils.java @@ -13,14 +13,12 @@ import edu.ie3.datamodel.utils.Try.Failure; import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.stream.Stream; 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."); } 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 2859a8b8f..80006953b 100644 --- a/src/main/java/edu/ie3/datamodel/utils/validation/ValidationUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/validation/ValidationUtils.java @@ -70,7 +70,7 @@ public static void check(Object obj) throws ValidationException { } else if (AssetTypeInput.class.isAssignableFrom(obj.getClass())) { exceptions.addAll(checkAssetType((AssetTypeInput) obj)); } else if (ThermalGrid.class.isAssignableFrom(obj.getClass())) { - exceptions.addAll(ThermalUnitValidationUtils.check((ThermalGrid) obj)); + exceptions.addAll(ThermalValidationUtils.check((ThermalGrid) obj)); } else { logNotImplemented(obj); } @@ -154,9 +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(ThermalUnitValidationUtils.check((ThermalUnitInput) assetInput)); + 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 96% 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 382a26821..baf8314ef 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalUnitValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy @@ -27,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") @@ -66,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 @@ -99,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 @@ -127,7 +127,7 @@ class ThermalUnitValidationUtilsTest extends Specification { ThermalGrid thermalGrid = new ThermalGrid(thermalBus, [thermalHouse], cylindricalStorageInput, domesticHotWaterStorageInput) - List> exceptions = ThermalUnitValidationUtils.check(thermalGrid).stream().filter { it -> it.failure }.toList() + List> exceptions = ThermalValidationUtils.check(thermalGrid).stream().filter { it -> it.failure }.toList() then: exceptions.size() == expectedSize From 452b91354f2cedfece396bc409e58034d6b361f9 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 29 Jan 2025 08:08:15 +0100 Subject: [PATCH 4/5] fix ThermalUnitValidationUtilsTest --- .../ThermalValidationUtilsTest.groovy | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy index baf8314ef..1b8297545 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy @@ -45,7 +45,7 @@ class ThermalValidationUtilsTest 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) @@ -108,23 +108,19 @@ class ThermalValidationUtilsTest 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 domesticHotWaterStorageInput = [ - ThermalUnitInputTestData.domesticHotWaterStorageInput - ] - def cylindricalStorageInput = [ - ThermalUnitInputTestData.cylindricalStorageInput - ] + def cylindricalStorageInput = [ThermalUnitInputTestData.cylindricStorageInput] - ThermalGrid thermalGrid = new ThermalGrid(thermalBus, [thermalHouse], cylindricalStorageInput, domesticHotWaterStorageInput) + + ThermalGrid thermalGrid = new ThermalGrid(thermalBus, [thermalHouse], cylindricalStorageInput) List> exceptions = ThermalValidationUtils.check(thermalGrid).stream().filter { it -> it.failure }.toList() @@ -137,7 +133,7 @@ class ThermalValidationUtilsTest extends Specification { 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, HOUSING_TYPE, NUMBER_INHABITANTS) || 1 || new InvalidEntityException("Target temperature must be higher than lower temperature limit and lower than upper temperature limit", thermalHouse) + 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) } } From 40a4174af231b3fc38d77fc57c446183686faf1a Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 29 Jan 2025 08:14:16 +0100 Subject: [PATCH 5/5] fmt --- .../utils/validation/ThermalValidationUtilsTest.groovy | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy index 1b8297545..aee73fe73 100644 --- a/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/utils/validation/ThermalValidationUtilsTest.groovy @@ -117,7 +117,9 @@ class ThermalValidationUtilsTest extends Specification { def "ThermalUnitValidationUtils.check() works for complete ThermalGrid as well"() { when: def thermalBus = ThermalUnitInputTestData.thermalBus - def cylindricalStorageInput = [ThermalUnitInputTestData.cylindricStorageInput] + def cylindricalStorageInput = [ + ThermalUnitInputTestData.cylindricStorageInput + ] ThermalGrid thermalGrid = new ThermalGrid(thermalBus, [thermalHouse], cylindricalStorageInput)