Skip to content

Commit 8181869

Browse files
Merge pull request #1231 from ie3-institute/ms/#1230-add-bdew-LoadProfileTimeSeries
Added `BdewLoadProfileTimeSeries`
2 parents dcc1850 + b49576e commit 8181869

File tree

20 files changed

+784
-22
lines changed

20 files changed

+784
-22
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
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)
1515
- Enhance `TimeSeriesSource` with method to retrieve the previous value before a given key [#1182](https://github.com/ie3-institute/PowerSystemDataModel/issues/1182)
16+
- Added `BdewLoadProfileTimeSeries` [#1230](https://github.com/ie3-institute/PowerSystemDataModel/issues/1230)
1617

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

docs/uml/main/TimeSeriesDatamodelConcept.puml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,21 @@ package models {
2222
childNote .. input
2323
childNote .. voltagelevels
2424

25-
interface StandardLoadProfile {
25+
interface LoadProfile {
2626
+ getKey: String
27+
+ {static} parse(String): LoadProfile
28+
+ {static} getAllProfiles: LoadProfile[]
29+
+ {static} getProfile(T[], String): T
2730
+ enum DefaultLoadProfiles
31+
+ enum RandomLoadProfile
32+
}
33+
34+
DefaultLoadProfiles --|> LoadProfile
35+
36+
interface StandardLoadProfile {
2837
+ {static} parse(String): StandardLoadProfile
2938
}
39+
StandardLoadProfile ..|> LoadProfile
3040

3141
enum BdewLoadProfile {
3242
- key: String
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* © 2024. 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.factory.timeseries;
7+
8+
import static tech.units.indriya.unit.Units.WATT;
9+
10+
import edu.ie3.datamodel.exceptions.FactoryException;
11+
import edu.ie3.datamodel.exceptions.ParsingException;
12+
import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation;
13+
import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
14+
import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry;
15+
import edu.ie3.datamodel.models.timeseries.repetitive.BdewLoadProfileTimeSeries;
16+
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
17+
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
18+
import java.util.*;
19+
import java.util.function.Function;
20+
import java.util.stream.Stream;
21+
import javax.measure.quantity.Energy;
22+
import javax.measure.quantity.Power;
23+
import tech.units.indriya.ComparableQuantity;
24+
import tech.units.indriya.quantity.Quantities;
25+
26+
public class BdewLoadProfileFactory
27+
extends LoadProfileFactory<BdewStandardLoadProfile, BdewLoadValues> {
28+
public static final String SUMMER_SATURDAY = "SuSa";
29+
public static final String SUMMER_SUNDAY = "SuSu";
30+
public static final String SUMMER_WEEKDAY = "SuWd";
31+
public static final String TRANSITION_SATURDAY = "TrSa";
32+
public static final String TRANSITION_SUNDAY = "TrSu";
33+
public static final String TRANSITION_WEEKDAY = "TrWd";
34+
public static final String WINTER_SATURDAY = "WiSa";
35+
public static final String WINTER_SUNDAY = "WiSu";
36+
public static final String WINTER_WEEKDAY = "WiWd";
37+
38+
public BdewLoadProfileFactory() {
39+
this(BdewLoadValues.class);
40+
}
41+
42+
public BdewLoadProfileFactory(Class<BdewLoadValues> valueClass) {
43+
super(valueClass);
44+
}
45+
46+
@Override
47+
protected LoadProfileEntry<BdewLoadValues> buildModel(LoadProfileData<BdewLoadValues> data) {
48+
int quarterHour = data.getInt(QUARTER_HOUR);
49+
50+
return new LoadProfileEntry<>(
51+
new BdewLoadValues(
52+
data.getDouble(SUMMER_SATURDAY),
53+
data.getDouble(SUMMER_SUNDAY),
54+
data.getDouble(SUMMER_WEEKDAY),
55+
data.getDouble(TRANSITION_SATURDAY),
56+
data.getDouble(TRANSITION_SUNDAY),
57+
data.getDouble(TRANSITION_WEEKDAY),
58+
data.getDouble(WINTER_SATURDAY),
59+
data.getDouble(WINTER_SUNDAY),
60+
data.getDouble(WINTER_WEEKDAY)),
61+
quarterHour);
62+
}
63+
64+
@Override
65+
protected List<Set<String>> getFields(Class<?> entityClass) {
66+
return List.of(
67+
newSet(
68+
QUARTER_HOUR,
69+
SUMMER_SATURDAY,
70+
SUMMER_SUNDAY,
71+
SUMMER_WEEKDAY,
72+
TRANSITION_SATURDAY,
73+
TRANSITION_SUNDAY,
74+
TRANSITION_WEEKDAY,
75+
WINTER_SATURDAY,
76+
WINTER_SUNDAY,
77+
WINTER_WEEKDAY));
78+
}
79+
80+
@Override
81+
public BdewLoadProfileTimeSeries build(
82+
LoadProfileMetaInformation metaInformation, Set<LoadProfileEntry<BdewLoadValues>> entries) {
83+
84+
BdewStandardLoadProfile profile = parseProfile(metaInformation.getProfile());
85+
ComparableQuantity<Power> maxPower = calculateMaxPower(profile, entries);
86+
ComparableQuantity<Energy> profileEnergyScaling = getLoadProfileEnergyScaling(profile);
87+
88+
return new BdewLoadProfileTimeSeries(
89+
metaInformation.getUuid(), profile, entries, maxPower, profileEnergyScaling);
90+
}
91+
92+
@Override
93+
public BdewStandardLoadProfile parseProfile(String profile) {
94+
try {
95+
return BdewStandardLoadProfile.get(profile);
96+
} catch (ParsingException e) {
97+
throw new FactoryException("An error occurred while parsing the profile: " + profile, e);
98+
}
99+
}
100+
101+
@Override
102+
public ComparableQuantity<Power> calculateMaxPower(
103+
BdewStandardLoadProfile loadProfile, Set<LoadProfileEntry<BdewLoadValues>> entries) {
104+
Function<BdewLoadValues, Stream<Double>> valueExtractor;
105+
106+
if (loadProfile == BdewStandardLoadProfile.H0) {
107+
// maximum dynamization factor is on day 366 (leap year) or day 365 (regular year).
108+
// The difference between day 365 and day 366 is negligible, thus pick 366
109+
valueExtractor =
110+
v ->
111+
Stream.of(v.getWiSa(), v.getWiSu(), v.getWiWd())
112+
.map(p -> BdewLoadValues.dynamization(p, 366));
113+
} else {
114+
valueExtractor = v -> v.values().stream();
115+
}
116+
117+
double maxPower =
118+
entries.stream()
119+
.map(TimeSeriesEntry::getValue)
120+
.flatMap(valueExtractor)
121+
.max(Comparator.naturalOrder())
122+
.orElse(0d);
123+
124+
return Quantities.getQuantity(maxPower, WATT);
125+
}
126+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ public String getTimeFieldString() {
5555

5656
/** Returns the load profile energy scaling. The default value is 1000 kWh */
5757
public ComparableQuantity<Energy> getLoadProfileEnergyScaling(P loadProfile) {
58-
return Quantities.getQuantity(1000, PowerSystemUnits.KILOWATTHOUR);
58+
return Quantities.getQuantity(1000d, PowerSystemUnits.KILOWATTHOUR);
5959
}
6060
}

src/main/java/edu/ie3/datamodel/io/processor/Processor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ protected String processMethodResult(Object methodReturnObject, Method method, S
224224
"double",
225225
"String",
226226
"DayOfWeek",
227+
"Season",
227228
"ChargingPointType",
228229
"EvcsLocationType" -> resultStringBuilder.append(methodReturnObject.toString());
229230
case "Quantity", "ComparableQuantity" -> resultStringBuilder.append(
@@ -260,7 +261,8 @@ protected String processMethodResult(Object methodReturnObject, Method method, S
260261
processVoltageLevel((VoltageLevel) methodReturnObject, fieldName));
261262
case "Point", "LineString" -> resultStringBuilder.append(
262263
geoJsonWriter.write((Geometry) methodReturnObject));
263-
case "LoadProfile" -> resultStringBuilder.append(((LoadProfile) methodReturnObject).getKey());
264+
case "LoadProfile", "BdewStandardLoadProfile" -> resultStringBuilder.append(
265+
((LoadProfile) methodReturnObject).getKey());
264266
case "AssetTypeInput",
265267
"BmTypeInput",
266268
"ChpTypeInput",

src/main/java/edu/ie3/datamodel/io/processor/timeseries/TimeSeriesProcessor.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry;
1414
import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries;
1515
import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue;
16+
import edu.ie3.datamodel.models.timeseries.repetitive.*;
1617
import edu.ie3.datamodel.models.value.*;
18+
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
1719
import java.lang.reflect.Method;
1820
import java.util.*;
1921
import java.util.stream.Collectors;
@@ -50,7 +52,9 @@ public class TimeSeriesProcessor<
5052
new TimeSeriesProcessorKey(
5153
IndividualTimeSeries.class, TimeBasedValue.class, SValue.class),
5254
new TimeSeriesProcessorKey(
53-
IndividualTimeSeries.class, TimeBasedValue.class, HeatAndSValue.class));
55+
IndividualTimeSeries.class, TimeBasedValue.class, HeatAndSValue.class),
56+
new TimeSeriesProcessorKey(
57+
BdewLoadProfileTimeSeries.class, LoadProfileEntry.class, BdewLoadValues.class));
5458

5559
/**
5660
* Specific combination of time series class, entry class and value class, this processor is
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* © 2024. 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.models;
7+
8+
import edu.ie3.datamodel.exceptions.ParsingException;
9+
import java.time.ZonedDateTime;
10+
11+
public enum BdewSeason {
12+
WINTER("Wi"),
13+
SUMMER("Su"),
14+
TRANSITION("Tr");
15+
16+
private final String key;
17+
18+
BdewSeason(String key) {
19+
this.key = key.toLowerCase();
20+
}
21+
22+
public static BdewSeason parse(String key) throws ParsingException {
23+
return switch (key) {
24+
case "Wi", "Winter" -> WINTER;
25+
case "Su", "Summer" -> SUMMER;
26+
case "Tr", "Intermediate" -> TRANSITION;
27+
default -> throw new ParsingException(
28+
"There is no season for key:"
29+
+ key
30+
+ ". Permissible keys: 'Wi', 'Winter', 'Su', 'Summer', 'Tr', 'Intermediate'");
31+
};
32+
}
33+
34+
/**
35+
* Creates a season from given time
36+
*
37+
* @param time the time
38+
* @return a season
39+
*/
40+
public static BdewSeason getSeason(ZonedDateTime time) {
41+
int day = time.getDayOfMonth();
42+
43+
// winter: 1.11.-20.03.
44+
// summer: 15.05.-14.09.
45+
// transition: 21.03.-14.05. and
46+
// 15.09.-31.10.
47+
// (VDEW handbook)
48+
49+
return switch (time.getMonth()) {
50+
case NOVEMBER, DECEMBER, JANUARY, FEBRUARY -> WINTER;
51+
case MARCH -> {
52+
if (day <= 20) {
53+
yield WINTER;
54+
} else {
55+
yield TRANSITION;
56+
}
57+
}
58+
case MAY -> {
59+
if (day >= 15) {
60+
yield SUMMER;
61+
} else {
62+
yield TRANSITION;
63+
}
64+
}
65+
case JUNE, JULY, AUGUST -> SUMMER;
66+
case SEPTEMBER -> {
67+
if (day <= 14) {
68+
yield SUMMER;
69+
} else {
70+
yield TRANSITION;
71+
}
72+
}
73+
default -> TRANSITION;
74+
};
75+
}
76+
77+
public String getKey() {
78+
return key;
79+
}
80+
81+
@Override
82+
public String toString() {
83+
return key;
84+
}
85+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* © 2024. 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.models.timeseries.repetitive;
7+
8+
import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
9+
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
10+
import java.util.Objects;
11+
import java.util.Set;
12+
import java.util.UUID;
13+
import javax.measure.quantity.Energy;
14+
import javax.measure.quantity.Power;
15+
import tech.units.indriya.ComparableQuantity;
16+
17+
/**
18+
* Describes a bdew load profile time series with repetitive values that can be calculated from a
19+
* pattern. Each value of this timeseries is given in W.
20+
*/
21+
public class BdewLoadProfileTimeSeries extends LoadProfileTimeSeries<BdewLoadValues> {
22+
23+
public BdewLoadProfileTimeSeries(
24+
UUID uuid,
25+
BdewStandardLoadProfile loadProfile,
26+
Set<LoadProfileEntry<BdewLoadValues>> values,
27+
ComparableQuantity<Power> maxPower,
28+
ComparableQuantity<Energy> profileEnergyScaling) {
29+
super(uuid, loadProfile, values, maxPower, profileEnergyScaling);
30+
}
31+
32+
@Override
33+
public BdewStandardLoadProfile getLoadProfile() {
34+
return (BdewStandardLoadProfile) super.getLoadProfile();
35+
}
36+
37+
@Override
38+
public boolean equals(Object o) {
39+
if (this == o) return true;
40+
if (o == null || getClass() != o.getClass()) return false;
41+
return super.equals(o);
42+
}
43+
44+
@Override
45+
public int hashCode() {
46+
return Objects.hash(super.hashCode());
47+
}
48+
49+
@Override
50+
public String toString() {
51+
return "BDEWLoadProfileTimeSeries{"
52+
+ "uuid="
53+
+ getUuid()
54+
+ "loadProfile="
55+
+ getLoadProfile()
56+
+ ", valueMapping="
57+
+ getValueMapping()
58+
+ '}';
59+
}
60+
}

0 commit comments

Comments
 (0)