Skip to content

Enhancing load profile source. #1295

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 3 commits into
base: dev
Choose a base branch
from
Open
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 @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed
- Replaced `return this` with `return thisInstance` in CopyBuilders [#1250](https://github.com/ie3-institute/PowerSystemDataModel/issues/1250)
- Enhancing load profile source [#1294](https://github.com/ie3-institute/PowerSystemDataModel/issues/1294)

## [6.0.0] - 2025-02-27

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
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 edu.ie3.datamodel.models.value.load.LoadValues;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Stream;
Expand Down Expand Up @@ -98,6 +100,12 @@ public BdewStandardLoadProfile parseProfile(String profile) {
}
}

@Override
public LoadValues.Provider buildProvider(
BdewLoadValues loadValue, ZonedDateTime time, BdewStandardLoadProfile loadProfile) {
return last -> loadValue.getValue(time, loadProfile);
}

@Override
public ComparableQuantity<Power> calculateMaxPower(
BdewStandardLoadProfile loadProfile, Set<LoadProfileEntry<BdewLoadValues>> entries) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.util.quantities.PowerSystemUnits;
import java.time.ZonedDateTime;
import java.util.Set;
import javax.measure.quantity.Energy;
import javax.measure.quantity.Power;
Expand All @@ -37,6 +38,16 @@ public abstract LoadProfileTimeSeries<V> build(

public abstract P parseProfile(String profile);

/**
* Method to build a {@link LoadValues.Provider}.
*
* @param loadValue used for the provider
* @param time used for the provider
* @param loadProfile used for the provider
* @return a value provider
*/
public abstract LoadValues.Provider buildProvider(V loadValue, ZonedDateTime time, P loadProfile);

/**
* Calculates the maximum average power consumption per quarter-hour for a given calculated over
* all seasons and weekday types of given load profile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
import edu.ie3.datamodel.models.profile.LoadProfile.RandomLoadProfile;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
import edu.ie3.datamodel.models.timeseries.repetitive.RandomLoadProfileTimeSeries;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.datamodel.models.value.load.RandomLoadValues;
import edu.ie3.util.quantities.PowerSystemUnits;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.Set;
import javax.measure.quantity.Energy;
Expand Down Expand Up @@ -88,6 +90,12 @@ public RandomLoadProfile parseProfile(String profile) {
return RANDOM_LOAD_PROFILE;
}

@Override
public LoadValues.Provider buildProvider(
RandomLoadValues loadValue, ZonedDateTime time, RandomLoadProfile loadProfile) {
return last -> loadValue.sample(time);
}

/**
* This is the 95 % quantile resulting from 10,000 evaluations of the year 2019. It is only
* needed, when the load is meant to be scaled to rated active power.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries;
import edu.ie3.datamodel.models.timeseries.repetitive.RandomLoadProfileTimeSeries;
import edu.ie3.datamodel.models.value.PValue;
import edu.ie3.datamodel.models.value.Value;
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.datamodel.models.value.load.RandomLoadValues;
Expand All @@ -48,8 +46,7 @@ protected LoadProfileSource(Class<V> entryClass, LoadProfileFactory<P, V> entryF
}

/**
* Build a list of type {@code E}, whereas the underlying {@link Value} does not need any
* additional information.
* Build a {@link LoadProfileEntry} of type {@code V}.
*
* @param fieldToValues Mapping from field id to values
* @return {@link Try} of simple time based value
Expand Down Expand Up @@ -77,7 +74,7 @@ protected Try<LoadProfileEntry<V>, FactoryException> createEntries(
* @return an optional
* @throws SourceException if an exception occurred
*/
public abstract Optional<PValue> getValue(ZonedDateTime time) throws SourceException;
public abstract Optional<LoadValues.Provider> getValue(ZonedDateTime time) throws SourceException;

/** Returns the load profile of this source. */
public abstract P getLoadProfile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries;
import edu.ie3.datamodel.models.value.PValue;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.datamodel.utils.Try;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.measure.quantity.Energy;
Expand Down Expand Up @@ -72,7 +74,7 @@ public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
}

@Override
public Optional<PValue> getValue(ZonedDateTime time) throws SourceException {
public Optional<LoadValues.Provider> getValue(ZonedDateTime time) throws SourceException {
return loadProfileTimeSeries.getValue(time);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileEntry;
import edu.ie3.datamodel.models.timeseries.repetitive.LoadProfileTimeSeries;
import edu.ie3.datamodel.models.value.PValue;
import edu.ie3.datamodel.models.value.Value;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.datamodel.utils.TimeSeriesUtils;
Expand Down Expand Up @@ -112,12 +111,14 @@ public List<ZonedDateTime> getTimeKeysAfter(ZonedDateTime time) {
}

@Override
public Optional<PValue> getValue(ZonedDateTime time) throws SourceException {
public Optional<LoadValues.Provider> getValue(ZonedDateTime time) throws SourceException {
Set<LoadProfileEntry<V>> entries =
getEntries(queryTime, ps -> ps.setInt(1, TimeSeriesUtils.calculateQuarterHourOfDay(time)));
if (entries.isEmpty()) return Optional.empty();
if (entries.size() > 1) log.warn("Retrieved more than one result value, using the first");
return Optional.of(entries.stream().toList().get(0).getValue().getValue(time, loadProfile));

V loadValue = entries.stream().toList().get(0).getValue();
return Optional.of(entryFactory.buildProvider(loadValue, time, loadProfile));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
import edu.ie3.datamodel.models.value.load.BdewLoadValues;
import edu.ie3.datamodel.models.value.load.LoadValues;
import java.time.ZonedDateTime;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
Expand All @@ -29,6 +31,11 @@ public BdewLoadProfileTimeSeries(
super(uuid, loadProfile, values, maxPower, profileEnergyScaling);
}

@Override
protected LoadValues.Provider buildFunction(BdewLoadValues loadValue, ZonedDateTime time) {
return last -> loadValue.getValue(time, (BdewStandardLoadProfile) loadProfile);
}

@Override
public BdewStandardLoadProfile getLoadProfile() {
return (BdewStandardLoadProfile) super.getLoadProfile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package edu.ie3.datamodel.models.timeseries.repetitive;

import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.value.PValue;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.datamodel.utils.TimeSeriesUtils;
import java.time.ZonedDateTime;
Expand All @@ -18,10 +17,12 @@

/**
* Describes a load profile time series with repetitive values that can be calculated from a pattern
*
* @param <V> type of {@link LoadValues} used in this time series.
*/
public class LoadProfileTimeSeries<V extends LoadValues>
extends RepetitiveTimeSeries<LoadProfileEntry<V>, V, PValue> {
private final LoadProfile loadProfile;
public abstract class LoadProfileTimeSeries<V extends LoadValues>
extends RepetitiveTimeSeries<LoadProfileEntry<V>, V, LoadValues.Provider> {
protected final LoadProfile loadProfile;
private final Map<Integer, V> valueMapping;

/**
Expand All @@ -33,7 +34,7 @@ public class LoadProfileTimeSeries<V extends LoadValues>
/** The profile energy scaling in kWh. */
private final ComparableQuantity<Energy> profileEnergyScaling;

public LoadProfileTimeSeries(
protected LoadProfileTimeSeries(
UUID uuid,
LoadProfile loadProfile,
Set<LoadProfileEntry<V>> entries,
Expand All @@ -50,6 +51,21 @@ public LoadProfileTimeSeries(
this.profileEnergyScaling = profileEnergyScaling;
}

@Override
protected LoadValues.Provider calc(ZonedDateTime time) {
int quarterHour = TimeSeriesUtils.calculateQuarterHourOfDay(time);
return buildFunction(valueMapping.get(quarterHour), time);
}

/**
* Method to build a {@link LoadValues.Provider} for the given {@link LoadValues} and time.
*
* @param loadValue used for the provider
* @param time used for the provider
* @return a {@link LoadValues.Provider}
*/
protected abstract LoadValues.Provider buildFunction(V loadValue, ZonedDateTime time);

/**
* Returns the maximum average power consumption per quarter-hour calculated over all seasons and
* weekday types of given load profile in Watt.
Expand Down Expand Up @@ -97,12 +113,6 @@ protected Map<Integer, V> getValueMapping() {
return valueMapping;
}

@Override
protected PValue calc(ZonedDateTime time) {
int quarterHour = TimeSeriesUtils.calculateQuarterHourOfDay(time);
return valueMapping.get(quarterHour).getValue(time, loadProfile);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

import de.lmu.ifi.dbs.elki.math.statistics.distribution.GeneralizedExtremeValueDistribution;
import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.value.load.LoadValues;
import edu.ie3.datamodel.models.value.load.RandomLoadValues;
import java.time.ZonedDateTime;
import java.util.Set;
import java.util.UUID;
import javax.measure.quantity.Energy;
Expand All @@ -29,6 +31,11 @@ public RandomLoadProfileTimeSeries(
super(uuid, loadProfile, entries, maxPower, profileEnergyScaling);
}

@Override
protected LoadValues.Provider buildFunction(RandomLoadValues loadValue, ZonedDateTime time) {
return last -> loadValue.sample(time);
}

@Override
public LoadProfile.RandomLoadProfile getLoadProfile() {
return (LoadProfile.RandomLoadProfile) super.getLoadProfile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import edu.ie3.datamodel.models.BdewSeason;
import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile;
import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.value.PValue;
import java.time.ZonedDateTime;
import java.util.List;
Expand All @@ -21,7 +20,7 @@
import tech.units.indriya.quantity.Quantities;

/** Load values for a {@link BdewStandardLoadProfile} */
public class BdewLoadValues implements LoadValues {
public final class BdewLoadValues implements LoadValues {

Check warning on line 23 in src/main/java/edu/ie3/datamodel/models/value/load/BdewLoadValues.java

View check run for this annotation

SonarQubeGithubPRChecks / PowerSystemDataModel Sonarqube Results

src/main/java/edu/ie3/datamodel/models/value/load/BdewLoadValues.java#L23

Refactor this class declaration to use 'record BdewLoadValues(double suSa, double suSu, double suWd, double t...)'.
private final double suSa;
private final double suSu;
private final double suWd;
Expand Down Expand Up @@ -53,8 +52,13 @@
this.wiWd = wiWd;
}

@Override
public PValue getValue(ZonedDateTime time, LoadProfile loadProfile) {
/**
* Method to calculate an actual load power value for the given time.
*
* @param time given time
* @return a new {@link PValue}
*/
public PValue getValue(ZonedDateTime time, BdewStandardLoadProfile loadProfile) {
Map<BdewSeason, Double> mapping =
switch (time.getDayOfWeek()) {
case SATURDAY -> Map.of(
Expand Down
37 changes: 28 additions & 9 deletions src/main/java/edu/ie3/datamodel/models/value/load/LoadValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,38 @@
*/
package edu.ie3.datamodel.models.value.load;

import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.value.PValue;
import edu.ie3.datamodel.models.value.Value;
import java.time.ZonedDateTime;
import java.util.Optional;

/** Interface for load values. */
public interface LoadValues extends Value {

/**
* Method to calculate an actual load power value for the given time.
*
* @param time given time
* @return a new {@link PValue}
*/
PValue getValue(ZonedDateTime time, LoadProfile loadProfile);
/** Functional interface that is used to provide a {@link PValue}. */
@FunctionalInterface
interface Provider extends Value {

/**
* Method to provide a {@link PValue}.
*
* @param lastOption option for the last value.
* @return a new value
*/
PValue provide(Optional<PValue> lastOption);

/** Provides a {@link PValue}. */
default PValue provide() {
return provide(Optional.empty());
}

/**
* Provides a {@link PValue} considering the last value.
*
* @param last {@link PValue}.
* @return a new {@link PValue}
*/
default PValue withLast(PValue last) {
return provide(Optional.of(last));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import de.lmu.ifi.dbs.elki.math.statistics.distribution.GeneralizedExtremeValueDistribution;
import de.lmu.ifi.dbs.elki.utilities.random.RandomFactory;
import edu.ie3.datamodel.models.profile.LoadProfile;
import edu.ie3.datamodel.models.value.PValue;
import java.time.DayOfWeek;
import java.time.ZonedDateTime;
Expand All @@ -23,7 +22,7 @@
* sampled for each quarter hour of a day, subdivided into workdays, Saturdays and Sundays. In
* general the GEV is described by the three parameters "location", "scale" and "shape"
*/
public class RandomLoadValues implements LoadValues {
public final class RandomLoadValues implements LoadValues {
/** Shape parameter for a Saturday */
private final double kSa;

Expand Down Expand Up @@ -89,13 +88,18 @@ public RandomLoadValues(
RandomFactory factory = RandomFactory.get(new Random().nextLong());

this.gevWd = new GeneralizedExtremeValueDistribution(myWd, sigmaWd, kWd, factory.getRandom());

this.gevSa = new GeneralizedExtremeValueDistribution(mySa, sigmaSa, kSa, factory.getRandom());
this.gevSu = new GeneralizedExtremeValueDistribution(mySu, sigmaSu, kSu, factory.getRandom());
}

@Override
public PValue getValue(ZonedDateTime time, LoadProfile loadProfile) {
/**
* Method to sample a new random {@link PValue} from the {@link
* GeneralizedExtremeValueDistribution}.
*
* @param time to use for the sampling
* @return a new {@link PValue}
*/
public PValue sample(ZonedDateTime time) {
return new PValue(Quantities.getQuantity(getValue(time.getDayOfWeek()), KILOWATT));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class SqlLoadProfileSourceIT extends Specification implements TestContainerHelpe

then:
value.present
value.get().p.get() == G3_VALUE_00MIN.p.get()
value.get().provide().p.get() == G3_VALUE_00MIN.p.get()
}

def "A SqlTimeSeriesSource can read all value data"() {
Expand Down