Skip to content

Enhancing value retrieval in TimeSeriesSource. #1281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased/Snapshot]

### Added
- Enhancing value retrieval in `TimeSeriesSource` [1280](https://github.com/ie3-institute/PowerSystemDataModel/issues/1280)

### Fixed
- Fixed handling of `CongestionResult.InputModelType` in `EntityProcessor` [#1325](https://github.com/ie3-institute/PowerSystemDataModel/issues/1325)

Expand Down
24 changes: 24 additions & 0 deletions src/main/java/edu/ie3/datamodel/io/source/TimeSeriesSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ public abstract IndividualTimeSeries<V> getTimeSeries(ClosedInterval<ZonedDateTi

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

/**
* Method to retrieve the value of the given time or the last timestamp before the given time.
*
* @param time given time
* @return an option for a value
*/
public Optional<V> getValueOrLast(ZonedDateTime time) {
Optional<V> value = getValue(time);

if (value.isEmpty()) {
return getPreviousTimeBasedValue(time).map(TimeBasedValue::getValue);
}

return value;
}

public abstract Optional<TimeBasedValue<V>> getPreviousTimeBasedValue(ZonedDateTime time);

/**
Expand All @@ -61,4 +77,12 @@ public abstract IndividualTimeSeries<V> getTimeSeries(ClosedInterval<ZonedDateTi
* @return a list of time keys
*/
public abstract List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time);

/**
* Method to return all last known time keys before a given timestamp.
*
* @param time given time
* @return an option for the time key
*/
public abstract Optional<ZonedDateTime> getLastTimeKeyBefore(ZonedDateTime time);
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,11 @@ public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
return timeSeries.getTimeKeysAfter(time);
}

@Override
public Optional<ZonedDateTime> getLastTimeKeyBefore(ZonedDateTime time) {
return timeSeries.getPreviousDateTime(time);
}

// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
.toList();
}

@Override
public Optional<ZonedDateTime> getLastTimeKeyBefore(ZonedDateTime time) {
return dataSource
.executeQuery(
queryForValueBefore, ps -> ps.setTimestamp(1, Timestamp.from(time.toInstant())))
.map(valueFactory::extractTime)
.findFirst();
}

// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

/** Creates a set of TimeBasedValues from database */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public Optional<TimeBasedValue<R>> getTimeBasedValue(ZonedDateTime time) {
* @param time Reference in time
* @return The next earlier known time instant
*/
protected abstract Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time);
public abstract Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time);

/**
* Get the next later known time instant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public Optional<V> getValue(ZonedDateTime time) {
}

@Override
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
public Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
return timeToValue.keySet().stream()
.filter(valueTime -> valueTime.compareTo(time) < 0)
.max(Comparator.naturalOrder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public Set<LoadProfileEntry<V>> getEntries() {
}

@Override
protected Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
public Optional<ZonedDateTime> getPreviousDateTime(ZonedDateTime time) {
return Optional.of(time.minusMinutes(15));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta {
actual.data.get() == expected
}

def "The csv time series source returns the last value, if there is no current value"() {
given:
def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue)
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)
def time = TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:13:00Z")

when:
def actual = source.getValueOrLast(time)

then:
actual == Optional.of(new EnergyPriceValue(Quantities.getQuantity(100.0, ENERGY_PRICE)))
}

def "The csv time series source returns the time keys after a given key correctly"() {
given:
def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue)
Expand All @@ -63,6 +76,27 @@ class CsvTimeSeriesSourceTest extends Specification implements CsvTestDataMeta {
]
}

def "The csv time series source returns the time key before a given key correctly"() {
given:
def factory = new TimeBasedSimpleValueFactory(EnergyPriceValue)
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)

when:
def time = TimeUtil.withDefaults.toZonedDateTime(timeKey)

def actual = source.getLastTimeKeyBefore(time)

then:
actual == expectedKey

where:
timeKey | expectedKey
"2019-12-31T23:59:59Z" | Optional.empty()
"2020-01-01T00:00:00Z" | Optional.empty()
"2020-01-01T00:15:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"))
"2020-01-03T00:00:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:15:00Z"))
}

def "The factory method in csv time series source refuses to build time series with unsupported column type"() {
given:
def metaInformation = new CsvIndividualTimeSeriesMetaInformation(UUID.fromString("8bc9120d-fb9b-4484-b4e3-0cdadf0feea9"), ColumnScheme.WEATHER, Path.of("its_weather_8bc9120d-fb9b-4484-b4e3-0cdadf0feea9"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package edu.ie3.datamodel.io.source.sql

import static edu.ie3.test.common.TimeSeriesSourceTestData.*
import static edu.ie3.util.quantities.PowerSystemUnits.KILOWATT

import edu.ie3.datamodel.exceptions.SourceException
import edu.ie3.datamodel.io.connectors.SqlConnector
Expand All @@ -23,6 +24,7 @@ import org.testcontainers.spock.Testcontainers
import org.testcontainers.utility.MountableFile
import spock.lang.Shared
import spock.lang.Specification
import tech.units.indriya.quantity.Quantities

import java.time.format.DateTimeFormatter

Expand Down Expand Up @@ -124,6 +126,17 @@ class SqlTimeSeriesSourceIT extends Specification implements TestContainerHelper
value.get() == P_VALUE_00MIN
}

def "The cSqlTimeSeriesSource returns the last value, if there is no current value"() {
given:
def time = TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:13:00Z")

when:
def actual = pSource.getValueOrLast(time)

then:
actual == Optional.of(new PValue(Quantities.getQuantity(1000.0, KILOWATT)))
}

def "A SqlTimeSeriesSource is able to return the previous value for a given time"() {
when:
def actual = pSource.getPreviousTimeBasedValue(time)
Expand Down Expand Up @@ -173,4 +186,21 @@ class SqlTimeSeriesSourceIT extends Specification implements TestContainerHelper
TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:15:00Z")
]
}

def "The SqlTimeSeriesSource returns the time key before a given key correctly"() {
when:
def time = TimeUtil.withDefaults.toZonedDateTime(timeKey)

def actual = pSource.getLastTimeKeyBefore(time)

then:
actual == expectedKey

where:
timeKey | expectedKey
"2019-12-31T23:59:59Z" | Optional.empty()
"2020-01-01T00:00:00Z" | Optional.empty()
"2020-01-01T00:15:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"))
"2020-01-03T00:00:00Z" | Optional.of(TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:15:00Z"))
}
}