Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased/Snapshot]

### Added
- Added support for external em communication [#304](https://github.com/ie3-institute/simonaAPI/issues/304)

### Changed
- Removed Jenkinsfile [#290](https://github.com/ie3-institute/simonaAPI/issues/290)
- Adapted dependabot workflow and added CODEOWNERS [#294](https://github.com/ie3-institute/simonaAPI/issues/294)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
package edu.ie3.simona.api.data.connection;

import edu.ie3.simona.api.data.model.em.EmSetPoint;
import edu.ie3.simona.api.ontology.em.EmDataMessageFromExt;
import edu.ie3.simona.api.ontology.em.EmDataResponseMessageToExt;
import edu.ie3.simona.api.ontology.em.ProvideEmSetPointData;
import edu.ie3.simona.api.data.model.em.ExtendedFlexOptionsResult;
import edu.ie3.simona.api.data.model.em.FlexOptionRequest;
import edu.ie3.simona.api.data.model.em.FlexOptions;
import edu.ie3.simona.api.ontology.em.*;
import java.util.*;
import org.slf4j.Logger;

Expand All @@ -34,11 +35,47 @@ public List<UUID> getControlledEms() {
return new ArrayList<>(controlled);
}

/**
* Sends the em flex requests to SIMONA.
*
* @param tick current tick
* @param data receiver to flex request, that should be sent to SIMONA
* @param maybeNextTick option for the next tick in the simulation
* @param log logger
*/
public void sendFlexRequests(
long tick, Map<UUID, FlexOptionRequest> data, Optional<Long> maybeNextTick, Logger log) {
if (data.isEmpty()) {
log.debug("No em flex requests found! Sending no em data to SIMONA for tick {}.", tick);
} else {
log.debug("Provided SIMONA with em flex requests.");
sendExtMsg(new ProvideFlexRequestData(tick, data, maybeNextTick));
}
}

/**
* Sends the em flex options to SIMONA.
*
* @param tick current tick
* @param data receiver to flex options, that should be sent to SIMONA
* @param maybeNextTick option for the next tick in the simulation
* @param log logger
*/
public void sendFlexOptions(
long tick, Map<UUID, List<FlexOptions>> data, Optional<Long> maybeNextTick, Logger log) {
if (data.isEmpty()) {
log.debug("No em flex options found! Sending no em data to SIMONA for tick {}.", tick);
} else {
log.debug("Provided SIMONA with em flex options.");
sendExtMsg(new ProvideEmFlexOptionData(tick, data, maybeNextTick));
}
}

/**
* Sends the em set points to SIMONA.
*
* @param tick current tick
* @param setPoints to be sent
* @param setPoints receiver to set point, that should be sent to SIMONA
* @param maybeNextTick option for the next tick in the simulation
* @param log logger
*/
Expand All @@ -52,6 +89,31 @@ public void sendSetPoints(
}
}

/**
* Method to request em flexibility options from SIMONA.
*
* @param tick for which set points are requested
* @param emEntities for which set points are requested
* @return an {@link FlexOptionsResponse} message
* @throws InterruptedException - on interruptions
*/
public Map<UUID, ExtendedFlexOptionsResult> requestEmFlexResults(
long tick, List<UUID> emEntities, boolean disaggregated) throws InterruptedException {
sendExtMsg(new RequestEmFlexResults(tick, emEntities, disaggregated));
return receiveWithType(FlexOptionsResponse.class).receiverToFlexOptions();
}

/**
* Method to request the completion of the em service in SIMONA for the given tick.
*
* @param tick for which the em service should stop
* @return an option for the next tick in SIMONA
*/
public Optional<Long> requestCompletion(long tick) throws InterruptedException {
sendExtMsg(new RequestEmCompletion(tick));
return receiveWithType(EmCompletion.class).maybeNextTick();
}

/** Mode of the em connection */
public enum EmMode {
BASE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
public final class ExtPrimaryDataConnection
extends ExtInputDataConnection<PrimaryDataMessageFromExt> {

private final Map<UUID, Class<Value>> valueClasses;
private final Map<UUID, Class<? extends Value>> valueClasses;

public ExtPrimaryDataConnection(Map<UUID, Class<Value>> valueClasses) {
public ExtPrimaryDataConnection(Map<UUID, Class<? extends Value>> valueClasses) {
this.valueClasses = valueClasses;
}

Expand All @@ -34,7 +34,7 @@ public List<UUID> getPrimaryDataAssets() {
* @param uuid of the model
* @return an option for the value class associated with the model.
*/
public Optional<Class<Value>> getValueClass(UUID uuid) {
public Optional<Class<? extends Value>> getValueClass(UUID uuid) {
return Optional.ofNullable(valueClasses.get(uuid));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ public void addRequest(UUID receiver, Optional<UUID> sender) {
flexRequests.put(receiver, new FlexOptionRequest(receiver, sender));
}

public void addRequest(UUID receiver, FlexOptionRequest request) {
flexRequests.put(receiver, request);
}

/**
* Method for adding flex options to a given receiver.
*
Expand Down Expand Up @@ -123,7 +127,7 @@ public void addSetPoint(UUID asset, PValue power) {
* @param setPoint given set point
*/
public void addSetPoint(EmSetPoint setPoint) {
setPoints.put(setPoint.receiver, setPoint);
setPoints.put(setPoint.receiver(), setPoint);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,11 @@

package edu.ie3.simona.api.data.container;

import static edu.ie3.util.quantities.PowerSystemUnits.PU;

import edu.ie3.datamodel.models.result.NodeResult;
import edu.ie3.datamodel.models.result.ResultEntity;
import edu.ie3.datamodel.models.result.connector.LineResult;
import edu.ie3.datamodel.models.result.system.SystemParticipantResult;
import edu.ie3.util.quantities.PowerSystemUnits;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import javax.measure.quantity.Dimensionless;
import tech.units.indriya.ComparableQuantity;
import tech.units.indriya.quantity.Quantities;

/** Contains all SIMONA results for a certain tick. */
public final class ExtResultContainer implements ExtDataContainer {
Expand Down Expand Up @@ -103,61 +94,4 @@ public Optional<Long> getMaybeNextTick() {
public ResultEntity getResult(UUID assetId) {
return resultMap.get(assetId);
}

/**
* Returns the voltage deviation in pu for a certain asset, if this asset provided a {@link
* NodeResult}
*/
public double getVoltageDeviation(UUID assetId) {
if (resultMap.get(assetId) instanceof NodeResult nodeResult) {
ComparableQuantity<Dimensionless> 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! AssetId: " + assetId);
}
}

/**
* Returns the voltage deviation for certain asset, if this asset provided a {@link NodeResult}
*/
public double getVoltage(UUID assetId) {
if (resultMap.get(assetId) instanceof NodeResult nodeResult) {
return nodeResult.getvMag().getValue().doubleValue();
} else {
throw new IllegalArgumentException("Voltage is only available for NodeResult's!");
}
}

/**
* Returns the active power in MW for certain asset, if this asset provided a {@link
* SystemParticipantResult}
*/
public double getActivePower(UUID assetId) {
if (resultMap.get(assetId) instanceof SystemParticipantResult systemParticipantResult) {
return systemParticipantResult.getP().to(PowerSystemUnits.MEGAWATT).getValue().doubleValue();
} else {
throw new IllegalArgumentException(
"Active power is only available for SystemParticipantResult's!");
}
}

/**
* Returns the reactive power in MVAr for certain asset, if this asset provided a {@link
* SystemParticipantResult}
*/
public double getReactivePower(UUID assetId) {
if (resultMap.get(assetId) instanceof SystemParticipantResult systemParticipantResult) {
return systemParticipantResult.getQ().to(PowerSystemUnits.MEGAVAR).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(UUID assetId) {
throw new IllegalArgumentException("Line loading is not implemented yet!");
}
}
58 changes: 29 additions & 29 deletions src/main/java/edu/ie3/simona/api/data/model/em/EmSetPoint.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,46 +7,46 @@
package edu.ie3.simona.api.data.model.em;

import edu.ie3.datamodel.models.value.PValue;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import javax.measure.quantity.Power;
import tech.units.indriya.ComparableQuantity;

/** Energy management set point that will be sent to SIMONA. */
public final class EmSetPoint {
public final UUID receiver;
public final Optional<PValue> power;

/**
* Energy management set point that will be sent to SIMONA
*
* @param receiver The receiver of the message.
* @param power An option for the em set point.
*/
public record EmSetPoint(UUID receiver, Optional<PValue> power) {
/**
* Constructor for {@link EmSetPoint}.
*
* <p>Note: Using this constructor will signal SIMONA, that the current set point should be kept.
*
* @param receiver of the set point.
*/
public EmSetPoint(UUID receiver) {
this.receiver = receiver;
this.power = Optional.empty();
this(receiver, Optional.empty());
}

/**
* Constructor for {@link EmSetPoint}.
*
* @param receiver of the set point.
* @param p power value of the set point
*/
public EmSetPoint(UUID receiver, ComparableQuantity<Power> p) {
this.receiver = receiver;
this.power = Optional.of(new PValue(p));
this(receiver, Optional.of(new PValue(p)));
}

/**
* Constructor for {@link EmSetPoint}.
*
* @param receiver of the set point.
* @param power value of the set point
*/
public EmSetPoint(UUID receiver, PValue power) {
this.receiver = receiver;
this.power = Optional.of(power);
}

@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
EmSetPoint that = (EmSetPoint) o;
return Objects.equals(receiver, that.receiver) && Objects.equals(power, that.power);
}

@Override
public int hashCode() {
return Objects.hash(receiver, power);
}

@Override
public String toString() {
return "EmSetPoint{" + "receiver=" + receiver + ", power=" + power + '}';
this(receiver, Optional.ofNullable(power));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* © 2025. 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.model.em;

import edu.ie3.datamodel.models.result.ResultEntity;
import edu.ie3.datamodel.models.value.PValue;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;

/** Em set point result. */
public final class EmSetPointResult extends ResultEntity {

private final Map<UUID, PValue> receiverToSetPoints;

/**
* Basic constructor of an em set point result.
*
* @param time date and time when the result is produced
* @param sender uuid of the sending model
* @param receiverToSetPoints map: uuid to set point
*/
public EmSetPointResult(ZonedDateTime time, UUID sender, Map<UUID, PValue> receiverToSetPoints) {
super(time, sender);
this.receiverToSetPoints = receiverToSetPoints;
}

/** Returns the sender of the results. */
public UUID getSender() {
return getInputModel();
}

/** Returns the mapped (receiver to set point) set point. */
public Map<UUID, PValue> getReceiverToSetPoint() {
return receiverToSetPoints;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EmSetPointResult that = (EmSetPointResult) o;
return Objects.equals(receiverToSetPoints, that.receiverToSetPoints);
}

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

@Override
public String toString() {
return "EmSetPointResult{"
+ "time="
+ getTime()
+ ", sender="
+ getInputModel()
+ ", receiverToSetPoints="
+ receiverToSetPoints
+ '}';
}
}
Loading