Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
- -Fixed em fields in input models [#1331](https://github.com/ie3-institute/PowerSystemDataModel/issues/1331)
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"))
}
}