Skip to content

Commit ea8514a

Browse files
Merge pull request #1281 from ie3-institute/ms/#1280-enhance-value-retrieval-in-TimeSeriesSource
Enhancing value retrieval in `TimeSeriesSource`.
2 parents de620b0 + c91f559 commit ea8514a

File tree

9 files changed

+108
-5
lines changed

9 files changed

+108
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
### Added
1010
- Enhanced check for invalid field names in sources [#1383](https://github.com/ie3-institute/PowerSystemDataModel/issues/1383)
11+
- Enhancing value retrieval in `TimeSeriesSource` [1280](https://github.com/ie3-institute/PowerSystemDataModel/issues/1280)
1112

1213
### Fixed
1314

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,22 @@ public abstract IndividualTimeSeries<V> getTimeSeries(ClosedInterval<ZonedDateTi
5252

5353
public abstract Optional<V> getValue(ZonedDateTime time);
5454

55+
/**
56+
* Method to retrieve the value of the given time or the last timestamp before the given time.
57+
*
58+
* @param time given time
59+
* @return an option for a value
60+
*/
61+
public Optional<V> getValueOrLast(ZonedDateTime time) {
62+
Optional<V> value = getValue(time);
63+
64+
if (value.isEmpty()) {
65+
return getPreviousTimeBasedValue(time).map(TimeBasedValue::getValue);
66+
}
67+
68+
return value;
69+
}
70+
5571
public abstract Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time);
5672

5773
/**
@@ -61,4 +77,12 @@ public abstract IndividualTimeSeries<V> getTimeSeries(ClosedInterval<ZonedDateTi
6177
* @return a list of time keys
6278
*/
6379
public abstract List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time);
80+
81+
/**
82+
* Method to return all last known time keys before a given timestamp.
83+
*
84+
* @param time given time
85+
* @return an option for the time key
86+
*/
87+
public abstract Optional<ZonedDateTime> getLastTimeKeyBefore(ZonedDateTime time);
6488
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
142142
return timeSeries.getTimeKeysAfter(time);
143143
}
144144

145+
@Override
146+
public Optional<ZonedDateTime> getLastTimeKeyBefore(ZonedDateTime time) {
147+
return timeSeries.getPreviousDateTime(time);
148+
}
149+
145150
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
146151

147152
/**

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
199199
.toList();
200200
}
201201

202+
@Override
203+
public Optional<ZonedDateTime> getLastTimeKeyBefore(ZonedDateTime time) {
204+
return dataSource
205+
.executeQuery(
206+
queryForValueBefore, ps -> ps.setTimestamp(1, Timestamp.from(time.toInstant())))
207+
.map(valueFactory::extractTime)
208+
.max(ZonedDateTime::compareTo);
209+
}
210+
202211
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
203212

204213
/** Creates a set of TimeBasedValues from database */

src/main/java/edu/ie3/datamodel/models/timeseries/TimeSeries.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public Optional<TimeBasedValue<R>> getTimeBasedValue(ZonedDateTime time) {
6262
* @param time Reference in time
6363
* @return The next earlier known time instant
6464
*/
65-
protected abstract Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time);
65+
public abstract Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time);
6666

6767
/**
6868
* Get the next later known time instant

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ public Optional<V> getValue(ZonedDateTime time) {
5353
}
5454

5555
@Override
56-
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
56+
public Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
5757
return timeToValue.keySet().stream()
58-
.filter(valueTime -> valueTime.compareTo(time) < 0)
59-
.max(Comparator.naturalOrder());
58+
.filter(valueTime -> valueTime.isBefore(time))
59+
.max(ZonedDateTime::compareTo);
6060
}
6161

6262
@Override

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public Set<LoadProfileEntry<V>> getEntries() {
7878
}
7979

8080
@Override
81-
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
81+
public Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
8282
return Optional.of(time.minusMinutes(15));
8383
}
8484

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta {
4747
actual.data.get() == expected
4848
}
4949

50+
def "The csv time series source returns the last value, if there is no current value"() {
51+
given:
52+
def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue)
53+
def source = new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), Path.of("its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), EnergyPriceValue, factory)
54+
def time = TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:13:00Z")
55+
56+
when:
57+
def actual = source.getValueOrLast(time)
58+
59+
then:
60+
actual == Optional.of(new EnergyPriceValue(Quantities.getQuantity(100.0, ENERGY_PRICE)))
61+
}
62+
5063
def "The csv time series source returns the time keys after a given key correctly"() {
5164
given:
5265
def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue)
@@ -63,6 +76,27 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta {
6376
]
6477
}
6578

79+
def "The csv time series source returns the time key before a given key correctly"() {
80+
given:
81+
def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue)
82+
def source = new CsvTimeSeriesSource(";", timeSeriesFolderPath, new FileNamingStrategy(), UUID.fromString("2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), Path.of("its_c_2fcb3e53-b94a-4b96-bea4-c469e499f1a1"), EnergyPriceValue, factory)
83+
84+
when:
85+
def time = TimeUtil.withDefaults.toZonedDateTime(timeKey)
86+
87+
def actual = source.getLastTimeKeyBefore(time)
88+
89+
then:
90+
actual == expectedKey
91+
92+
where:
93+
timeKey | expectedKey
94+
"2019-12-31T23:59:59Z" | Optional.empty()
95+
"2020-01-01T00:00:00Z" | Optional.empty()
96+
"2020-01-01T00:15:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"))
97+
"2020-01-03T00:00:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:15:00Z"))
98+
}
99+
66100
def "The factory method in csv time series source refuses to build time series with unsupported column type"() {
67101
given:
68102
def metaInformation = new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("8bc9120d-fb9b-4484-b4e3-0cdadf0feea9"), ColumnScheme.WEATHER, Path.of("its_weather_8bc9120d-fb9b-4484-b4e3-0cdadf0feea9"))

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package edu.ie3.datamodel.io.source.sql
77

88
import static edu.ie3.test.common.TimeSeriesSourceTestData.*
9+
import static edu.ie3.util.quantities.PowerSystemUnits.KILOWATT
910

1011
import edu.ie3.datamodel.exceptions.SourceException
1112
import edu.ie3.datamodel.io.connectors.SqlConnector
@@ -23,6 +24,7 @@ import org.testcontainers.spock.Testcontainers
2324
import org.testcontainers.utility.MountableFile
2425
import spock.lang.Shared
2526
import spock.lang.Specification
27+
import tech.units.indriya.quantity.Quantities
2628

2729
import java.time.format.DateTimeFormatter
2830

@@ -124,6 +126,17 @@ class SqlTimeSeriesSourceIT extends Specification implements TestContainerHelper
124126
value.get() == P_VALUE_00MIN
125127
}
126128

129+
def "The cSqlTimeSeriesSource returns the last value, if there is no current value"() {
130+
given:
131+
def time = TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:13:00Z")
132+
133+
when:
134+
def actual = pSource.getValueOrLast(time)
135+
136+
then:
137+
actual == Optional.of(new PValue(Quantities.getQuantity(1000.0, KILOWATT)))
138+
}
139+
127140
def "A SqlTimeSeriesSource is able to return the previous value for a given time"() {
128141
when:
129142
def actual = pSource.getPreviousTimeBasedValue(time)
@@ -173,4 +186,21 @@ class SqlTimeSeriesSourceIT extends Specification implements TestContainerHelper
173186
TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:15:00Z")
174187
]
175188
}
189+
190+
def "The SqlTimeSeriesSource returns the time key before a given key correctly"() {
191+
when:
192+
def time = TimeUtil.withDefaults.toZonedDateTime(timeKey)
193+
194+
def actual = pSource.getLastTimeKeyBefore(time)
195+
196+
then:
197+
actual == expectedKey
198+
199+
where:
200+
timeKey | expectedKey
201+
"2019-12-31T23:59:59Z" | Optional.empty()
202+
"2020-01-01T00:00:00Z" | Optional.empty()
203+
"2020-01-01T00:15:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"))
204+
"2020-01-03T00:00:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:15:00Z"))
205+
}
176206
}

0 commit comments

Comments
 (0)