diff --git a/CHANGELOG.md b/CHANGELOG.md index 288162525..63fa6a8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased/Snapshot] ### Added +- Enhance `TimeSeriesSource` with method to retrieve all time keys after a given key [#543](https://github.com/ie3-institute/PowerSystemDataModel/issues/543) +- Enhance `WeatherSource` with method to retrieve all time keys after a given key [#572](https://github.com/ie3-institute/PowerSystemDataModel/issues/572) ### Fixed diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/CosmoTimeBasedWeatherValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/CosmoTimeBasedWeatherValueFactory.java index f70d3dfd3..09048fb89 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/CosmoTimeBasedWeatherValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/CosmoTimeBasedWeatherValueFactory.java @@ -45,11 +45,6 @@ public CosmoTimeBasedWeatherValueFactory() { super(); } - @Override - public String getTimeFieldString() { - return TIME; - } - @Override protected List> getFields(Class entityClass) { Set minConstructorParams = diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/IconTimeBasedWeatherValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/IconTimeBasedWeatherValueFactory.java index c6833cf86..189e40c57 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/IconTimeBasedWeatherValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/IconTimeBasedWeatherValueFactory.java @@ -42,11 +42,6 @@ public IconTimeBasedWeatherValueFactory(DateTimeFormatter dateTimeFormatter) { super(dateTimeFormatter); } - @Override - public String getTimeFieldString() { - return TIME; - } - @Override protected List> getFields(Class entityClass) { Set minParameters = diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java index ecbc89dd5..ab128d1e6 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedSimpleValueFactory.java @@ -11,7 +11,6 @@ import edu.ie3.datamodel.models.StandardUnits; import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue; import edu.ie3.datamodel.models.value.*; -import edu.ie3.util.TimeUtil; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -26,26 +25,13 @@ public class TimeBasedSimpleValueFactory private static final String REACTIVE_POWER = "q"; private static final String HEAT_DEMAND = "heatDemand"; - private final TimeUtil timeUtil; - public TimeBasedSimpleValueFactory(Class valueClasses) { super(valueClasses); - this.timeUtil = TimeUtil.withDefaults; } public TimeBasedSimpleValueFactory( Class valueClasses, DateTimeFormatter dateTimeFormatter) { - super(valueClasses); - this.timeUtil = new TimeUtil(dateTimeFormatter); - } - - /** - * Return the field name for the date time - * - * @return the field name for the date time - */ - public String getTimeFieldString() { - return TIME; + super(valueClasses, dateTimeFormatter); } @Override diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedValueFactory.java index 9fa785ae6..724ac2c24 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedValueFactory.java @@ -8,6 +8,10 @@ import edu.ie3.datamodel.io.factory.Factory; import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue; import edu.ie3.datamodel.models.value.Value; +import edu.ie3.util.TimeUtil; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; /** * Abstract class that is able to build {@link TimeBasedValue}s from "flat" information @@ -18,7 +22,52 @@ public abstract class TimeBasedValueFactory, V extends Value> extends Factory> { + protected static final String TIME = "time"; + + protected final TimeUtil timeUtil; + protected TimeBasedValueFactory(Class... valueClasses) { super(valueClasses); + this.timeUtil = TimeUtil.withDefaults; + } + + protected TimeBasedValueFactory( + Class valueClasses, DateTimeFormatter dateTimeFormatter) { + super(valueClasses); + this.timeUtil = new TimeUtil(dateTimeFormatter); + } + + protected TimeBasedValueFactory(Class valueClasses, TimeUtil timeUtil) { + super(valueClasses); + this.timeUtil = timeUtil; + } + + /** + * Return the field name for the date time + * + * @return the field name for the date time + */ + public String getTimeFieldString() { + return TIME; + } + + /** + * Method to extract a time string from a given map and convert into a {@link ZonedDateTime}. + * + * @param fieldsToAttributes map with time field + * @return a {@link ZonedDateTime} + */ + public ZonedDateTime extractTime(Map fieldsToAttributes) { + return toZonedDateTime(fieldsToAttributes.get(getTimeFieldString())); + } + + /** + * Method to convert a given string into a {@link ZonedDateTime}. + * + * @param time string to convert + * @return a {@link ZonedDateTime} + */ + public ZonedDateTime toZonedDateTime(String time) { + return timeUtil.toZonedDateTime(time); } } diff --git a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedWeatherValueFactory.java b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedWeatherValueFactory.java index b83d4dd97..c281dd270 100644 --- a/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedWeatherValueFactory.java +++ b/src/main/java/edu/ie3/datamodel/io/factory/timeseries/TimeBasedWeatherValueFactory.java @@ -15,24 +15,18 @@ */ public abstract class TimeBasedWeatherValueFactory extends TimeBasedValueFactory { - protected static final String TIME = "time"; protected static final String COORDINATE_ID = "coordinateId"; - protected final TimeUtil timeUtil; - protected TimeBasedWeatherValueFactory() { super(WeatherValue.class); - this.timeUtil = TimeUtil.withDefaults; } protected TimeBasedWeatherValueFactory(DateTimeFormatter dateTimeFormatter) { - super(WeatherValue.class); - this.timeUtil = new TimeUtil(dateTimeFormatter); + super(WeatherValue.class, dateTimeFormatter); } protected TimeBasedWeatherValueFactory(TimeUtil timeUtil) { - super(WeatherValue.class); - this.timeUtil = timeUtil; + super(WeatherValue.class, timeUtil); } /** @@ -43,11 +37,4 @@ protected TimeBasedWeatherValueFactory(TimeUtil timeUtil) { public String getCoordinateIdFieldString() { return COORDINATE_ID; } - - /** - * Return the field name for the date time - * - * @return the field name for the date time - */ - public abstract String getTimeFieldString(); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesSource.java b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesSource.java index 994f0f440..a9ade054e 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/TimeSeriesSource.java @@ -51,4 +51,12 @@ public abstract IndividualTimeSeries getTimeSeries(ClosedInterval getValue(ZonedDateTime time) throws SourceException; + + /** + * Method to return all time keys after a given timestamp. + * + * @param time given time + * @return a list of time keys + */ + public abstract List getTimeKeysAfter(ZonedDateTime time); } diff --git a/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java b/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java index 959613b7c..a7a056d85 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/WeatherSource.java @@ -18,6 +18,7 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.tuple.Pair; import org.locationtech.jts.geom.Point; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,8 +30,6 @@ public abstract class WeatherSource extends EntitySource { protected TimeBasedWeatherValueFactory weatherFactory; - protected Map> coordinateToTimeSeries; - protected IdCoordinateSource idCoordinateSource; protected static final String COORDINATE_ID = "coordinateid"; @@ -65,6 +64,14 @@ public abstract Map> getWeather( public abstract Optional> getWeather( ZonedDateTime date, Point coordinate) throws SourceException; + public abstract Map> getTimeKeysAfter(ZonedDateTime time) + throws SourceException; + + public List getTimeKeysAfter(ZonedDateTime time, Point coordinate) + throws SourceException { + return getTimeKeysAfter(time).getOrDefault(coordinate, Collections.emptyList()); + } + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- /** @@ -111,6 +118,37 @@ protected Map> mapWeatherValuesToPoint return coordinateToTimeSeriesMap; } + protected Map> toTimeKeys( + Stream> fieldMaps, TimeBasedWeatherValueFactory factory) { + return groupTime( + fieldMaps.map( + fieldMap -> { + String coordinateValue = fieldMap.get(COORDINATE_ID); + int coordinateId = Integer.parseInt(coordinateValue); + Optional coordinate = idCoordinateSource.getCoordinate(coordinateId); + ZonedDateTime time = factory.extractTime(fieldMap); + + if (coordinate.isEmpty()) { + log.warn("Unable to match coordinate ID {} to a point", coordinateId); + } + return Pair.of(coordinate, time); + })); + } + + protected Map> groupTime( + Stream, ZonedDateTime>> values) { + return values + .filter(pair -> pair.getKey().isPresent()) + .map(pair -> Pair.of(pair.getKey().get(), pair.getValue())) + .collect(Collectors.groupingBy(Pair::getKey, Collectors.toSet())) + .entrySet() + .stream() + .collect( + Collectors.toMap( + Map.Entry::getKey, + e -> e.getValue().stream().map(Pair::getValue).sorted().toList())); + } + // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- /** diff --git a/src/main/java/edu/ie3/datamodel/io/source/couchbase/CouchbaseWeatherSource.java b/src/main/java/edu/ie3/datamodel/io/source/couchbase/CouchbaseWeatherSource.java index 74732dbb0..8dc56cafe 100644 --- a/src/main/java/edu/ie3/datamodel/io/source/couchbase/CouchbaseWeatherSource.java +++ b/src/main/java/edu/ie3/datamodel/io/source/couchbase/CouchbaseWeatherSource.java @@ -25,6 +25,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; import org.locationtech.jts.geom.Point; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -165,6 +166,37 @@ public Optional> getWeather(ZonedDateTime date, Poi } } + @Override + public Map> getTimeKeysAfter(ZonedDateTime time) { + String query = createQueryStringForFollowingTimeKeys(time); + CompletableFuture futureResult = connector.query(query); + QueryResult queryResult = futureResult.join(); + List jsonWeatherInputs = Collections.emptyList(); + try { + jsonWeatherInputs = queryResult.rowsAsObject(); + } catch (DecodingFailureException ex) { + logger.error("Querying weather inputs failed!", ex); + } + if (jsonWeatherInputs != null && !jsonWeatherInputs.isEmpty()) { + return groupTime( + jsonWeatherInputs.stream() + .map( + json -> { + int coordinateId = json.getInt(COORDINATE_ID); + Optional coordinate = idCoordinateSource.getCoordinate(coordinateId); + ZonedDateTime timestamp = + weatherFactory.toZonedDateTime( + json.getString(weatherFactory.getTimeFieldString())); + if (coordinate.isEmpty()) { + log.warn("Unable to match coordinate ID {} to a point", coordinateId); + } + return Pair.of(coordinate, timestamp); + }) + .filter(value -> value.getValue().isAfter(time))); + } + return Collections.emptyMap(); + } + /** * Generates a key for weather documents with the pattern: {@code * weather::::