diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1e499ca..b8984b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased/Snapshot]
+## [0.6.0] - 2024-12-02
+
+### Added
+- Enable initialization of external data simulation [#167](https://github.com/ie3-institute/simonaAPI/issues/167)
+- `ExtResultContainer` returns result map [#217](https://github.com/ie3-institute/simonaAPI/issues/217)
+
+### Changed
+- Renaming power fields in `EvModel` [#208](https://github.com/ie3-institute/simonaAPI/issues/208)
+- Enhancing external data connections [#219](https://github.com/ie3-institute/simonaAPI/issues/219)
+
## [0.5.0] - 2024-08-09
### Added
@@ -37,7 +47,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Renamed messages to ease understanding [#62](https://github.com/ie3-institute/simonaAPI/issues/62)
- Separating departures and arrivals in message protocol, properly handling exceptions [#77](https://github.com/ie3-institute/simonaAPI/issues/77)
-[Unreleased/Snapshot]: https://github.com/ie3-institute/simonaapi/compare/0.5.0...HEAD
+[Unreleased/Snapshot]: https://github.com/ie3-institute/simonaapi/compare/0.6.0...HEAD
+[0.6.0]: https://github.com/ie3-institute/powersystemdatamodel/compare/0.5.0...0.6.0
[0.5.0]: https://github.com/ie3-institute/powersystemdatamodel/compare/0.4.0...0.5.0
[0.4.0]: https://github.com/ie3-institute/powersystemdatamodel/compare/0.3.0...0.4.0
[0.3.0]: https://github.com/ie3-institute/powersystemdatamodel/compare/0.2.0...0.3.0
diff --git a/build.gradle b/build.gradle
index e27b37f..6f31561 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,8 +3,8 @@ plugins {
id 'java' // java support
id 'com.diffplug.spotless' version '6.25.0'//code format
id 'pmd' // code check, working on source code
- id 'com.github.spotbugs' version '6.0.20' // code check, working on byte code
- id "org.sonarqube" version "5.1.0.4882" // sonarqube
+ id 'com.github.spotbugs' version '6.0.26' // code check, working on byte code
+ id "org.sonarqube" version "6.0.1.5171" // sonarqube
id 'signing'
id 'maven-publish' // publish to a maven repo (local or mvn central, has to be defined)
id 'jacoco' // java code coverage plugin
@@ -17,8 +17,8 @@ ext {
// required for pekko
scalaVersion = "2.13"
- scalaBinaryVersion = "2.13.14"
- pekkoVersion = "1.0.3"
+ scalaBinaryVersion = "2.13.15"
+ pekkoVersion = "1.1.2"
}
group = 'com.github.ie3-institute'
@@ -46,18 +46,20 @@ repositories {
dependencies{
- implementation 'tech.units:indriya:2.2' // quantities
+ implementation 'tech.units:indriya:2.2.1' // quantities
// scala (needed for pekko)
implementation "org.scala-lang:scala-library:${scalaBinaryVersion}"
- //PSDM
+ //PSU
implementation('com.github.ie3-institute:PowerSystemUtils:2.2.1') {
exclude group: 'org.apache.logging.log4j'
exclude group: 'org.slf4j'
/* Exclude our own nested dependencies */
exclude group: 'com.github.ie3-institute'
}
+
+ //PSDM
implementation('com.github.ie3-institute:PowerSystemDataModel:5.1.0') {
exclude group: 'org.apache.logging.log4j'
exclude group: 'org.slf4j'
@@ -65,14 +67,18 @@ dependencies{
exclude group: 'com.github.ie3-institute'
}
+ // logging
+ implementation platform('org.apache.logging.log4j:log4j-bom:2.24.2')
+ implementation 'org.apache.logging.log4j:log4j-api' // log4j
+ implementation 'org.apache.logging.log4j:log4j-core' // log4j
+ implementation 'org.apache.logging.log4j:log4j-slf4j-impl' // log4j -> slf4j
+
// pekko
implementation "org.apache.pekko:pekko-actor_${scalaVersion}:${pekkoVersion}"
testImplementation "org.apache.pekko:pekko-testkit_${scalaVersion}:${pekkoVersion}" // pekko testkit
// TESTING
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
-
- implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.17.2'
}
task printVersion {
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7f93135..a4b76b9 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 09523c0..e2847c8 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 1aa94a4..f5feea6 100755
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/gradlew.bat b/gradlew.bat
index 93e3f59..9d21a21 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/src/main/java/edu/ie3/simona/api/ExtLinkInterface.java b/src/main/java/edu/ie3/simona/api/ExtLinkInterface.java
index e69a27c..0761008 100644
--- a/src/main/java/edu/ie3/simona/api/ExtLinkInterface.java
+++ b/src/main/java/edu/ie3/simona/api/ExtLinkInterface.java
@@ -6,20 +6,25 @@
package edu.ie3.simona.api;
-import edu.ie3.simona.api.data.ExtDataSimulation;
+import edu.ie3.simona.api.exceptions.NoExtSimulationException;
+import edu.ie3.simona.api.simulation.ExtSimAdapterData;
import edu.ie3.simona.api.simulation.ExtSimulation;
-import java.util.List;
/**
* Every external simulation has to provide a class {@code edu.ie3.simona.api.ExtLink} which
* implements this interface.
- *
- *
{@link #getExtSimulation()} and {@link #getExtDataSimulations()} can return references to the
- * same object, if that object implements both {@link ExtSimulation} and one or more variants of
- * {@link ExtDataSimulation}.
*/
public interface ExtLinkInterface {
- ExtSimulation getExtSimulation();
+ /** Returns the external simulation. */
+ default ExtSimulation getExtSimulation() {
+ throw new NoExtSimulationException(this.getClass());
+ }
- List getExtDataSimulations();
+ /**
+ * Method to set up an external simulation. Everything that needs to be set up before the external
+ * simulation can be retrieved should be done here.
+ *
+ * @param data used for setting up the external simulation
+ */
+ void setup(ExtSimAdapterData data);
}
diff --git a/src/main/java/edu/ie3/simona/api/data/DataQueueExtSimulationExtSimulator.java b/src/main/java/edu/ie3/simona/api/data/DataQueueExtSimulationExtSimulator.java
new file mode 100644
index 0000000..67d8cb0
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/DataQueueExtSimulationExtSimulator.java
@@ -0,0 +1,22 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+/** Data queue to allow data flow between SimonaAPI and an external simulation */
+public class DataQueueExtSimulationExtSimulator {
+ private final LinkedBlockingQueue receiverTriggerQueue = new LinkedBlockingQueue<>();
+
+ public void queueData(V data) throws InterruptedException {
+ this.receiverTriggerQueue.put(data);
+ }
+
+ public V takeData() throws InterruptedException {
+ return this.receiverTriggerQueue.take();
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/ExtData.java b/src/main/java/edu/ie3/simona/api/data/ExtDataConnection.java
similarity index 61%
rename from src/main/java/edu/ie3/simona/api/data/ExtData.java
rename to src/main/java/edu/ie3/simona/api/data/ExtDataConnection.java
index fd35fe7..9de5c6a 100644
--- a/src/main/java/edu/ie3/simona/api/data/ExtData.java
+++ b/src/main/java/edu/ie3/simona/api/data/ExtDataConnection.java
@@ -6,4 +6,5 @@
package edu.ie3.simona.api.data;
-public interface ExtData {}
+/** Interface that defines a data connection between SIMONA and an external simulation. */
+public interface ExtDataConnection {}
diff --git a/src/main/java/edu/ie3/simona/api/exceptions/ConvertionException.java b/src/main/java/edu/ie3/simona/api/data/ExtDataContainer.java
similarity index 50%
rename from src/main/java/edu/ie3/simona/api/exceptions/ConvertionException.java
rename to src/main/java/edu/ie3/simona/api/data/ExtDataContainer.java
index 2065203..224b9de 100644
--- a/src/main/java/edu/ie3/simona/api/exceptions/ConvertionException.java
+++ b/src/main/java/edu/ie3/simona/api/data/ExtDataContainer.java
@@ -4,11 +4,7 @@
* Research group Distribution grid planning and operation
*/
-package edu.ie3.simona.api.exceptions;
+package edu.ie3.simona.api.data;
-public class ConvertionException extends Exception {
-
- public ConvertionException(final String message) {
- super(message);
- }
-}
+/** Interface for data that are exchanged between an external simulation and SimonaAPI */
+public interface ExtDataContainer {}
diff --git a/src/main/java/edu/ie3/simona/api/data/ExtDataSimulation.java b/src/main/java/edu/ie3/simona/api/data/ExtDataSimulation.java
deleted file mode 100644
index ffb06ec..0000000
--- a/src/main/java/edu/ie3/simona/api/data/ExtDataSimulation.java
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * © 2021. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data;
-
-/**
- * Represents a data flow inside the external simulation. An external simulation can operate
- * multiple data flows of different types. For each data type, there needs to be an interface
- * extending this interface which provides methods that receive a data adapter.
- *
- * See {@link edu.ie3.simona.api.data.ev.ExtEvSimulation} for an example.
- */
-public interface ExtDataSimulation {}
diff --git a/src/main/java/edu/ie3/simona/api/data/ExtInputDataConnection.java b/src/main/java/edu/ie3/simona/api/data/ExtInputDataConnection.java
new file mode 100644
index 0000000..d8a29a7
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/ExtInputDataConnection.java
@@ -0,0 +1,21 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data;
+
+import org.apache.pekko.actor.ActorRef;
+
+public interface ExtInputDataConnection extends ExtDataConnection {
+
+ /**
+ * Sets the actor refs for data and control flow.
+ *
+ * @param dataService actor ref to the adapter of the data service for schedule activation
+ * messages
+ * @param extSimAdapter actor ref to the extSimAdapter
+ */
+ void setActorRefs(ActorRef dataService, ActorRef extSimAdapter);
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/ExtInputDataContainer.java b/src/main/java/edu/ie3/simona/api/data/ExtInputDataContainer.java
new file mode 100644
index 0000000..bec23e5
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/ExtInputDataContainer.java
@@ -0,0 +1,69 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data;
+
+import edu.ie3.datamodel.models.value.Value;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+/** Contains all inputs for SIMONA for a certain tick */
+public class ExtInputDataContainer implements ExtDataContainer {
+
+ /** The tick, the input data is meant for */
+ private final long tick;
+
+ /** Map external id to an input value for SIMONA */
+ private final Map dataMap;
+
+ /** The next tick, when data will be provided, if available */
+ private final Optional maybeNextTick;
+
+ /**
+ * Container class for input data for SIMONA which can be read by SimonaAPI
+ *
+ * @param tick The tick, the input data is meant for
+ * @param dataMap data to be provided to SIMONA
+ * @param nextTick tick, when the next data will be provided
+ */
+ public ExtInputDataContainer(long tick, Map dataMap, long nextTick) {
+ this.tick = tick;
+ this.dataMap = dataMap;
+ this.maybeNextTick = Optional.of(nextTick);
+ }
+
+ public ExtInputDataContainer(long tick, Map dataMap) {
+ this.tick = tick;
+ this.dataMap = dataMap;
+ this.maybeNextTick = Optional.empty();
+ }
+
+ public ExtInputDataContainer(long tick) {
+ this(tick, new HashMap<>());
+ }
+
+ public ExtInputDataContainer(long tick, long nextTick) {
+ this(tick, new HashMap<>(), nextTick);
+ }
+
+ public long getTick() {
+ return tick;
+ }
+
+ public Map getSimonaInputMap() {
+ return dataMap;
+ }
+
+ public Optional getMaybeNextTick() {
+ return maybeNextTick;
+ }
+
+ /** Adds a value to the input map */
+ public void addValue(String id, Value value) {
+ dataMap.put(id, value);
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/ExtOutputDataConnection.java b/src/main/java/edu/ie3/simona/api/data/ExtOutputDataConnection.java
new file mode 100644
index 0000000..6ac15e7
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/ExtOutputDataConnection.java
@@ -0,0 +1,27 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data;
+
+import org.apache.pekko.actor.ActorRef;
+
+/**
+ * Interface for a connection between SIMONA and an external simulation with data flow from SIMONA
+ * to external
+ */
+public interface ExtOutputDataConnection extends ExtDataConnection {
+
+ /**
+ * Sets the actor refs for data and control flow
+ *
+ * @param extResultDataService actor ref to the adapter of the data service for data messages
+ * @param dataServiceActivation actor ref to the adapter of the data service for schedule
+ * activation messages
+ * @param extSimAdapter actor ref to the extSimAdapter
+ */
+ void setActorRefs(
+ ActorRef extResultDataService, ActorRef dataServiceActivation, ActorRef extSimAdapter);
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/em/ExtEmDataConnection.java b/src/main/java/edu/ie3/simona/api/data/em/ExtEmDataConnection.java
new file mode 100644
index 0000000..5a0bbaa
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/em/ExtEmDataConnection.java
@@ -0,0 +1,81 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data.em;
+
+import edu.ie3.datamodel.models.value.PValue;
+import edu.ie3.datamodel.models.value.Value;
+import edu.ie3.simona.api.data.ExtInputDataConnection;
+import edu.ie3.simona.api.data.em.ontology.EmDataMessageFromExt;
+import edu.ie3.simona.api.data.em.ontology.ProvideEmSetPointData;
+import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.apache.pekko.actor.ActorRef;
+import org.slf4j.Logger;
+
+/** Enables data connection of em data between SIMONA and SimonaAPI */
+public class ExtEmDataConnection implements ExtInputDataConnection {
+
+ /** Actor reference to service that handles ev data within SIMONA */
+ private ActorRef emDataService;
+
+ /** Actor reference to adapter that handles scheduler control flow in SIMONA */
+ private ActorRef extSimAdapter;
+
+ /** Assets that provide primary data to SIMONA */
+ private final Map extEmMapping;
+
+ public ExtEmDataConnection(Map extEmMapping) {
+ this.extEmMapping = extEmMapping;
+ }
+
+ @Override
+ public void setActorRefs(ActorRef emDataService, ActorRef extSimAdapter) {
+ this.emDataService = emDataService;
+ this.extSimAdapter = extSimAdapter;
+ }
+
+ public void convertAndSend(
+ long tick, Map data, Optional maybeNextTick, Logger log) {
+ // filtering the data and converting the keys
+ Map convertedMap =
+ data.entrySet().stream()
+ .filter(e -> extEmMapping.containsKey(e.getKey()))
+ .collect(
+ Collectors.toMap(e -> extEmMapping.get(e.getKey()), e -> (PValue) e.getValue()));
+
+ if (convertedMap.isEmpty()) {
+ log.warn("No em data found! Sending no em data to SIMONA for tick {}.", tick);
+ } else {
+ log.debug("Provided SIMONA with em data.");
+ provideEmData(tick, convertedMap, maybeNextTick);
+ }
+ }
+
+ /** Returns a list of the uuids of the em agents that expect external set points */
+ public List getControlledEms() {
+ return extEmMapping.values().stream().toList();
+ }
+
+ /** Provide primary data from an external simulation for one tick. */
+ public void provideEmData(Long tick, Map emData, Optional maybeNextTick) {
+ sendExtMsg(new ProvideEmSetPointData(tick, emData, maybeNextTick));
+ }
+
+ /**
+ * Send information from the external simulation to SIMONA's external primary data service.
+ * Furthermore, ExtSimAdapter within SIMONA is instructed to activate the ev data service with the
+ * current tick.
+ *
+ * @param msg the data/information that is sent to SIMONA's external primary data service
+ */
+ public void sendExtMsg(EmDataMessageFromExt msg) {
+ emDataService.tell(msg, ActorRef.noSender());
+ // we need to schedule data receiver activation with scheduler
+ extSimAdapter.tell(new ScheduleDataServiceMessage(emDataService), ActorRef.noSender());
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/em/ontology/EmDataMessageFromExt.java b/src/main/java/edu/ie3/simona/api/data/em/ontology/EmDataMessageFromExt.java
new file mode 100644
index 0000000..5125e29
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/em/ontology/EmDataMessageFromExt.java
@@ -0,0 +1,12 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data.em.ontology;
+
+import edu.ie3.simona.api.data.ontology.DataMessageFromExt;
+
+/** Messages that are sent from an external data simulation which provides em data to SIMONA */
+public interface EmDataMessageFromExt extends DataMessageFromExt {}
diff --git a/src/main/java/edu/ie3/simona/api/data/em/ontology/ProvideEmSetPointData.java b/src/main/java/edu/ie3/simona/api/data/em/ontology/ProvideEmSetPointData.java
new file mode 100644
index 0000000..dc505dc
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/em/ontology/ProvideEmSetPointData.java
@@ -0,0 +1,17 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data.em.ontology;
+
+import edu.ie3.datamodel.models.value.PValue;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+/** Message that provides em data (set points) from an external simulation */
+public record ProvideEmSetPointData(
+ long tick, Map emData, Optional maybeNextTick)
+ implements EmDataMessageFromExt {}
diff --git a/src/main/java/edu/ie3/simona/api/data/ev/ExtEvData.java b/src/main/java/edu/ie3/simona/api/data/ev/ExtEvDataConnection.java
similarity index 92%
rename from src/main/java/edu/ie3/simona/api/data/ev/ExtEvData.java
rename to src/main/java/edu/ie3/simona/api/data/ev/ExtEvDataConnection.java
index 303ff1f..53a71e8 100644
--- a/src/main/java/edu/ie3/simona/api/data/ev/ExtEvData.java
+++ b/src/main/java/edu/ie3/simona/api/data/ev/ExtEvDataConnection.java
@@ -6,28 +6,30 @@
package edu.ie3.simona.api.data.ev;
-import edu.ie3.simona.api.data.ExtData;
+import edu.ie3.simona.api.data.ExtInputDataConnection;
import edu.ie3.simona.api.data.ev.model.EvModel;
import edu.ie3.simona.api.data.ev.ontology.*;
import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage;
-import java.util.*;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.pekko.actor.ActorRef;
-public class ExtEvData implements ExtData {
+public class ExtEvDataConnection implements ExtInputDataConnection {
/** Data message queue containing messages from SIMONA */
public final LinkedBlockingQueue receiveTriggerQueue =
new LinkedBlockingQueue<>();
/** Actor reference to service that handles ev data within SIMONA */
- private final ActorRef dataService;
+ private ActorRef dataService;
/** Actor reference to adapter that handles scheduler control flow in SIMONA */
- private final ActorRef extSimAdapter;
+ private ActorRef extSimAdapter;
- // important trigger queue must be the same as hold in actor
- // to make it safer one might consider asking the actor for ara reference on its trigger queue?!
- public ExtEvData(ActorRef dataService, ActorRef extSimAdapter) {
+ @Override
+ public void setActorRefs(ActorRef dataService, ActorRef extSimAdapter) {
this.dataService = dataService;
this.extSimAdapter = extSimAdapter;
}
diff --git a/src/main/java/edu/ie3/simona/api/data/ev/ExtEvSimulation.java b/src/main/java/edu/ie3/simona/api/data/ev/ExtEvSimulation.java
deleted file mode 100644
index b14fb1f..0000000
--- a/src/main/java/edu/ie3/simona/api/data/ev/ExtEvSimulation.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * © 2021. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data.ev;
-
-import edu.ie3.simona.api.data.ExtDataSimulation;
-
-/**
- * An external simulation that provides an ev mobility simulation should implement this interface
- * and handle the ExtEvData that is handed over.
- */
-public interface ExtEvSimulation extends ExtDataSimulation {
-
- /**
- * Hand over an ExtEvData which enables communication regarding ev movements.
- *
- * @param evData the ev data
- */
- void setExtEvData(ExtEvData evData);
-}
diff --git a/src/main/java/edu/ie3/simona/api/data/ev/model/EvModel.java b/src/main/java/edu/ie3/simona/api/data/ev/model/EvModel.java
index 06f8b7c..2ea3082 100644
--- a/src/main/java/edu/ie3/simona/api/data/ev/model/EvModel.java
+++ b/src/main/java/edu/ie3/simona/api/data/ev/model/EvModel.java
@@ -23,14 +23,14 @@ public interface EvModel {
String getId();
/**
- * @return the maximum AC charging power of this ev
+ * @return the maximum AC charging power of this ev (as active power)
*/
- ComparableQuantity getSRatedAC();
+ ComparableQuantity getPRatedAC();
/**
- * @return the maximum DC charging power of this ev
+ * @return the maximum DC charging power of this ev (as active power)
*/
- ComparableQuantity getSRatedDC();
+ ComparableQuantity getPRatedDC();
/**
* @return the storage capacity of this ev's battery
diff --git a/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryData.java b/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryData.java
deleted file mode 100644
index 7188e29..0000000
--- a/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryData.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * © 2024. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data.primarydata;
-
-import edu.ie3.datamodel.models.value.Value;
-import edu.ie3.simona.api.data.ExtData;
-import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage;
-import edu.ie3.simona.api.data.primarydata.ontology.PrimaryDataMessageFromExt;
-import edu.ie3.simona.api.data.primarydata.ontology.ProvidePrimaryData;
-import edu.ie3.simona.api.exceptions.ConvertionException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-import org.apache.pekko.actor.ActorRef;
-
-public class ExtPrimaryData implements ExtData {
-
- /** Actor reference to service that handles ev data within SIMONA */
- private final ActorRef dataService;
-
- /** Actor reference to adapter that handles scheduler control flow in SIMONA */
- private final ActorRef extSimAdapter;
-
- /** Factory to convert an external object to PSDM primary data */
- private final PrimaryDataFactory factory;
-
- public ExtPrimaryData(ActorRef dataService, ActorRef extSimAdapter, PrimaryDataFactory factory) {
- this.dataService = dataService;
- this.extSimAdapter = extSimAdapter;
- this.factory = factory;
- }
-
- /** Provide primary data from an external simulation in one tick. */
- public void providePrimaryData(Long tick, Map primaryData) {
- Map convertedMap = new HashMap<>();
- primaryData.forEach(
- (k, v) -> {
- try {
- convertedMap.put(UUID.fromString(k), factory.convert(v));
- } catch (ConvertionException e) {
- throw new RuntimeException(e);
- }
- });
- sendExtMsg(new ProvidePrimaryData(tick, convertedMap));
- }
-
- /**
- * Send information from the external simulation to SIMONA's external primary data service.
- * Furthermore, ExtSimAdapter within SIMONA is instructed to activate the ev data service with the
- * current tick.
- *
- * @param msg the data/information that is sent to SIMONA's external primary data service
- */
- public void sendExtMsg(PrimaryDataMessageFromExt msg) {
- dataService.tell(msg, ActorRef.noSender());
- // we need to schedule data receiver activation with scheduler
- extSimAdapter.tell(new ScheduleDataServiceMessage(dataService), ActorRef.noSender());
- }
-}
diff --git a/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataConnection.java b/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataConnection.java
new file mode 100644
index 0000000..10fe184
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataConnection.java
@@ -0,0 +1,81 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data.primarydata;
+
+import edu.ie3.datamodel.models.value.Value;
+import edu.ie3.simona.api.data.ExtInputDataConnection;
+import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage;
+import edu.ie3.simona.api.data.primarydata.ontology.PrimaryDataMessageFromExt;
+import edu.ie3.simona.api.data.primarydata.ontology.ProvidePrimaryData;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.apache.pekko.actor.ActorRef;
+import org.slf4j.Logger;
+
+/** Enables data connection of primary data between SIMONA and SimonaAPI */
+public class ExtPrimaryDataConnection implements ExtInputDataConnection {
+
+ /** Actor reference to service that handles primary data within SIMONA */
+ private ActorRef dataService;
+
+ /** Actor reference to adapter that handles scheduler control flow in SIMONA */
+ private ActorRef extSimAdapter;
+
+ /** Assets that provide primary data to SIMONA */
+ private final Map extPrimaryDataMapping;
+
+ public ExtPrimaryDataConnection(Map extPrimaryDataMapping) {
+ this.extPrimaryDataMapping = extPrimaryDataMapping;
+ }
+
+ @Override
+ public void setActorRefs(ActorRef dataService, ActorRef extSimAdapter) {
+ this.dataService = dataService;
+ this.extSimAdapter = extSimAdapter;
+ }
+
+ public void convertAndSend(
+ long tick, Map data, Optional maybeNextTick, Logger log) {
+ // filtering the data and converting the keys
+ Map convertedMap =
+ data.entrySet().stream()
+ .filter(e -> extPrimaryDataMapping.containsKey(e.getKey()))
+ .collect(
+ Collectors.toMap(e -> extPrimaryDataMapping.get(e.getKey()), Map.Entry::getValue));
+
+ if (convertedMap.isEmpty()) {
+ log.warn("No primary data found! Sending no primary data to SIMONA for tick {}.", tick);
+ } else {
+ log.debug("Provided SIMONA with primary data.");
+ providePrimaryData(tick, convertedMap, maybeNextTick);
+ }
+ }
+
+ /** Returns a list of the uuids of the system participants that expect external primary data */
+ public List getPrimaryDataAssets() {
+ return extPrimaryDataMapping.values().stream().toList();
+ }
+
+ /** Provide primary data from an external simulation in one tick. */
+ public void providePrimaryData(
+ Long tick, Map primaryData, Optional maybeNextTick) {
+ sendExtMsg(new ProvidePrimaryData(tick, primaryData, maybeNextTick));
+ }
+
+ /**
+ * Send information from the external simulation to SIMONA's external primary data service.
+ * Furthermore, ExtSimAdapter within SIMONA is instructed to activate the ev data service with the
+ * current tick.
+ *
+ * @param msg the data/information that is sent to SIMONA's external primary data service
+ */
+ public void sendExtMsg(PrimaryDataMessageFromExt msg) {
+ dataService.tell(msg, ActorRef.noSender());
+ // we need to schedule data receiver activation with scheduler
+ extSimAdapter.tell(new ScheduleDataServiceMessage(dataService), ActorRef.noSender());
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataSimulation.java b/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataSimulation.java
deleted file mode 100644
index d217209..0000000
--- a/src/main/java/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataSimulation.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * © 2024. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data.primarydata;
-
-import edu.ie3.simona.api.data.ExtDataSimulation;
-
-/**
- * An external simulation that provides primary data should implement this interface and handle the
- * ExtPrimaryData that is handed over.
- */
-public interface ExtPrimaryDataSimulation extends ExtDataSimulation {
-
- /** Hand over an ExtPrimaryData which enables communication regarding primary data. */
- void setExtPrimaryData(ExtPrimaryData extPrimaryData);
-
- /** Should implement the convertion of the external format to the PSDM format of primary data. */
- PrimaryDataFactory getPrimaryDataFactory();
-}
diff --git a/src/main/java/edu/ie3/simona/api/data/primarydata/PrimaryDataFactory.java b/src/main/java/edu/ie3/simona/api/data/primarydata/PrimaryDataFactory.java
deleted file mode 100644
index 9ff74d5..0000000
--- a/src/main/java/edu/ie3/simona/api/data/primarydata/PrimaryDataFactory.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * © 2024. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data.primarydata;
-
-import edu.ie3.datamodel.models.value.Value;
-import edu.ie3.simona.api.exceptions.ConvertionException;
-
-/** Interface that should be implemented by an external simulation. */
-public interface PrimaryDataFactory {
-
- /** Should convert an object to a primary data value with a check if the object is primary data */
- Value convert(Object entity) throws ConvertionException;
-}
diff --git a/src/main/java/edu/ie3/simona/api/data/primarydata/ontology/ProvidePrimaryData.java b/src/main/java/edu/ie3/simona/api/data/primarydata/ontology/ProvidePrimaryData.java
index a87d9f7..2c31632 100644
--- a/src/main/java/edu/ie3/simona/api/data/primarydata/ontology/ProvidePrimaryData.java
+++ b/src/main/java/edu/ie3/simona/api/data/primarydata/ontology/ProvidePrimaryData.java
@@ -8,8 +8,10 @@
import edu.ie3.datamodel.models.value.Value;
import java.util.Map;
+import java.util.Optional;
import java.util.UUID;
/** Message that provides primary data from an external primary data simulation */
-public record ProvidePrimaryData(long tick, Map primaryData)
+public record ProvidePrimaryData(
+ long tick, Map primaryData, Optional maybeNextTick)
implements PrimaryDataMessageFromExt {}
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ExtResultContainer.java b/src/main/java/edu/ie3/simona/api/data/results/ExtResultContainer.java
new file mode 100644
index 0000000..531faf7
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/data/results/ExtResultContainer.java
@@ -0,0 +1,110 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.data.results;
+
+import static edu.ie3.util.quantities.PowerSystemUnits.PU;
+
+import edu.ie3.datamodel.models.result.ModelResultEntity;
+import edu.ie3.datamodel.models.result.NodeResult;
+import edu.ie3.datamodel.models.result.connector.LineResult;
+import edu.ie3.datamodel.models.result.system.SystemParticipantResult;
+import edu.ie3.simona.api.data.ExtDataContainer;
+import java.util.Map;
+import java.util.Optional;
+import javax.measure.quantity.Dimensionless;
+import tech.units.indriya.ComparableQuantity;
+import tech.units.indriya.quantity.Quantities;
+
+/** Contains all results from SIMONA for a certain tick */
+public class ExtResultContainer implements ExtDataContainer {
+
+ /** Tick the results are meant for */
+ private final long tick;
+
+ /** Tick the external simulation can expect the next results */
+ private final Optional maybeNextTick;
+
+ /**
+ * Map external id to result from SIMONA ATTENTION: The time stamp of the result entities is not
+ * necessarily corresponding to the tick
+ */
+ private final Map simonaResultsMap;
+
+ /**
+ * Container class for result data from SIMONA
+ *
+ * @param tick current tick
+ * @param simonaResultsMap results from SIMONA with external id as key
+ * @param nextTick tick the external simulation can expect the next results
+ */
+ public ExtResultContainer(
+ long tick, Map simonaResultsMap, Optional nextTick) {
+ this.tick = tick;
+ this.simonaResultsMap = simonaResultsMap;
+ this.maybeNextTick = nextTick;
+ }
+
+ public ExtResultContainer(long tick, Map simonaResultsMap) {
+ this(tick, simonaResultsMap, Optional.empty());
+ }
+
+ public Map getResults() {
+ return simonaResultsMap;
+ }
+
+ public Long getTick() {
+ return tick;
+ }
+
+ public Optional getNextTick() {
+ return maybeNextTick;
+ }
+
+ /**
+ * Returns the voltage deviation for certain asset, if this asset provided a {@link NodeResult}
+ */
+ public double getVoltageDeviation(String assetId) {
+ if (simonaResultsMap.get(assetId) instanceof NodeResult nodeResult) {
+ ComparableQuantity vMagDev =
+ Quantities.getQuantity(-1.0, PU).add(nodeResult.getvMag());
+ return vMagDev.getValue().doubleValue();
+ } else {
+ throw new IllegalArgumentException("VOLTAGE DEVIATION is only available for NodeResult's!");
+ }
+ }
+
+ /**
+ * Returns the active power in kW for certain asset, if this asset provided a {@link
+ * SystemParticipantResult}
+ */
+ public double getActivePower(String assetId) {
+ if (simonaResultsMap.get(assetId) instanceof SystemParticipantResult systemParticipantResult) {
+ return systemParticipantResult.getP().getValue().doubleValue();
+ } else {
+ throw new IllegalArgumentException(
+ "ACTIVE POWER is only available for SystemParticipantResult's!");
+ }
+ }
+
+ /**
+ * Returns the reactive power in kVAr for certain asset, if this asset provided a {@link
+ * SystemParticipantResult}
+ */
+ public double getReactivePower(String assetId) {
+ if (simonaResultsMap.get(assetId) instanceof SystemParticipantResult systemParticipantResult) {
+ return systemParticipantResult.getQ().getValue().doubleValue();
+ } else {
+ throw new IllegalArgumentException(
+ "REACTIVE POWER is only available for SystemParticipantResult's!");
+ }
+ }
+
+ /** Returns the line loading for certain asset, if this asset provided a {@link LineResult} */
+ public double getLineLoading(String assetId) {
+ throw new IllegalArgumentException("LINE LOADING is not implemented yet!");
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ExtResultData.java b/src/main/java/edu/ie3/simona/api/data/results/ExtResultDataConnection.java
similarity index 51%
rename from src/main/java/edu/ie3/simona/api/data/results/ExtResultData.java
rename to src/main/java/edu/ie3/simona/api/data/results/ExtResultDataConnection.java
index ae5d0ea..de90fa4 100644
--- a/src/main/java/edu/ie3/simona/api/data/results/ExtResultData.java
+++ b/src/main/java/edu/ie3/simona/api/data/results/ExtResultDataConnection.java
@@ -7,62 +7,101 @@
package edu.ie3.simona.api.data.results;
import edu.ie3.datamodel.models.result.ModelResultEntity;
-import edu.ie3.simona.api.data.ExtData;
+import edu.ie3.datamodel.models.result.NodeResult;
+import edu.ie3.datamodel.models.result.system.SystemParticipantResult;
+import edu.ie3.simona.api.data.ExtOutputDataConnection;
import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage;
import edu.ie3.simona.api.data.results.ontology.ProvideResultEntities;
import edu.ie3.simona.api.data.results.ontology.RequestResultEntities;
import edu.ie3.simona.api.data.results.ontology.ResultDataMessageFromExt;
import edu.ie3.simona.api.data.results.ontology.ResultDataResponseMessageToExt;
-import edu.ie3.simona.api.exceptions.ConvertionException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.pekko.actor.ActorRef;
-public class ExtResultData implements ExtData {
+/** Enables data connection of results between SIMONA and SimonaAPI */
+public class ExtResultDataConnection implements ExtOutputDataConnection {
/** Data message queue containing messages from SIMONA */
public final LinkedBlockingQueue receiveTriggerQueue =
new LinkedBlockingQueue<>();
- /** Actor reference to service that handles ev data within SIMONA */
- private final ActorRef dataService;
+ /** Actor reference to service that handles result data within SIMONA */
+ private ActorRef extResultDataService;
+
+ /** Actor reference to the dataServiceAdapter */
+ private ActorRef dataServiceActivation;
/** Actor reference to adapter that handles scheduler control flow in SIMONA */
- private final ActorRef extSimAdapter;
+ private ActorRef extSimAdapter;
+
+ /** Map uuid to external id of grid related entities */
+ private final Map gridResultAssetMapping;
+
+ /** Map uuid to external id of system participants */
+ private final Map participantResultAssetMapping;
- private final ResultDataFactory factory;
+ public ExtResultDataConnection(
+ Map participantResultAssetMapping, Map gridResultAssetMapping) {
+ this.participantResultAssetMapping = participantResultAssetMapping;
+ this.gridResultAssetMapping = gridResultAssetMapping;
+ }
- public ExtResultData(ActorRef dataService, ActorRef extSimAdapter, ResultDataFactory factory) {
- this.dataService = dataService;
+ /**
+ * Sets the actor refs for data and control flow
+ *
+ * @param extResultDataService actor ref to the adapter of the data service for data messages
+ * @param dataServiceActivation actor ref to the adapter of the data service for schedule
+ * activation messages
+ * @param extSimAdapter actor ref to the extSimAdapter
+ */
+ public void setActorRefs(
+ ActorRef extResultDataService, ActorRef dataServiceActivation, ActorRef extSimAdapter) {
+ this.extResultDataService = extResultDataService;
+ this.dataServiceActivation = dataServiceActivation;
this.extSimAdapter = extSimAdapter;
- this.factory = factory;
+ }
+
+ public List getGridResultDataAssets() {
+ return gridResultAssetMapping.keySet().stream().toList();
+ }
+
+ public List getParticipantResultDataAssets() {
+ return participantResultAssetMapping.keySet().stream().toList();
}
/** Method that an external simulation can request results from SIMONA as a list. */
- public List requestResults() throws InterruptedException {
- sendExtMsg(new RequestResultEntities());
+ private List requestResultList(long tick) throws InterruptedException {
+ sendExtMsg(new RequestResultEntities(tick));
return receiveWithType(ProvideResultEntities.class).results();
}
/**
* Method that an external simulation can request results from SIMONA as a map string to object.
*/
- public Map requestResultObjects()
- throws ConvertionException, InterruptedException {
- return convertResultsList(requestResults());
+ public Map requestResults(long tick) throws InterruptedException {
+ return createResultMap(requestResultList(tick));
}
- protected Map convertResultsList(List results)
- throws ConvertionException {
- Map resultsMap = new HashMap<>();
- Object convertedResult;
- for (ModelResultEntity res : results) {
- convertedResult = factory.convert(res);
- resultsMap.put(res.getInputModel().toString(), convertedResult);
- }
- return resultsMap;
+ protected Map createResultMap(List results) {
+ Map resultMap = new HashMap<>();
+ results.forEach(
+ result -> {
+ if (result instanceof NodeResult nodeResult) {
+ resultMap.put(gridResultAssetMapping.get(nodeResult.getInputModel()), nodeResult);
+ } else if (result instanceof SystemParticipantResult systemParticipantResult) {
+ resultMap.put(
+ participantResultAssetMapping.get(systemParticipantResult.getInputModel()),
+ systemParticipantResult);
+ } else {
+ throw new IllegalArgumentException(
+ "ExtResultData can only handle NodeResult's and SystemParticipantResult's!");
+ }
+ });
+ return resultMap;
}
/**
@@ -73,9 +112,9 @@ protected Map convertResultsList(List results
* @param msg the data/information that is sent to SIMONA's result data service
*/
public void sendExtMsg(ResultDataMessageFromExt msg) {
- dataService.tell(msg, ActorRef.noSender());
+ extResultDataService.tell(msg, ActorRef.noSender());
// we need to schedule data receiver activation with scheduler
- extSimAdapter.tell(new ScheduleDataServiceMessage(dataService), ActorRef.noSender());
+ extSimAdapter.tell(new ScheduleDataServiceMessage(dataServiceActivation), ActorRef.noSender());
}
/** Queues message from SIMONA that should be handled by the external simulation. */
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ExtResultDataSimulation.java b/src/main/java/edu/ie3/simona/api/data/results/ExtResultDataSimulation.java
deleted file mode 100644
index 31ea7ac..0000000
--- a/src/main/java/edu/ie3/simona/api/data/results/ExtResultDataSimulation.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * © 2024. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data.results;
-
-import edu.ie3.simona.api.data.ExtDataSimulation;
-
-/**
- * An external simulation that needs results from SIMONA should implement this interface and handle
- * the ExtResultsData that is handed over.
- */
-public interface ExtResultDataSimulation extends ExtDataSimulation {
-
- /** Hand over an ExtPrimaryData which enables communication regarding primary data. */
- void setExtResultData(ExtResultData extResultData);
-
- /** Should implement the convertion of the PSDM format to the external format of result data. */
- ResultDataFactory getResultDataFactory();
-}
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ResultDataFactory.java b/src/main/java/edu/ie3/simona/api/data/results/ResultDataFactory.java
deleted file mode 100644
index 1632944..0000000
--- a/src/main/java/edu/ie3/simona/api/data/results/ResultDataFactory.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * © 2024. TU Dortmund University,
- * Institute of Energy Systems, Energy Efficiency and Energy Economics,
- * Research group Distribution grid planning and operation
- */
-
-package edu.ie3.simona.api.data.results;
-
-import edu.ie3.datamodel.models.result.ResultEntity;
-import edu.ie3.simona.api.exceptions.ConvertionException;
-
-public interface ResultDataFactory {
-
- /**
- * Should convert a result entity to an object, that can be read by the external simulation, with
- * a check if the object is primary data
- */
- Object convert(ResultEntity entity) throws ConvertionException;
-}
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ontology/ProvideResultEntities.java b/src/main/java/edu/ie3/simona/api/data/results/ontology/ProvideResultEntities.java
index 7c11cfb..525d702 100644
--- a/src/main/java/edu/ie3/simona/api/data/results/ontology/ProvideResultEntities.java
+++ b/src/main/java/edu/ie3/simona/api/data/results/ontology/ProvideResultEntities.java
@@ -8,7 +8,13 @@
import edu.ie3.datamodel.models.result.ModelResultEntity;
import java.util.List;
+import java.util.Map;
+import java.util.UUID;
/** Provides a list of results from SIMONA to an external simulation. */
public record ProvideResultEntities(List results)
- implements ResultDataResponseMessageToExt {}
+ implements ResultDataResponseMessageToExt {
+ public ProvideResultEntities(Map resultMap) {
+ this(resultMap.values().stream().toList());
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ontology/RequestResultEntities.java b/src/main/java/edu/ie3/simona/api/data/results/ontology/RequestResultEntities.java
index 05f8aae..8ef656b 100644
--- a/src/main/java/edu/ie3/simona/api/data/results/ontology/RequestResultEntities.java
+++ b/src/main/java/edu/ie3/simona/api/data/results/ontology/RequestResultEntities.java
@@ -7,4 +7,4 @@
package edu.ie3.simona.api.data.results.ontology;
/** Request calculated results from SIMONA in the current tick */
-public record RequestResultEntities() implements ResultDataMessageFromExt {}
+public record RequestResultEntities(Long tick) implements ResultDataMessageFromExt {}
diff --git a/src/main/java/edu/ie3/simona/api/data/results/ontology/ResultDataMessageFromExt.java b/src/main/java/edu/ie3/simona/api/data/results/ontology/ResultDataMessageFromExt.java
index 60ebff4..83b2e31 100644
--- a/src/main/java/edu/ie3/simona/api/data/results/ontology/ResultDataMessageFromExt.java
+++ b/src/main/java/edu/ie3/simona/api/data/results/ontology/ResultDataMessageFromExt.java
@@ -6,5 +6,7 @@
package edu.ie3.simona.api.data.results.ontology;
+import edu.ie3.simona.api.data.ontology.DataMessageFromExt;
+
/** Messages that are sent from an external simulation to the SIMONA */
-public interface ResultDataMessageFromExt {}
+public interface ResultDataMessageFromExt extends DataMessageFromExt {}
diff --git a/src/main/java/edu/ie3/simona/api/exceptions/NoExtSimulationException.java b/src/main/java/edu/ie3/simona/api/exceptions/NoExtSimulationException.java
new file mode 100644
index 0000000..f4a242b
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/exceptions/NoExtSimulationException.java
@@ -0,0 +1,20 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.exceptions;
+
+import edu.ie3.simona.api.ExtLinkInterface;
+
+public class NoExtSimulationException extends RuntimeException {
+
+ public NoExtSimulationException(Class extends ExtLinkInterface> linkClass) {
+ this("No external simulation was set up in ExtLinkInterface: ." + linkClass.getSimpleName());
+ }
+
+ public NoExtSimulationException(final String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/ExtCoSimulation.java b/src/main/java/edu/ie3/simona/api/simulation/ExtCoSimulation.java
new file mode 100644
index 0000000..f07ec9b
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/simulation/ExtCoSimulation.java
@@ -0,0 +1,178 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.simulation;
+
+import edu.ie3.datamodel.models.result.ModelResultEntity;
+import edu.ie3.datamodel.models.value.Value;
+import edu.ie3.simona.api.data.DataQueueExtSimulationExtSimulator;
+import edu.ie3.simona.api.data.ExtInputDataContainer;
+import edu.ie3.simona.api.data.em.ExtEmDataConnection;
+import edu.ie3.simona.api.data.primarydata.ExtPrimaryDataConnection;
+import edu.ie3.simona.api.data.results.ExtResultContainer;
+import edu.ie3.simona.api.data.results.ExtResultDataConnection;
+import edu.ie3.simona.api.simulation.mapping.DataType;
+import edu.ie3.simona.api.simulation.mapping.ExtEntityMapping;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import org.slf4j.Logger;
+
+/**
+ * Abstract class for an external co-simulation with the structure: external api - ext-co-simulation
+ * - extsimulation - simonaAPI - simona It contains all function to transfer primary data and em
+ * data to SIMONA and results to the external co-simulation.
+ */
+public abstract class ExtCoSimulation extends ExtSimulation {
+
+ /** Queue for the data connection from the external co-simulation to SimonaAPI */
+ protected final DataQueueExtSimulationExtSimulator
+ dataQueueExtCoSimulatorToSimonaApi;
+
+ /** Queue for the data connection from SimonaAPI to the external co-simulation */
+ protected final DataQueueExtSimulationExtSimulator
+ dataQueueSimonaApiToExtCoSimulator;
+
+ /** Name of the external co-simulation */
+ protected final String extSimulatorName;
+
+ protected ExtCoSimulation(String simulationName, String extSimulatorName) {
+ super(simulationName);
+ this.extSimulatorName = extSimulatorName;
+ this.dataQueueExtCoSimulatorToSimonaApi = new DataQueueExtSimulationExtSimulator<>();
+ this.dataQueueSimonaApiToExtCoSimulator = new DataQueueExtSimulationExtSimulator<>();
+ }
+
+ /**
+ * Builds an {@link ExtPrimaryDataConnection}.
+ *
+ * @param mapping between the external simulation and SIMONA.
+ * @param log logger
+ * @return an ext primary data connection
+ */
+ protected static ExtPrimaryDataConnection buildPrimaryConnection(
+ ExtEntityMapping mapping, Logger log) {
+ Map primaryMapping = mapping.getExtId2UuidMapping(DataType.EXT_PRIMARY_INPUT);
+ ExtPrimaryDataConnection extPrimaryDataConnection =
+ new ExtPrimaryDataConnection(primaryMapping);
+
+ if (primaryMapping.isEmpty()) {
+ log.warn("Primary with 0 entities created.");
+ } else {
+ log.info("Primary connection with {} entities created.", primaryMapping.size());
+ }
+
+ return extPrimaryDataConnection;
+ }
+
+ /**
+ * Builds an {@link ExtEmDataConnection}.
+ *
+ * @param mapping between the external simulation and SIMONA.
+ * @param log logger
+ * @return an ext em data connection
+ */
+ protected static ExtEmDataConnection buildEmConnection(ExtEntityMapping mapping, Logger log) {
+ Map emMapping = mapping.getExtId2UuidMapping(DataType.EXT_EM_INPUT);
+ ExtEmDataConnection extEmDataConnection = new ExtEmDataConnection(emMapping);
+
+ if (emMapping.isEmpty()) {
+ log.warn("Em connection with 0 entities created.");
+ } else {
+ log.info("Em connection with {} entities created.", emMapping.size());
+ }
+
+ return extEmDataConnection;
+ }
+
+ /**
+ * Builds an {@link ExtResultDataConnection}.
+ *
+ * @param mapping between the external simulation and SIMONA.
+ * @param log logger
+ * @return an ext result data connection
+ */
+ protected static ExtResultDataConnection buildResultConnection(
+ ExtEntityMapping mapping, Logger log) {
+ Map resultParticipantMapping =
+ mapping.getExtUuid2IdMapping(DataType.EXT_PARTICIPANT_RESULT);
+ Map resultGridMapping = mapping.getExtUuid2IdMapping(DataType.EXT_GRID_RESULT);
+ ExtResultDataConnection extResultDataConnection =
+ new ExtResultDataConnection(resultParticipantMapping, resultGridMapping);
+
+ if (resultParticipantMapping.isEmpty() && resultGridMapping.isEmpty()) {
+ log.warn("Result connection with 0 participants and 0 grid assets created.");
+ } else {
+ log.info(
+ "Result connection with {} participants and {} grid assets created.",
+ resultParticipantMapping.size(),
+ resultGridMapping.size());
+ }
+
+ return extResultDataConnection;
+ }
+
+ /**
+ * Function to send primary data to SIMONA using ExtPrimaryData
+ *
+ * @param extPrimaryDataConnection the connection to SIMONA
+ * @param tick for which data is sent
+ * @param dataMap map: id to value
+ * @param maybeNextTick option for the next tick data is sent
+ * @param log logger
+ */
+ protected void sendPrimaryDataToSimona(
+ ExtPrimaryDataConnection extPrimaryDataConnection,
+ long tick,
+ Map dataMap,
+ Optional maybeNextTick,
+ Logger log) {
+ log.debug("Wait for Primary Data from {}", extSimulatorName);
+ log.debug("Received Primary Data from {}", extSimulatorName);
+ extPrimaryDataConnection.convertAndSend(tick, dataMap, maybeNextTick, log);
+ log.debug("Provided Primary Data to SIMONA!");
+ }
+
+ /**
+ * Function to send em data to SIMONA using ExtPrimaryData nextTick is necessary, because the em
+ * agents have an own scheduler that should know, when the next set point arrives.
+ *
+ * @param extEmDataConnection the connection to SIMONA
+ * @param tick for which data is sent
+ * @param dataMap map: id to value
+ * @param maybeNextTick option for the next tick data is sent
+ * @param log logger
+ */
+ protected void sendEmDataToSimona(
+ ExtEmDataConnection extEmDataConnection,
+ long tick,
+ Map dataMap,
+ Optional maybeNextTick,
+ Logger log) {
+ log.debug("Received EmData from {}", extSimulatorName);
+ extEmDataConnection.convertAndSend(tick, dataMap, maybeNextTick, log);
+ log.debug("Provided EmData to SIMONA!");
+ }
+
+ /**
+ * Function to get result data from SIMONA using the available {@link ExtResultDataConnection}
+ *
+ * @param connection the connection to SIMONA
+ * @param tick for which data is received
+ * @param maybeNextTick option for the next tick data is received
+ * @param log logger
+ */
+ protected void sendDataToExt(
+ ExtResultDataConnection connection, long tick, Optional maybeNextTick, Logger log)
+ throws InterruptedException {
+ log.debug("Request results from SIMONA!");
+ Map resultsToBeSend = connection.requestResults(tick);
+ log.debug("Received results from SIMONA!");
+ dataQueueSimonaApiToExtCoSimulator.queueData(
+ new ExtResultContainer(tick, resultsToBeSend, maybeNextTick));
+ log.debug("Sent results to {}", extSimulatorName);
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/ExtSimAdapterData.java b/src/main/java/edu/ie3/simona/api/simulation/ExtSimAdapterData.java
index 20004bc..e0906ce 100644
--- a/src/main/java/edu/ie3/simona/api/simulation/ExtSimAdapterData.java
+++ b/src/main/java/edu/ie3/simona/api/simulation/ExtSimAdapterData.java
@@ -17,7 +17,7 @@ public class ExtSimAdapterData {
public final LinkedBlockingQueue receiveMessageQueue =
new LinkedBlockingQueue<>();
- /** Actor reference to adapter that handles scheduler control flow in SIMONA */
+ /** Actor reference to the adapter for the phases that handles scheduler control flow in SIMONA */
private final ActorRef extSimAdapter;
/** CLI arguments with which SIMONA is initiated */
@@ -30,6 +30,10 @@ public ExtSimAdapterData(ActorRef extSimAdapter, String[] mainArgs) {
this.mainArgs = mainArgs;
}
+ public ActorRef getAdapter() {
+ return extSimAdapter;
+ }
+
/**
* Called within SIMONA to queue messages for the external simulation
*
diff --git a/src/main/java/edu/ie3/simona/api/simulation/ExtSimulation.java b/src/main/java/edu/ie3/simona/api/simulation/ExtSimulation.java
index ae900cd..0e52a81 100644
--- a/src/main/java/edu/ie3/simona/api/simulation/ExtSimulation.java
+++ b/src/main/java/edu/ie3/simona/api/simulation/ExtSimulation.java
@@ -6,13 +6,10 @@
package edu.ie3.simona.api.simulation;
-import edu.ie3.simona.api.data.ExtData;
-import edu.ie3.simona.api.data.ev.ExtEvData;
-import edu.ie3.simona.api.data.ev.ExtEvSimulation;
+import edu.ie3.simona.api.data.ExtDataConnection;
import edu.ie3.simona.api.simulation.ontology.*;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Optional;
+import java.util.Set;
/**
* Every external simulation must extend this class in order to get triggered by the main
@@ -20,9 +17,13 @@
*/
public abstract class ExtSimulation implements Runnable {
+ protected String simulationName;
+
private ExtSimAdapterData data;
- protected ExtSimulation() {}
+ protected ExtSimulation(String simulationName) {
+ this.simulationName = simulationName;
+ }
public void run() {
try {
@@ -100,22 +101,14 @@ protected void terminate(Boolean simulationSuccessful) {
// to be overwritten in subclass
}
- public final List> getRequiredAdapters() {
- ArrayList> classes = new ArrayList<>();
-
- if (this instanceof ExtEvSimulation) classes.add(ExtEvData.class);
-
- return classes;
- }
-
- public final void setup(ExtSimAdapterData data, List adapters) {
+ /**
+ * Method to set the external simulation adapter data. This method should be called during {@link
+ * edu.ie3.simona.api.ExtLinkInterface#setup(ExtSimAdapterData)}.
+ *
+ * @param data to set up
+ */
+ public final void setAdapterData(ExtSimAdapterData data) {
this.data = data;
-
- // todo sanity check if all required data is available
- for (ExtData adapter : adapters) {
- if (adapter instanceof ExtEvData && this instanceof ExtEvSimulation)
- ((ExtEvSimulation) this).setExtEvData((ExtEvData) adapter);
- }
}
/**
@@ -126,4 +119,12 @@ public final void setup(ExtSimAdapterData data, List adapters) {
protected String[] getMainArgs() {
return data.getMainArgs();
}
+
+ /** Returns the name of this external simulation. */
+ public final String getSimulationName() {
+ return simulationName;
+ }
+
+ /** Returns all {@link ExtDataConnection} of this simulation. */
+ public abstract Set getDataConnections();
}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/mapping/DataType.java b/src/main/java/edu/ie3/simona/api/simulation/mapping/DataType.java
new file mode 100644
index 0000000..67bfaa1
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/simulation/mapping/DataType.java
@@ -0,0 +1,32 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.simulation.mapping;
+
+import edu.ie3.datamodel.exceptions.ParsingException;
+
+public enum DataType {
+ EXT_PRIMARY_INPUT("primary_input"),
+ EXT_EM_INPUT("em_input"),
+ EXT_GRID_RESULT("grid_result"),
+ EXT_PARTICIPANT_RESULT("participant_result");
+
+ public final String type;
+
+ DataType(String type) {
+ this.type = type;
+ }
+
+ public static DataType parse(String type) throws ParsingException {
+ return switch (type) {
+ case "primary_input" -> EXT_PRIMARY_INPUT;
+ case "em_input" -> EXT_EM_INPUT;
+ case "grid_result" -> EXT_GRID_RESULT;
+ case "participant_result" -> EXT_PARTICIPANT_RESULT;
+ default -> throw new ParsingException("Data type " + type + " is not supported!");
+ };
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityEntry.java b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityEntry.java
new file mode 100644
index 0000000..1444c3e
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityEntry.java
@@ -0,0 +1,43 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.simulation.mapping;
+
+import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme;
+import edu.ie3.datamodel.models.input.InputEntity;
+import java.util.UUID;
+
+/**
+ * Container for an external asset with all information for the mapping
+ *
+ * @param uuid SIMONA uuid
+ * @param id external id
+ * @param columnScheme data types the external asset expects
+ * @param dataType data types the external asset expects
+ */
+public record ExtEntityEntry(
+ UUID uuid,
+ String id,
+ ColumnScheme columnScheme, // FIXME: placeholder -> ColumnScheme should handle more data types
+ DataType dataType)
+ implements InputEntity {
+
+ public String toString() {
+ return "ExtEntityEntry={"
+ + "UUID="
+ + uuid
+ + ", "
+ + "extId="
+ + id
+ + ", "
+ + "columnScheme="
+ + columnScheme
+ + ", "
+ + "dataType="
+ + dataType
+ + "}";
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityFactory.java b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityFactory.java
new file mode 100644
index 0000000..9a82025
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityFactory.java
@@ -0,0 +1,56 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.simulation.mapping;
+
+import edu.ie3.datamodel.exceptions.FactoryException;
+import edu.ie3.datamodel.exceptions.ParsingException;
+import edu.ie3.datamodel.io.factory.EntityData;
+import edu.ie3.datamodel.io.factory.EntityFactory;
+import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/** Class to build a mapping entry from the external simulation to SIMONA */
+public class ExtEntityFactory extends EntityFactory {
+
+ public static final String SIMONA_UUID = "uuid";
+ public static final String EXT_ID = "id";
+ public static final String COLUMN_SCHEME = "columnScheme";
+ public static final String DATA_TYPE = "dataType";
+
+ public ExtEntityFactory() {
+ super(ExtEntityEntry.class);
+ }
+
+ @Override
+ protected List> getFields(Class> entityClass) {
+ return Collections.singletonList(
+ Stream.of(SIMONA_UUID, EXT_ID, COLUMN_SCHEME, DATA_TYPE).collect(Collectors.toSet()));
+ }
+
+ @Override
+ protected ExtEntityEntry buildModel(EntityData data) {
+ UUID simonaUuid = data.getUUID(SIMONA_UUID);
+ String extId = data.getField(EXT_ID);
+ Optional columnScheme = ColumnScheme.parse(data.getField(COLUMN_SCHEME));
+
+ DataType inputType;
+ try {
+ inputType = DataType.parse(data.getField(DATA_TYPE));
+ } catch (ParsingException e) {
+ throw new FactoryException(e);
+ }
+
+ return new ExtEntityEntry(
+ simonaUuid,
+ extId,
+ columnScheme
+ .orElseThrow(), // FIXME: Interim version -> ColumnScheme should handle more data types
+ inputType);
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityMapping.java b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityMapping.java
new file mode 100644
index 0000000..8fd033e
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityMapping.java
@@ -0,0 +1,43 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.simulation.mapping;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/** Contains the mapping between SIMONA uuid, the external id and the data type the assets hold */
+public class ExtEntityMapping {
+
+ private final Map> extEntities;
+
+ public ExtEntityMapping(List extEntityEntryList) {
+ this.extEntities =
+ extEntityEntryList.stream().collect(Collectors.groupingBy(ExtEntityEntry::dataType));
+ }
+
+ /**
+ * Mapping external id to SIMONA uuid
+ *
+ * @param dataType data type the external asset expects
+ * @return Mapping external id to SIMONA uuid
+ */
+ public Map getExtId2UuidMapping(DataType dataType) {
+ return extEntities.getOrDefault(dataType, Collections.emptyList()).stream()
+ .collect(Collectors.toMap(ExtEntityEntry::id, ExtEntityEntry::uuid));
+ }
+
+ /**
+ * Mapping SIMONA uuid to external id
+ *
+ * @param dataType data type the external asset expects
+ * @return Mapping SIMONA uuid to external id
+ */
+ public Map getExtUuid2IdMapping(DataType dataType) {
+ return extEntities.getOrDefault(dataType, Collections.emptyList()).stream()
+ .collect(Collectors.toMap(ExtEntityEntry::uuid, ExtEntityEntry::id));
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingSource.java b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingSource.java
new file mode 100644
index 0000000..1d24d7f
--- /dev/null
+++ b/src/main/java/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingSource.java
@@ -0,0 +1,88 @@
+/*
+ * © 2024. TU Dortmund University,
+ * Institute of Energy Systems, Energy Efficiency and Energy Economics,
+ * Research group Distribution grid planning and operation
+ */
+
+package edu.ie3.simona.api.simulation.mapping;
+
+import edu.ie3.datamodel.exceptions.SourceException;
+import edu.ie3.datamodel.io.factory.EntityData;
+import edu.ie3.datamodel.io.naming.EntityPersistenceNamingStrategy;
+import edu.ie3.datamodel.io.naming.FileNamingStrategy;
+import edu.ie3.datamodel.io.source.DataSource;
+import edu.ie3.datamodel.io.source.csv.CsvDataSource;
+import edu.ie3.datamodel.models.Entity;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Optional;
+
+/** Source for external entity mapping. */
+public class ExtEntityMappingSource {
+
+ protected final DataSource dataSource;
+ protected final ExtEntityFactory factory;
+
+ protected ExtEntityMappingSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ this.factory = new ExtEntityFactory();
+ }
+
+ /**
+ * Creates an {@link ExtEntityMapping} from a given file.
+ *
+ * @param filepath path to the file including its name
+ * @return a new mapping
+ * @throws SourceException if an error occurred
+ */
+ public static ExtEntityMapping fromFile(Path filepath) throws SourceException {
+ String filename = filepath.getFileName().toString();
+ Path directoryPath;
+
+ if (!filename.contains(".csv")) {
+ directoryPath = filepath;
+ } else {
+ directoryPath = filepath.getParent();
+ }
+
+ ExtEntityNaming naming = new ExtEntityNaming(filename);
+ CsvDataSource source = new CsvDataSource(",", directoryPath, new FileNamingStrategy(naming));
+
+ return new ExtEntityMappingSource(source).getMapping();
+ }
+
+ /** Return the mapping from a given {@link DataSource}. */
+ public ExtEntityMapping getMapping() throws SourceException {
+ return new ExtEntityMapping(
+ dataSource.getSourceData(ExtEntityEntry.class).map(this::createExtEntityEntry).toList());
+ }
+
+ /**
+ * Creates an ext entity entry from a given map.
+ *
+ * @param fieldToValues map: field name to value
+ * @return a new {@link ExtEntityEntry}
+ */
+ private ExtEntityEntry createExtEntityEntry(Map fieldToValues) {
+ return factory.get(new EntityData(fieldToValues, ExtEntityEntry.class)).getOrThrow();
+ }
+
+ /** Csv naming for ext entity mapping. */
+ private static class ExtEntityNaming extends EntityPersistenceNamingStrategy {
+
+ private final String filename;
+
+ private ExtEntityNaming(String filename) {
+ this.filename = filename.replace(".csv", "");
+ }
+
+ @Override
+ public Optional getEntityName(Class extends Entity> cls) {
+ if (ExtEntityEntry.class.isAssignableFrom(cls)) {
+ return Optional.of(filename);
+ } else {
+ return super.getEntityName(cls);
+ }
+ }
+ }
+}
diff --git a/src/main/java/edu/ie3/simona/api/simulation/ontology/ControlMessageToExt.java b/src/main/java/edu/ie3/simona/api/simulation/ontology/ControlMessageToExt.java
index 42826eb..601b162 100644
--- a/src/main/java/edu/ie3/simona/api/simulation/ontology/ControlMessageToExt.java
+++ b/src/main/java/edu/ie3/simona/api/simulation/ontology/ControlMessageToExt.java
@@ -6,4 +6,5 @@
package edu.ie3.simona.api.simulation.ontology;
+/** Interface for control messages from the SIMONA to the external simulation */
public interface ControlMessageToExt {}
diff --git a/src/test/groovy/edu/ie3/simona/api/data/em/ExtEmDataConnectionTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/em/ExtEmDataConnectionTest.groovy
new file mode 100644
index 0000000..d8f798f
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/data/em/ExtEmDataConnectionTest.groovy
@@ -0,0 +1,98 @@
+package edu.ie3.simona.api.data.em
+
+import edu.ie3.datamodel.models.value.PValue
+import edu.ie3.datamodel.models.value.Value
+import edu.ie3.simona.api.data.em.ontology.ProvideEmSetPointData
+import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage
+import edu.ie3.simona.api.data.primarydata.ontology.ProvidePrimaryData
+import edu.ie3.simona.api.test.common.DataServiceTestData
+import org.apache.pekko.actor.ActorSystem
+import org.apache.pekko.testkit.TestProbe
+import org.apache.pekko.testkit.javadsl.TestKit
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import spock.lang.Shared
+import spock.lang.Specification
+
+class ExtEmDataConnectionTest extends Specification implements DataServiceTestData {
+
+ @Shared
+ ActorSystem actorSystem
+
+ @Shared
+ Map extEmDataMapping = Map.of(
+ "Em",
+ inputUuid
+ )
+
+ def setupSpec() {
+ actorSystem = ActorSystem.create()
+ }
+
+ def cleanupSpec() {
+ TestKit.shutdownActorSystem(actorSystem)
+ actorSystem = null
+ }
+
+ def "ExtEmDataConnection should provide em data correctly"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extEmDataConnection = new ExtEmDataConnection(extEmDataMapping)
+ extEmDataConnection.setActorRefs(
+ dataService.ref(),
+ extSimAdapter.ref()
+ )
+
+ def emData = [:] as HashMap
+ def uuid = UUID.randomUUID()
+ emData.put(uuid.toString(), pValue)
+
+ def convertedEmData = Map.of(uuid, pValue as PValue)
+
+ when:
+ extEmDataConnection.provideEmData(0L, convertedEmData, Optional.of(900L))
+
+ then:
+ dataService.expectMsg(new ProvideEmSetPointData(0, convertedEmData, Optional.of(900L)))
+ extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
+ }
+
+ def "ExtEmDataConnection should convert input data correctly"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extEmDataConnection = new ExtEmDataConnection(extEmDataMapping)
+ extEmDataConnection.setActorRefs(
+ dataService.ref(),
+ extSimAdapter.ref()
+ )
+ def inputDataMap = Map.of("Em", pValue)
+
+ when:
+ extEmDataConnection.convertAndSend(0L, inputDataMap, Optional.of(900L), log)
+
+ then:
+ dataService.expectMsg(new ProvideEmSetPointData(0L, Map.of(inputUuid, pValue), Optional.of(900L)))
+ extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
+ }
+
+ def "ExtEmDataConnection should send no message, if input data for a not requested asset was provided"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extEmDataConnection = new ExtEmDataConnection(extEmDataMapping)
+ extEmDataConnection.setActorRefs(
+ dataService.ref(),
+ extSimAdapter.ref()
+ )
+ def inputDataMap = Map.of("Load", pValue)
+
+ when:
+ extEmDataConnection.convertAndSend(0L, inputDataMap, Optional.of(900L), log)
+
+ then:
+ dataService.expectNoMessage()
+ }
+
+}
diff --git a/src/test/groovy/edu/ie3/simona/api/data/ev/ExtEvDataTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/ev/ExtEvDataConnectionTest.groovy
similarity index 66%
rename from src/test/groovy/edu/ie3/simona/api/data/ev/ExtEvDataTest.groovy
rename to src/test/groovy/edu/ie3/simona/api/data/ev/ExtEvDataConnectionTest.groovy
index 63441e4..8487efc 100644
--- a/src/test/groovy/edu/ie3/simona/api/data/ev/ExtEvDataTest.groovy
+++ b/src/test/groovy/edu/ie3/simona/api/data/ev/ExtEvDataConnectionTest.groovy
@@ -15,7 +15,7 @@ import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage
import spock.lang.Shared
import spock.lang.Specification
-class ExtEvDataTest extends Specification {
+class ExtEvDataConnectionTest extends Specification {
@Shared
ActorSystem actorSystem
@@ -29,18 +29,19 @@ class ExtEvDataTest extends Specification {
actorSystem = null
}
- def "ExtEvData should request and receive free evcs lots correctly"() {
+ def "ExtEvDataConnection should request and receive free evcs lots correctly"() {
given:
def dataService = new TestProbe(actorSystem)
def extSimAdapter = new TestProbe(actorSystem)
- def extEvData = new ExtEvData(dataService.ref(), extSimAdapter.ref())
+ def extEvDataConnection = new ExtEvDataConnection()
+ extEvDataConnection.setActorRefs(dataService.ref(), extSimAdapter.ref())
def sentMsg = new ProvideEvcsFreeLots()
when:
// we need to queue the msg beforehand because the receive method is blocking
- extEvData.queueExtResponseMsg(sentMsg)
- def actualReceivedEvcs = extEvData.requestAvailablePublicEvcs()
+ extEvDataConnection.queueExtResponseMsg(sentMsg)
+ def actualReceivedEvcs = extEvDataConnection.requestAvailablePublicEvcs()
then:
dataService.expectMsg(new RequestEvcsFreeLots())
@@ -48,18 +49,19 @@ class ExtEvDataTest extends Specification {
actualReceivedEvcs == sentMsg.evcs()
}
- def "ExtEvData should request and receive current charging prices correctly"() {
+ def "ExtEvDataConnection should request and receive current charging prices correctly"() {
given:
def dataService = new TestProbe(actorSystem)
def extSimAdapter = new TestProbe(actorSystem)
- def extEvData = new ExtEvData(dataService.ref(), extSimAdapter.ref())
+ def extEvDataConnection = new ExtEvDataConnection()
+ extEvDataConnection.setActorRefs(dataService.ref(), extSimAdapter.ref())
def sentMsg = new ProvideCurrentPrices()
when:
// we need to queue the msg beforehand because the receive method is blocking
- extEvData.queueExtResponseMsg(sentMsg)
- def actualReceivedPrices = extEvData.requestCurrentPrices()
+ extEvDataConnection.queueExtResponseMsg(sentMsg)
+ def actualReceivedPrices = extEvDataConnection.requestCurrentPrices()
then:
dataService.expectMsg(new RequestCurrentPrices())
@@ -67,11 +69,12 @@ class ExtEvDataTest extends Specification {
actualReceivedPrices == sentMsg.prices()
}
- def "ExtEvData should request and receive departing EVs correctly"() {
+ def "ExtEvDataConnection should request and receive departing EVs correctly"() {
given:
def dataService = new TestProbe(actorSystem)
def extSimAdapter = new TestProbe(actorSystem)
- def extEvData = new ExtEvData(dataService.ref(), extSimAdapter.ref())
+ def extEvDataConnection = new ExtEvDataConnection()
+ extEvDataConnection.setActorRefs(dataService.ref(), extSimAdapter.ref())
def requestedDepartingEvs = new HashMap>()
requestedDepartingEvs.put(UUID.randomUUID(), new ArrayList())
@@ -79,8 +82,8 @@ class ExtEvDataTest extends Specification {
when:
// we need to queue the msg beforehand because the receive method is blocking
- extEvData.queueExtResponseMsg(sentMsg)
- def actualReceivedEvs = extEvData.requestDepartingEvs(requestedDepartingEvs)
+ extEvDataConnection.queueExtResponseMsg(sentMsg)
+ def actualReceivedEvs = extEvDataConnection.requestDepartingEvs(requestedDepartingEvs)
then:
dataService.expectMsg(new RequestDepartingEvs(requestedDepartingEvs))
@@ -88,35 +91,37 @@ class ExtEvDataTest extends Specification {
actualReceivedEvs == sentMsg.departedEvs()
}
- def "ExtEvData should provide arriving EVs correctly"() {
+ def "ExtEvDataConnection should provide arriving EVs correctly"() {
given:
def dataService = new TestProbe(actorSystem)
def extSimAdapter = new TestProbe(actorSystem)
- def extEvData = new ExtEvData(dataService.ref(), extSimAdapter.ref())
+ def extEvDataConnection = new ExtEvDataConnection()
+ extEvDataConnection.setActorRefs(dataService.ref(), extSimAdapter.ref())
def arrivingEvs = new HashMap>()
arrivingEvs.put(UUID.randomUUID(), new ArrayList())
when:
- extEvData.provideArrivingEvs(arrivingEvs, Optional.of(60L))
+ extEvDataConnection.provideArrivingEvs(arrivingEvs, Optional.of(60L))
then:
dataService.expectMsg(new ProvideArrivingEvs(arrivingEvs, Optional.of(60L)))
extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
}
- def "ExtEvData should fail if wrong response is sent"() {
+ def "ExtEvDataConnection should fail if wrong response is sent"() {
given:
def dataService = new TestProbe(actorSystem)
def extSimAdapter = new TestProbe(actorSystem)
- def extEvData = new ExtEvData(dataService.ref(), extSimAdapter.ref())
+ def extEvDataConnection = new ExtEvDataConnection()
+ extEvDataConnection.setActorRefs(dataService.ref(), extSimAdapter.ref())
def unexpectedMsg = new ProvideCurrentPrices()
when:
// we need to queue the msg beforehand because the receive method is blocking
- extEvData.queueExtResponseMsg(unexpectedMsg)
- extEvData.requestAvailablePublicEvcs()
+ extEvDataConnection.queueExtResponseMsg(unexpectedMsg)
+ extEvDataConnection.requestAvailablePublicEvcs()
then:
dataService.expectMsg(new RequestEvcsFreeLots())
diff --git a/src/test/groovy/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataConnectionTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataConnectionTest.groovy
new file mode 100644
index 0000000..5aba77d
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataConnectionTest.groovy
@@ -0,0 +1,93 @@
+package edu.ie3.simona.api.data.primarydata
+
+import edu.ie3.datamodel.models.value.Value
+import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage
+import edu.ie3.simona.api.data.primarydata.ontology.ProvidePrimaryData
+import edu.ie3.simona.api.test.common.DataServiceTestData
+import org.apache.pekko.actor.ActorSystem
+import org.apache.pekko.testkit.TestProbe
+import org.apache.pekko.testkit.javadsl.TestKit
+import spock.lang.Shared
+import spock.lang.Specification
+
+class ExtPrimaryDataConnectionTest extends Specification implements DataServiceTestData {
+
+ @Shared
+ ActorSystem actorSystem
+
+ @Shared
+ Map extPrimaryDataMapping = Map.of(
+ "Pv",
+ inputUuid
+ )
+
+ def setupSpec() {
+ actorSystem = ActorSystem.create()
+ }
+
+ def cleanupSpec() {
+ TestKit.shutdownActorSystem(actorSystem)
+ actorSystem = null
+ }
+
+ def "ExtPrimaryDataConnection should provide primary data correctly"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extPrimaryDataConnection = new ExtPrimaryDataConnection(extPrimaryDataMapping)
+ extPrimaryDataConnection.setActorRefs(
+ dataService.ref(),
+ extSimAdapter.ref()
+ )
+
+ def primaryData = [:] as HashMap
+ def uuid = UUID.randomUUID()
+ primaryData.put(uuid.toString(), pValue)
+
+ def convertedPrimaryData = Map.of(uuid, pValue as Value)
+
+ when:
+ extPrimaryDataConnection.providePrimaryData(0L, convertedPrimaryData, Optional.of(900L))
+
+ then:
+ dataService.expectMsg(new ProvidePrimaryData(0L, convertedPrimaryData, Optional.of(900L)))
+ extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
+ }
+
+ def "ExtPrimaryDataConnection should convert input data correctly"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extPrimaryDataConnection = new ExtPrimaryDataConnection(extPrimaryDataMapping)
+ extPrimaryDataConnection.setActorRefs(
+ dataService.ref(),
+ extSimAdapter.ref()
+ )
+ def inputDataMap = Map.of("Pv", pValue)
+
+ when:
+ extPrimaryDataConnection.convertAndSend(0L, inputDataMap, Optional.of(900L), log)
+
+ then:
+ dataService.expectMsg(new ProvidePrimaryData(0L, Map.of(inputUuid, pValue), Optional.of(900L)))
+ extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
+ }
+
+ def "ExtPrimaryDataConnection should send no message, if input data for a not requested asset was provided"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extPrimaryDataConnection = new ExtPrimaryDataConnection(extPrimaryDataMapping)
+ extPrimaryDataConnection.setActorRefs(
+ dataService.ref(),
+ extSimAdapter.ref()
+ )
+ def inputDataMap = Map.of("Load", pValue)
+
+ when:
+ extPrimaryDataConnection.convertAndSend(0L, inputDataMap, Optional.empty(), log)
+
+ then:
+ dataService.expectNoMessage()
+ }
+}
diff --git a/src/test/groovy/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataTest.groovy
deleted file mode 100644
index 7163f0b..0000000
--- a/src/test/groovy/edu/ie3/simona/api/data/primarydata/ExtPrimaryDataTest.groovy
+++ /dev/null
@@ -1,62 +0,0 @@
-package edu.ie3.simona.api.data.primarydata
-
-import edu.ie3.datamodel.models.StandardUnits
-import edu.ie3.datamodel.models.value.PValue
-import edu.ie3.datamodel.models.value.Value
-import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage
-import edu.ie3.simona.api.data.primarydata.ontology.ProvidePrimaryData
-import edu.ie3.simona.api.exceptions.ConvertionException
-import org.apache.pekko.actor.ActorSystem
-import org.apache.pekko.testkit.TestProbe
-import org.apache.pekko.testkit.javadsl.TestKit
-import spock.lang.Shared
-import spock.lang.Specification
-import tech.units.indriya.quantity.Quantities
-
-class ExtPrimaryDataTest extends Specification {
-
- @Shared
- ActorSystem actorSystem
-
-
- class PValuePrimaryDataFactory implements PrimaryDataFactory {
-
- @Override
- Value convert(Object entity) throws ConvertionException {
- if (entity.getClass() == PValue) {
- return (PValue) entity
- } else {
- throw new ConvertionException("This factory can convert PValue entities only!")
- }
- }
- }
-
- def setupSpec() {
- actorSystem = ActorSystem.create()
- }
-
- def cleanupSpec() {
- TestKit.shutdownActorSystem(actorSystem)
- actorSystem = null
- }
-
- def "ExtPrimaryData should provide primary data correctly"() {
- given:
- def dataService = new TestProbe(actorSystem)
- def extSimAdapter = new TestProbe(actorSystem)
- def extPrimaryData = new ExtPrimaryData(dataService.ref(), extSimAdapter.ref(), new PValuePrimaryDataFactory())
-
- def primaryData = new HashMap()
- def uuid = UUID.randomUUID()
- primaryData.put(uuid.toString(), new PValue(Quantities.getQuantity(500.0, StandardUnits.ACTIVE_POWER_IN)))
-
- def convertedPrimaryData = Map.of(uuid, new PValue(Quantities.getQuantity(500.0, StandardUnits.ACTIVE_POWER_IN)))
-
- when:
- extPrimaryData.providePrimaryData(0, primaryData)
-
- then:
- dataService.expectMsg(new ProvidePrimaryData(0, convertedPrimaryData))
- extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
- }
-}
diff --git a/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultContainerTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultContainerTest.groovy
new file mode 100644
index 0000000..b86f6ae
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultContainerTest.groovy
@@ -0,0 +1,95 @@
+package edu.ie3.simona.api.data.results
+
+import edu.ie3.datamodel.models.StandardUnits
+import edu.ie3.datamodel.models.result.NodeResult
+import edu.ie3.simona.api.test.common.DataServiceTestData
+import edu.ie3.util.quantities.PowerSystemUnits
+import spock.lang.Shared
+import spock.lang.Specification
+import tech.units.indriya.quantity.Quantities
+
+import java.time.ZonedDateTime
+
+class ExtResultContainerTest extends Specification implements DataServiceTestData {
+
+ @Shared
+ UUID nodeUuid = UUID.fromString("55b97041-64be-4e6b-983a-72dbde6eddf4")
+
+ @Shared
+ NodeResult nodeResult = new NodeResult(
+ ZonedDateTime.parse("2020-01-30T17:26:44Z"),
+ nodeUuid,
+ Quantities.getQuantity(0.95, PowerSystemUnits.PU),
+ Quantities.getQuantity(45, StandardUnits.VOLTAGE_ANGLE)
+ )
+
+ def "ExtResultContainer should return voltage deviation correctly"() {
+ given:
+ def resultMap = Map.of(
+ "Node", nodeResult
+ )
+ def extResultContainer = new ExtResultContainer(0L, resultMap)
+
+ when:
+ def calculatedVoltageDeviation = extResultContainer.getVoltageDeviation("Node")
+
+ then:
+ calculatedVoltageDeviation == -0.05d
+ }
+
+ def "ExtResultContainer should throw an exception, if voltage deviation was requested for a not NodeResult"() {
+ given:
+ def resultMap = Map.of(
+ "Load", loadResult
+ )
+ def extResultContainer = new ExtResultContainer(0L, resultMap)
+
+ when:
+ extResultContainer.getVoltageDeviation("Load")
+
+ then:
+ thrown IllegalArgumentException
+ }
+
+ def "ExtResultContainer should return active power correctly"() {
+ given:
+ def resultMap = Map.of(
+ "Load", loadResult
+ )
+ def extResultContainer = new ExtResultContainer(0L, resultMap)
+
+ when:
+ def returnedActivePower = extResultContainer.getActivePower("Load")
+
+ then:
+ returnedActivePower == 10d
+ }
+
+ def "ExtResultContainer should return reactive power correctly"() {
+ given:
+ def resultMap = Map.of(
+ "Load", loadResult
+ )
+ def extResultContainer = new ExtResultContainer(0L, resultMap)
+
+ when:
+ def returnedReactivePower = extResultContainer.getReactivePower("Load")
+
+ then:
+ returnedReactivePower == 5d
+ }
+
+ def "ExtResultContainer should throw an exception, if active power was requested for a not SystemParticipantResult"() {
+ given:
+ def resultMap = Map.of(
+ "Node", nodeResult
+ )
+ def extResultContainer = new ExtResultContainer(0L, resultMap)
+
+ when:
+ extResultContainer.getActivePower("Node")
+
+ then:
+ thrown IllegalArgumentException
+ }
+}
\ No newline at end of file
diff --git a/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultDataConnectionTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultDataConnectionTest.groovy
new file mode 100644
index 0000000..7dc0dc2
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultDataConnectionTest.groovy
@@ -0,0 +1,123 @@
+package edu.ie3.simona.api.data.results
+
+import edu.ie3.datamodel.models.StandardUnits
+import edu.ie3.datamodel.models.result.connector.LineResult
+import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage
+import edu.ie3.simona.api.data.results.ontology.ProvideResultEntities
+import edu.ie3.simona.api.data.results.ontology.RequestResultEntities
+import edu.ie3.simona.api.data.results.ontology.ResultDataResponseMessageToExt
+import edu.ie3.simona.api.test.common.DataServiceTestData
+import org.apache.pekko.actor.ActorSystem
+import org.apache.pekko.testkit.TestProbe
+import org.apache.pekko.testkit.javadsl.TestKit
+import spock.lang.Shared
+import spock.lang.Specification
+import tech.units.indriya.quantity.Quantities
+
+import javax.measure.Quantity
+import javax.measure.quantity.Angle
+import javax.measure.quantity.ElectricCurrent
+import java.time.ZonedDateTime
+
+class ExtResultDataConnectionTest extends Specification implements DataServiceTestData {
+
+ @Shared
+ ActorSystem actorSystem
+
+ @Shared
+ Map participantResultAssetMapping = Map.of(inputUuid, "Load")
+
+ @Shared
+ Map gridResultAssetMapping = [:]
+
+ class WrongResultDataResponseMessageToExt implements ResultDataResponseMessageToExt {}
+
+ def setupSpec() {
+ actorSystem = ActorSystem.create()
+ }
+
+ def cleanupSpec() {
+ TestKit.shutdownActorSystem(actorSystem)
+ actorSystem = null
+ }
+
+ def "ExtResultsData should request and receive results correctly as ModelResultEntity"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def dataServiceActivation = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extResultDataConnection = new ExtResultDataConnection(participantResultAssetMapping, gridResultAssetMapping)
+ extResultDataConnection.setActorRefs(
+ dataService.ref(),
+ dataServiceActivation.ref(),
+ extSimAdapter.ref()
+ )
+
+ def sentMsg = new ProvideResultEntities([loadResult])
+
+ when:
+ // we need to queue the msg beforehand because the receive method is blocking
+ extResultDataConnection.queueExtResponseMsg(sentMsg)
+ def receivedResults = extResultDataConnection.requestResults(0L)
+
+ then:
+ dataService.expectMsg(new RequestResultEntities(0L))
+ extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataServiceActivation.ref()))
+ receivedResults.get("Load") == loadResult
+ }
+
+ def "ExtResultsData should fail if wrong response is sent"() {
+ given:
+ def dataService = new TestProbe(actorSystem)
+ def dataServiceActivation = new TestProbe(actorSystem)
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extResultDataConnection = new ExtResultDataConnection(participantResultAssetMapping, gridResultAssetMapping)
+ extResultDataConnection.setActorRefs(
+ dataService.ref(),
+ dataServiceActivation.ref(),
+ extSimAdapter.ref()
+ )
+
+ def unexpectedMsg = new WrongResultDataResponseMessageToExt()
+
+ when:
+ // we need to queue the msg beforehand because the receive method is blocking
+ extResultDataConnection.queueExtResponseMsg(unexpectedMsg)
+ extResultDataConnection.requestResults(0L)
+
+ then:
+ dataService.expectMsg(new RequestResultEntities(0L))
+ extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataServiceActivation.ref()))
+ thrown RuntimeException
+ }
+
+ def "ExtResultData should convert a list of result entities correctly to a map of resultAssetMappingId to result entity"() {
+ given:
+ def extResultDataConnection = new ExtResultDataConnection(participantResultAssetMapping, gridResultAssetMapping)
+
+ when:
+ def mapOfResults = extResultDataConnection.createResultMap([loadResult])
+
+ then:
+ mapOfResults.size() == 1
+ mapOfResults.get("Load") == loadResult
+ }
+
+ def "ExtResultData should throw an exception, if a result with a wrong data type was provided"() {
+ given:
+ def extResultDataConnection = new ExtResultDataConnection(participantResultAssetMapping, gridResultAssetMapping)
+ Quantity iAMag = Quantities.getQuantity(100, StandardUnits.ELECTRIC_CURRENT_MAGNITUDE)
+ Quantity iAAng = Quantities.getQuantity(45, StandardUnits.ELECTRIC_CURRENT_ANGLE)
+ Quantity iBMag = Quantities.getQuantity(150, StandardUnits.ELECTRIC_CURRENT_MAGNITUDE)
+ Quantity iBAng = Quantities.getQuantity(30, StandardUnits.ELECTRIC_CURRENT_ANGLE)
+ def wrongResult = new LineResult(
+ ZonedDateTime.parse("2020-01-30T17:26:44Z"), inputUuid, iAMag, iAAng, iBMag, iBAng
+ )
+
+ when:
+ extResultDataConnection.createResultMap([wrongResult])
+
+ then:
+ thrown IllegalArgumentException
+ }
+}
\ No newline at end of file
diff --git a/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultDataTest.groovy b/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultDataTest.groovy
deleted file mode 100644
index 5b0ee7c..0000000
--- a/src/test/groovy/edu/ie3/simona/api/data/results/ExtResultDataTest.groovy
+++ /dev/null
@@ -1,130 +0,0 @@
-package edu.ie3.simona.api.data.results
-
-import edu.ie3.datamodel.models.StandardUnits
-import edu.ie3.datamodel.models.result.ResultEntity
-import edu.ie3.datamodel.models.result.system.LoadResult
-import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage
-import edu.ie3.simona.api.data.results.ontology.ProvideResultEntities
-import edu.ie3.simona.api.data.results.ontology.RequestResultEntities
-import edu.ie3.simona.api.data.results.ontology.ResultDataResponseMessageToExt
-import edu.ie3.simona.api.exceptions.ConvertionException
-import org.apache.pekko.actor.ActorSystem
-import org.apache.pekko.testkit.TestProbe
-import org.apache.pekko.testkit.javadsl.TestKit
-import spock.lang.Shared
-import spock.lang.Specification
-import tech.units.indriya.quantity.Quantities
-
-import java.time.ZonedDateTime
-
-class ExtResultDataTest extends Specification {
-
- @Shared
- ActorSystem actorSystem
-
- @Shared
- UUID loadUuid = UUID.fromString("22bea5fc-2cb2-4c61-beb9-b476e0107f52")
-
- @Shared
- LoadResult loadResult = new LoadResult(
- ZonedDateTime.parse("2020-01-30T17:26:44Z[UTC]"),
- loadUuid,
- Quantities.getQuantity(10, StandardUnits.ACTIVE_POWER_IN),
- Quantities.getQuantity(10, StandardUnits.REACTIVE_POWER_IN)
- )
-
- class DefaultResultFactory implements ResultDataFactory {
-
- @Override
- Object convert(ResultEntity entity) throws ConvertionException {
- if (entity instanceof LoadResult) {
- return "{\"p\":\"" + entity.p.toString() + ",\"q\":\"" + entity.q.toString() + "\"}"
- } else {
- throw new ConvertionException("This factory can convert LoadResult's only!")
- }
- }
- }
-
- class WrongResultDataResponseMessageToExt implements ResultDataResponseMessageToExt {}
-
- def setupSpec() {
- actorSystem = ActorSystem.create()
- }
-
- def cleanupSpec() {
- TestKit.shutdownActorSystem(actorSystem)
- actorSystem = null
- }
-
- def "ExtResultsData should request and receive results correctly as Object"() {
- given:
- def dataService = new TestProbe(actorSystem)
- def extSimAdapter = new TestProbe(actorSystem)
- def resultDataFactory = new DefaultResultFactory()
- def extResultData = new ExtResultData(dataService.ref(), extSimAdapter.ref(), resultDataFactory)
-
- def sentMsg = new ProvideResultEntities([loadResult])
-
- when:
- // we need to queue the msg beforehand because the receive method is blocking
- extResultData.queueExtResponseMsg(sentMsg)
- def receivedResults = extResultData.requestResultObjects()
-
- then:
- dataService.expectMsg(new RequestResultEntities())
- extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
- receivedResults.get(loadUuid.toString()) == resultDataFactory.convert(loadResult)
- }
-
- def "ExtResultsData should request and receive results correctly as a list of results entities"() {
- given:
- def dataService = new TestProbe(actorSystem)
- def extSimAdapter = new TestProbe(actorSystem)
- def extResultData = new ExtResultData(dataService.ref(), extSimAdapter.ref(), new DefaultResultFactory())
-
- def sentMsg = new ProvideResultEntities([loadResult])
-
- when:
- // we need to queue the msg beforehand because the receive method is blocking
- extResultData.queueExtResponseMsg(sentMsg)
- def receivedResults = extResultData.requestResults()
-
- then:
- dataService.expectMsg(new RequestResultEntities())
- extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
- receivedResults == sentMsg.results()
- }
-
- def "ExtResultsData should fail if wrong response is sent"() {
- given:
- def dataService = new TestProbe(actorSystem)
- def extSimAdapter = new TestProbe(actorSystem)
- def extResultData = new ExtResultData(dataService.ref(), extSimAdapter.ref(), new DefaultResultFactory())
-
- def unexpectedMsg = new WrongResultDataResponseMessageToExt()
-
- when:
- // we need to queue the msg beforehand because the receive method is blocking
- extResultData.queueExtResponseMsg(unexpectedMsg)
- extResultData.requestResults()
-
- then:
- dataService.expectMsg(new RequestResultEntities())
- extSimAdapter.expectMsg(new ScheduleDataServiceMessage(dataService.ref()))
- thrown RuntimeException
- }
-
- def "ExtResultData should convert a list of result entities correctly to a map of objects"() {
- given:
- def dataService = new TestProbe(actorSystem)
- def extSimAdapter = new TestProbe(actorSystem)
- def extResultData = new ExtResultData(dataService.ref(), extSimAdapter.ref(), new DefaultResultFactory())
-
- when:
- def mapOfResults = extResultData.convertResultsList([loadResult])
-
- then:
- mapOfResults.size() == 1
- mapOfResults.get(loadUuid.toString()) == "{\"p\":\"10 kW,\"q\":\"10 kvar\"}"
- }
-}
diff --git a/src/test/groovy/edu/ie3/simona/api/simulation/ExtCoSimulationTest.groovy b/src/test/groovy/edu/ie3/simona/api/simulation/ExtCoSimulationTest.groovy
new file mode 100644
index 0000000..2903384
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/simulation/ExtCoSimulationTest.groovy
@@ -0,0 +1,74 @@
+package edu.ie3.simona.api.simulation
+
+import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme
+import edu.ie3.simona.api.simulation.mapping.DataType
+import edu.ie3.simona.api.simulation.mapping.ExtEntityEntry
+import edu.ie3.simona.api.simulation.mapping.ExtEntityMapping
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import spock.lang.Shared
+import spock.lang.Specification
+
+class ExtCoSimulationTest extends Specification {
+
+ @Shared
+ private static final Logger log = LoggerFactory.getLogger(ExtCoSimulationTest)
+
+ def "An ExtCoSimulation can build a primary data connection correctly"() {
+ given:
+ UUID uuid1 = UUID.randomUUID()
+ UUID uuid2 = UUID.randomUUID()
+ UUID uuid3 = UUID.randomUUID()
+
+ ExtEntityMapping mapping = new ExtEntityMapping([
+ new ExtEntityEntry(uuid1, "primary1", ColumnScheme.ACTIVE_POWER, DataType.EXT_PRIMARY_INPUT),
+ new ExtEntityEntry(uuid2, "em1", ColumnScheme.ACTIVE_POWER, DataType.EXT_EM_INPUT),
+ new ExtEntityEntry(uuid3, "primary2", ColumnScheme.ACTIVE_POWER, DataType.EXT_PRIMARY_INPUT),
+ ])
+
+ when:
+ def actual = ExtCoSimulation.buildPrimaryConnection(mapping, log)
+
+ then:
+ actual.getPrimaryDataAssets() == [uuid3, uuid1]
+ }
+
+ def "An ExtCoSimulation can build an em data connection correctly"() {
+ given:
+ UUID uuid1 = UUID.randomUUID()
+ UUID uuid2 = UUID.randomUUID()
+ UUID uuid3 = UUID.randomUUID()
+
+ ExtEntityMapping mapping = new ExtEntityMapping([
+ new ExtEntityEntry(uuid1, "em1", ColumnScheme.ACTIVE_POWER, DataType.EXT_EM_INPUT),
+ new ExtEntityEntry(uuid2, "em2", ColumnScheme.ACTIVE_POWER, DataType.EXT_EM_INPUT),
+ new ExtEntityEntry(uuid3, "primary1", ColumnScheme.ACTIVE_POWER, DataType.EXT_PRIMARY_INPUT),
+ ])
+
+ when:
+ def actual = ExtCoSimulation.buildEmConnection(mapping, log)
+
+ then:
+ actual.getControlledEms() == [uuid1, uuid2]
+ }
+
+ def "An ExtCoSimulation can build a result data connection correctly"() {
+ given:
+ UUID uuid1 = UUID.randomUUID()
+ UUID uuid2 = UUID.randomUUID()
+ UUID uuid3 = UUID.randomUUID()
+
+ ExtEntityMapping mapping = new ExtEntityMapping([
+ new ExtEntityEntry(uuid1, "grid_result", ColumnScheme.ACTIVE_POWER, DataType.EXT_GRID_RESULT),
+ new ExtEntityEntry(uuid2, "participant_result", ColumnScheme.ACTIVE_POWER, DataType.EXT_PARTICIPANT_RESULT),
+ new ExtEntityEntry(uuid3, "primary1", ColumnScheme.ACTIVE_POWER, DataType.EXT_PRIMARY_INPUT),
+ ])
+
+ when:
+ def actual = ExtCoSimulation.buildResultConnection(mapping, log)
+
+ then:
+ actual.getGridResultDataAssets() == [uuid1]
+ actual.getParticipantResultDataAssets() == [uuid2]
+ }
+}
diff --git a/src/test/groovy/edu/ie3/simona/api/simulation/ExtSimulationSpec.groovy b/src/test/groovy/edu/ie3/simona/api/simulation/ExtSimulationSpec.groovy
index c1fd13b..029056f 100644
--- a/src/test/groovy/edu/ie3/simona/api/simulation/ExtSimulationSpec.groovy
+++ b/src/test/groovy/edu/ie3/simona/api/simulation/ExtSimulationSpec.groovy
@@ -3,7 +3,7 @@ package edu.ie3.simona.api.simulation
import org.apache.pekko.actor.ActorSystem
import org.apache.pekko.testkit.TestProbe
import org.apache.pekko.testkit.javadsl.TestKit
-import edu.ie3.simona.api.data.ExtData
+import edu.ie3.simona.api.data.ExtDataConnection
import edu.ie3.simona.api.simulation.ontology.ActivationMessage
import edu.ie3.simona.api.simulation.ontology.CompletionMessage
import edu.ie3.simona.api.simulation.ontology.ControlMessageToExt
@@ -32,6 +32,7 @@ class ExtSimulationSpec extends Specification {
private Optional activationReturnTick
TestSimulation(Long initReturnTick, Optional activationReturnTick) {
+ super("TestSimulation")
this.initReturnTick = initReturnTick
this.activationReturnTick = activationReturnTick
}
@@ -45,6 +46,11 @@ class ExtSimulationSpec extends Specification {
protected Optional doActivity(long tick) {
return this.activationReturnTick
}
+
+ @Override
+ Set getDataConnections() {
+ return []
+ }
}
def setupSpec() {
@@ -62,86 +68,86 @@ class ExtSimulationSpec extends Specification {
def "An ExtSimulation should handle initialization"() {
given:
- def tick = -1L
- def newTick = 0L
- def testProbe = new TestProbe(actorSystem)
- def extSimData = new ExtSimAdapterData(testProbe.ref(), new String[0])
- def extSim = new TestSimulation(newTick, Optional.of(-2L))
- extSim.setup(extSimData, new ArrayList())
+ def tick = -1L
+ def newTick = 0L
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extSimData = new ExtSimAdapterData(extSimAdapter.ref(), new String[0])
+ def extSim = new TestSimulation(newTick, Optional.of(-2L))
+ extSim.setAdapterData(extSimData)
when:
- extSimData.queueExtMsg(new ActivationMessage(tick))
- def finishedActual = handleMessage.invoke(extSim)
+ extSimData.queueExtMsg(new ActivationMessage(tick))
+ def finishedActual = handleMessage.invoke(extSim)
then:
- finishedActual == false
- testProbe.expectMsg(new CompletionMessage(Optional.of(newTick)))
+ finishedActual == false
+ extSimAdapter.expectMsg(new CompletionMessage(Optional.of(newTick)))
}
def "An ExtSimulation should handle activation and return given new triggers"() {
given:
- def testProbe = new TestProbe(actorSystem)
- def extSimData = new ExtSimAdapterData(testProbe.ref(), new String[0])
- def newTickOpt = newTick.isEmpty() ?
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extSimData = new ExtSimAdapterData(extSimAdapter.ref(), new String[0])
+ def newTickOpt = newTick.isEmpty() ?
Optional.empty() : Optional.of(newTick.first())
- def extSim = new TestSimulation(-2L, newTickOpt)
- extSim.setup(extSimData, new ArrayList())
+ def extSim = new TestSimulation(-2L, newTickOpt)
+ extSim.setAdapterData(extSimData)
when:
- extSimData.queueExtMsg(new ActivationMessage(tick))
- def finishedActual = handleMessage.invoke(extSim)
+ extSimData.queueExtMsg(new ActivationMessage(tick))
+ def finishedActual = handleMessage.invoke(extSim)
then:
- finishedActual == finished
- testProbe.expectMsg(new CompletionMessage(newTickOpt))
+ finishedActual == finished
+ extSimAdapter.expectMsg(new CompletionMessage(newTickOpt))
where:
- tick | newTick || finished
- 0L | [900L] || false
- 3600L | [7200L] || false
- 7200L | [] || true
- 10800L | [] || true
+ tick | newTick || finished
+ 0L | [900L] || false
+ 3600L | [7200L] || false
+ 7200L | [] || true
+ 10800L | [] || true
}
def "An ExtSimulation should handle termination properly"() {
given:
- def testProbe = new TestProbe(actorSystem)
- def extSimData = new ExtSimAdapterData(testProbe.ref(), new String[0])
- def extSim = new TestSimulation(-1L, Optional.empty())
- extSim.setup(extSimData, new ArrayList())
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extSimData = new ExtSimAdapterData(extSimAdapter.ref(), new String[0])
+ def extSim = new TestSimulation(-1L, Optional.empty())
+ extSim.setAdapterData(extSimData)
when:
- extSimData.queueExtMsg(new TerminationMessage(simlulationSuccessful))
- def finishedActual = handleMessage.invoke(extSim)
+ extSimData.queueExtMsg(new TerminationMessage(simlulationSuccessful))
+ def finishedActual = handleMessage.invoke(extSim)
then:
- finishedActual == finished
- testProbe.expectMsg(new TerminationCompleted())
+ finishedActual == finished
+ extSimAdapter.expectMsg(new TerminationCompleted())
where:
- simlulationSuccessful || finished
- false || true
- true || true
+ simlulationSuccessful || finished
+ false || true
+ true || true
}
class UnknownMessage implements ControlMessageToExt {}
def "An ExtSimulation should handle unknown messages by throwing an exception"() {
given:
- def testProbe = new TestProbe(actorSystem)
- def extSimData = new ExtSimAdapterData(testProbe.ref(), new String[0])
- def extSim = new TestSimulation(-1L, Optional.empty())
- extSim.setup(extSimData, new ArrayList())
+ def extSimAdapter = new TestProbe(actorSystem)
+ def extSimData = new ExtSimAdapterData(extSimAdapter.ref(), new String[0])
+ def extSim = new TestSimulation(-1L, Optional.empty())
+ extSim.setAdapterData(extSimData)
when:
- extSimData.queueExtMsg(new UnknownMessage())
- handleMessage.invoke(extSim)
+ extSimData.queueExtMsg(new UnknownMessage())
+ handleMessage.invoke(extSim)
then:
- Exception ex = thrown()
- // since we call a private method through reflection,
- // our expected exception is wrapped in an InvocationTargetException
- ex.getCause().getClass() == IllegalArgumentException
- testProbe.expectNoMessage()
+ Exception ex = thrown()
+ // since we call a private method through reflection,
+ // our expected exception is wrapped in an InvocationTargetException
+ ex.getCause().getClass() == IllegalArgumentException
+ extSimAdapter.expectNoMessage()
}
}
diff --git a/src/test/groovy/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingSourceTest.groovy b/src/test/groovy/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingSourceTest.groovy
new file mode 100644
index 0000000..2589e21
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingSourceTest.groovy
@@ -0,0 +1,36 @@
+package edu.ie3.simona.api.simulation.mapping
+
+import edu.ie3.datamodel.models.input.NodeInput
+import spock.lang.Specification
+
+import java.nio.file.Path
+
+class ExtEntityMappingSourceTest extends Specification {
+
+ def "An ExtEntityMappingSource can create a naming correctly"() {
+ given:
+ def naming = new ExtEntityMappingSource.ExtEntityNaming("ext_entity_mapping")
+
+ when:
+ def ext_entity_naming = naming.getEntityName(ExtEntityEntry)
+ def other = naming.getEntityName(NodeInput)
+
+ then:
+ ext_entity_naming == Optional.of("ext_entity_mapping")
+ other == Optional.of("node_input")
+ }
+
+ def "An ExtEntityMappingSource can read a mapping from file correctly"() {
+ given:
+ Path filePath = Path.of(ExtEntityMappingSourceTest.getResource("ext_entity_mapping.csv").toURI())
+
+ when:
+ def actual = ExtEntityMappingSource.fromFile(filePath)
+
+ then:
+ actual.getExtUuid2IdMapping(DataType.EXT_PRIMARY_INPUT).size() == 2
+ actual.getExtUuid2IdMapping(DataType.EXT_EM_INPUT).size() == 0
+ actual.getExtUuid2IdMapping(DataType.EXT_GRID_RESULT).size() == 2
+ actual.getExtUuid2IdMapping(DataType.EXT_PARTICIPANT_RESULT).size() == 0
+ }
+}
\ No newline at end of file
diff --git a/src/test/groovy/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingTest.groovy b/src/test/groovy/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingTest.groovy
new file mode 100644
index 0000000..9f49f61
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/simulation/mapping/ExtEntityMappingTest.groovy
@@ -0,0 +1,52 @@
+package edu.ie3.simona.api.simulation.mapping
+
+import edu.ie3.datamodel.io.naming.timeseries.ColumnScheme
+import spock.lang.Shared
+import spock.lang.Specification
+
+class ExtEntityMappingTest extends Specification {
+ @Shared
+ UUID loadUuid = UUID.fromString("22bea5fc-2cb2-4c61-beb9-b476e0107f52")
+
+ @Shared
+ ExtEntityEntry extResultEntry = new ExtEntityEntry(
+ loadUuid,
+ "Load",
+ ColumnScheme.parse("p").get(),
+ DataType.EXT_PARTICIPANT_RESULT
+ )
+
+ @Shared
+ ExtEntityEntry extInputEntry = new ExtEntityEntry(
+ loadUuid,
+ "Load",
+ ColumnScheme.parse("p").get(),
+ DataType.EXT_PRIMARY_INPUT
+ )
+
+ def "ExtEntityMapping should return SIMONA uuid mapping correctly"() {
+ given:
+ def extAssetList = List.of(extResultEntry, extInputEntry)
+ def extEntryMapping = new ExtEntityMapping(extAssetList)
+
+ when:
+ def inputMap = extEntryMapping.getExtId2UuidMapping(DataType.EXT_PRIMARY_INPUT)
+
+ then:
+ inputMap.size() == 1
+ inputMap.get("Load") == loadUuid
+ }
+
+ def "ExtEntityMapping should return external id mapping correctly"() {
+ given:
+ def extAssetList = List.of(extResultEntry, extInputEntry)
+ def extEntryMapping = new ExtEntityMapping(extAssetList)
+
+ when:
+ def inputMap = extEntryMapping.getExtUuid2IdMapping(DataType.EXT_PRIMARY_INPUT)
+
+ then:
+ inputMap.size() == 1
+ inputMap.get(loadUuid) == "Load"
+ }
+}
\ No newline at end of file
diff --git a/src/test/groovy/edu/ie3/simona/api/test/common/DataServiceTestData.groovy b/src/test/groovy/edu/ie3/simona/api/test/common/DataServiceTestData.groovy
new file mode 100644
index 0000000..fa8e537
--- /dev/null
+++ b/src/test/groovy/edu/ie3/simona/api/test/common/DataServiceTestData.groovy
@@ -0,0 +1,24 @@
+package edu.ie3.simona.api.test.common
+
+import edu.ie3.datamodel.models.StandardUnits
+import edu.ie3.datamodel.models.result.system.LoadResult
+import edu.ie3.datamodel.models.value.PValue
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import tech.units.indriya.quantity.Quantities
+
+import java.time.ZonedDateTime
+
+trait DataServiceTestData {
+ Logger log = LoggerFactory.getLogger(DataServiceTestData)
+
+ UUID inputUuid = UUID.fromString("22bea5fc-2cb2-4c61-beb9-b476e0107f52")
+ PValue pValue = new PValue(Quantities.getQuantity(500.0, StandardUnits.ACTIVE_POWER_IN))
+
+ LoadResult loadResult = new LoadResult(
+ ZonedDateTime.parse("2020-01-30T17:26:44Z[UTC]"),
+ inputUuid,
+ Quantities.getQuantity(10, StandardUnits.ACTIVE_POWER_IN),
+ Quantities.getQuantity(5, StandardUnits.REACTIVE_POWER_IN)
+ )
+}
\ No newline at end of file
diff --git a/src/test/resources/edu/ie3/simona/api/simulation/mapping/ext_entity_mapping.csv b/src/test/resources/edu/ie3/simona/api/simulation/mapping/ext_entity_mapping.csv
new file mode 100644
index 0000000..2163547
--- /dev/null
+++ b/src/test/resources/edu/ie3/simona/api/simulation/mapping/ext_entity_mapping.csv
@@ -0,0 +1,5 @@
+uuid,id,column_scheme,data_type
+00d03670-7833-47ee-ad52-04d18d1c64fd,NS_Node_1,p,grid_result
+dfae9806-9b44-4995-ba27-d66d8e4a43e0,NS_Node_2,p,grid_result
+4dca3b1d-5d24-444a-b4df-f4fa23b9ef1b,LOAD_NS_Node_1,pq,primary_input
+9c5991bc-24df-496b-b4ce-5ec27657454c,LOAD_NS_Node_2,pq,primary_input
\ No newline at end of file
diff --git a/version.properties b/version.properties
index 4fd9773..142da6e 100644
--- a/version.properties
+++ b/version.properties
@@ -1,8 +1,8 @@
#Generated by the Semver Plugin for Gradle
-#Thu Nov 30 15:04:34 CET 2023
+#Fri Aug 09 15:42:54 CEST 2024
version.buildmeta=
version.major=0
-version.minor=5
+version.minor=6
version.patch=0
version.prerelease=
-version.semver=0.5.0
+version.semver=0.6.0