From 8ec5faacedecca18a494e0b463386e9be2c44a42 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Mon, 3 Feb 2025 12:38:45 +0100 Subject: [PATCH 1/4] Replaced `LoadProfileInput` with `LoadProfileTimeSeries` --- CHANGELOG.md | 1 + .../io/connectors/CsvFileConnector.java | 3 +- .../datamodel/io/csv/CsvFileDefinition.java | 2 +- .../TimeSeriesMetaInformationFactory.java | 21 +++- .../io/naming/DatabaseNamingStrategy.java | 22 ++-- .../io/naming/DefaultDirectoryHierarchy.java | 5 +- .../EntityPersistenceNamingStrategy.java | 35 ++---- .../io/naming/FileNamingStrategy.java | 14 ++- ...n.java => LoadProfileMetaInformation.java} | 11 +- .../io/processor/ProcessorProvider.java | 4 +- .../processor/input/InputEntityProcessor.java | 1 - .../timeseries/TimeSeriesProcessor.java | 10 +- .../ie3/datamodel/io/sink/CsvFileSink.java | 4 +- .../edu/ie3/datamodel/io/sink/DataSink.java | 2 +- .../ie3/datamodel/io/sink/InfluxDbSink.java | 11 +- .../edu/ie3/datamodel/io/sink/SqlSink.java | 59 +++++++--- .../SqlTimeSeriesMetaInformationSource.java | 5 +- .../models/timeseries/TimeSeries.java | 2 +- .../repetitive/LoadProfileEntry.java | 40 +++---- .../repetitive/LoadProfileInput.java | 87 -------------- .../repetitive/LoadProfileTimeSeries.java | 108 ++++++++++++++++++ .../repetitive/RepetitiveTimeSeries.java | 28 +++-- .../models/value/load/LoadValues.java | 23 ++++ .../ie3/datamodel/utils/TimeSeriesUtils.java | 10 ++ ...EntityPersistenceNamingStrategyTest.groovy | 63 ++-------- .../io/naming/FileNamingStrategyTest.groovy | 80 ++++--------- .../io/processor/ProcessorProviderTest.groovy | 4 - .../input/InputEntityProcessorTest.groovy | 38 ------ .../timeseries/TimeSeriesProcessorTest.groovy | 13 --- .../datamodel/io/sink/CsvFileSinkTest.groovy | 1 - .../ie3/test/common/TimeSeriesTestData.groovy | 43 ------- 31 files changed, 329 insertions(+), 421 deletions(-) rename src/main/java/edu/ie3/datamodel/io/naming/timeseries/{LoadProfileTimeSeriesMetaInformation.java => LoadProfileMetaInformation.java} (76%) delete mode 100644 src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileInput.java create mode 100644 src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java create mode 100644 src/main/java/edu/ie3/datamodel/models/value/load/LoadValues.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3abd7d730..50384ec7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Renamed timeseries mapping `participant` column to `asset` [#1191](https://github.com/ie3-institute/PowerSystemDataModel/issues/1191) - Removed attribute `dsm` from `LoadInput` [#1195](https://github.com/ie3-institute/PowerSystemDataModel/issues/1195) - Fix spotless deprecations [#1123](https://github.com/ie3-institute/PowerSystemDataModel/issues/1223) +- Replaced `LoadProfileInput` with `LoadProfileTimeSeries` [#1228](https://github.com/ie3-institute/PowerSystemDataModel/issues/1228) ## [5.1.0] - 2024-06-24 diff --git a/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java b/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java index 7628bf3b2..358b60739 100644 --- a/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java +++ b/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java @@ -63,7 +63,8 @@ public synchronized BufferedCsvWriter getOrInitWriter( } } - public synchronized , E extends TimeSeriesEntry, V extends Value> + public synchronized < + T extends TimeSeries, E extends TimeSeriesEntry, V extends Value> BufferedCsvWriter getOrInitWriter(T timeSeries, CsvFileDefinition fileDefinition) throws ConnectorException { /* Try to the right writer */ diff --git a/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java b/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java index 6afe95a39..f220f537a 100644 --- a/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java +++ b/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java @@ -68,7 +68,7 @@ public CsvFileDefinition( * @param fileNamingStrategy that should be used * @throws FileException If the definition cannot be determined */ - public , E extends TimeSeriesEntry, V extends Value> + public , E extends TimeSeriesEntry, V extends Value> CsvFileDefinition( T timeSeries, String[] headLineElements, diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMetaInformationFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMetaInformationFactory.java index 327f920eb..71c64cbd8 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMetaInformationFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeSeriesMetaInformationFactory.java @@ -7,8 +7,10 @@ import edu.ie3.datamodel.io.factory.EntityData; import edu.ie3.datamodel.io.factory.EntityFactory; +import edu.ie3.datamodel.io.naming.TimeSeriesMetaInformation; import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme; import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation; +import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation; import java.util.Collections; import java.util.List; import java.util.Set; @@ -21,12 +23,13 @@ * mappings */ public class TimeSeriesMetaInformationFactory - extends EntityFactory { + extends EntityFactory { private static final String TIME_SERIES = "timeSeries"; private static final String COLUMN_SCHEME = "columnScheme"; + private static final String LOAD_PROFILE = "loadProfile"; public TimeSeriesMetaInformationFactory() { - super(IndividualTimeSeriesMetaInformation.class); + super(IndividualTimeSeriesMetaInformation.class, LoadProfileMetaInformation.class); } @Override @@ -36,9 +39,15 @@ protected List> getFields(Class entityClass) { } @Override - protected IndividualTimeSeriesMetaInformation buildModel(EntityData data) { - UUID timeSeries = data.getUUID(TIME_SERIES); - ColumnScheme columnScheme = ColumnScheme.parse(data.getField(COLUMN_SCHEME)).orElseThrow(); - return new IndividualTimeSeriesMetaInformation(timeSeries, columnScheme); + protected TimeSeriesMetaInformation buildModel(EntityData data) { + if (LoadProfileMetaInformation.class.isAssignableFrom(data.getTargetClass())) { + String profile = data.getField(LOAD_PROFILE); + return new LoadProfileMetaInformation(profile); + } else { + UUID timeSeries = data.getUUID(TIME_SERIES); + + ColumnScheme columnScheme = ColumnScheme.parse(data.getField(COLUMN_SCHEME)).orElseThrow(); + return new IndividualTimeSeriesMetaInformation(timeSeries, columnScheme); + } } } diff --git a/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java index b3b35172b..03a9a32d2 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java @@ -12,7 +12,7 @@ import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries; -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries; import edu.ie3.datamodel.models.value.Value; import java.util.Optional; @@ -21,7 +21,7 @@ public class DatabaseNamingStrategy { private static final String TIME_SERIES_PREFIX = "time_series_"; - private static final String LOAD_PROFILE_PREFIX = "load_profile_"; + private static final String LOAD_PROFILE = "load_profiles"; private final EntityPersistenceNamingStrategy entityPersistenceNamingStrategy; @@ -42,6 +42,11 @@ public String getTimeSeriesPrefix() { return TIME_SERIES_PREFIX; } + /** Returns the String of the load profile table */ + public String getLoadProfileTableName() { + return LOAD_PROFILE; + } + /** * Provides the name of a time series table given a column scheme * @@ -53,13 +58,12 @@ public String getTimeSeriesEntityName(ColumnScheme columnScheme) { } /** - * Provides the name of a load profile given by the load profile key + * Provides the name of the load profile table. * - * @param lpKey Load profile key * @return the table name */ - private String getLoadProfileEntityName(String lpKey) { - return LOAD_PROFILE_PREFIX + lpKey; + public String getLoadProfileEntityName() { + return getLoadProfileTableName(); } /** @@ -78,7 +82,7 @@ public Optional getEntityName(Class cls) { * @param timeSeries to be named TimeSeries * @return the table name */ - public , E extends TimeSeriesEntry, V extends Value> + public , E extends TimeSeriesEntry, V extends Value> Optional getEntityName(T timeSeries) { if (timeSeries instanceof IndividualTimeSeries individualTimeSeries) { Optional maybeFirstElement = individualTimeSeries.getEntries().stream().findFirst(); @@ -89,8 +93,8 @@ Optional getEntityName(T timeSeries) { logger.error("Unable to determine content of time series {}", timeSeries); return Optional.empty(); } - } else if (timeSeries instanceof LoadProfileInput loadProfileInput) { - return Optional.of(getLoadProfileEntityName(loadProfileInput.getType().getKey())); + } else if (timeSeries instanceof LoadProfileTimeSeries) { + return Optional.of(getLoadProfileEntityName()); } else { logger.error("There is no naming strategy defined for {}", timeSeries); return Optional.empty(); diff --git a/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java b/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java index 5964b2433..fff633bbe 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/DefaultDirectoryHierarchy.java @@ -30,7 +30,6 @@ import edu.ie3.datamodel.models.result.system.*; import edu.ie3.datamodel.models.result.thermal.ThermalUnitResult; import edu.ie3.datamodel.models.timeseries.TimeSeries; -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -250,9 +249,7 @@ private enum SubDirectories { StorageTypeInput.class, WecTypeInput.class, OperatorInput.class, - WecCharacteristicInput.class, - RandomLoadParameters.class, - LoadProfileInput.class) + WecCharacteristicInput.class) .collect(Collectors.toSet())), PARTICIPANTS_INPUT( Constants.INPUT_SUB_TREE.resolve("participants"), diff --git a/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java index 208fa0b81..37a070aa3 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java @@ -7,7 +7,7 @@ import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme; import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation; -import edu.ie3.datamodel.io.naming.timeseries.LoadProfileTimeSeriesMetaInformation; +import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation; import edu.ie3.datamodel.io.source.TimeSeriesMappingSource; import edu.ie3.datamodel.models.Entity; import edu.ie3.datamodel.models.input.*; @@ -17,7 +17,7 @@ import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries; -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries; import edu.ie3.datamodel.models.value.*; import edu.ie3.util.StringUtils; import java.util.Optional; @@ -60,7 +60,7 @@ public class EntityPersistenceNamingStrategy { * profile is accessible via the named capturing group "profile", the uuid by the group "uuid" */ private static final String LOAD_PROFILE_TIME_SERIES = - "lpts_(?[a-zA-Z][0-9])_(?" + UUID_STRING + ")"; + "lpts_(?[a-zA-Z]{1,11}[0-9]{0,3})"; /** * Pattern to identify load profile time series in this instance of the naming strategy (takes @@ -156,15 +156,13 @@ public IndividualTimeSeriesMetaInformation individualTimesSeriesMetaInformation( * @param fileName File name to extract information from * @return Meta information form load profile time series file name */ - public LoadProfileTimeSeriesMetaInformation loadProfileTimesSeriesMetaInformation( - String fileName) { + public LoadProfileMetaInformation loadProfileTimesSeriesMetaInformation(String fileName) { Matcher matcher = getLoadProfileTimeSeriesPattern().matcher(fileName); if (!matcher.matches()) throw new IllegalArgumentException( "Cannot extract meta information on load profile time series from '" + fileName + "'."); - return new LoadProfileTimeSeriesMetaInformation( - UUID.fromString(matcher.group("uuid")), matcher.group("profile")); + return new LoadProfileMetaInformation(matcher.group("profile")); } /** @@ -215,8 +213,6 @@ public Optional getInputEntityName(Class cls) { return getTypeEntityName(cls.asSubclass(AssetTypeInput.class)); if (AssetInput.class.isAssignableFrom(cls)) return getAssetInputEntityName(cls.asSubclass(AssetInput.class)); - if (RandomLoadParameters.class.isAssignableFrom(cls)) - return getRandomLoadParametersEntityName(cls.asSubclass(RandomLoadParameters.class)); if (GraphicInput.class.isAssignableFrom(cls)) return getGraphicsInputEntityName(cls.asSubclass(GraphicInput.class)); if (OperatorInput.class.isAssignableFrom(cls)) @@ -274,19 +270,6 @@ public Optional getAssetCharacteristicsEntityName( return Optional.of(addPrefixAndSuffix(assetCharString)); } - /** - * Get the entity name for all {@link RandomLoadParameters} - * - * @param randomLoadParamClass the random load parameters class an entity name string should be - * generated from - * @return the entity name string - */ - public Optional getRandomLoadParametersEntityName( - Class randomLoadParamClass) { - String loadParamString = camelCaseToSnakeCase(randomLoadParamClass.getSimpleName()); - return Optional.of(addPrefixAndSuffix(loadParamString.concat("_input"))); - } - /** * Converts a given camel case string to its snake case representation * @@ -359,7 +342,7 @@ public Optional getTimeSeriesMappingEntityName() { * @param timeSeries Time series to derive naming information from * @return A file name for this particular time series */ - public , E extends TimeSeriesEntry, V extends Value> + public , E extends TimeSeriesEntry, V extends Value> Optional getEntityName(T timeSeries) { if (timeSeries instanceof IndividualTimeSeries) { Optional maybeFirstElement = timeSeries.getEntries().stream().findFirst(); @@ -383,14 +366,12 @@ Optional getEntityName(T timeSeries) { logger.error("Unable to determine content of time series {}", timeSeries); return Optional.empty(); } - } else if (timeSeries instanceof LoadProfileInput loadProfileInput) { + } else if (timeSeries instanceof LoadProfileTimeSeries loadProfileTimeSeries) { return Optional.of( prefix .concat("lpts") .concat("_") - .concat(loadProfileInput.getType().getKey()) - .concat("_") - .concat(loadProfileInput.getUuid().toString()) + .concat(loadProfileTimeSeries.getLoadProfile().getKey()) .concat(suffix)); } else { logger.error("There is no naming strategy defined for {}", timeSeries); diff --git a/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java index 8aadbc0be..dc3e8dc66 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java @@ -7,11 +7,12 @@ import edu.ie3.datamodel.io.IoUtil; import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation; +import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation; import edu.ie3.datamodel.models.Entity; import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries; -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries; import edu.ie3.datamodel.models.value.Value; import edu.ie3.datamodel.utils.FileUtils; import java.nio.file.Path; @@ -136,7 +137,7 @@ public Optional getDirectoryPath(Class cls) { * @param timeSeries Time series to derive naming information from * @return An optional sub directory path */ - public , E extends TimeSeriesEntry, V extends Value> + public , E extends TimeSeriesEntry, V extends Value> Optional getDirectoryPath(T timeSeries) { Optional maybeDirectoryName = fileHierarchy.getSubDirectory(timeSeries.getClass()); if (maybeDirectoryName.isEmpty()) { @@ -180,7 +181,7 @@ public Pattern getIndividualTimeSeriesPattern() { * @return A load profile time series pattern */ public Pattern getLoadProfileTimeSeriesPattern() { - Optional subDirectory = fileHierarchy.getSubDirectory(LoadProfileInput.class); + Optional subDirectory = fileHierarchy.getSubDirectory(LoadProfileTimeSeries.class); if (subDirectory.isEmpty()) { return entityPersistenceNamingStrategy.getLoadProfileTimeSeriesPattern(); @@ -237,6 +238,11 @@ public IndividualTimeSeriesMetaInformation individualTimeSeriesMetaInformation(S removeFileNameEnding(fileName)); } + public LoadProfileMetaInformation loadProfileTimeSeriesMetaInformation(String fileName) { + return entityPersistenceNamingStrategy.loadProfileTimesSeriesMetaInformation( + removeFileNameEnding(fileName)); + } + public static String removeFileNameEnding(String fileName) { return fileName.replaceAll("(?:\\.[^.\\\\/\\s]{1,255}){1,2}$", ""); } @@ -274,7 +280,7 @@ public Optional getEntityName(Class cls) { * @param timeSeries Time series to derive naming information from * @return A file name for this particular time series */ - public , E extends TimeSeriesEntry, V extends Value> + public , E extends TimeSeriesEntry, V extends Value> Optional getEntityName(T timeSeries) { return entityPersistenceNamingStrategy.getEntityName(timeSeries); } diff --git a/src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileTimeSeriesMetaInformation.java b/src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileMetaInformation.java similarity index 76% rename from src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileTimeSeriesMetaInformation.java rename to src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileMetaInformation.java index d1e319668..875c881e6 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileTimeSeriesMetaInformation.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileMetaInformation.java @@ -10,10 +10,15 @@ import java.util.UUID; /** Specific meta information, that can be derived from a load profile time series file */ -public class LoadProfileTimeSeriesMetaInformation extends TimeSeriesMetaInformation { +public class LoadProfileMetaInformation extends TimeSeriesMetaInformation { private final String profile; - public LoadProfileTimeSeriesMetaInformation(UUID uuid, String profile) { + public LoadProfileMetaInformation(String profile) { + super(UUID.randomUUID()); + this.profile = profile; + } + + public LoadProfileMetaInformation(UUID uuid, String profile) { super(uuid); this.profile = profile; } @@ -25,7 +30,7 @@ public String getProfile() { @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof LoadProfileTimeSeriesMetaInformation that)) return false; + if (!(o instanceof LoadProfileMetaInformation that)) return false; if (!super.equals(o)) return false; return profile.equals(that.profile); } diff --git a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java index 58cad7354..8fc1a538a 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java @@ -122,7 +122,7 @@ private EntityProcessor getEntityProcessor(Class Type of the value inside the time series entries * @return A set of mappings from field name to value */ - public , E extends TimeSeriesEntry, V extends Value> + public , E extends TimeSeriesEntry, V extends Value> Set> handleTimeSeries(T timeSeries) throws ProcessorProviderException { TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(timeSeries); @@ -145,7 +145,7 @@ Set> handleTimeSeries(T timeSeries) * @throws ProcessorProviderException If no fitting processor can be found */ @SuppressWarnings("unchecked cast") - private , E extends TimeSeriesEntry, V extends Value> + private , E extends TimeSeriesEntry, V extends Value> TimeSeriesProcessor getTimeSeriesProcessor(TimeSeriesProcessorKey processorKey) throws ProcessorProviderException { TimeSeriesProcessor processor = diff --git a/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java index d21212531..18c6a723f 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/input/InputEntityProcessor.java @@ -35,7 +35,6 @@ public class InputEntityProcessor extends EntityProcessor { List.of( /* InputEntity */ OperatorInput.class, - RandomLoadParameters.class, TimeSeriesMappingSource.MappingEntry.class, IdCoordinateInput.class, /* - AssetInput */ diff --git a/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java index 52f1a602a..65edd5980 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java @@ -13,8 +13,6 @@ import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries; import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue; -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry; -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput; import edu.ie3.datamodel.models.value.*; import java.lang.reflect.Method; import java.util.*; @@ -22,7 +20,7 @@ import java.util.stream.Stream; public class TimeSeriesProcessor< - T extends TimeSeries, E extends TimeSeriesEntry, V extends Value> + T extends TimeSeries, E extends TimeSeriesEntry, V extends Value> extends EntityProcessor { /** * List of all combinations of time series class, entry class and value class, this processor is @@ -49,8 +47,7 @@ public class TimeSeriesProcessor< new TimeSeriesProcessorKey( IndividualTimeSeries.class, TimeBasedValue.class, SValue.class), new TimeSeriesProcessorKey( - IndividualTimeSeries.class, TimeBasedValue.class, HeatAndSValue.class), - new TimeSeriesProcessorKey(LoadProfileInput.class, LoadProfileEntry.class, PValue.class)); + IndividualTimeSeries.class, TimeBasedValue.class, HeatAndSValue.class)); /** * Specific combination of time series class, entry class and value class, this processor is @@ -110,7 +107,8 @@ private SortedMap buildFieldToSource( throws EntityProcessorException { /* Get the mapping from field name to getter method ignoring the getter for returning all entries */ Map timeSeriesMapping = - mapFieldNameToGetter(timeSeriesClass, Arrays.asList("entries", "uuid", "type")) + mapFieldNameToGetter( + timeSeriesClass, Arrays.asList("entries", "uuid", "type", "loadProfile")) .entrySet() .stream() .collect( diff --git a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java index 8635534a7..26f0801ac 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java @@ -243,7 +243,7 @@ public void shutdown() { } @Override - public , V extends Value> void persistTimeSeries( + public , V extends Value> void persistTimeSeries( TimeSeries timeSeries) { try { TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(timeSeries); @@ -264,7 +264,7 @@ public , V extends Value> void persistTimeSeries( } } - private , V extends Value> void persistTimeSeries( + private , V extends Value> void persistTimeSeries( TimeSeries timeSeries, BufferedCsvWriter writer) throws ProcessorProviderException { try { Set> entityFieldData = diff --git a/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java b/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java index 1d45320dc..d4dca754e 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java @@ -62,6 +62,6 @@ public interface DataSink { * @param Type of entry in the time series * @param Type of actual value, that is inside the entry */ - , V extends Value> void persistTimeSeries( + , V extends Value> void persistTimeSeries( TimeSeries timeSeries) throws ProcessorProviderException; } diff --git a/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java b/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java index 5730a1585..85255f916 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java @@ -85,7 +85,7 @@ public void persistAll(Collection entities) } @Override - public , V extends Value> void persistTimeSeries( + public , V extends Value> void persistTimeSeries( TimeSeries timeSeries) throws ProcessorProviderException { Set points = transformToPoints(timeSeries); writeAll(points); @@ -146,8 +146,8 @@ private Point transformToPoint(ResultEntity entity, String measurementName) * * @param timeSeries the time series to transform */ - private , V extends Value> Set transformToPoints( - TimeSeries timeSeries) throws ProcessorProviderException { + private , V extends Value> + Set transformToPoints(TimeSeries timeSeries) throws ProcessorProviderException { if (timeSeries.getEntries().isEmpty()) return Collections.emptySet(); Optional measurementName = entityPersistenceNamingStrategy.getEntityName(timeSeries); @@ -169,8 +169,9 @@ private , V extends Value> Set transformToPo * @param timeSeries the time series to transform * @param measurementName equivalent to the name of a relational table */ - private , V extends Value> Set transformToPoints( - TimeSeries timeSeries, String measurementName) throws ProcessorProviderException { + private , V extends Value> + Set transformToPoints(TimeSeries timeSeries, String measurementName) + throws ProcessorProviderException { Set points = new HashSet<>(); Set> entityFieldData = processorProvider.handleTimeSeries(timeSeries); diff --git a/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java b/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java index 907322b1f..35cdf3b9e 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java @@ -5,10 +5,12 @@ */ package edu.ie3.datamodel.io.sink; -import static edu.ie3.datamodel.io.SqlUtils.*; +import static edu.ie3.datamodel.io.SqlUtils.quote; import static java.util.stream.Collectors.groupingBy; -import edu.ie3.datamodel.exceptions.*; +import edu.ie3.datamodel.exceptions.EntityProcessorException; +import edu.ie3.datamodel.exceptions.ExtractorException; +import edu.ie3.datamodel.exceptions.ProcessorProviderException; import edu.ie3.datamodel.io.DbGridMetadata; import edu.ie3.datamodel.io.connectors.SqlConnector; import edu.ie3.datamodel.io.extractor.Extractor; @@ -18,17 +20,22 @@ import edu.ie3.datamodel.io.processor.ProcessorProvider; import edu.ie3.datamodel.io.processor.timeseries.TimeSeriesProcessorKey; import edu.ie3.datamodel.models.Entity; -import edu.ie3.datamodel.models.input.*; -import edu.ie3.datamodel.models.input.connector.*; +import edu.ie3.datamodel.models.input.AssetTypeInput; +import edu.ie3.datamodel.models.input.InputEntity; +import edu.ie3.datamodel.models.input.NodeInput; +import edu.ie3.datamodel.models.input.OperatorInput; +import edu.ie3.datamodel.models.input.connector.ConnectorInput; import edu.ie3.datamodel.models.input.container.JointGridContainer; import edu.ie3.datamodel.models.input.graphics.GraphicInput; -import edu.ie3.datamodel.models.input.system.*; +import edu.ie3.datamodel.models.input.system.SystemParticipantInput; import edu.ie3.datamodel.models.input.thermal.ThermalBusInput; import edu.ie3.datamodel.models.input.thermal.ThermalUnitInput; import edu.ie3.datamodel.models.result.ResultEntity; import edu.ie3.datamodel.models.timeseries.TimeSeries; import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries; import edu.ie3.datamodel.models.value.Value; +import edu.ie3.datamodel.utils.TriFunction; import edu.ie3.util.StringUtils; import java.sql.SQLException; import java.util.*; @@ -47,6 +54,7 @@ public class SqlSink { private final String schemaName; private static final String TIME_SERIES = "time_series"; + private static final String LOAD_PROFILE = "load_profile"; public SqlSink( String schemaName, DatabaseNamingStrategy databaseNamingStrategy, SqlConnector connector) @@ -109,12 +117,12 @@ public void persistAll(Collection entities, DbGridMetadata } /** - * Persist an entity. By default this method takes care of the extraction process of nested + * Persist an entity. By default, this method takes care of the extraction process of nested * entities (if any) * * @param entity the entity that should be persisted * @param identifier identifier of the grid - * @throws SQLException + * @throws SQLException if an error occurred */ public void persist(C entity, DbGridMetadata identifier) throws SQLException { if (entity instanceof InputEntity inputEntity) { @@ -178,7 +186,7 @@ private void persistMixedList(List entities, DbGridMetadat * Persist a list of entities with same types. To minimize the number of queries, the entities * will be grouped by their class. */ - private , V extends Value> void persistList( + private , V extends Value> void persistList( List entities, Class cls, DbGridMetadata identifier) throws SQLException { // Check if there are only elements of the same class Class firstClass = entities.get(0).getClass(); @@ -222,7 +230,7 @@ private void insertListIgnoreNested( } /** Persist one time series. */ - protected , V extends Value> void persistTimeSeries( + protected , V extends Value> void persistTimeSeries( TimeSeries timeSeries, DbGridMetadata identifier) { try { TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(timeSeries); @@ -234,17 +242,30 @@ protected , V extends Value> void persistTimeSeries } } - private , V extends Value> void persistTimeSeries( + private , V extends Value> void persistTimeSeries( TimeSeries timeSeries, String[] headerElements, DbGridMetadata identifier) throws ProcessorProviderException { try { + + TriFunction queryBuilder; + String timeSeriesIdentifier; + + if (timeSeries instanceof LoadProfileTimeSeries lpts) { + timeSeriesIdentifier = lpts.getLoadProfile().getKey(); + queryBuilder = this::basicInsertQueryValuesLPTS; + } else { + timeSeriesIdentifier = timeSeries.getUuid().toString(); + queryBuilder = this::basicInsertQueryValuesITS; + } + String query = - basicInsertQueryValuesITS( + queryBuilder.apply( schemaName, databaseNamingStrategy.getEntityName(timeSeries).orElseThrow(), headerElements); Set> entityFieldData = processorProvider.handleTimeSeries(timeSeries); + query = query + entityFieldData.stream() @@ -254,7 +275,7 @@ private , V extends Value> void persistTimeSeries( sqlEntityFieldData(data), headerElements, identifier, - timeSeries.getUuid().toString())) + timeSeriesIdentifier)) .collect(Collectors.joining(",\n", "", ";")); executeQueryToPersist(query); } catch (ProcessorProviderException e) { @@ -352,13 +373,13 @@ private String queryTimeSeriesValueLine( Map entityFieldData, String[] headerElements, DbGridMetadata identifier, - String tsUuid) { + String timeSeriesIdentifier) { return writeOneLine( Stream.concat( Stream.concat( Arrays.stream(headerElements).map(entityFieldData::get), identifier.getStreamForQuery()), - Stream.of(quote(tsUuid, "'")))); + Stream.of(quote(timeSeriesIdentifier, "'")))); } private LinkedHashMap sqlEntityFieldData( @@ -397,6 +418,16 @@ private String basicInsertQueryValuesITS( + "\nVALUES\n"; } + /** Provides the insert, column names, grid identifier, and the VALUES statement for a query. */ + private String basicInsertQueryValuesLPTS( + String schemaName, String tableName, String[] headerElements) { + String[] addParams = {DbGridMetadata.GRID_UUID_COLUMN, LOAD_PROFILE}; + return basicInsertQuery(schemaName, tableName) + + " " + + writeOneLine(StringUtils.camelCaseToSnakeCase(headerElements), addParams) + + "\nVALUES\n"; + } + /** Converts a stream of strings into an one line string with brackets. */ private String writeOneLine(Stream entries) { return "(" + entries.collect(Collectors.joining(",")) + ")"; diff --git a/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java b/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java index f0144b986..ad372d2fd 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java @@ -94,6 +94,9 @@ private Optional createEntity( Map fieldToValues) { EntityData entityData = new EntityData(fieldToValues, IndividualTimeSeriesMetaInformation.class); - return mappingFactory.get(entityData).getData(); + return mappingFactory + .get(entityData) + .map(meta -> (IndividualTimeSeriesMetaInformation) meta) + .getData(); } } diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java index 279c100d9..62593b0ae 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java @@ -17,7 +17,7 @@ * @param Type of the entries, the time series is foreseen to contain * @param Type of the values, the entries will have */ -public abstract class TimeSeries, V extends Value> +public abstract class TimeSeries, V extends Value> extends UniqueEntity { private final Set entries; diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileEntry.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileEntry.java index 2e0359967..10f90d632 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileEntry.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileEntry.java @@ -6,27 +6,20 @@ package edu.ie3.datamodel.models.timeseries.repetitive; import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; -import edu.ie3.datamodel.models.value.PValue; -import java.time.DayOfWeek; +import edu.ie3.datamodel.models.value.load.LoadValues; import java.util.Objects; -/** Unique entry to a {@link LoadProfileInput} */ -public class LoadProfileEntry extends TimeSeriesEntry { - private final DayOfWeek dayOfWeek; - private final int quarterHourOfDay; +/** Unique entry to a {@link LoadProfileTimeSeries} */ +public class LoadProfileEntry extends TimeSeriesEntry { + private final int quarterHour; - public LoadProfileEntry(PValue value, DayOfWeek dayOfWeek, int quarterHourOfDay) { - super(value); - this.dayOfWeek = dayOfWeek; - this.quarterHourOfDay = quarterHourOfDay; + public LoadProfileEntry(L values, int quarterHour) { + super(values); + this.quarterHour = quarterHour; } - public DayOfWeek getDayOfWeek() { - return dayOfWeek; - } - - public int getQuarterHourOfDay() { - return quarterHourOfDay; + public int getQuarterHour() { + return quarterHour; } @Override @@ -34,24 +27,17 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; - LoadProfileEntry that = (LoadProfileEntry) o; - return quarterHourOfDay == that.quarterHourOfDay && dayOfWeek == that.dayOfWeek; + LoadProfileEntry that = (LoadProfileEntry) o; + return quarterHour == that.quarterHour; } @Override public int hashCode() { - return Objects.hash(super.hashCode(), dayOfWeek, quarterHourOfDay); + return Objects.hash(super.hashCode(), quarterHour); } @Override public String toString() { - return "LoadProfileEntry{" - + "dayOfWeek=" - + dayOfWeek - + ", quarterHourOfDay=" - + quarterHourOfDay - + ", value=" - + value - + '}'; + return "LoadProfileEntry{" + "quarterHour=" + quarterHour + ", value=" + value + '}'; } } diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileInput.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileInput.java deleted file mode 100644 index 017e28c02..000000000 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileInput.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * © 2021. TU Dortmund University, - * Institute of Energy Systems, Energy Efficiency and Energy Economics, - * Research group Distribution grid planning and operation -*/ -package edu.ie3.datamodel.models.timeseries.repetitive; - -import edu.ie3.datamodel.models.profile.StandardLoadProfile; -import edu.ie3.datamodel.models.value.PValue; -import java.time.DayOfWeek; -import java.time.ZonedDateTime; -import java.util.*; -import java.util.stream.Collectors; - -// TODO This is a sample implementation, please implement a real scenario -public class LoadProfileInput extends RepetitiveTimeSeries { - private final StandardLoadProfile type; - private final Map> dayOfWeekToHourlyValues; - - public LoadProfileInput(UUID uuid, StandardLoadProfile type, Set values) { - super(uuid, values); - this.type = type; - this.dayOfWeekToHourlyValues = - getEntries().stream() - .collect( - Collectors.groupingBy( - LoadProfileEntry::getDayOfWeek, - Collectors.toMap( - LoadProfileEntry::getQuarterHourOfDay, LoadProfileEntry::getValue))); - } - - public LoadProfileInput(StandardLoadProfile type, Set values) { - this(UUID.randomUUID(), type, values); - } - - @Override - public PValue calc(ZonedDateTime time) { - // dummy value - return dayOfWeekToHourlyValues.get(time.getDayOfWeek()).get(time.getHour()); - } - - @Override - protected Optional getPreviousDateTime(ZonedDateTime time) { - // dummy value - return Optional.of(time.minusMinutes(15)); - } - - @Override - protected Optional getNextDateTime(ZonedDateTime time) { - // dummy value - return Optional.of(time.plusMinutes(15)); - } - - @Override - public List getTimeKeysAfter(ZonedDateTime time) { - // dummy value - return List.of(time.plusHours(1)); - } - - public StandardLoadProfile getType() { - return type; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - LoadProfileInput that = (LoadProfileInput) o; - return type.equals(that.type) && dayOfWeekToHourlyValues.equals(that.dayOfWeekToHourlyValues); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), type, dayOfWeekToHourlyValues); - } - - @Override - public String toString() { - return "LoadProfileInput{" - + "type=" - + type - + ", dayOfWeekToHourlyValues=" - + dayOfWeekToHourlyValues - + '}'; - } -} diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java new file mode 100644 index 000000000..6a14a863c --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java @@ -0,0 +1,108 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.models.timeseries.repetitive; + +import edu.ie3.datamodel.models.profile.LoadProfile; +import edu.ie3.datamodel.models.value.PValue; +import edu.ie3.datamodel.models.value.load.LoadValues; +import edu.ie3.datamodel.utils.TimeSeriesUtils; +import java.time.ZonedDateTime; +import java.util.*; +import java.util.stream.Collectors; +import javax.measure.quantity.Energy; +import javax.measure.quantity.Power; +import tech.units.indriya.ComparableQuantity; + +/** + * Describes a load profile time series with repetitive values that can be calculated from a pattern + */ +public class LoadProfileTimeSeries + extends RepetitiveTimeSeries, PValue> { + private final LoadProfile loadProfile; + private final Map valueMapping; + + /** + * The maximum average power consumption per quarter-hour for a given calculated over all seasons + * and weekday types of given load profile. + */ + public final Optional> maxPower; + + /** The profile energy scaling in kWh. */ + public final Optional> profileEnergyScaling; + + public LoadProfileTimeSeries( + UUID uuid, + LoadProfile loadProfile, + Set> entries, + Optional> maxPower, + Optional> profileEnergyScaling) { + super(uuid, entries); + this.loadProfile = loadProfile; + this.valueMapping = + entries.stream() + .collect( + Collectors.toMap(LoadProfileEntry::getQuarterHour, LoadProfileEntry::getValue)); + + this.maxPower = maxPower; + this.profileEnergyScaling = profileEnergyScaling; + } + + /** Returns the {@link LoadProfile}. */ + public LoadProfile getLoadProfile() { + return loadProfile; + } + + @Override + public Set> getEntries() { + // to ensure that the entries are ordered by their quarter-hour + TreeSet> set = + new TreeSet<>(Comparator.comparing(LoadProfileEntry::getQuarterHour)); + set.addAll(super.getEntries()); + return set; + } + + @Override + public List getTimeKeysAfter(ZonedDateTime time) { + return List.of(time.plusMinutes(15)); // dummy value that will return next quarter-hour value + } + + /** Returns the value mapping. */ + protected Map getValueMapping() { + return valueMapping; + } + + @Override + protected PValue calc(ZonedDateTime time) { + int quarterHour = TimeSeriesUtils.calculateQuarterHourOfDay(time); + return valueMapping.get(quarterHour).getValue(time, loadProfile); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + LoadProfileTimeSeries that = (LoadProfileTimeSeries) o; + return loadProfile.equals(that.loadProfile) && valueMapping.equals(that.valueMapping); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode()); + } + + @Override + public String toString() { + return "LoadProfileTimeSeries{" + + "uuid=" + + getUuid() + + "loadProfile=" + + getLoadProfile() + + ", valueMapping=" + + getValueMapping() + + '}'; + } +} diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java index 672ee5589..c26f951f1 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java @@ -9,16 +9,12 @@ import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry; import edu.ie3.datamodel.models.value.Value; import java.time.ZonedDateTime; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; +import java.util.*; /** Describes a TimeSeries with repetitive values that can be calculated from a pattern */ -public abstract class RepetitiveTimeSeries, V extends Value> +public abstract class RepetitiveTimeSeries< + E extends TimeSeriesEntry, V extends Value> extends TimeSeries { - protected RepetitiveTimeSeries(Set entries) { - super(entries); - } protected RepetitiveTimeSeries(UUID uuid, Set entries) { super(uuid, entries); @@ -34,6 +30,22 @@ protected RepetitiveTimeSeries(UUID uuid, Set entries) { @Override public Optional getValue(ZonedDateTime time) { - return Optional.of(calc(time)); + return Optional.ofNullable(calc(time)); + } + + @Override + protected Optional getPreviousDateTime(ZonedDateTime time) { + return Optional.of(time.minusHours(1)); + } + + @Override + protected Optional getNextDateTime(ZonedDateTime time) { + return Optional.of(time.plusHours(1)); + } + + @Override + public List getTimeKeysAfter(ZonedDateTime time) { + // dummy value + return getNextDateTime(time).map(List::of).orElseGet(Collections::emptyList); } } diff --git a/src/main/java/edu/ie3/datamodel/models/value/load/LoadValues.java b/src/main/java/edu/ie3/datamodel/models/value/load/LoadValues.java new file mode 100644 index 000000000..ae7fc4e26 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/value/load/LoadValues.java @@ -0,0 +1,23 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.models.value.load; + +import edu.ie3.datamodel.models.profile.LoadProfile; +import edu.ie3.datamodel.models.value.PValue; +import edu.ie3.datamodel.models.value.Value; +import java.time.ZonedDateTime; + +/** Interface for load values. */ +public interface LoadValues extends Value { + + /** + * Method to calculate an actual load power value for the given time. + * + * @param time given time + * @return a new {@link PValue} + */ + PValue getValue(ZonedDateTime time, LoadProfile loadProfile); +} diff --git a/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java b/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java index 16fdcb24f..c7cb56b24 100644 --- a/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java +++ b/src/main/java/edu/ie3/datamodel/utils/TimeSeriesUtils.java @@ -69,4 +69,14 @@ public static Set getAcceptedColumnSchemes() { public static boolean isSchemeAccepted(ColumnScheme scheme) { return ACCEPTED_COLUMN_SCHEMES.contains(scheme); } + + /** + * Method to calculate the quarter-hour of a day from a given time. + * + * @param time given time + * @return the quarter-hour + */ + public static int calculateQuarterHourOfDay(ZonedDateTime time) { + return time.getHour() * 4 + time.getMinute() / 15; + } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy index f34873c24..7986a3774 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategyTest.groovy @@ -9,7 +9,6 @@ import edu.ie3.datamodel.io.source.TimeSeriesMappingSource import edu.ie3.datamodel.models.input.EmInput import edu.ie3.datamodel.models.input.MeasurementUnitInput import edu.ie3.datamodel.models.input.NodeInput -import edu.ie3.datamodel.models.input.RandomLoadParameters import edu.ie3.datamodel.models.input.connector.LineInput import edu.ie3.datamodel.models.input.connector.SwitchInput import edu.ie3.datamodel.models.input.connector.Transformer2WInput @@ -19,22 +18,8 @@ import edu.ie3.datamodel.models.input.connector.type.Transformer2WTypeInput import edu.ie3.datamodel.models.input.connector.type.Transformer3WTypeInput import edu.ie3.datamodel.models.input.graphics.LineGraphicInput import edu.ie3.datamodel.models.input.graphics.NodeGraphicInput -import edu.ie3.datamodel.models.input.system.BmInput -import edu.ie3.datamodel.models.input.system.ChpInput -import edu.ie3.datamodel.models.input.system.EvInput -import edu.ie3.datamodel.models.input.system.EvcsInput -import edu.ie3.datamodel.models.input.system.FixedFeedInInput -import edu.ie3.datamodel.models.input.system.HpInput -import edu.ie3.datamodel.models.input.system.LoadInput -import edu.ie3.datamodel.models.input.system.PvInput -import edu.ie3.datamodel.models.input.system.StorageInput -import edu.ie3.datamodel.models.input.system.WecInput -import edu.ie3.datamodel.models.input.system.type.BmTypeInput -import edu.ie3.datamodel.models.input.system.type.ChpTypeInput -import edu.ie3.datamodel.models.input.system.type.EvTypeInput -import edu.ie3.datamodel.models.input.system.type.HpTypeInput -import edu.ie3.datamodel.models.input.system.type.StorageTypeInput -import edu.ie3.datamodel.models.input.system.type.WecTypeInput +import edu.ie3.datamodel.models.input.system.* +import edu.ie3.datamodel.models.input.system.type.* import edu.ie3.datamodel.models.input.thermal.CylindricalStorageInput import edu.ie3.datamodel.models.input.thermal.ThermalHouseInput import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile @@ -43,23 +28,13 @@ import edu.ie3.datamodel.models.result.connector.LineResult import edu.ie3.datamodel.models.result.connector.SwitchResult import edu.ie3.datamodel.models.result.connector.Transformer2WResult import edu.ie3.datamodel.models.result.connector.Transformer3WResult -import edu.ie3.datamodel.models.result.system.BmResult -import edu.ie3.datamodel.models.result.system.ChpResult -import edu.ie3.datamodel.models.result.system.EmResult -import edu.ie3.datamodel.models.result.system.EvResult -import edu.ie3.datamodel.models.result.system.EvcsResult -import edu.ie3.datamodel.models.result.system.FixedFeedInResult -import edu.ie3.datamodel.models.result.system.FlexOptionsResult -import edu.ie3.datamodel.models.result.system.LoadResult -import edu.ie3.datamodel.models.result.system.PvResult -import edu.ie3.datamodel.models.result.system.StorageResult -import edu.ie3.datamodel.models.result.system.WecResult +import edu.ie3.datamodel.models.result.system.* import edu.ie3.datamodel.models.result.thermal.CylindricalStorageResult import edu.ie3.datamodel.models.result.thermal.ThermalHouseResult import edu.ie3.datamodel.models.timeseries.IntValue import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries import edu.ie3.datamodel.models.timeseries.repetitive.RepetitiveTimeSeries import edu.ie3.datamodel.models.value.EnergyPriceValue import edu.ie3.util.quantities.PowerSystemUnits @@ -105,7 +80,7 @@ class EntityPersistenceNamingStrategyTest extends Specification { def "The pattern for a repetitive load profile time series file name actually matches a valid file name and extracts the correct groups"() { given: def ens = new EntityPersistenceNamingStrategy() - def validFileName = "lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304" + def validFileName = "lpts_g3" when: def matcher = ens.loadProfileTimeSeriesPattern.matcher(validFileName) @@ -114,11 +89,9 @@ class EntityPersistenceNamingStrategyTest extends Specification { matcher.matches() then: "it also has correct capturing groups" - matcher.groupCount() == 2 + matcher.groupCount() == 1 matcher.group(1) == "g3" - matcher.group(2) == "bee0a8b6-4788-4f18-bf72-be52035f7304" matcher.group("profile") == "g3" - matcher.group("uuid") == "bee0a8b6-4788-4f18-bf72-be52035f7304" } def "Trying to extract individual time series meta information throws an Exception, if it is provided a malformed string"() { @@ -344,22 +317,6 @@ class EntityPersistenceNamingStrategyTest extends Specification { WecTypeInput || "wec_type_input" } - def "A EntityPersistenceNamingStrategy without pre- or suffixes should return valid strings for a Load Parameter Model"() { - given: "a naming strategy without pre- or suffixes" - EntityPersistenceNamingStrategy strategy = new EntityPersistenceNamingStrategy() - - when: - Optional res = strategy.getEntityName(modelClass) - - then: - res.present - res.get() == expectedString - - where: - modelClass || expectedString - RandomLoadParameters || "random_load_parameters_input" - } - def "A EntityPersistenceNamingStrategy without pre- or suffixes should return valid strings for a graphic input Model"() { given: "a naming strategy without pre- or suffixes" EntityPersistenceNamingStrategy strategy = new EntityPersistenceNamingStrategy() @@ -455,9 +412,9 @@ class EntityPersistenceNamingStrategyTest extends Specification { def "A EntityPersistenceNamingStrategy without pre- or suffix should return valid file name for load profile input" () { given: EntityPersistenceNamingStrategy strategy = new EntityPersistenceNamingStrategy() - LoadProfileInput timeSeries = Mock(LoadProfileInput) + LoadProfileTimeSeries timeSeries = Mock(LoadProfileTimeSeries) timeSeries.uuid >> uuid - timeSeries.type >> type + timeSeries.loadProfile >> type when: Optional actual = strategy.getEntityName(timeSeries) @@ -467,8 +424,8 @@ class EntityPersistenceNamingStrategyTest extends Specification { actual.get() == expectedFileName where: - clazz | uuid | type || expectedFileName - LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || "lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304" + clazz | uuid | type || expectedFileName + LoadProfileTimeSeries | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || "lpts_g3" } def "A EntityPersistenceNamingStrategy returns empty Optional, when there is no naming defined for a given time series class"() { diff --git a/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy index fceb34480..528529532 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/naming/FileNamingStrategyTest.groovy @@ -7,12 +7,11 @@ package edu.ie3.datamodel.io.naming import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation -import edu.ie3.datamodel.io.naming.timeseries.LoadProfileTimeSeriesMetaInformation +import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation import edu.ie3.datamodel.io.source.TimeSeriesMappingSource import edu.ie3.datamodel.models.UniqueEntity import edu.ie3.datamodel.models.input.MeasurementUnitInput import edu.ie3.datamodel.models.input.NodeInput -import edu.ie3.datamodel.models.input.RandomLoadParameters import edu.ie3.datamodel.models.input.connector.LineInput import edu.ie3.datamodel.models.input.connector.SwitchInput import edu.ie3.datamodel.models.input.connector.Transformer2WInput @@ -61,7 +60,7 @@ import edu.ie3.datamodel.models.result.thermal.CylindricalStorageResult import edu.ie3.datamodel.models.result.thermal.ThermalHouseResult import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries import edu.ie3.datamodel.models.value.EnergyPriceValue import edu.ie3.util.quantities.PowerSystemUnits import spock.lang.Shared @@ -199,7 +198,7 @@ class FileNamingStrategyTest extends Specification { def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffix should return valid directory path for load profile time series"() { given: def strategy = new FileNamingStrategy(simpleEntityNaming, defaultHierarchy) - def timeSeries = Mock(LoadProfileInput) + def timeSeries = Mock(LoadProfileTimeSeries) when: def actual = strategy.getDirectoryPath(timeSeries) @@ -210,7 +209,7 @@ class FileNamingStrategyTest extends Specification { where: clazz || expected - LoadProfileInput || Path.of("test_grid", "input", "global") + LoadProfileTimeSeries || Path.of("test_grid", "input", "participants", "time_series") } def "A FileNamingStrategy with DefaultHierarchy and should return valid directory path for individual time series"() { @@ -335,38 +334,6 @@ class FileNamingStrategyTest extends Specification { WecTypeInput || Path.of("test_grid", "input", "global", "wec_type_input") } - def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory path for a Load Parameter Model"() { - given: "a file naming strategy without pre- or suffixes" - def strategy = new FileNamingStrategy(simpleEntityNaming, defaultHierarchy) - - when: - def res = strategy.getDirectoryPath(modelClass) - - then: - res.present - res.get() == expectedPath - - where: - modelClass || expectedPath - RandomLoadParameters || Path.of("test_grid", "input", "global") - } - - def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file path for a Load Parameter Model"() { - given: "a file naming strategy without pre- or suffixes" - def strategy = new FileNamingStrategy(simpleEntityNaming, defaultHierarchy) - - when: - def res = strategy.getFilePath(modelClass) - - then: - res.present - res.get() == expectedPath - - where: - modelClass || expectedPath - RandomLoadParameters || Path.of("test_grid", "input", "global", "random_load_parameters_input") - } - def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid file paths for a graphic input Model"() { given: "a file naming strategy without pre- or suffixes" def strategy = new FileNamingStrategy(simpleEntityNaming, defaultHierarchy) @@ -431,9 +398,8 @@ class FileNamingStrategyTest extends Specification { def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffix should return valid file path for load profile time series"() { given: def strategy = new FileNamingStrategy(simpleEntityNaming, defaultHierarchy) - def timeSeries = Mock(LoadProfileInput) - timeSeries.uuid >> uuid - timeSeries.type >> type + def timeSeries = Mock(LoadProfileTimeSeries) + timeSeries.loadProfile >> type when: def actual = strategy.getFilePath(timeSeries) @@ -443,8 +409,8 @@ class FileNamingStrategyTest extends Specification { actual.get() == expectedFileName where: - clazz | uuid | type || expectedFileName - LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || Path.of("test_grid", "input", "global", "lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304") + clazz | type || expectedFileName + LoadProfileTimeSeries | BdewStandardLoadProfile.G3 || Path.of("test_grid", "input", "participants", "time_series", "lpts_g3") } def "A FileNamingStrategy with DefaultHierarchy and without pre- or suffixes should return valid directory path for time series mapping"() { @@ -601,14 +567,13 @@ class FileNamingStrategyTest extends Specification { where: modelClass || expected - RandomLoadParameters || Optional.empty() TimeSeriesMappingSource.MappingEntry || Optional.empty() } def "A FileNamingStrategy with FlatHierarchy does return empty sub directory path for load profile time series"() { given: "a naming strategy without pre- or suffixes" def strategy = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def timeSeries = Mock(LoadProfileInput) + def timeSeries = Mock(LoadProfileTimeSeries) when: def actual = strategy.getDirectoryPath(timeSeries) @@ -739,9 +704,8 @@ class FileNamingStrategyTest extends Specification { def "A FileNamingStrategy with FlatHierarchy does return valid file path for load profile time series"() { given: "a naming strategy without pre- or suffixes" def strategy = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def timeSeries = Mock(LoadProfileInput) - timeSeries.uuid >> uuid - timeSeries.type >> type + def timeSeries = Mock(LoadProfileTimeSeries) + timeSeries.loadProfile >> type when: def actual = strategy.getFilePath(timeSeries) @@ -751,8 +715,8 @@ class FileNamingStrategyTest extends Specification { actual.get() == expectedFilePath where: - clazz | uuid | type || expectedFilePath - LoadProfileInput | UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") | BdewStandardLoadProfile.G3 || Path.of("lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304") + clazz | type || expectedFilePath + LoadProfileTimeSeries | BdewStandardLoadProfile.G3 || Path.of("lpts_g3") } def "A FileNamingStrategy with FlatHierarchy does return valid file path for individual time series"() { @@ -798,7 +762,7 @@ class FileNamingStrategyTest extends Specification { def actual = strategy.loadProfileTimeSeriesPattern.pattern() then: - actual == "test_grid" + escapedFileSeparator + "input" + escapedFileSeparator + "global" + escapedFileSeparator + "lpts_(?[a-zA-Z][0-9])_(?[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12})" + actual == "test_grid" + escapedFileSeparator + "input" + escapedFileSeparator + "participants" + escapedFileSeparator + "time_series" + escapedFileSeparator + "lpts_(?[a-zA-Z]{1,11}[0-9]{0,3})" } def "A FileNamingStrategy with FlatHierarchy returns correct individual time series file name pattern"() { @@ -820,7 +784,7 @@ class FileNamingStrategyTest extends Specification { def actual = strategy.loadProfileTimeSeriesPattern.pattern() then: - actual == "lpts_(?[a-zA-Z][0-9])_(?[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12})" + actual == "lpts_(?[a-zA-Z]{1,11}[0-9]{0,3})" } def "Trying to extract time series meta information throws an Exception, if it is provided a malformed string"() { @@ -942,15 +906,14 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy extracts correct meta information from a valid load profile time series file name"() { given: def fns = new FileNamingStrategy(simpleEntityNaming, flatHierarchy) - def path = Path.of("/bla/foo/lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304.csv") + def path = Path.of("/bla/foo/lpts_g3.csv") when: def metaInformation = fns.timeSeriesMetaInformation(path) then: - LoadProfileTimeSeriesMetaInformation.isAssignableFrom(metaInformation.getClass()) - (metaInformation as LoadProfileTimeSeriesMetaInformation).with { - assert uuid == UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") + LoadProfileMetaInformation.isAssignableFrom(metaInformation.getClass()) + (metaInformation as LoadProfileMetaInformation).with { assert profile == "g3" } } @@ -958,15 +921,14 @@ class FileNamingStrategyTest extends Specification { def "The FileNamingStrategy extracts correct meta information from a valid load profile time series file name with pre- and suffix"() { given: def fns = new FileNamingStrategy(new EntityPersistenceNamingStrategy("prefix", "suffix"), flatHierarchy) - def path = Path.of("/bla/foo/prefix_lpts_g3_bee0a8b6-4788-4f18-bf72-be52035f7304_suffix.csv") + def path = Path.of("/bla/foo/prefix_lpts_g3_suffix.csv") when: def metaInformation = fns.timeSeriesMetaInformation(path) then: - LoadProfileTimeSeriesMetaInformation.isAssignableFrom(metaInformation.getClass()) - (metaInformation as LoadProfileTimeSeriesMetaInformation).with { - assert uuid == UUID.fromString("bee0a8b6-4788-4f18-bf72-be52035f7304") + LoadProfileMetaInformation.isAssignableFrom(metaInformation.getClass()) + (metaInformation as LoadProfileMetaInformation).with { assert profile == "g3" } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy index b5e145799..aa65e1c84 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy @@ -40,8 +40,6 @@ import edu.ie3.datamodel.models.timeseries.TimeSeries import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput import edu.ie3.datamodel.models.value.* import edu.ie3.datamodel.utils.Try import edu.ie3.test.common.TimeSeriesTestData @@ -60,7 +58,6 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData List knownEntityProcessors = [ /* InputEntity */ OperatorInput, - RandomLoadParameters, TimeSeriesMappingSource.MappingEntry, IdCoordinateInput, /* - AssetInput */ @@ -142,7 +139,6 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, HeatAndPValue), new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, SValue), new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, HeatAndSValue), - new TimeSeriesProcessorKey(LoadProfileInput, LoadProfileEntry, PValue) ] as Set when: diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy index 2dece01b2..e22ff1a99 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/input/InputEntityProcessorTest.groovy @@ -13,7 +13,6 @@ import edu.ie3.datamodel.models.StandardUnits import edu.ie3.datamodel.models.UniqueEntity import edu.ie3.datamodel.models.input.NodeInput import edu.ie3.datamodel.models.input.OperatorInput -import edu.ie3.datamodel.models.input.RandomLoadParameters import edu.ie3.datamodel.models.input.connector.LineInput import edu.ie3.datamodel.models.input.connector.SwitchInput import edu.ie3.datamodel.models.input.connector.Transformer2WInput @@ -362,43 +361,6 @@ class InputEntityProcessorTest extends Specification { actual == expected } - def "The InputEntityProcessor should serialize a provided RandomLoadParameters correctly"() { - given: - InputEntityProcessor processor = new InputEntityProcessor(RandomLoadParameters) - RandomLoadParameters parameters = new RandomLoadParameters( - UUID.fromString("a5b0f432-27b5-4b3e-b87a-61867b9edd79"), - 4, - 1.2, - 2.3, - 3.4, - 4.5, - 5.6, - 6.7, - 7.8, - 8.9, - 9.10 - ) - Map expected = [ - "uuid" : "a5b0f432-27b5-4b3e-b87a-61867b9edd79", - "quarterHour": "4", - "kWd" : "1.2", - "kSa" : "2.3", - "kSu" : "3.4", - "myWd" : "4.5", - "mySa" : "5.6", - "mySu" : "6.7", - "sigmaWd" : "7.8", - "sigmaSa" : "8.9", - "sigmaSu" : "9.1" - ] - - when: - Map actual = processor.handleEntity(parameters) - - then: - actual == expected - } - def "The InputEntityProcessor should serialize a provided WecTypeInput correctly"() { given: InputEntityProcessor processor = new InputEntityProcessor(WecTypeInput) diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy index 671482420..8c782715e 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy @@ -10,8 +10,6 @@ import edu.ie3.datamodel.io.processor.Processor import edu.ie3.datamodel.models.timeseries.IntValue import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput import edu.ie3.datamodel.models.value.* import edu.ie3.test.common.TimeSeriesTestData import spock.lang.Specification @@ -209,15 +207,4 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat then: actual == individualHeatAndSTimeSeriesProcessed } - - def "A TimeSeriesProcessors handles a complete LoadProfileInput correctly"() { - given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(LoadProfileInput, LoadProfileEntry, PValue) - - when: - Set> actual = processor.handleTimeSeries(loadProfileInput) - - then: - actual == loadProfileInputProcessed - } } diff --git a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy index c7d18de70..e6b03240c 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy @@ -236,7 +236,6 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { testBaseFolderPath.resolve("its_ph_56c20b88-c001-4225-8dac-cd13a75c6b48.csv").toFile().exists() testBaseFolderPath.resolve("its_pqh_83b577cc-06b1-47a1-bfff-ad648a00784b.csv").toFile().exists() testBaseFolderPath.resolve("its_c_a4bbcb77-b9d0-4b88-92be-b9a14a3e332b.csv").toFile().exists() - testBaseFolderPath.resolve("lpts_g2_b56853fe-b800-4c18-b324-db1878b22a28.csv").toFile().exists() testBaseFolderPath.resolve("its_weather_4fcbdfcd-4ff0-46dd-b0df-f3af7ae3ed98.csv").toFile().exists() } diff --git a/src/test/groovy/edu/ie3/test/common/TimeSeriesTestData.groovy b/src/test/groovy/edu/ie3/test/common/TimeSeriesTestData.groovy index 18e5030d3..efa2ccdea 100644 --- a/src/test/groovy/edu/ie3/test/common/TimeSeriesTestData.groovy +++ b/src/test/groovy/edu/ie3/test/common/TimeSeriesTestData.groovy @@ -18,7 +18,6 @@ import edu.ie3.datamodel.models.timeseries.TimeSeries import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry -import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileInput import edu.ie3.datamodel.models.value.* import org.locationtech.jts.geom.Coordinate import org.locationtech.jts.geom.GeometryFactory @@ -26,7 +25,6 @@ import org.locationtech.jts.geom.Point import org.locationtech.jts.geom.PrecisionModel import tech.units.indriya.quantity.Quantities -import java.time.DayOfWeek import java.time.ZoneId import java.time.ZonedDateTime @@ -401,46 +399,6 @@ trait TimeSeriesTestData { ] as LinkedHashMap ] as Set - LoadProfileInput loadProfileInput = new LoadProfileInput( - UUID.fromString("b56853fe-b800-4c18-b324-db1878b22a28"), - BdewStandardLoadProfile.G2, - [ - new LoadProfileEntry( - new PValue(Quantities.getQuantity(5d, KILOWATT)), - DayOfWeek.MONDAY, - 0 - ), - new LoadProfileEntry( - new PValue(Quantities.getQuantity(15d, KILOWATT)), - DayOfWeek.MONDAY, - 1 - ), - new LoadProfileEntry( - new PValue(Quantities.getQuantity(10d, KILOWATT)), - DayOfWeek.MONDAY, - 2 - ) - ] as Set - ) - - Set> loadProfileInputProcessed = [ - [ - "dayOfWeek" : "MONDAY", - "p" : "5.0", - "quarterHourOfDay" : "0" - ] as LinkedHashMap, - [ - "dayOfWeek" : "MONDAY", - "p" : "15.0", - "quarterHourOfDay" : "1" - ] as LinkedHashMap, - [ - "dayOfWeek" : "MONDAY", - "p" : "10.0", - "quarterHourOfDay" : "2" - ] as LinkedHashMap - ] as Set - List allTimeSeries = [ individualPTimeSeries, individualEnergyPriceTimeSeries, @@ -450,6 +408,5 @@ trait TimeSeriesTestData { individualPTimeSeries, individualSTimeSeries, individualWeatherTimeSeries, - loadProfileInput ] } \ No newline at end of file From 4c7374d6253b634c0c459f37acb92f6748fe2af3 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Tue, 4 Feb 2025 12:46:01 +0100 Subject: [PATCH 2/4] Addressing reviewers comments. --- .../io/connectors/CsvFileConnector.java | 5 +- .../datamodel/io/csv/CsvFileDefinition.java | 6 ++- .../io/naming/DatabaseNamingStrategy.java | 6 ++- .../EntityPersistenceNamingStrategy.java | 6 ++- .../io/naming/FileNamingStrategy.java | 18 ++++++-- .../io/processor/ProcessorProvider.java | 46 ++++++++++++++----- .../timeseries/TimeSeriesProcessor.java | 5 +- .../timeseries/TimeSeriesProcessorKey.java | 2 +- .../ie3/datamodel/io/sink/CsvFileSink.java | 10 ++-- .../edu/ie3/datamodel/io/sink/DataSink.java | 5 +- .../ie3/datamodel/io/sink/InfluxDbSink.java | 15 +++--- .../edu/ie3/datamodel/io/sink/SqlSink.java | 17 +++---- .../models/timeseries/TimeSeries.java | 15 +++--- .../individual/IndividualTimeSeries.java | 2 +- .../repetitive/LoadProfileTimeSeries.java | 12 ++++- .../repetitive/RepetitiveTimeSeries.java | 18 ++------ .../io/processor/ProcessorProviderTest.groovy | 10 ++-- .../timeseries/TimeSeriesProcessorTest.groovy | 28 +++++------ .../datamodel/io/sink/CsvFileSinkTest.groovy | 4 +- .../ie3/datamodel/io/sink/SqlSinkTest.groovy | 6 +-- 20 files changed, 147 insertions(+), 89 deletions(-) diff --git a/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java b/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java index 358b60739..43ce34b66 100644 --- a/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java +++ b/src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java @@ -64,7 +64,10 @@ public synchronized BufferedCsvWriter getOrInitWriter( } public synchronized < - T extends TimeSeries, E extends TimeSeriesEntry, V extends Value> + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> BufferedCsvWriter getOrInitWriter(T timeSeries, CsvFileDefinition fileDefinition) throws ConnectorException { /* Try to the right writer */ diff --git a/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java b/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java index f220f537a..fe56a4294 100644 --- a/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java +++ b/src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java @@ -68,7 +68,11 @@ public CsvFileDefinition( * @param fileNamingStrategy that should be used * @throws FileException If the definition cannot be determined */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> CsvFileDefinition( T timeSeries, String[] headLineElements, diff --git a/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java index 03a9a32d2..7e720e2d2 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/DatabaseNamingStrategy.java @@ -82,7 +82,11 @@ public Optional getEntityName(Class cls) { * @param timeSeries to be named TimeSeries * @return the table name */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> Optional getEntityName(T timeSeries) { if (timeSeries instanceof IndividualTimeSeries individualTimeSeries) { Optional maybeFirstElement = individualTimeSeries.getEntries().stream().findFirst(); diff --git a/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java index 37a070aa3..da19edf2f 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/EntityPersistenceNamingStrategy.java @@ -342,7 +342,11 @@ public Optional getTimeSeriesMappingEntityName() { * @param timeSeries Time series to derive naming information from * @return A file name for this particular time series */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> Optional getEntityName(T timeSeries) { if (timeSeries instanceof IndividualTimeSeries) { Optional maybeFirstElement = timeSeries.getEntries().stream().findFirst(); diff --git a/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java b/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java index dc3e8dc66..fd7084a60 100644 --- a/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java +++ b/src/main/java/edu/ie3/datamodel/io/naming/FileNamingStrategy.java @@ -86,7 +86,11 @@ public Optional getFilePath(Class cls) { * @param timeSeries Time series to derive naming information from * @return An optional sub path to the actual file */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> Optional getFilePath(T timeSeries) { return FileUtils.of( entityPersistenceNamingStrategy.getEntityName(timeSeries), getDirectoryPath(timeSeries)); @@ -137,7 +141,11 @@ public Optional getDirectoryPath(Class cls) { * @param timeSeries Time series to derive naming information from * @return An optional sub directory path */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> Optional getDirectoryPath(T timeSeries) { Optional maybeDirectoryName = fileHierarchy.getSubDirectory(timeSeries.getClass()); if (maybeDirectoryName.isEmpty()) { @@ -280,7 +288,11 @@ public Optional getEntityName(Class cls) { * @param timeSeries Time series to derive naming information from * @return A file name for this particular time series */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> Optional getEntityName(T timeSeries) { return entityPersistenceNamingStrategy.getEntityName(timeSeries); } diff --git a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java index 8fc1a538a..f1858c44b 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/ProcessorProvider.java @@ -41,7 +41,10 @@ public class ProcessorProvider { private final Map< TimeSeriesProcessorKey, TimeSeriesProcessor< - TimeSeries, Value>, TimeSeriesEntry, Value>> + TimeSeries, Value, Value>, + TimeSeriesEntry, + Value, + Value>> timeSeriesProcessors; /** Get an instance of this class with all existing entity processors */ @@ -62,7 +65,10 @@ public ProcessorProvider( Map< TimeSeriesProcessorKey, TimeSeriesProcessor< - TimeSeries, Value>, TimeSeriesEntry, Value>> + TimeSeries, Value, Value>, + TimeSeriesEntry, + Value, + Value>> timeSeriesProcessors) { this.entityProcessors = init(entityProcessors); this.timeSeriesProcessors = timeSeriesProcessors; @@ -120,13 +126,19 @@ private EntityProcessor getEntityProcessor(Class Type of the time series * @param Type of the time series entries * @param Type of the value inside the time series entries + * @param Type of the value, the time series will return * @return A set of mappings from field name to value */ - public , E extends TimeSeriesEntry, V extends Value> + public < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> Set> handleTimeSeries(T timeSeries) throws ProcessorProviderException { TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(timeSeries); - return Try.of(() -> this.getTimeSeriesProcessor(key), ProcessorProviderException.class) + return Try.of( + () -> this.getTimeSeriesProcessor(key), ProcessorProviderException.class) .flatMap( processor -> Try.of(() -> processor.handleTimeSeries(timeSeries), EntityProcessorException.class) @@ -141,15 +153,20 @@ Set> handleTimeSeries(T timeSeries) * @param Type of the time series * @param Type of the entry of the time series * @param Type of the entry's value + * @param Type of the value, the time series will return * @return The correct processor * @throws ProcessorProviderException If no fitting processor can be found */ @SuppressWarnings("unchecked cast") - private , E extends TimeSeriesEntry, V extends Value> - TimeSeriesProcessor getTimeSeriesProcessor(TimeSeriesProcessorKey processorKey) + private < + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> + TimeSeriesProcessor getTimeSeriesProcessor(TimeSeriesProcessorKey processorKey) throws ProcessorProviderException { - TimeSeriesProcessor processor = - (TimeSeriesProcessor) timeSeriesProcessors.get(processorKey); + TimeSeriesProcessor processor = + (TimeSeriesProcessor) timeSeriesProcessors.get(processorKey); if (processor == null) throw new ProcessorProviderException( "Cannot find processor for time series combination '" @@ -206,7 +223,11 @@ public String[] getHeaderElements(Class clazz) public String[] getHeaderElements(TimeSeriesProcessorKey processorKey) throws ProcessorProviderException { try { - TimeSeriesProcessor, Value>, TimeSeriesEntry, Value> + TimeSeriesProcessor< + TimeSeries, Value, Value>, + TimeSeriesEntry, + Value, + Value> processor = getTimeSeriesProcessor(processorKey); return processor.getHeaderElements(); } catch (ProcessorProviderException e) { @@ -287,7 +308,10 @@ public static Collection> allResultEntityProce public static Map< TimeSeriesProcessorKey, TimeSeriesProcessor< - TimeSeries, Value>, TimeSeriesEntry, Value>> + TimeSeries, Value, Value>, + TimeSeriesEntry, + Value, + Value>> allTimeSeriesProcessors() throws EntityProcessorException { try { return Try.scanStream( @@ -297,7 +321,7 @@ public static Collection> allResultEntityProce Try.of( () -> new TimeSeriesProcessor<>( - (Class, Value>>) + (Class, Value, Value>>) key.getTimeSeriesClass(), (Class>) key.getEntryClass(), (Class) key.getValueClass()), diff --git a/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java b/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java index 65edd5980..77a85e69d 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java @@ -20,7 +20,10 @@ import java.util.stream.Stream; public class TimeSeriesProcessor< - T extends TimeSeries, E extends TimeSeriesEntry, V extends Value> + T extends TimeSeries, + E extends TimeSeriesEntry, + V extends Value, + R extends Value> extends EntityProcessor { /** * List of all combinations of time series class, entry class and value class, this processor is diff --git a/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorKey.java b/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorKey.java index 44ecd18be..b76d276db 100644 --- a/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorKey.java +++ b/src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorKey.java @@ -19,7 +19,7 @@ public class TimeSeriesProcessorKey { private final Class entryClass; private final Class valueClass; - public TimeSeriesProcessorKey(TimeSeries, ?> timeSeries) { + public TimeSeriesProcessorKey(TimeSeries, ?, ?> timeSeries) { this.timeSeriesClass = timeSeries.getClass(); this.entryClass = timeSeries.getEntries().stream() diff --git a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java index 26f0801ac..4b08d00f6 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/CsvFileSink.java @@ -114,7 +114,7 @@ public void persist(T entity) { persistIncludeNested(inputEntity); } else if (entity instanceof ResultEntity) { write(entity); - } else if (entity instanceof TimeSeries timeSeries) { + } else if (entity instanceof TimeSeries timeSeries) { persistTimeSeries(timeSeries); } else { log.error( @@ -243,8 +243,8 @@ public void shutdown() { } @Override - public , V extends Value> void persistTimeSeries( - TimeSeries timeSeries) { + public , V extends Value, R extends Value> void persistTimeSeries( + TimeSeries timeSeries) { try { TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(timeSeries); String[] headerElements = csvHeaderElements(processorProvider.getHeaderElements(key)); @@ -264,8 +264,8 @@ public , V extends Value> void persis } } - private , V extends Value> void persistTimeSeries( - TimeSeries timeSeries, BufferedCsvWriter writer) throws ProcessorProviderException { + private , V extends Value, R extends Value> void persistTimeSeries( + TimeSeries timeSeries, BufferedCsvWriter writer) throws ProcessorProviderException { try { Set> entityFieldData = processorProvider.handleTimeSeries(timeSeries); diff --git a/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java b/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java index d4dca754e..553392391 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/DataSink.java @@ -61,7 +61,8 @@ public interface DataSink { * @param timeSeries Time series to persist * @param Type of entry in the time series * @param Type of actual value, that is inside the entry + * @param Type of the value, the time series will return */ - , V extends Value> void persistTimeSeries( - TimeSeries timeSeries) throws ProcessorProviderException; + , V extends Value, R extends Value> void persistTimeSeries( + TimeSeries timeSeries) throws ProcessorProviderException; } diff --git a/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java b/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java index 85255f916..80d0795d5 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/InfluxDbSink.java @@ -85,8 +85,8 @@ public void persistAll(Collection entities) } @Override - public , V extends Value> void persistTimeSeries( - TimeSeries timeSeries) throws ProcessorProviderException { + public , V extends Value, R extends Value> void persistTimeSeries( + TimeSeries timeSeries) throws ProcessorProviderException { Set points = transformToPoints(timeSeries); writeAll(points); } @@ -146,8 +146,9 @@ private Point transformToPoint(ResultEntity entity, String measurementName) * * @param timeSeries the time series to transform */ - private , V extends Value> - Set transformToPoints(TimeSeries timeSeries) throws ProcessorProviderException { + private , V extends Value, R extends Value> + Set transformToPoints(TimeSeries timeSeries) + throws ProcessorProviderException { if (timeSeries.getEntries().isEmpty()) return Collections.emptySet(); Optional measurementName = entityPersistenceNamingStrategy.getEntityName(timeSeries); @@ -169,8 +170,8 @@ Set transformToPoints(TimeSeries timeSeries) throws ProcessorProvid * @param timeSeries the time series to transform * @param measurementName equivalent to the name of a relational table */ - private , V extends Value> - Set transformToPoints(TimeSeries timeSeries, String measurementName) + private , V extends Value, R extends Value> + Set transformToPoints(TimeSeries timeSeries, String measurementName) throws ProcessorProviderException { Set points = new HashSet<>(); Set> entityFieldData = @@ -205,7 +206,7 @@ private Set extractPoints(C entity) throws ProcessorPr /* Distinguish between result models and time series */ if (entity instanceof ResultEntity resultEntity) { points.add(transformToPoint(resultEntity)); - } else if (entity instanceof TimeSeries timeSeries) { + } else if (entity instanceof TimeSeries timeSeries) { points.addAll(transformToPoints(timeSeries)); } else { log.error( diff --git a/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java b/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java index 35cdf3b9e..08d2645d8 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java @@ -129,7 +129,7 @@ public void persist(C entity, DbGridMetadata identifier) thro persistIncludeNested(inputEntity, identifier); } else if (entity instanceof ResultEntity resultEntity) { insert(resultEntity, identifier); - } else if (entity instanceof TimeSeries timeSeries) { + } else if (entity instanceof TimeSeries timeSeries) { persistTimeSeries(timeSeries, identifier); } else { log.error( @@ -186,8 +186,9 @@ private void persistMixedList(List entities, DbGridMetadat * Persist a list of entities with same types. To minimize the number of queries, the entities * will be grouped by their class. */ - private , V extends Value> void persistList( - List entities, Class cls, DbGridMetadata identifier) throws SQLException { + private , V extends Value, R extends Value> + void persistList(List entities, Class cls, DbGridMetadata identifier) + throws SQLException { // Check if there are only elements of the same class Class firstClass = entities.get(0).getClass(); boolean allSameClass = entities.stream().allMatch(e -> e.getClass() == firstClass); @@ -198,7 +199,7 @@ private , V extends Value> void p } else if (ResultEntity.class.isAssignableFrom(cls)) { insertListIgnoreNested(entities, cls, identifier, false); } else if (TimeSeries.class.isAssignableFrom(cls)) { - entities.forEach(ts -> persistTimeSeries((TimeSeries) ts, identifier)); + entities.forEach(ts -> persistTimeSeries((TimeSeries) ts, identifier)); } else { log.error("I don't know how to handle an entity of class {}", cls.getSimpleName()); } @@ -230,8 +231,8 @@ private void insertListIgnoreNested( } /** Persist one time series. */ - protected , V extends Value> void persistTimeSeries( - TimeSeries timeSeries, DbGridMetadata identifier) { + protected , V extends Value, R extends Value> void persistTimeSeries( + TimeSeries timeSeries, DbGridMetadata identifier) { try { TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(timeSeries); String[] headerElements = processorProvider.getHeaderElements(key); @@ -242,8 +243,8 @@ protected , V extends Value> void persistTimeSeries } } - private , V extends Value> void persistTimeSeries( - TimeSeries timeSeries, String[] headerElements, DbGridMetadata identifier) + private , V extends Value, R extends Value> void persistTimeSeries( + TimeSeries timeSeries, String[] headerElements, DbGridMetadata identifier) throws ProcessorProviderException { try { diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java index 62593b0ae..b42238286 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java @@ -16,8 +16,9 @@ * * @param Type of the entries, the time series is foreseen to contain * @param Type of the values, the entries will have + * @param Type of the value, the time series will return */ -public abstract class TimeSeries, V extends Value> +public abstract class TimeSeries, V extends Value, R extends Value> extends UniqueEntity { private final Set entries; @@ -36,8 +37,8 @@ protected TimeSeries(UUID uuid, Set entries) { * @param time Reference in time * @return the value at the given time step as a TimeBasedValue */ - public Optional> getTimeBasedValue(ZonedDateTime time) { - V content = getValue(time).orElse(null); + public Optional> getTimeBasedValue(ZonedDateTime time) { + R content = getValue(time).orElse(null); if (content != null) { return Optional.of(new TimeBasedValue<>(time, content)); @@ -53,7 +54,7 @@ public Optional> getTimeBasedValue(ZonedDateTime time) { * @param time Queried time * @return An option on the raw value at the given time step */ - public abstract Optional getValue(ZonedDateTime time); + public abstract Optional getValue(ZonedDateTime time); /** * Get the next earlier known time instant @@ -85,7 +86,7 @@ public Optional> getTimeBasedValue(ZonedDateTime time) { * @param time Reference in time * @return the most recent available value before or at the given time step as a TimeBasedValue */ - public Optional> getPreviousTimeBasedValue(ZonedDateTime time) { + public Optional> getPreviousTimeBasedValue(ZonedDateTime time) { return getPreviousDateTime(time).flatMap(this::getTimeBasedValue); } @@ -95,7 +96,7 @@ public Optional> getPreviousTimeBasedValue(ZonedDateTime time) * @param time Reference in time * @return the next available value after or at the given time step as a TimeBasedValue */ - public Optional> getNextTimeBasedValue(ZonedDateTime time) { + public Optional> getNextTimeBasedValue(ZonedDateTime time) { return getNextDateTime(time).flatMap(this::getTimeBasedValue); } @@ -113,7 +114,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; - TimeSeries that = (TimeSeries) o; + TimeSeries that = (TimeSeries) o; return entries.equals(that.entries); } diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/individual/IndividualTimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/individual/IndividualTimeSeries.java index a89e1a234..1ae846da3 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/individual/IndividualTimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/individual/IndividualTimeSeries.java @@ -13,7 +13,7 @@ import java.util.stream.Collectors; /** Describes a TimeSeries with individual values per time step */ -public class IndividualTimeSeries extends TimeSeries, V> { +public class IndividualTimeSeries extends TimeSeries, V, V> { /** Maps a time to its respective value to retrieve faster */ private final Map> timeToValue; diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java index 6a14a863c..ef254c35e 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java @@ -20,7 +20,7 @@ * Describes a load profile time series with repetitive values that can be calculated from a pattern */ public class LoadProfileTimeSeries - extends RepetitiveTimeSeries, PValue> { + extends RepetitiveTimeSeries, V, PValue> { private final LoadProfile loadProfile; private final Map valueMapping; @@ -64,6 +64,16 @@ public Set> getEntries() { return set; } + @Override + protected Optional getPreviousDateTime(ZonedDateTime time) { + return Optional.of(time.minusMinutes(15)); + } + + @Override + protected Optional getNextDateTime(ZonedDateTime time) { + return Optional.of(time.plusMinutes(15)); + } + @Override public List getTimeKeysAfter(ZonedDateTime time) { return List.of(time.plusMinutes(15)); // dummy value that will return next quarter-hour value diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java index c26f951f1..9338688bb 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/RepetitiveTimeSeries.java @@ -13,8 +13,8 @@ /** Describes a TimeSeries with repetitive values that can be calculated from a pattern */ public abstract class RepetitiveTimeSeries< - E extends TimeSeriesEntry, V extends Value> - extends TimeSeries { + E extends TimeSeriesEntry, V extends Value, R extends Value> + extends TimeSeries { protected RepetitiveTimeSeries(UUID uuid, Set entries) { super(uuid, entries); @@ -26,23 +26,13 @@ protected RepetitiveTimeSeries(UUID uuid, Set entries) { * @param time Questioned time * @return The value for the queried time */ - protected abstract V calc(ZonedDateTime time); + protected abstract R calc(ZonedDateTime time); @Override - public Optional getValue(ZonedDateTime time) { + public Optional getValue(ZonedDateTime time) { return Optional.ofNullable(calc(time)); } - @Override - protected Optional getPreviousDateTime(ZonedDateTime time) { - return Optional.of(time.minusHours(1)); - } - - @Override - protected Optional getNextDateTime(ZonedDateTime time) { - return Optional.of(time.plusHours(1)); - } - @Override public List getTimeKeysAfter(ZonedDateTime time) { // dummy value diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy index aa65e1c84..4f9b5c011 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/ProcessorProviderTest.groovy @@ -153,7 +153,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData ProcessorProvider provider = new ProcessorProvider([ new ResultEntityProcessor(PvResult), new ResultEntityProcessor(EvResult) - ], [] as Map, Value>, TimeSeriesEntry, Value>>) + ], [] as Map, Value, Value>, TimeSeriesEntry, Value, Value>>) when: String[] headerResults = provider.getHeaderElements(PvResult) @@ -177,7 +177,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData def "A ProcessorProvider should return the header elements for a time series key known by one of its processors and do nothing otherwise"() { given: TimeSeriesProcessorKey availableKey = new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) - Map, Value>, TimeSeriesEntry, Value>> timeSeriesProcessors = new HashMap<>() + Map, Value, Value>, TimeSeriesEntry, Value, Value>> timeSeriesProcessors = new HashMap<>() timeSeriesProcessors.put(availableKey, new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue)) ProcessorProvider provider = new ProcessorProvider([], timeSeriesProcessors) @@ -203,7 +203,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData ProcessorProvider provider = new ProcessorProvider([ new ResultEntityProcessor(PvResult), new ResultEntityProcessor(EvResult) - ], [] as Map, Value>, TimeSeriesEntry, Value>>) + ], [] as Map, Value, Value>, TimeSeriesEntry, Value, Value>>) Map expectedMap = [ "inputModel": "22bea5fc-2cb2-4c61-beb9-b476e0107f52", @@ -244,7 +244,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData def "A ProcessorProvider returns an empty Optional, if none of the assigned processors is able to handle a time series"() { given: TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) Map timeSeriesProcessorMap = new HashMap<>() timeSeriesProcessorMap.put(key, processor) ProcessorProvider provider = new ProcessorProvider([], timeSeriesProcessorMap) @@ -261,7 +261,7 @@ class ProcessorProviderTest extends Specification implements TimeSeriesTestData def "A ProcessorProvider handles a time series correctly"() { given: TimeSeriesProcessorKey key = new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) Map timeSeriesProcessorMap = new HashMap<>() timeSeriesProcessorMap.put(key, processor) ProcessorProvider provider = new ProcessorProvider([], timeSeriesProcessorMap) diff --git a/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy index 8c782715e..d551d35d0 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessorTest.groovy @@ -19,7 +19,7 @@ import java.lang.reflect.Method class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestData { def "A TimeSeriesProcessor is instantiated correctly"() { when: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) Map expectedSourceMapping = [ "price": FieldSourceToMethod.FieldSource.VALUE, "time": FieldSourceToMethod.FieldSource.ENTRY] @@ -54,7 +54,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessor throws an Exception, when the simple handle method is called"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) when: processor.handleEntity(individualEnergyPriceTimeSeries) @@ -66,7 +66,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessor correctly extracts the field name to getter map"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) when: Map actual = processor.extractFieldToMethod(source) @@ -83,7 +83,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessor handles an entry correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) Map expected = Processor.putUuidFirst([ "price": "5.0", "time" : "2020-04-02 10:00:00" @@ -100,7 +100,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with EnergyPriceValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) when: Set> actual = processor.handleTimeSeries(individualEnergyPriceTimeSeries) @@ -111,7 +111,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with TemperatureValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, TemperatureValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, TemperatureValue) when: Set> actual = processor.handleTimeSeries(individualTemperatureTimeSeries) @@ -122,7 +122,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with WindValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, WindValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, WindValue) when: Set> actual = processor.handleTimeSeries(individualWindTimeSeries) @@ -133,7 +133,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with IrradianceValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, SolarIrradianceValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, SolarIrradianceValue) when: Set> actual = processor.handleTimeSeries(individualIrradianceTimeSeries) @@ -144,7 +144,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with WeatherValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, WeatherValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, WeatherValue) when: Set> actual = processor.handleTimeSeries(individualWeatherTimeSeries) @@ -155,7 +155,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with HeatDemandValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, HeatDemandValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, HeatDemandValue) when: Set> actual = processor.handleTimeSeries(individualHeatDemandTimeSeries) @@ -166,7 +166,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with PValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, PValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, PValue) when: Set> actual = processor.handleTimeSeries(individualPTimeSeries) @@ -177,7 +177,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with HeatAndPValues correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, HeatAndPValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, HeatAndPValue) when: Set> actual = processor.handleTimeSeries(individualHeatAndPTimeSeries) @@ -188,7 +188,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with SValue correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, SValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, SValue) when: Set> actual = processor.handleTimeSeries(individualSTimeSeries) @@ -199,7 +199,7 @@ class TimeSeriesProcessorTest extends Specification implements TimeSeriesTestDat def "A TimeSeriesProcessors handles a complete time series with HeatAndSValue correctly"() { given: - TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, HeatAndSValue) + TimeSeriesProcessor processor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, HeatAndSValue) when: Set> actual = processor.handleTimeSeries(individualHeatAndSTimeSeries) diff --git a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy index e6b03240c..4b2be267b 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/sink/CsvFileSinkTest.groovy @@ -199,7 +199,7 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { def "A valid CsvFileSink should persist a time series correctly"() { given: - TimeSeriesProcessor timeSeriesProcessor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor timeSeriesProcessor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) TimeSeriesProcessorKey timeSeriesProcessorKey = new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) HashMap timeSeriesProcessorMap = new HashMap<>() timeSeriesProcessorMap.put(timeSeriesProcessorKey, timeSeriesProcessor) @@ -315,7 +315,7 @@ class CsvFileSinkTest extends Specification implements TimeSeriesTestData { testBaseFolderPath, new ProcessorProvider( ProcessorProvider.allEntityProcessors(), - new HashMap, Value>, TimeSeriesEntry, Value>>()), + new HashMap, Value, Value>, TimeSeriesEntry, Value, Value>>()), new FileNamingStrategy(), ",") diff --git a/src/test/groovy/edu/ie3/datamodel/io/sink/SqlSinkTest.groovy b/src/test/groovy/edu/ie3/datamodel/io/sink/SqlSinkTest.groovy index 67e5065e4..db8828495 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/sink/SqlSinkTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/sink/SqlSinkTest.groovy @@ -101,7 +101,7 @@ class SqlSinkTest extends Specification implements TestContainerHelper, TimeSeri def "SQL sink can persist provided elements correctly"() { given: - TimeSeriesProcessor timeSeriesProcessor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor timeSeriesProcessor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) TimeSeriesProcessorKey timeSeriesProcessorKey = new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) HashMap timeSeriesProcessorMap = new HashMap<>() timeSeriesProcessorMap.put(timeSeriesProcessorKey, timeSeriesProcessor) @@ -167,7 +167,7 @@ class SqlSinkTest extends Specification implements TestContainerHelper, TimeSeri def "A SqlSink can persist a time series."() { given: - TimeSeriesProcessor timeSeriesProcessor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) + TimeSeriesProcessor timeSeriesProcessor = new TimeSeriesProcessor<>(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) TimeSeriesProcessorKey timeSeriesProcessorKey = new TimeSeriesProcessorKey(IndividualTimeSeries, TimeBasedValue, EnergyPriceValue) HashMap timeSeriesProcessorMap = new HashMap<>() timeSeriesProcessorMap.put(timeSeriesProcessorKey, timeSeriesProcessor) @@ -244,7 +244,7 @@ class SqlSinkTest extends Specification implements TestContainerHelper, TimeSeri schemaName, new ProcessorProvider( ProcessorProvider.allEntityProcessors(), - new HashMap, Value>, TimeSeriesEntry, Value>>()), + new HashMap, Value, Value>, TimeSeriesEntry, Value, Value>>()), namingStrategy, connector) From a6301d594a8e2cbbf4281c3acc8ed61e17e030d9 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Tue, 4 Feb 2025 13:03:26 +0100 Subject: [PATCH 3/4] Fixing `InfluxDbSinkIT` test. --- src/test/groovy/edu/ie3/datamodel/io/sink/InfluxDbSinkIT.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/edu/ie3/datamodel/io/sink/InfluxDbSinkIT.groovy b/src/test/groovy/edu/ie3/datamodel/io/sink/InfluxDbSinkIT.groovy index 7939b4dc9..b79f62336 100644 --- a/src/test/groovy/edu/ie3/datamodel/io/sink/InfluxDbSinkIT.groovy +++ b/src/test/groovy/edu/ie3/datamodel/io/sink/InfluxDbSinkIT.groovy @@ -273,7 +273,7 @@ class InfluxDbSinkIT extends Specification { } @Override - , E extends TimeSeriesEntry, V extends Value> Optional getEntityName(T timeSeries) { + , E extends TimeSeriesEntry, V extends Value, R extends Value> Optional getEntityName(T timeSeries) { return Optional.empty() } } From 8ad0a663fc9285ec1e8a65c23b790dc2ccdc62d3 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Thu, 6 Feb 2025 10:41:14 +0100 Subject: [PATCH 4/4] Fixing sonarqube issues. --- .../factory/timeseries/LoadProfileData.java | 22 +++++++ .../timeseries/LoadProfileFactory.java | 60 +++++++++++++++++++ .../edu/ie3/datamodel/io/sink/SqlSink.java | 19 +++--- .../SqlTimeSeriesMetaInformationSource.java | 2 +- .../repetitive/LoadProfileTimeSeries.java | 8 +-- 5 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileData.java create mode 100644 src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileFactory.java diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileData.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileData.java new file mode 100644 index 000000000..abdb140b3 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileData.java @@ -0,0 +1,22 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.factory.timeseries; + +import edu.ie3.datamodel.io.factory.FactoryData; +import edu.ie3.datamodel.models.value.load.LoadValues; +import java.util.Map; + +/** + * Data, that is used to build a {@link + * edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry} within a factory + * + * @param Type of load values class + */ +public class LoadProfileData extends FactoryData { + public LoadProfileData(Map fieldsToAttributes, Class targetClass) { + super(fieldsToAttributes, targetClass); + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileFactory.java new file mode 100644 index 000000000..f2b511eef --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileFactory.java @@ -0,0 +1,60 @@ +/* + * © 2024. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.factory.timeseries; + +import edu.ie3.datamodel.io.factory.Factory; +import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation; +import edu.ie3.datamodel.models.profile.LoadProfile; +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry; +import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries; +import edu.ie3.datamodel.models.value.load.LoadValues; +import edu.ie3.util.quantities.PowerSystemUnits; +import java.util.Set; +import javax.measure.quantity.Energy; +import javax.measure.quantity.Power; +import tech.units.indriya.ComparableQuantity; +import tech.units.indriya.quantity.Quantities; + +/** + * Base factory for all {@link LoadProfileTimeSeries}. + * + * @param

type of load profile + * @param type of load values + */ +public abstract class LoadProfileFactory

+ extends Factory, LoadProfileEntry> { + protected static final String QUARTER_HOUR = "quarterHour"; + + public LoadProfileFactory(Class valueClass) { + super(valueClass); + } + + public abstract LoadProfileTimeSeries build( + LoadProfileMetaInformation metaInformation, Set> entries); + + public abstract P parseProfile(String profile); + + /** + * Calculates the maximum average power consumption per quarter-hour for a given calculated over + * all seasons and weekday types of given load profile + * + * @param loadProfile given load profile + * @param entries with power values + * @return the maximal average power + */ + public abstract ComparableQuantity calculateMaxPower( + P loadProfile, Set> entries); + + /** Returns the quarter-hour field. */ + public String getTimeFieldString() { + return QUARTER_HOUR; + } + + /** Returns the load profile energy scaling. The default value is 1000 kWh */ + public ComparableQuantity getLoadProfileEnergyScaling(P loadProfile) { + return Quantities.getQuantity(1000, PowerSystemUnits.KILOWATTHOUR); + } +} diff --git a/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java b/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java index 08d2645d8..ea99d17a3 100644 --- a/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java +++ b/src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java @@ -400,10 +400,8 @@ private static String basicInsertQuery(String schemaName, String tableName) { private String basicInsertQueryValuesGrid( String schemaName, String tableName, String[] headerElements) { String[] addParams = {DbGridMetadata.GRID_UUID_COLUMN}; - return basicInsertQuery(schemaName, tableName) - + " " - + writeOneLine(StringUtils.camelCaseToSnakeCase(headerElements), addParams) - + "\nVALUES\n"; + return basicInsertQueryWith( + schemaName, tableName, StringUtils.camelCaseToSnakeCase(headerElements), addParams); } /** @@ -413,16 +411,21 @@ private String basicInsertQueryValuesGrid( private String basicInsertQueryValuesITS( String schemaName, String tableName, String[] headerElements) { String[] addParams = {DbGridMetadata.GRID_UUID_COLUMN, TIME_SERIES}; - return basicInsertQuery(schemaName, tableName) - + " " - + writeOneLine(StringUtils.camelCaseToSnakeCase(headerElements), addParams) - + "\nVALUES\n"; + return basicInsertQueryWith( + schemaName, tableName, StringUtils.camelCaseToSnakeCase(headerElements), addParams); } /** Provides the insert, column names, grid identifier, and the VALUES statement for a query. */ private String basicInsertQueryValuesLPTS( String schemaName, String tableName, String[] headerElements) { String[] addParams = {DbGridMetadata.GRID_UUID_COLUMN, LOAD_PROFILE}; + return basicInsertQueryWith( + schemaName, tableName, StringUtils.camelCaseToSnakeCase(headerElements), addParams); + } + + /** Provides the insert, column names, grid identifier, and the VALUES statement for a query */ + private String basicInsertQueryWith( + String schemaName, String tableName, String[] headerElements, String[] addParams) { return basicInsertQuery(schemaName, tableName) + " " + writeOneLine(StringUtils.camelCaseToSnakeCase(headerElements), addParams) diff --git a/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java b/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java index ad372d2fd..7d05bb462 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesMetaInformationSource.java @@ -96,7 +96,7 @@ private Optional createEntity( new EntityData(fieldToValues, IndividualTimeSeriesMetaInformation.class); return mappingFactory .get(entityData) - .map(meta -> (IndividualTimeSeriesMetaInformation) meta) + .map(IndividualTimeSeriesMetaInformation.class::cast) .getData(); } } diff --git a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java index ef254c35e..3de25d9c2 100644 --- a/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java +++ b/src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileTimeSeries.java @@ -28,17 +28,17 @@ public class LoadProfileTimeSeries * The maximum average power consumption per quarter-hour for a given calculated over all seasons * and weekday types of given load profile. */ - public final Optional> maxPower; + public final ComparableQuantity maxPower; /** The profile energy scaling in kWh. */ - public final Optional> profileEnergyScaling; + public final ComparableQuantity profileEnergyScaling; public LoadProfileTimeSeries( UUID uuid, LoadProfile loadProfile, Set> entries, - Optional> maxPower, - Optional> profileEnergyScaling) { + ComparableQuantity maxPower, + ComparableQuantity profileEnergyScaling) { super(uuid, entries); this.loadProfile = loadProfile; this.valueMapping =