From 478d57d2af679363c3677a1a40652ab71801c41c Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Fri, 4 Jul 2025 13:04:34 +0200 Subject: [PATCH 1/2] Added support to provide the PSDM with custom `LoadProfile` --- CHANGELOG.md | 3 ++ .../datamodel/models/profile/LoadProfile.java | 16 +++++---- .../models/profile/LoadProfileProvider.java | 34 +++++++++++++++++++ src/main/java/module-info.java | 30 ++++++++++++++++ 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java create mode 100644 src/main/java/module-info.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a7593a97d..1326237be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased/Snapshot] +## Added +- Added support to provide the PSDM with custom `LoadProfile` [#1362](https://github.com/ie3-institute/PowerSystemDataModel/issues/1362) + ### 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) diff --git a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java index c68ba3435..654cac3b8 100644 --- a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java +++ b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java @@ -8,8 +8,9 @@ import edu.ie3.datamodel.exceptions.ParsingException; import java.io.Serializable; import java.util.Arrays; +import java.util.Collection; +import java.util.ServiceLoader; import java.util.stream.Collectors; -import java.util.stream.Stream; public interface LoadProfile extends Serializable { /** @return The identifying String */ @@ -28,12 +29,15 @@ static LoadProfile parse(String key) throws ParsingException { return LoadProfile.getProfile(getAllProfiles(), key); } + /** + * Returns all {@link LoadProfile}s, that are either provided by the PSDM or provided using the + * {@link LoadProfileProvider}. + */ static LoadProfile[] getAllProfiles() { - return Stream.of( - BdewStandardLoadProfile.values(), - NbwTemperatureDependantLoadProfile.values(), - (LoadProfile[]) RandomLoadProfile.values()) - .flatMap(Arrays::stream) + return ServiceLoader.load(LoadProfileProvider.class).stream() + .map(ServiceLoader.Provider::get) + .map(LoadProfileProvider::getProfiles) + .flatMap(Collection::stream) .toArray(LoadProfile[]::new); } diff --git a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java new file mode 100644 index 000000000..51edeeb72 --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java @@ -0,0 +1,34 @@ +/* + * © 2025. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.models.profile; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +/** Interface defining a provider for {@link LoadProfile}s. */ +public interface LoadProfileProvider { + + /** Returns a list of {@link LoadProfile}s. */ + List getProfiles(); + + /** + * Default load profile provider. This class is used to provide the {@link LoadProfile}s defined + * in the PSDM. + */ + final class DefaultLoadProfileProvider implements LoadProfileProvider { + + @Override + public List getProfiles() { + return Stream.of( + BdewStandardLoadProfile.values(), + NbwTemperatureDependantLoadProfile.values(), + (LoadProfile[]) LoadProfile.RandomLoadProfile.values()) + .flatMap(Arrays::stream) + .toList(); + } + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 000000000..e1c57b76d --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,30 @@ +import edu.ie3.datamodel.models.profile.LoadProfileProvider; + +open module PowerSystemDataModel.main { + // our own projects + requires PowerSystemUtils; + + // dependencies + requires com.couchbase.client.core; + requires com.couchbase.client.java; + requires elki.core.math; + requires elki.core.util; + requires influxdb.java; + requires java.desktop; + requires java.measure; + requires java.sql; + requires org.apache.commons.io; + requires org.apache.commons.lang3; + requires org.jgrapht.core; + requires org.locationtech.jts; + requires org.locationtech.jts.io; + requires org.slf4j; + requires tech.units.indriya; + + // used to provide load profiles + uses LoadProfileProvider; + + // provide default load profiles to profile loader + provides LoadProfileProvider with + LoadProfileProvider.DefaultLoadProfileProvider; +} From c5d6ea7d7851f7c5987b8f7630b62eb232bc4c55 Mon Sep 17 00:00:00 2001 From: staudtMarius Date: Mon, 7 Jul 2025 10:41:39 +0200 Subject: [PATCH 2/2] Some improvements to providing the PSDM with LoadProfiles. --- build.gradle | 2 +- .../io/provider/LoadProfileProvider.java | 75 +++++++++++++++++++ .../datamodel/models/profile/LoadProfile.java | 9 +-- .../models/profile/LoadProfileProvider.java | 34 --------- src/main/java/module-info.java | 30 -------- ....datamodel.io.provider.LoadProfileProvider | 1 + .../models/profile/LoadProfileTest.groovy | 2 +- 7 files changed, 80 insertions(+), 73 deletions(-) create mode 100644 src/main/java/edu/ie3/datamodel/io/provider/LoadProfileProvider.java delete mode 100644 src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java delete mode 100644 src/main/java/module-info.java create mode 100644 src/main/resources/META-INF/services/edu.ie3.datamodel.io.provider.LoadProfileProvider diff --git a/build.gradle b/build.gradle index c70398ce3..e47a25fff 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'org.jgrapht:jgrapht-core:1.5.2' // Statistics (for random load model) - implementation 'de.lmu.ifi.dbs.elki:elki:0.7.5' + implementation 'de.lmu.ifi.dbs.elki:elki-core-math:0.7.5' // testing testImplementation "org.apache.groovy:groovy:$groovyBinaryVersion" diff --git a/src/main/java/edu/ie3/datamodel/io/provider/LoadProfileProvider.java b/src/main/java/edu/ie3/datamodel/io/provider/LoadProfileProvider.java new file mode 100644 index 000000000..20346328b --- /dev/null +++ b/src/main/java/edu/ie3/datamodel/io/provider/LoadProfileProvider.java @@ -0,0 +1,75 @@ +/* + * © 2025. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation +*/ +package edu.ie3.datamodel.io.provider; + +import edu.ie3.datamodel.io.factory.timeseries.BdewLoadProfileFactory; +import edu.ie3.datamodel.io.factory.timeseries.LoadProfileFactory; +import edu.ie3.datamodel.io.factory.timeseries.RandomLoadProfileFactory; +import edu.ie3.datamodel.models.profile.BdewStandardLoadProfile; +import edu.ie3.datamodel.models.profile.LoadProfile; +import edu.ie3.datamodel.models.profile.NbwTemperatureDependantLoadProfile; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** Interface defining a provider for {@link LoadProfile}s and their {@link LoadProfileFactory}. */ +public interface LoadProfileProvider { + + /** A list of all {@link LoadProfile}, that are known. */ + List loadedProfiles = + ServiceLoader.load(LoadProfileProvider.class).stream() + .map(ServiceLoader.Provider::get) + .map(LoadProfileProvider::getProfiles) + .flatMap(Collection::stream) + .toList(); + + /** A map of all known {@link LoadProfile} to their {@link LoadProfileFactory}. */ + Map> profileToFactories = + ServiceLoader.load(LoadProfileProvider.class).stream() + .map(ServiceLoader.Provider::get) + .map(LoadProfileProvider::getFactories) + .flatMap(map -> map.entrySet().stream()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + /** Returns a list of {@link LoadProfile}s. */ + List getProfiles(); + + /** Returns a map of {@link LoadProfile} to {@link LoadProfileFactory}. */ + Map> getFactories(); + + /** + * Default load profile provider. This class is used to provide the {@link LoadProfile}s defined + * in the PSDM. + */ + final class DefaultLoadProfileProvider implements LoadProfileProvider { + + @Override + public List getProfiles() { + return Stream.of( + BdewStandardLoadProfile.values(), + NbwTemperatureDependantLoadProfile.values(), + LoadProfile.RandomLoadProfile.values(), + LoadProfile.DefaultLoadProfiles.values()) + .flatMap(Arrays::stream) + .toList(); + } + + @Override + public Map> getFactories() { + BdewLoadProfileFactory bdewLoadProfileFactory = new BdewLoadProfileFactory(); + + Map> factories = new HashMap<>(); + + Arrays.stream(BdewStandardLoadProfile.values()) + .forEach(profile -> factories.put(profile, bdewLoadProfileFactory)); + + factories.put( + LoadProfile.RandomLoadProfile.RANDOM_LOAD_PROFILE, new RandomLoadProfileFactory()); + + return factories; + } + } +} diff --git a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java index 654cac3b8..8f96fbfd7 100644 --- a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java +++ b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfile.java @@ -6,10 +6,9 @@ package edu.ie3.datamodel.models.profile; import edu.ie3.datamodel.exceptions.ParsingException; +import edu.ie3.datamodel.io.provider.LoadProfileProvider; import java.io.Serializable; import java.util.Arrays; -import java.util.Collection; -import java.util.ServiceLoader; import java.util.stream.Collectors; public interface LoadProfile extends Serializable { @@ -34,11 +33,7 @@ static LoadProfile parse(String key) throws ParsingException { * {@link LoadProfileProvider}. */ static LoadProfile[] getAllProfiles() { - return ServiceLoader.load(LoadProfileProvider.class).stream() - .map(ServiceLoader.Provider::get) - .map(LoadProfileProvider::getProfiles) - .flatMap(Collection::stream) - .toArray(LoadProfile[]::new); + return LoadProfileProvider.loadedProfiles.toArray(LoadProfile[]::new); } /** diff --git a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java b/src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java deleted file mode 100644 index 51edeeb72..000000000 --- a/src/main/java/edu/ie3/datamodel/models/profile/LoadProfileProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * © 2025. TU Dortmund University, - * Institute of Energy Systems, Energy Efficiency and Energy Economics, - * Research group Distribution grid planning and operation -*/ -package edu.ie3.datamodel.models.profile; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - -/** Interface defining a provider for {@link LoadProfile}s. */ -public interface LoadProfileProvider { - - /** Returns a list of {@link LoadProfile}s. */ - List getProfiles(); - - /** - * Default load profile provider. This class is used to provide the {@link LoadProfile}s defined - * in the PSDM. - */ - final class DefaultLoadProfileProvider implements LoadProfileProvider { - - @Override - public List getProfiles() { - return Stream.of( - BdewStandardLoadProfile.values(), - NbwTemperatureDependantLoadProfile.values(), - (LoadProfile[]) LoadProfile.RandomLoadProfile.values()) - .flatMap(Arrays::stream) - .toList(); - } - } -} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java deleted file mode 100644 index e1c57b76d..000000000 --- a/src/main/java/module-info.java +++ /dev/null @@ -1,30 +0,0 @@ -import edu.ie3.datamodel.models.profile.LoadProfileProvider; - -open module PowerSystemDataModel.main { - // our own projects - requires PowerSystemUtils; - - // dependencies - requires com.couchbase.client.core; - requires com.couchbase.client.java; - requires elki.core.math; - requires elki.core.util; - requires influxdb.java; - requires java.desktop; - requires java.measure; - requires java.sql; - requires org.apache.commons.io; - requires org.apache.commons.lang3; - requires org.jgrapht.core; - requires org.locationtech.jts; - requires org.locationtech.jts.io; - requires org.slf4j; - requires tech.units.indriya; - - // used to provide load profiles - uses LoadProfileProvider; - - // provide default load profiles to profile loader - provides LoadProfileProvider with - LoadProfileProvider.DefaultLoadProfileProvider; -} diff --git a/src/main/resources/META-INF/services/edu.ie3.datamodel.io.provider.LoadProfileProvider b/src/main/resources/META-INF/services/edu.ie3.datamodel.io.provider.LoadProfileProvider new file mode 100644 index 000000000..209e64b45 --- /dev/null +++ b/src/main/resources/META-INF/services/edu.ie3.datamodel.io.provider.LoadProfileProvider @@ -0,0 +1 @@ +edu.ie3.datamodel.io.provider.LoadProfileProvider$DefaultLoadProfileProvider \ No newline at end of file diff --git a/src/test/groovy/edu/ie3/datamodel/models/profile/LoadProfileTest.groovy b/src/test/groovy/edu/ie3/datamodel/models/profile/LoadProfileTest.groovy index 0265d24c4..a5f056bcb 100644 --- a/src/test/groovy/edu/ie3/datamodel/models/profile/LoadProfileTest.groovy +++ b/src/test/groovy/edu/ie3/datamodel/models/profile/LoadProfileTest.groovy @@ -187,6 +187,6 @@ class LoadProfileTest extends Specification { then: def e = thrown(ParsingException) - e.message == "No predefined load profile with key 'not_a_key' found. Please provide one of the following keys: h0, l0, l1, l2, g0, g1, g2, g3, g4, g5, g6, ep1, ez2, random" + e.message == "No predefined load profile with key 'not_a_key' found. Please provide one of the following keys: h0, l0, l1, l2, g0, g1, g2, g3, g4, g5, g6, ep1, ez2, random, No load profile assigned" } }