Skip to content

Added BdewLoadProfileTimeSeries #1231

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

Merged
merged 6 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added Staudt to list of reviewers [#1190](https://github.com/ie3-institute/PowerSystemDataModel/issues/1190)
- Extend ValidationUtils for validating ThermalGrids [#1216](https://github.com/ie3-institute/PowerSystemDataModel/issues/1216)
- Enhance `TimeSeriesSource` with method to retrieve the previous value before a given key [#1182](https://github.com/ie3-institute/PowerSystemDataModel/issues/1182)
- Added `BdewLoadProfileTimeSeries` [#1230](https://github.com/ie3-institute/PowerSystemDataModel/issues/1230)

### Fixed
- Removing opened `SwitchInput` during connectivity check [#1221](https://github.com/ie3-institute/PowerSystemDataModel/issues/1221)
Expand Down
12 changes: 11 additions & 1 deletion docs/uml/main/TimeSeriesDatamodelConcept.puml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,21 @@ package models {
childNote .. input
childNote .. voltagelevels

interface StandardLoadProfile {
interface LoadProfile {
+ getKey: String
+ {static} parse(String): LoadProfile
+ {static} getAllProfiles: LoadProfile[]
+ {static} getProfile(T[], String): T
+ enum DefaultLoadProfiles
+ enum RandomLoadProfile
}

DefaultLoadProfiles --|> LoadProfile

interface StandardLoadProfile {
+ {static} parse(String): StandardLoadProfile
}
StandardLoadProfile ..|> LoadProfile

enum BdewLoadProfile {
- key: String
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* © 2024. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.io.factory.timeseries;

import static tech.units.indriya.unit.Units.WATT;

import edu.ie3.datamodel.exceptions.FactoryException;
import edu.ie3.datamodel.exceptions.ParsingException;
import edu.ie3.datamodel.io.naming.timeseries.LoadProfileMetaInformation;
import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry;
import edu.ie3.datamodel.models.timeseries.repetitive.BdewLoadProfileTimeSeries;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import tech.units.indriya.ComparableQuantity;
import tech.units.indriya.quantity.Quantities;

public class BdewLoadProfileFactory
extends LoadProfileFactory<BdewStandardLoadProfile, BdewLoadValues> {
public static final String SUMMER_SATURDAY = "SuSa";
public static final String SUMMER_SUNDAY = "SuSu";
public static final String SUMMER_WEEKDAY = "SuWd";
public static final String TRANSITION_SATURDAY = "TrSa";
public static final String TRANSITION_SUNDAY = "TrSu";
public static final String TRANSITION_WEEKDAY = "TrWd";
public static final String WINTER_SATURDAY = "WiSa";
public static final String WINTER_SUNDAY = "WiSu";
public static final String WINTER_WEEKDAY = "WiWd";

public BdewLoadProfileFactory() {
this(BdewLoadValues.class);
}

public BdewLoadProfileFactory(Class<BdewLoadValues> valueClass) {
super(valueClass);
}

@Override
protected LoadProfileEntry<BdewLoadValues> buildModel(LoadProfileData<BdewLoadValues> data) {
int quarterHour = data.getInt(QUARTER_HOUR);

return new LoadProfileEntry<>(
new BdewLoadValues(
data.getDouble(SUMMER_SATURDAY),
data.getDouble(SUMMER_SUNDAY),
data.getDouble(SUMMER_WEEKDAY),
data.getDouble(TRANSITION_SATURDAY),
data.getDouble(TRANSITION_SUNDAY),
data.getDouble(TRANSITION_WEEKDAY),
data.getDouble(WINTER_SATURDAY),
data.getDouble(WINTER_SUNDAY),
data.getDouble(WINTER_WEEKDAY)),
quarterHour);
}

@Override
protected List<Set<String>> getFields(Class<?> entityClass) {
return List.of(
newSet(
QUARTER_HOUR,
SUMMER_SATURDAY,
SUMMER_SUNDAY,
SUMMER_WEEKDAY,
TRANSITION_SATURDAY,
TRANSITION_SUNDAY,
TRANSITION_WEEKDAY,
WINTER_SATURDAY,
WINTER_SUNDAY,
WINTER_WEEKDAY));
}

@Override
public BdewLoadProfileTimeSeries build(
LoadProfileMetaInformation metaInformation, Set<LoadProfileEntry<BdewLoadValues>> entries) {

BdewStandardLoadProfile profile = parseProfile(metaInformation.getProfile());
ComparableQuantity<Power> maxPower = calculateMaxPower(profile, entries);
ComparableQuantity<Energy> profileEnergyScaling = getLoadProfileEnergyScaling(profile);

return new BdewLoadProfileTimeSeries(
metaInformation.getUuid(), profile, entries, maxPower, profileEnergyScaling);
}

@Override
public BdewStandardLoadProfile parseProfile(String profile) {
try {
return BdewStandardLoadProfile.get(profile);
} catch (ParsingException e) {
throw new FactoryException("An error occurred while parsing the profile: " + profile, e);
}
}

@Override
public ComparableQuantity<Power> calculateMaxPower(
BdewStandardLoadProfile loadProfile, Set<LoadProfileEntry<BdewLoadValues>> entries) {
Function<BdewLoadValues, Stream<Double>> valueExtractor;

if (loadProfile == BdewStandardLoadProfile.H0) {
// maximum dynamization factor is on day 366 (leap year) or day 365 (regular year).
// The difference between day 365 and day 366 is negligible, thus pick 366
valueExtractor =
v ->
Stream.of(v.getWiSa(), v.getWiSu(), v.getWiWd())
.map(p -> BdewLoadValues.dynamization(p, 366));
} else {
valueExtractor = v -> v.values().stream();
}

double maxPower =
entries.stream()
.map(TimeSeriesEntry::getValue)
.flatMap(valueExtractor)
.max(Comparator.naturalOrder())
.orElse(0d);

return Quantities.getQuantity(maxPower, WATT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ public String getTimeFieldString() {

/** Returns the load profile energy scaling. The default value is 1000 kWh */
public ComparableQuantity<Energy> getLoadProfileEnergyScaling(P loadProfile) {
return Quantities.getQuantity(1000, PowerSystemUnits.KILOWATTHOUR);
return Quantities.getQuantity(1000d, PowerSystemUnits.KILOWATTHOUR);
}
}
4 changes: 3 additions & 1 deletion src/main/java/edu/ie3/datamodel/io/processor/Processor.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ protected String processMethodResult(Object methodReturnObject, Method method, S
"double",
"String",
"DayOfWeek",
"Season",
"ChargingPointType",
"EvcsLocationType" -> resultStringBuilder.append(methodReturnObject.toString());
case "Quantity", "ComparableQuantity" -> resultStringBuilder.append(
Expand Down Expand Up @@ -260,7 +261,8 @@ protected String processMethodResult(Object methodReturnObject, Method method, S
processVoltageLevel((VoltageLevel) methodReturnObject, fieldName));
case "Point", "LineString" -> resultStringBuilder.append(
geoJsonWriter.write((Geometry) methodReturnObject));
case "LoadProfile" -> resultStringBuilder.append(((LoadProfile) methodReturnObject).getKey());
case "LoadProfile", "BdewStandardLoadProfile" -> resultStringBuilder.append(
((LoadProfile) methodReturnObject).getKey());
case "AssetTypeInput",
"BmTypeInput",
"ChpTypeInput",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
import edu.ie3.datamodel.models.timeseries.TimeSeriesEntry;
import edu.ie3.datamodel.models.timeseries.individual.IndividualTimeSeries;
import edu.ie3.datamodel.models.timeseries.individual.TimeBasedValue;
import edu.ie3.datamodel.models.timeseries.repetitive.*;
import edu.ie3.datamodel.models.value.*;
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -50,7 +52,9 @@ public class TimeSeriesProcessor<
new TimeSeriesProcessorKey(
IndividualTimeSeries.class, TimeBasedValue.class, SValue.class),
new TimeSeriesProcessorKey(
IndividualTimeSeries.class, TimeBasedValue.class, HeatAndSValue.class));
IndividualTimeSeries.class, TimeBasedValue.class, HeatAndSValue.class),
new TimeSeriesProcessorKey(
BdewLoadProfileTimeSeries.class, LoadProfileEntry.class, BdewLoadValues.class));

/**
* Specific combination of time series class, entry class and value class, this processor is
Expand Down
85 changes: 85 additions & 0 deletions src/main/java/edu/ie3/datamodel/models/BdewSeason.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* © 2024. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.models;

import edu.ie3.datamodel.exceptions.ParsingException;
import java.time.ZonedDateTime;

public enum BdewSeason {
WINTER("Wi"),
SUMMER("Su"),
TRANSITION("Tr");

private final String key;

BdewSeason(String key) {
this.key = key.toLowerCase();
}

public static BdewSeason parse(String key) throws ParsingException {
return switch (key) {
case "Wi", "Winter" -> WINTER;
case "Su", "Summer" -> SUMMER;
case "Tr", "Intermediate" -> TRANSITION;
default -> throw new ParsingException(
"There is no season for key:"
+ key
+ ". Permissible keys: 'Wi', 'Winter', 'Su', 'Summer', 'Tr', 'Intermediate'");
};
}

/**
* Creates a season from given time
*
* @param time the time
* @return a season
*/
public static BdewSeason getSeason(ZonedDateTime time) {
int day = time.getDayOfMonth();

// winter: 1.11.-20.03.
// summer: 15.05.-14.09.
// transition: 21.03.-14.05. and
// 15.09.-31.10.
// (VDEW handbook)

return switch (time.getMonth()) {
case NOVEMBER, DECEMBER, JANUARY, FEBRUARY -> WINTER;
case MARCH -> {
if (day <= 20) {
yield WINTER;
} else {
yield TRANSITION;
}
}
case MAY -> {
if (day >= 15) {
yield SUMMER;
} else {
yield TRANSITION;
}
}
case JUNE, JULY, AUGUST -> SUMMER;
case SEPTEMBER -> {
if (day <= 14) {
yield SUMMER;
} else {
yield TRANSITION;
}
}
default -> TRANSITION;
};
}

public String getKey() {
return key;
}

@Override
public String toString() {
return key;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* © 2024. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.models.timeseries.repetitive;

import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
import tech.units.indriya.ComparableQuantity;

/**
* Describes a bdew load profile time series with repetitive values that can be calculated from a
* pattern. Each value of this timeseries is given in W.
*/
public class BdewLoadProfileTimeSeries extends LoadProfileTimeSeries<BdewLoadValues> {

public BdewLoadProfileTimeSeries(
UUID uuid,
BdewStandardLoadProfile loadProfile,
Set<LoadProfileEntry<BdewLoadValues>> values,
ComparableQuantity<Power> maxPower,
ComparableQuantity<Energy> profileEnergyScaling) {
super(uuid, loadProfile, values, maxPower, profileEnergyScaling);
}

@Override
public BdewStandardLoadProfile getLoadProfile() {
return (BdewStandardLoadProfile) super.getLoadProfile();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return super.equals(o);
}

@Override
public int hashCode() {
return Objects.hash(super.hashCode());
}

@Override
public String toString() {
return "BDEWLoadProfileTimeSeries{"
+ "uuid="
+ getUuid()
+ "loadProfile="
+ getLoadProfile()
+ ", valueMapping="
+ getValueMapping()
+ '}';
}
}
Loading