Skip to content

Commit 5829b47

Browse files
Merge pull request #1439 from ie3-institute/ms/#1438-abstracting-power-value-sources
Added abstraction for power value sources.
2 parents 0cbd490 + c7e74b6 commit 5829b47

20 files changed

+229
-168
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
- Added standard asset parameter for `3wTransformer` in `ReadTheDocs` [#1417](https://github.com/ie3-institute/PowerSystemDataModel/issues/1417)
1212
- Added getter sRated for SystemParticipant inputs and updated them in tests in src[#1412](https://github.com/ie3-institute/PowerSystemDataModel/issues/1412)
1313
- Added converters documentation [#1139](https://github.com/ie3-institute/PowerSystemDataModel/issues/1139)
14+
- Added abstraction for power value sources [#1438](https://github.com/ie3-institute/PowerSystemDataModel/issues/1438)
1415

1516
### Fixed
1617
- Fixed small issues in tests [#1400](https://github.com/ie3-institute/PowerSystemDataModel/issues/1400)

src/main/java/edu/ie3/datamodel/io/factory/timeseries/BdewLoadProfileFactory.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import edu.ie3.datamodel.exceptions.FactoryException;
1111
import edu.ie3.datamodel.exceptions.ParsingException;
12-
import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation;
1312
import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
1413
import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry;
1514
import edu.ie3.datamodel.models.timeseries.repetitive.BdewLoadProfileTimeSeries;
@@ -70,9 +69,7 @@ protected List<Set<String>> getFields(Class<?> entityClass) {
7069

7170
@Override
7271
public BdewLoadProfileTimeSeries build(
73-
LoadProfileMetaInformation metaInformation, Set<LoadProfileEntry<BdewLoadValues>> entries) {
74-
75-
BdewStandardLoadProfile profile = parseProfile(metaInformation.getProfile());
72+
BdewStandardLoadProfile profile, Set<LoadProfileEntry<BdewLoadValues>> entries) {
7673
ComparableQuantity<Power> maxPower = calculateMaxPower(profile, entries);
7774
ComparableQuantity<Energy> profileEnergyScaling = getLoadProfileEnergyScaling(profile);
7875

src/main/java/edu/ie3/datamodel/io/factory/timeseries/LoadProfileFactory.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package edu.ie3.datamodel.io.factory.timeseries;
77

88
import edu.ie3.datamodel.io.factory.Factory;
9-
import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation;
109
import edu.ie3.datamodel.models.profile.LoadProfile;
1110
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
1211
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries;
@@ -37,8 +36,7 @@ protected LoadProfileFactory(Class<? extends V>... valueClass) {
3736
super(valueClass);
3837
}
3938

40-
public abstract LoadProfileTimeSeries<P, V> build(
41-
LoadProfileMetaInformation metaInformation, Set<LoadProfileEntry<V>> entries);
39+
public abstract LoadProfileTimeSeries<P, V> build(P profile, Set<LoadProfileEntry<V>> entries);
4240

4341
public abstract P parseProfile(String profile);
4442

src/main/java/edu/ie3/datamodel/io/factory/timeseries/RandomLoadProfileFactory.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import static edu.ie3.datamodel.models.profile.LoadProfile.RandomLoadProfile.RANDOM_LOAD_PROFILE;
99
import static tech.units.indriya.unit.Units.WATT;
1010

11-
import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation;
1211
import edu.ie3.datamodel.models.profile.LoadProfile.RandomLoadProfile;
1312
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
1413
import edu.ie3.datamodel.models.timeseries.repetitive.RandomLoadProfileTimeSeries;
@@ -73,9 +72,7 @@ protected List<Set<String>> getFields(Class<?> entityClass) {
7372

7473
@Override
7574
public RandomLoadProfileTimeSeries build(
76-
LoadProfileMetaInformation metaInformation, Set<LoadProfileEntry<RandomLoadValues>> entries) {
77-
RandomLoadProfile profile = RANDOM_LOAD_PROFILE;
78-
75+
RandomLoadProfile profile, Set<LoadProfileEntry<RandomLoadValues>> entries) {
7976
ComparableQuantity<Power> maxPower = calculateMaxPower(profile, entries);
8077
ComparableQuantity<Energy> profileEnergyScaling = getLoadProfileEnergyScaling(profile);
8178

src/main/java/edu/ie3/datamodel/io/naming/timeseries/LoadProfileMetaInformation.java

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ public LoadProfileMetaInformation(String profile) {
1717
this.profile = profile;
1818
}
1919

20-
public LoadProfileMetaInformation(UUID uuid, String profile) {
21-
super(uuid);
22-
this.profile = profile;
23-
}
24-
2520
public String getProfile() {
2621
return profile;
2722
}
@@ -41,13 +36,6 @@ public int hashCode() {
4136

4237
@Override
4338
public String toString() {
44-
return "LoadProfileTimeSeriesMetaInformation{"
45-
+ "uuid='"
46-
+ getUuid()
47-
+ '\''
48-
+ ", profile='"
49-
+ profile
50-
+ '\''
51-
+ '}';
39+
return "LoadProfileTimeSeriesMetaInformation{profile='" + profile + '}';
5240
}
5341
}

src/main/java/edu/ie3/datamodel/io/sink/SqlSink.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ private <C extends Entity> void persistMixedList(List<C> entities, DbGridMetadat
190190
void persistList(List<C> entities, Class<C> cls, DbGridMetadata identifier)
191191
throws SQLException {
192192
// Check if there are only elements of the same class
193-
Class<?> firstClass = entities.get(0).getClass();
193+
Class<?> firstClass = entities.getFirst().getClass();
194194
boolean allSameClass = entities.stream().allMatch(e -> e.getClass() == firstClass);
195195

196196
if (allSameClass) {

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

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,35 +14,36 @@
1414
import edu.ie3.datamodel.io.factory.timeseries.LoadProfileFactory;
1515
import edu.ie3.datamodel.io.factory.timeseries.RandomLoadProfileFactory;
1616
import edu.ie3.datamodel.io.naming.timeseries.FileLoadProfileMetaInformation;
17+
import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation;
1718
import edu.ie3.datamodel.io.source.csv.CsvDataSource;
1819
import edu.ie3.datamodel.io.source.csv.CsvLoadProfileSource;
1920
import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
2021
import edu.ie3.datamodel.models.profile.LoadProfile;
2122
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
22-
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries;
2323
import edu.ie3.datamodel.models.timeseries.repetitive.RandomLoadProfileTimeSeries;
24-
import edu.ie3.datamodel.models.value.PValue;
2524
import edu.ie3.datamodel.models.value.Value;
2625
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
2726
import edu.ie3.datamodel.models.value.load.LoadValues;
2827
import edu.ie3.datamodel.models.value.load.RandomLoadValues;
2928
import edu.ie3.datamodel.utils.Try;
3029
import java.time.ZonedDateTime;
31-
import java.util.List;
3230
import java.util.Map;
3331
import java.util.Optional;
32+
import java.util.Set;
3433
import java.util.function.Function;
3534
import java.util.stream.Collectors;
36-
import javax.measure.quantity.Energy;
37-
import javax.measure.quantity.Power;
38-
import tech.units.indriya.ComparableQuantity;
3935

4036
public abstract class LoadProfileSource<P extends LoadProfile, V extends LoadValues<P>>
41-
extends EntitySource {
37+
extends EntitySource implements PowerValueSource.TimeSeriesBased {
38+
protected final P profile;
4239
protected final Class<V> entryClass;
4340
protected final LoadProfileFactory<P, V> entryFactory;
4441

45-
protected LoadProfileSource(Class<V> entryClass, LoadProfileFactory<P, V> entryFactory) {
42+
protected LoadProfileSource(
43+
LoadProfileMetaInformation metaInformation,
44+
Class<V> entryClass,
45+
LoadProfileFactory<P, V> entryFactory) {
46+
this.profile = entryFactory.parseProfile(metaInformation.getProfile());
4647
this.entryClass = entryClass;
4748
this.entryFactory = entryFactory;
4849
}
@@ -60,33 +61,18 @@ protected Try<LoadProfileEntry<V>, FactoryException> createEntries(
6061
return entryFactory.get(factoryData);
6162
}
6263

63-
public abstract LoadProfileTimeSeries<P, V> getTimeSeries();
64+
/** Returns the load profile entries as a set. */
65+
public abstract Set<LoadProfileEntry<V>> getEntries();
6466

65-
/**
66-
* Method to return all time keys after a given timestamp.
67-
*
68-
* @param time given time
69-
* @return a list of time keys
70-
*/
71-
public abstract List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time);
72-
73-
/**
74-
* Method to get the value for a given time.
75-
*
76-
* @param time for which a value is needed
77-
* @return an optional
78-
* @throws SourceException if an exception occurred
79-
*/
80-
public abstract Optional<PValue> getValue(ZonedDateTime time) throws SourceException;
81-
82-
/** Returns the load profile of this source. */
83-
public abstract P getLoadProfile();
84-
85-
/** Returns the maximal power value of the time series */
86-
public abstract Optional<ComparableQuantity<Power>> getMaxPower();
67+
@Override
68+
public P getProfile() {
69+
return profile;
70+
}
8771

88-
/** Returns the load profile energy scaling for this load profile time series. */
89-
public abstract Optional<ComparableQuantity<Energy>> getLoadProfileEnergyScaling();
72+
@Override
73+
public Optional<ZonedDateTime> getNextTimeKey(ZonedDateTime time) {
74+
return Optional.of(time.plusSeconds(getResolution(getProfile())));
75+
}
9076

9177
/**
9278
* Returns the resolution for the given {@link LoadProfile}.
@@ -125,7 +111,7 @@ public static long getResolution(LoadProfile loadProfile) {
125111
metaInformation ->
126112
new CsvLoadProfileSource<>(
127113
buildInSource, metaInformation, BdewLoadValues.class, factory))
128-
.collect(Collectors.toMap(CsvLoadProfileSource::getLoadProfile, Function.identity()));
114+
.collect(Collectors.toMap(CsvLoadProfileSource::getProfile, Function.identity()));
129115
}
130116

131117
/**
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* © 2025. TU Dortmund University,
3+
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
4+
* Research group Distribution grid planning and operation
5+
*/
6+
package edu.ie3.datamodel.io.source;
7+
8+
import edu.ie3.datamodel.models.profile.LoadProfile;
9+
import edu.ie3.datamodel.models.profile.PowerProfile;
10+
import edu.ie3.datamodel.models.value.PValue;
11+
import java.time.ZonedDateTime;
12+
import java.util.Optional;
13+
import java.util.function.Supplier;
14+
import javax.measure.quantity.Energy;
15+
import javax.measure.quantity.Power;
16+
import tech.units.indriya.ComparableQuantity;
17+
18+
/** Interface defining base functionality for power value sources. */
19+
public sealed interface PowerValueSource<
20+
P extends PowerProfile, I extends PowerValueSource.PowerValueIdentifier>
21+
permits PowerValueSource.MarkovBased, PowerValueSource.TimeSeriesBased {
22+
23+
/** Returns the profile of this source. */
24+
P getProfile();
25+
26+
/**
27+
* Method to get a supplier for the next power value based on the provided input data. Depending
28+
* on the implementation the supplier will either always return the same value or each time a
29+
* random value.
30+
*
31+
* @param data input data that is used to calculate the next power value.
32+
* @return A supplier for an option on the value at the given time step.
33+
*/
34+
Supplier<Optional<PValue>> getValueSupplier(I data);
35+
36+
/**
37+
* Method to determine the next timestamp for which data is present.
38+
*
39+
* @param time current time
40+
* @return an option for the next timestamp or {@link Optional#empty()} if no timestamp was found.
41+
*/
42+
Optional<ZonedDateTime> getNextTimeKey(ZonedDateTime time);
43+
44+
/** Returns the maximal power that can be returned by this source. */
45+
Optional<ComparableQuantity<Power>> getMaxPower();
46+
47+
/** Returns the energy scaling of this power source. */
48+
Optional<ComparableQuantity<Energy>> getProfileEnergyScaling();
49+
50+
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
51+
// non-sealed implementations
52+
53+
/** Interface for time-series-based power value sources. */
54+
non-sealed interface TimeSeriesBased
55+
extends PowerValueSource<LoadProfile, TimeSeriesInputValue> {}
56+
57+
/** Interface for markov-chain-based power value sources. */
58+
non-sealed interface MarkovBased extends PowerValueSource<PowerProfile, PowerValueIdentifier> {}
59+
60+
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
61+
// input data
62+
63+
/**
64+
* Interface for the input data of {@link #getValueSupplier(PowerValueIdentifier)}. The data is
65+
* used to determine the next power.
66+
*/
67+
sealed interface PowerValueIdentifier permits PowerValueSource.TimeSeriesInputValue {
68+
/** Returns the timestamp for which a power value is needed. */
69+
ZonedDateTime getTime();
70+
}
71+
72+
/**
73+
* Input data for time-series-based power value sources.
74+
*
75+
* @param time
76+
*/
77+
record TimeSeriesInputValue(ZonedDateTime time) implements PowerValueIdentifier {
78+
@Override
79+
public ZonedDateTime getTime() {
80+
return time;
81+
}
82+
}
83+
}

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

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
import edu.ie3.datamodel.models.value.load.LoadValues;
1919
import edu.ie3.datamodel.utils.Try;
2020
import java.nio.file.Path;
21-
import java.time.ZonedDateTime;
2221
import java.util.*;
2322
import java.util.function.Function;
23+
import java.util.function.Supplier;
2424
import java.util.stream.Collectors;
2525
import javax.measure.quantity.Energy;
2626
import javax.measure.quantity.Power;
@@ -40,13 +40,13 @@ public CsvLoadProfileSource(
4040
FileLoadProfileMetaInformation metaInformation,
4141
Class<V> entryClass,
4242
LoadProfileFactory<P, V> entryFactory) {
43-
super(entryClass, entryFactory);
43+
super(metaInformation, entryClass, entryFactory);
4444
this.dataSource = source;
4545
this.filePath = metaInformation.getFullFilePath();
4646

4747
/* Read in the full time series */
4848
try {
49-
this.loadProfileTimeSeries = buildLoadProfileTimeSeries(metaInformation, this::createEntries);
49+
this.loadProfileTimeSeries = buildLoadProfileTimeSeries(this::createEntries);
5050
} catch (SourceException e) {
5151
throw new IllegalArgumentException(
5252
"Unable to obtain load profile time series with profile '"
@@ -61,24 +61,18 @@ public void validate() throws ValidationException {
6161
validate(entryClass, () -> dataSource.getSourceFields(filePath), entryFactory);
6262
}
6363

64-
@Override
6564
public LoadProfileTimeSeries<P, V> getTimeSeries() {
6665
return loadProfileTimeSeries;
6766
}
6867

6968
@Override
70-
public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
71-
return loadProfileTimeSeries.getTimeKeysAfter(time);
69+
public Set<LoadProfileEntry<V>> getEntries() {
70+
return loadProfileTimeSeries.getEntries();
7271
}
7372

7473
@Override
75-
public Optional<PValue> getValue(ZonedDateTime time) throws SourceException {
76-
return loadProfileTimeSeries.getValue(time);
77-
}
78-
79-
@Override
80-
public P getLoadProfile() {
81-
return getTimeSeries().getLoadProfile();
74+
public Supplier<Optional<PValue>> getValueSupplier(TimeSeriesInputValue data) {
75+
return loadProfileTimeSeries.supplyValue(data.time());
8276
}
8377

8478
@Override
@@ -87,7 +81,7 @@ public Optional<ComparableQuantity<Power>> getMaxPower() {
8781
}
8882

8983
@Override
90-
public Optional<ComparableQuantity<Energy>> getLoadProfileEnergyScaling() {
84+
public Optional<ComparableQuantity<Energy>> getProfileEnergyScaling() {
9185
return loadProfileTimeSeries.loadProfileScaling();
9286
}
9387

@@ -98,15 +92,12 @@ public Optional<ComparableQuantity<Energy>> getLoadProfileEnergyScaling() {
9892
* entries are obtained entries with the help of {@code fieldToValueFunction}. If the file does
9993
* not exist, an empty Stream is returned.
10094
*
101-
* @param metaInformation containing an unique identifier of the time series, a path to the file
102-
* to read as well as the profile
10395
* @param fieldToValueFunction function, that is able to transfer a mapping (from field to value)
10496
* onto a specific instance of the targeted entry class
10597
* @throws SourceException If the file cannot be read properly
10698
* @return an individual time series
10799
*/
108100
protected LoadProfileTimeSeries<P, V> buildLoadProfileTimeSeries(
109-
FileLoadProfileMetaInformation metaInformation,
110101
Function<Map<String, String>, Try<LoadProfileEntry<V>, FactoryException>>
111102
fieldToValueFunction)
112103
throws SourceException {
@@ -120,6 +111,6 @@ protected LoadProfileTimeSeries<P, V> buildLoadProfileTimeSeries(
120111
.getOrThrow()
121112
.collect(Collectors.toSet());
122113

123-
return entryFactory.build(metaInformation, entries);
114+
return entryFactory.build(profile, entries);
124115
}
125116
}

0 commit comments

Comments
 (0)