Skip to content

Commit 9af34b1

Browse files
Merge pull request #1183 from ie3-institute/ms/#1182-add-getPreviousValue-to-TimeSeriesSource
Enhance `TimeSeriesSource` with method to retrieve the previous value before a given key.
2 parents a1ab6f5 + d0fe103 commit 9af34b1

File tree

10 files changed

+96
-15
lines changed

10 files changed

+96
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Adding timeseries for voltage values [#1128](https://github.com/ie3-institute/PowerSystemDataModel/issues/1128)
1313
- Added Staudt to list of reviewers [#1190](https://github.com/ie3-institute/PowerSystemDataModel/issues/1190)
1414
- Extend ValidationUtils for validating ThermalGrids [#1216](https://github.com/ie3-institute/PowerSystemDataModel/issues/1216)
15+
- Enhance `TimeSeriesSource` with method to retrieve the previous value before a given key [#1182](https://github.com/ie3-institute/PowerSystemDataModel/issues/1182)
1516

1617
### Fixed
1718
- Removing opened `SwitchInput` during connectivity check [#1221](https://github.com/ie3-institute/PowerSystemDataModel/issues/1221)

src/main/java/edu/ie3/datamodel/io/source/TimeSeriesSource.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ protected Try<TimeBasedValue<V>, FactoryException> createTimeBasedValue(
5050
public abstract IndividualTimeSeries<V> getTimeSeries(ClosedInterval<ZonedDateTime> timeInterval)
5151
throws SourceException;
5252

53-
public abstract Optional<V> getValue(ZonedDateTime time) throws SourceException;
53+
public abstract Optional<V> getValue(ZonedDateTime time);
54+
55+
public abstract Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time);
5456

5557
/**
5658
* Method to return all time keys after a given timestamp.

src/main/java/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSource.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,15 @@ public Optional<V> getValue(ZonedDateTime time) {
128128
return timeSeries.getValue(time);
129129
}
130130

131+
@Override
132+
public Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time) {
133+
return timeSeries.getPreviousTimeBasedValue(time);
134+
}
135+
136+
public Optional<TimeBasedValue<V>> getNextTimeBasedValue(ZonedDateTime time) {
137+
return timeSeries.getNextTimeBasedValue(time);
138+
}
139+
131140
@Override
132141
public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
133142
return timeSeries.getTimeKeysAfter(time);

src/main/java/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesSource.java

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public class SqlTimeSeriesSource<V extends Value> extends TimeSeriesSource<V> {
4848

4949
private final String queryTimeInterval;
5050
private final String queryTimeKeysAfter;
51+
private final String queryForValueBefore;
5152
private final String queryTime;
5253

5354
public SqlTimeSeriesSource(
@@ -63,15 +64,16 @@ public SqlTimeSeriesSource(
6364
final ColumnScheme columnScheme = ColumnScheme.parse(valueClass).orElseThrow();
6465
this.tableName = sqlDataSource.databaseNamingStrategy.getTimeSeriesEntityName(columnScheme);
6566

67+
String schemaName = sqlDataSource.schemaName;
68+
6669
String dbTimeColumnName =
6770
sqlDataSource.getDbColumnName(factory.getTimeFieldString(), tableName);
6871

69-
this.queryFull = createQueryFull(sqlDataSource.schemaName, tableName);
70-
this.queryTimeInterval =
71-
createQueryForTimeInterval(sqlDataSource.schemaName, tableName, dbTimeColumnName);
72-
this.queryTimeKeysAfter =
73-
createQueryForTimeKeysAfter(sqlDataSource.schemaName, tableName, dbTimeColumnName);
74-
this.queryTime = createQueryForTime(sqlDataSource.schemaName, tableName, dbTimeColumnName);
72+
this.queryFull = createQueryFull(schemaName, tableName);
73+
this.queryTimeInterval = createQueryForTimeInterval(schemaName, tableName, dbTimeColumnName);
74+
this.queryTimeKeysAfter = createQueryForTimeKeysAfter(schemaName, tableName, dbTimeColumnName);
75+
this.queryForValueBefore = createQueryForValueBefore(schemaName, tableName, dbTimeColumnName);
76+
this.queryTime = createQueryForTime(schemaName, tableName, dbTimeColumnName);
7577
}
7678

7779
/**
@@ -179,6 +181,14 @@ public Optional<V> getValue(ZonedDateTime time) {
179181
return Optional.of(timeBasedValues.stream().toList().get(0).getValue());
180182
}
181183

184+
@Override
185+
public Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time) {
186+
return getTimeBasedValueSet(
187+
queryForValueBefore, ps -> ps.setTimestamp(1, Timestamp.from(time.toInstant())))
188+
.stream()
189+
.max(TimeBasedValue::compareTo);
190+
}
191+
182192
@Override
183193
public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
184194
return dataSource
@@ -278,8 +288,30 @@ private String createQueryForTimeKeysAfter(
278288
}
279289

280290
/**
281-
* Creates a basic query to retrieve an entry for the given time series uuid and time with the
282-
* following pattern: <br>
291+
* Creates a base query to retrieve all time keys after a given time for given time series with
292+
* the following pattern: <br>
293+
* {@code <base query> WHERE time_series = $timeSeriesUuid AND <time column> < ?;}
294+
*
295+
* @param schemaName the name of the database schema
296+
* @param tableName the name of the database table
297+
* @param timeColumnName the name of the column holding the timestamp info
298+
* @return the query string
299+
*/
300+
private String createQueryForValueBefore(
301+
String schemaName, String tableName, String timeColumnName) {
302+
return createBaseQueryString(schemaName, tableName)
303+
+ WHERE
304+
+ TIME_SERIES
305+
+ " = '"
306+
+ timeSeriesUuid.toString()
307+
+ "' AND "
308+
+ timeColumnName
309+
+ " < ?"
310+
+ "ORDER BY time DESC LIMIT 1;";
311+
}
312+
/**
313+
* Creates a base query to retrieve all time keys before a given time for given time series with
314+
* the following pattern: <br>
283315
* {@code <base query> WHERE time_series = $timeSeriesUuid AND <time column>=?;}
284316
*
285317
* @param schemaName the name of the database schema

src/main/java/edu/ie3/datamodel/models/timeseries/individual/IndividualTimeSeries.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ public Optional<V> getValue(ZonedDateTime time) {
5555
@Override
5656
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
5757
return timeToValue.keySet().stream()
58-
.filter(valueTime -> valueTime.compareTo(time) <= 0)
58+
.filter(valueTime -> valueTime.compareTo(time) < 0)
5959
.max(Comparator.naturalOrder());
6060
}
6161

6262
@Override
6363
protected Optional<ZonedDateTime> getNextDateTime(ZonedDateTime time) {
6464
return timeToValue.keySet().stream()
65-
.filter(valueTime -> valueTime.compareTo(time) >= 0)
65+
.filter(valueTime -> valueTime.compareTo(time) > 0)
6666
.min(Comparator.naturalOrder());
6767
}
6868

src/main/java/edu/ie3/datamodel/models/timeseries/repetitive/LoadProfileInput.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ public PValue calc(ZonedDateTime time) {
4242
@Override
4343
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
4444
// dummy value
45-
return Optional.of(time.minusHours(1));
45+
return Optional.of(time.minusMinutes(15));
4646
}
4747

4848
@Override
4949
protected Optional<ZonedDateTime> getNextDateTime(ZonedDateTime time) {
5050
// dummy value
51-
return Optional.of(time.plusHours(1));
51+
return Optional.of(time.plusMinutes(15));
5252
}
5353

5454
@Override

src/test/groovy/edu/ie3/datamodel/io/source/csv/CsvTimeSeriesSourceIT.groovy

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,24 @@ class CsvTimeSeriesSourceIT extends Specification implements CsvTestDataMeta {
8585
actual.present
8686
actual.get() == PH_VALUE_15MIN
8787
}
88+
89+
def "A csv time series source is able to return the previous value for a given time"() {
90+
when:
91+
def actual = source.getPreviousTimeBasedValue(TIME_15MIN)
92+
93+
then:
94+
actual.isPresent()
95+
actual.get().time == TIME_00MIN
96+
actual.get().value == PH_VALUE_00MIN
97+
}
98+
99+
def "A csv time series source is able to return the next value for a given time"() {
100+
when:
101+
def actual = source.getNextTimeBasedValue(TIME_00MIN)
102+
103+
then:
104+
actual.isPresent()
105+
actual.get().time == TIME_15MIN
106+
actual.get().value == PH_VALUE_15MIN
107+
}
88108
}

src/test/groovy/edu/ie3/datamodel/io/source/sql/SqlTimeSeriesSourceIT.groovy

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import edu.ie3.datamodel.io.connectors.SqlConnector
1212
import edu.ie3.datamodel.io.naming.DatabaseNamingStrategy
1313
import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme
1414
import edu.ie3.datamodel.io.naming.timeseries.IndividualTimeSeriesMetaInformation
15+
import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue
1516
import edu.ie3.datamodel.models.value.*
1617
import edu.ie3.test.helper.TestContainerHelper
1718
import edu.ie3.util.TimeUtil
@@ -123,6 +124,21 @@ class SqlTimeSeriesSourceIT extends Specification implements TestContainerHelper
123124
value.get() == P_VALUE_00MIN
124125
}
125126

127+
def "A SqlTimeSeriesSource is able to return the previous value for a given time"() {
128+
when:
129+
def actual = pSource.getPreviousTimeBasedValue(time)
130+
131+
then:
132+
actual.isPresent() == expectedResult.isPresent()
133+
actual == expectedResult
134+
135+
where:
136+
time | expectedResult
137+
TIME_00MIN | Optional.empty()
138+
TIME_15MIN | Optional.of(new TimeBasedValue<>(TIME_00MIN, P_VALUE_00MIN))
139+
TIME_30MIN | Optional.of(new TimeBasedValue<>(TIME_15MIN, P_VALUE_15MIN))
140+
}
141+
126142
def "A SqlTimeSeriesSource can read multiple time series values for a time interval"() {
127143
given:
128144
def timeInterval = new ClosedInterval(TIME_00MIN, TIME_15MIN)

src/test/groovy/edu/ie3/datamodel/models/timeseries/IndividualTimeSeriesTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class IndividualTimeSeriesTest extends Specification implements TimeSeriesTestDa
7272
Optional<TimeBasedValue<IntValue>> expected = Optional.of(new TimeBasedValue<>(ZonedDateTime.of(1990, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")), new IntValue(3)))
7373

7474
when:
75-
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getPreviousTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")))
75+
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getPreviousTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 5, 0, 0, ZoneId.of("UTC")))
7676

7777
then:
7878
expected.present
@@ -103,7 +103,7 @@ class IndividualTimeSeriesTest extends Specification implements TimeSeriesTestDa
103103
Optional<TimeBasedValue<IntValue>> expected = Optional.of(new TimeBasedValue<>(ZonedDateTime.of(1990, 1, 1, 0, 15, 0, 0, ZoneId.of("UTC")), new IntValue(4)))
104104

105105
when:
106-
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getNextTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 15, 0, 0, ZoneId.of("UTC")))
106+
Optional<TimeBasedValue<IntValue>> actual = individualIntTimeSeries.getNextTimeBasedValue(ZonedDateTime.of(1990, 1, 1, 0, 10, 0, 0, ZoneId.of("UTC")))
107107

108108
then:
109109
expected.present

src/test/groovy/edu/ie3/test/common/TimeSeriesSourceTestData.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ final class TimeSeriesSourceTestData {
2020

2121
public static final ZonedDateTime TIME_00MIN = ZonedDateTime.parse("2020-01-01T00:00:00Z")
2222
public static final ZonedDateTime TIME_15MIN = ZonedDateTime.parse("2020-01-01T00:15:00Z")
23+
public static final ZonedDateTime TIME_30MIN = ZonedDateTime.parse("2020-01-01T00:30:00Z")
2324

2425
public static final PValue P_VALUE_00MIN = new PValue(
2526
Quantities.getQuantity(1000.0d, StandardUnits.ACTIVE_POWER_IN)

0 commit comments

Comments
 (0)