Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated docker documentation [#488](https://github.com/ie3-institute/simona/issues/488)
- Added support classes for transformer tap position calculation [#1543](https://github.com/ie3-institute/simona/issues/1543)
- Added basic external em service [#1566](https://github.com/ie3-institute/simona/issues/1566)
- Added external result provider [#1530](https://github.com/ie3-institute/simona/issues/1530)

### Changed
- Upgraded `scala2` to `scala3` [#53](https://github.com/ie3-institute/simona/issues/53)
Expand Down
4 changes: 4 additions & 0 deletions src/main/scala/edu/ie3/simona/agent/EnvironmentRefs.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import edu.ie3.simona.event.RuntimeEvent
import edu.ie3.simona.ontology.messages.{SchedulerMessage, ServiceMessage}
import edu.ie3.simona.service.em.ExtEmDataService
import edu.ie3.simona.service.ev.ExtEvDataService
import edu.ie3.simona.service.results.ResultServiceProxy
import org.apache.pekko.actor.typed.ActorRef

/** Container class, that gather together reference to relevant entities, that
Expand All @@ -21,6 +22,8 @@ import org.apache.pekko.actor.typed.ActorRef
* Reference to the runtime event listener.
* @param primaryServiceProxy
* Reference to the primary service proxy.
* @param resultProxy
* Reference to the result service proxy.
* @param weather
* Reference to the service, that provides weather information.
* @param loadProfiles
Expand All @@ -34,6 +37,7 @@ final case class EnvironmentRefs(
scheduler: ActorRef[SchedulerMessage],
runtimeEventListener: ActorRef[RuntimeEvent],
primaryServiceProxy: ActorRef[ServiceMessage],
resultProxy: ActorRef[ResultServiceProxy.Message],
weather: ActorRef[ServiceMessage],
loadProfiles: ActorRef[ServiceMessage],
emDataService: Option[ActorRef[ExtEmDataService.Message]],
Expand Down
30 changes: 13 additions & 17 deletions src/main/scala/edu/ie3/simona/agent/em/EmAgent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ object EmAgent {
* agent is em-controlled, or a [[Left]] with a reference to the scheduler
* that is activating this agent.
* @param listener
* A collection of result event listeners.
* A listener for result events.
* @param emDataService
* An energy management service.
*/
Expand All @@ -74,7 +74,7 @@ object EmAgent {
modelStrategy: String,
simulationStartDate: ZonedDateTime,
parent: Either[ActorRef[SchedulerMessage], ActorRef[FlexResponse]],
listener: Iterable[ActorRef[ResultEvent]],
listener: ActorRef[ResultEvent],
emDataService: Option[ActorRef[ExtEmDataService.Message]] = None,
): Behavior[Message] = Behaviors.setup[Message] { ctx =>

Expand Down Expand Up @@ -265,9 +265,7 @@ object EmAgent {
)
)

emData.listener.foreach {
_ ! FlexOptionsResultEvent(flexResult)
}
emData.listener ! FlexOptionsResultEvent(flexResult)
}

emData.parent match {
Expand Down Expand Up @@ -422,17 +420,15 @@ object EmAgent {
}

maybeResult.foreach { result =>
emData.listener.foreach {
_ ! ParticipantResultEvent(
new EmResult(
lastActiveTick
.toDateTime(using emData.simulationStartDate),
modelShell.uuid,
result.p.toMegawatts.asMegaWatt,
result.q.toMegavars.asMegaVar,
)
emData.listener ! ParticipantResultEvent(
new EmResult(
lastActiveTick
.toDateTime(using emData.simulationStartDate),
modelShell.uuid,
result.p.toMegawatts.asMegaWatt,
result.q.toMegavars.asMegaVar,
)
}
)

emData.parent.foreach {
_ ! FlexResult(modelShell.uuid, result)
Expand Down Expand Up @@ -463,13 +459,13 @@ object EmAgent {
* agent is em-controlled, or a [[Left]] with a reference to the scheduler
* that is activating this agent.
* @param listener
* A collection of result event listeners.
* A listener for result events.
*/
private final case class EmData(
outputConfig: NotifierConfig,
simulationStartDate: ZonedDateTime,
parent: Either[ActorRef[SchedulerMessage], ActorRef[FlexResponse]],
listener: Iterable[ActorRef[ResultEvent]],
listener: ActorRef[ResultEvent],
)

/** The existence of this data object indicates that the corresponding agent
Expand Down
10 changes: 8 additions & 2 deletions src/main/scala/edu/ie3/simona/agent/grid/GridAgent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{
Completion,
ScheduleActivation,
}
import edu.ie3.simona.service.results.ResultServiceProxy.ExpectResult
import edu.ie3.simona.util.TickUtil.TickLong
import org.apache.pekko.actor.typed.scaladsl.AskPattern.Askable
import org.apache.pekko.actor.typed.scaladsl.{
Expand Down Expand Up @@ -68,7 +69,6 @@ object GridAgent extends DBFSAlgorithm with DCMAlgorithm {
def apply(
environmentRefs: EnvironmentRefs,
simonaConfig: SimonaConfig,
listener: Iterable[ActorRef[ResultEvent]],
): Behavior[Message] = Behaviors.withStash(100) { buffer =>
val cfg = simonaConfig.simona

Expand All @@ -83,7 +83,6 @@ object GridAgent extends DBFSAlgorithm with DCMAlgorithm {
val agentValues = GridAgentConstantData(
environmentRefs,
simonaConfig,
listener,
resolution,
simStartTime,
simEndTime,
Expand Down Expand Up @@ -229,6 +228,13 @@ object GridAgent extends DBFSAlgorithm with DCMAlgorithm {
ctx.self,
Some(activation.tick),
)

// inform the result proxy that this grid agent will send new results
constantData.environmentRefs.resultProxy ! ExpectResult(
gridAgentBaseData.assets,
activation.tick,
)

buffer.unstashAll(simulateGrid(gridAgentBaseData, activation.tick))

case (_, msg: Message) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,9 @@ object GridAgentBuilder {

given ParticipantRefs = ParticipantRefs(
gridAgentContext.self,
constantData.environmentRefs.primaryServiceProxy,
environmentRefs.primaryServiceProxy,
environmentRefs.resultProxy,
serviceMap,
constantData.listener,
)

given SimulationParameters = SimulationParameters(
Expand Down Expand Up @@ -488,7 +488,7 @@ object GridAgentBuilder {
maybeControllingEm.toRight(
constantData.environmentRefs.scheduler
),
constantData.listener,
constantData.environmentRefs.resultProxy,
emDataService,
),
actorName(classOf[EmAgent.type], emInput.getId),
Expand Down
18 changes: 11 additions & 7 deletions src/main/scala/edu/ie3/simona/agent/grid/GridAgentData.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,6 @@ object GridAgentData {
* the grid agent.
* @param simonaConfig
* Configuration of SIMONA, that is used for.
* @param listener
* A sequence of listeners, that will receive the results from the grid
* agent.
* @param resolution
* That is used for the power flow. If no power flow should be carried out,
* this value is set to [[Long.MaxValue]].
Expand All @@ -60,14 +57,12 @@ object GridAgentData {
final case class GridAgentConstantData(
environmentRefs: EnvironmentRefs,
simonaConfig: SimonaConfig,
listener: Iterable[ActorRef[ResultEvent]],
resolution: Long,
simStartTime: ZonedDateTime,
simEndTime: ZonedDateTime,
) {
def notifyListeners(event: ResultEvent): Unit = {
listener.foreach(_ ! event)
}
def notifyListeners(event: ResultEvent): Unit =
environmentRefs.resultProxy ! event

val participantConfigUtil: ParticipantConfigUtil =
ConfigUtil.ParticipantConfigUtil(simonaConfig.simona.runtime.participant)
Expand Down Expand Up @@ -323,6 +318,15 @@ object GridAgentData {
) extends GridAgentData
with GridAgentDataHelper {

val assets: Seq[UUID] = {
val components = gridEnv.gridModel.gridComponents
components.nodes.map(_.uuid) ++ components.lines.map(
_.uuid
) ++ components.switches.map(_.uuid) ++ components.transformers.map(
_.uuid
) ++ components.transformers3w.map(_.uuid)
}

override protected val subgridGates: Vector[SubGridGate] =
gridEnv.subgridGateToActorRef.keys.toVector
override protected val subgridId: Int = gridEnv.gridModel.subnetNo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.*
import edu.ie3.simona.ontology.messages.{SchedulerMessage, ServiceMessage}
import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey
import edu.ie3.simona.service.ServiceType
import edu.ie3.simona.service.results.ResultServiceProxy.ExpectResult
import edu.ie3.simona.service.weather.WeatherDataType
import edu.ie3.simona.service.weather.WeatherService.WeatherRegistrationData
import edu.ie3.simona.util.Coordinate
Expand All @@ -59,16 +60,16 @@ object ParticipantAgentInit {
* Reference to the grid agent.
* @param primaryServiceProxy
* Reference to the primary service proxy.
* @param resultServiceProxy
* Reference to the result service proxy.
* @param services
* References to services by service type.
* @param resultListener
* Reference to the result listeners.
*/
final case class ParticipantRefs(
gridAgent: ActorRef[GridAgent.Message],
primaryServiceProxy: ActorRef[ServiceMessage],
resultServiceProxy: ActorRef[ResultEvent | ExpectResult],
services: Map[ServiceType, ActorRef[ServiceMessage]],
resultListener: Iterable[ActorRef[ResultEvent]],
)

/** Container class that holds parameters related to the simulation.
Expand Down Expand Up @@ -421,7 +422,7 @@ object ParticipantAgentInit {
simulationParams.requestVoltageDeviationTolerance,
),
ParticipantResultHandler(
participantRefs.resultListener,
participantRefs.resultServiceProxy,
notifierConfig,
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,21 @@ import edu.ie3.simona.event.ResultEvent.{
}
import edu.ie3.simona.event.notifier.NotifierConfig
import edu.ie3.simona.exceptions.CriticalFailureException
import edu.ie3.simona.service.results.ResultServiceProxy.ExpectResult
import org.apache.pekko.actor.typed.ActorRef

import java.util.UUID

/** Handles all kind of results stemming from the participant by sending them to
* the result listener, if applicable.
* the result proxy, if applicable.
*
* @param listener
* The actor reference to the result listener.
* @param resultProxy
* The actor reference to the result resultProxy.
* @param config
* The result configuration.
*/
final case class ParticipantResultHandler(
private val listener: Iterable[ActorRef[ResultEvent]],
private val resultProxy: ActorRef[ResultEvent | ExpectResult],
private val config: NotifierConfig,
) {

Expand All @@ -42,18 +45,16 @@ final case class ParticipantResultHandler(
*/
def maybeSend(result: ResultEntity): Unit =
if config.simulationResultInfo then {
listener.foreach(actor =>
result match {
case thermalResult: ThermalUnitResult =>
actor ! ThermalResultEvent(thermalResult)
case participantResult: SystemParticipantResult =>
actor ! ParticipantResultEvent(participantResult)
case unsupported =>
throw new CriticalFailureException(
s"Results of class '${unsupported.getClass.getSimpleName}' are currently not supported."
)
}
)
result match {
case thermalResult: ThermalUnitResult =>
resultProxy ! ThermalResultEvent(thermalResult)
case participantResult: SystemParticipantResult =>
resultProxy ! ParticipantResultEvent(participantResult)
case unsupported =>
throw new CriticalFailureException(
s"Results of class '${unsupported.getClass.getSimpleName}' are currently not supported."
)
}
}

/** Send the flex options result to all listeners, if enabled.
Expand All @@ -63,9 +64,10 @@ final case class ParticipantResultHandler(
*/
def maybeSend(result: FlexOptionsResult): Unit =
if config.flexResult then {
listener.foreach(
_ ! FlexOptionsResultEvent(result)
)
resultProxy ! FlexOptionsResultEvent(result)
}

def informProxy(uuid: UUID, tick: Long): Unit =
resultProxy ! ExpectResult(uuid, tick)

}
3 changes: 1 addition & 2 deletions src/main/scala/edu/ie3/simona/event/ResultEvent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,13 @@ import edu.ie3.datamodel.models.result.thermal.{
}
import edu.ie3.datamodel.models.result.{CongestionResult, NodeResult}
import edu.ie3.simona.agent.grid.GridResultsSupport.PartialTransformer3wResult
import edu.ie3.simona.event.listener.ResultEventListener
import tech.units.indriya.ComparableQuantity

import java.time.ZonedDateTime
import java.util.UUID
import javax.measure.quantity.{Energy, Power, Temperature}

sealed trait ResultEvent extends Event with ResultEventListener.Request
sealed trait ResultEvent extends Event

/** Calculation result events
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ object DelayedStopHelper {
* functionality
*/
sealed trait StoppingMsg
extends ResultEventListener.Request
extends ResultListener.Request
with RuntimeEventListener.Request

/** Message indicating that [[RuntimeEventListener]] should stop. Instead of
Expand Down
Loading