diff --git a/CHANGELOG.md b/CHANGELOG.md index 61882126f3..5035f6ba03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Enhanced Newton-Raphson-PowerFlow failures with more information [#815](https://github.com/ie3-institute/simona/issues/815) - Update RTD references and bibliography [#868](https://github.com/ie3-institute/simona/issues/868) - Add gradle application plugin for command line execution with gradle run [#890](https://github.com/ie3-institute/simona/issues/890) +- Integration test for thermal grids [#878](https://github.com/ie3-institute/simona/issues/878) ### Changed - Adapted to changed data source in PSDM [#435](https://github.com/ie3-institute/simona/issues/435) @@ -66,6 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rewrote SystemComponentTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - Converting remaining rst files to markdown [#838](https://github.com/ie3-institute/simona/issues/838) - Merging both `FixedFeedInModelSpec` tests [#870](https://github.com/ie3-institute/simona/issues/870) +- Merged `HpModelTestData` with `HpTestData` to `HpInputTestData` [#872](https://github.com/ie3-institute/simona/issues/872) - Prepare ThermalStorageTestData for Storage without storageVolumeLvlMin [#894](https://github.com/ie3-institute/simona/issues/894) ### Fixed @@ -93,6 +95,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Handle MobSim requests for current prices [#892](https://github.com/ie3-institute/simona/issues/892) - Fixed Hp results leading to overheating house and other effects [#827](https://github.com/ie3-institute/simona/issues/827) - Fixed thermal storage getting recharged when empty [#827](https://github.com/ie3-institute/simona/issues/827) +- Provide actual ambient temperature of tick to HpModel when calculate state [#882](https://github.com/ie3-institute/simona/issues/882) ## [3.0.0] - 2023-08-07 diff --git a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala index 8ac5f1b44a..860881a535 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -54,7 +54,6 @@ import edu.ie3.simona.event.ResultEvent import edu.ie3.simona.event.ResultEvent.{ FlexOptionsResultEvent, ParticipantResultEvent, - ThermalResultEvent, } import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.exceptions.CriticalFailureException @@ -1940,8 +1939,9 @@ protected trait ParticipantAgentFundamentals[ def buildResultEvent[R <: ResultEntity]( result: R ): Option[ResultEvent] = result match { - case thermalResult: ThermalUnitResult => - Some(ThermalResultEvent(thermalResult)) + case thermalUnitResult: ThermalUnitResult => + Some(ResultEvent.ThermalResultEvent(thermalUnitResult)) + case unsupported => log.debug( s"Results of class '${unsupported.getClass.getSimpleName}' are currently not supported." diff --git a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala index d81242c608..a1a765d977 100644 --- a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala +++ b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala @@ -16,9 +16,18 @@ import edu.ie3.datamodel.models.result.system.{ FlexOptionsResult, SystemParticipantResult, } -import edu.ie3.datamodel.models.result.thermal.ThermalUnitResult +import edu.ie3.datamodel.models.result.thermal.{ + CylindricalStorageResult, + ThermalHouseResult, + ThermalUnitResult, +} 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 @@ -44,6 +53,54 @@ object ResultEvent { thermalResult: ThermalUnitResult ) extends ResultEvent + object ThermalHouseResult { + def unapply(result: ThermalHouseResult): Option[ + ( + ZonedDateTime, + UUID, + ComparableQuantity[Power], + ComparableQuantity[Temperature], + ) + ] = { + if (result != null) { + Some( + ( + result.getTime, + result.getInputModel, + result.getqDot, + result.getIndoorTemperature, + ) + ) + } else { + None + } + } + } + + object CylindricalThermalStorageResult { + def unapply(result: CylindricalStorageResult): Option[ + ( + ZonedDateTime, + UUID, + ComparableQuantity[Power], + ComparableQuantity[Energy], + ) + ] = { + if (result != null) { + Some( + ( + result.getTime, + result.getInputModel, + result.getqDot, + result.getEnergy, + ) + ) + } else { + None + } + } + } + /** Event that holds all grid calculation results of a power flow calculation. * The usage of a type is necessary here, to avoid passing in other instances * of [[edu.ie3.datamodel.models.result.ResultEntity]] except of the wanted diff --git a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala index cf694fb05f..ac1549cc18 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -20,7 +20,6 @@ import edu.ie3.simona.ontology.messages.flex.FlexibilityMessage.ProvideFlexOptio import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions import edu.ie3.util.quantities.PowerSystemUnits import edu.ie3.util.scala.OperationInterval -import edu.ie3.util.scala.quantities.DefaultQuantities import edu.ie3.util.scala.quantities.DefaultQuantities._ import squants.energy.{Energy, KilowattHours, Kilowatts} import squants.{Power, Temperature} @@ -217,7 +216,7 @@ final case class HpModel( thermalGrid.updateState( relevantData.currentTick, state.thermalGridState, - state.ambientTemperature.getOrElse(relevantData.ambientTemperature), + relevantData.ambientTemperature, newThermalPower, houseDemand, storageDemand, diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala new file mode 100644 index 0000000000..9fe31484e7 --- /dev/null +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -0,0 +1,810 @@ +/* + * © 2020. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.agent.grid + +import edu.ie3.simona.agent.participant.data.secondary.SecondaryDataService.ActorWeatherService +import edu.ie3.simona.agent.participant.hp.HpAgent +import edu.ie3.simona.agent.participant.statedata.ParticipantStateData.ParticipantInitializeStateData +import edu.ie3.simona.config.SimonaConfig.HpRuntimeConfig +import edu.ie3.simona.event.ResultEvent.{ + CylindricalThermalStorageResult, + ParticipantResultEvent, + ThermalHouseResult, +} +import edu.ie3.simona.event.notifier.NotifierConfig +import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} +import edu.ie3.simona.model.thermal.ThermalHouseTestData +import edu.ie3.simona.ontology.messages.SchedulerMessage.Completion +import edu.ie3.simona.ontology.messages.services.ServiceMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.PrimaryServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.{ + RegistrationFailedMessage, + RegistrationSuccessfulMessage, +} +import edu.ie3.simona.ontology.messages.services.WeatherMessage.{ + ProvideWeatherMessage, + RegisterForWeatherMessage, + WeatherData, +} +import edu.ie3.simona.ontology.messages.{Activation, SchedulerMessage} +import edu.ie3.simona.test.common.DefaultTestData +import edu.ie3.simona.test.common.input.EmInputTestData +import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import edu.ie3.simona.util.TickUtil.TickLong +import edu.ie3.util.TimeUtil +import edu.ie3.util.quantities.QuantityMatchers.equalWithTolerance +import edu.ie3.util.quantities.QuantityUtils.RichQuantityDouble +import edu.ie3.util.scala.quantities.WattsPerSquareMeter +import org.apache.pekko.actor.ActorSystem +import org.apache.pekko.actor.testkit.typed.scaladsl.{ + ScalaTestWithActorTestKit, + TestProbe, +} +import org.apache.pekko.actor.typed.scaladsl.adapter.{TypedActorRefOps, _} +import org.apache.pekko.testkit.TestActorRef +import org.scalatest.matchers.should +import org.scalatest.wordspec.AnyWordSpecLike +import org.scalatestplus.mockito.MockitoSugar +import squants.motion.MetersPerSecond +import squants.thermal.Celsius + +import java.time.ZonedDateTime +import scala.language.postfixOps + +/** Test to ensure the functions that a thermal grid and its connected assets is + * capable. + */ +class ThermalGridIT + extends ScalaTestWithActorTestKit + with ThermalHouseTestData + with AnyWordSpecLike + with should.Matchers + with EmInputTestData + with MockitoSugar + with DefaultTestData { + private implicit val classicSystem: ActorSystem = system.toClassic + protected implicit val simulationStartDate: ZonedDateTime = + TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z") + protected val simulationEndDate: ZonedDateTime = + TimeUtil.withDefaults.toZonedDateTime("2020-01-02T02:00:00Z") + + private val resolution = + simonaConfig.simona.powerflow.resolution.getSeconds + + private val outputConfigOn = NotifierConfig( + simulationResultInfo = true, + powerRequestReply = false, + flexResult = false, + ) + + val scheduler: TestProbe[SchedulerMessage] = TestProbe("scheduler") + val runtimeEvents: TestProbe[RuntimeEvent] = + TestProbe("runtimeEvents") + val primaryServiceProxy = + TestProbe[ServiceMessage]("PrimaryServiceProxy") + + val weatherService = TestProbe[ServiceMessage]("WeatherService") + + val resultListener: TestProbe[ResultEvent] = TestProbe("resultListener") + + "A Thermal Grid with thermal house, storage and heat pump not under the control of an energy management" should { + "be initialized correctly and run through some activations" in { + val heatPumpAgent = TestActorRef( + new HpAgent( + scheduler = scheduler.ref.toClassic, + initStateData = ParticipantInitializeStateData( + typicalHpInputModel, + typicalThermalGrid, + HpRuntimeConfig( + calculateMissingReactivePowerWithModel = true, + 1.0, + List.empty[String], + ), + primaryServiceProxy.ref.toClassic, + Iterable(ActorWeatherService(weatherService.ref.toClassic)), + simulationStartDate, + simulationEndDate, + resolution, + simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, + outputConfigOn, + None, + ), + listener = Iterable(resultListener.ref.toClassic), + ), + "HeatPumpAgent1", + ) + + val pRunningHp = 0.0038.asMegaWatt + val qRunningHp = 0.0012489995996796802.asMegaVar + + scheduler.expectNoMessage() + + /* INIT */ + + // heat pump + heatPumpAgent ! Activation(INIT_SIM_TICK) + + primaryServiceProxy.expectMessage( + PrimaryServiceRegistrationMessage(typicalHpInputModel.getUuid) + ) + heatPumpAgent ! RegistrationFailedMessage( + primaryServiceProxy.ref.toClassic + ) + + weatherService.expectMessage( + RegisterForWeatherMessage( + typicalHpInputModel.getNode.getGeoPosition.getY, + typicalHpInputModel.getNode.getGeoPosition.getX, + ) + ) + + heatPumpAgent ! RegistrationSuccessfulMessage( + weatherService.ref.toClassic, + Some(0L), + ) + val weatherDependentAgents = Seq(heatPumpAgent) + + /* TICK 0 + Start of Simulation + House demand heating : requiredDemand = 0.0 kWh, additionalDemand ~ 15 kWh + House demand water : tba + ThermalStorage : requiredDemand = 10.44 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + Heat pump: turned on - to serve the storage demand, but will heat up the house first + */ + + heatPumpAgent ! Activation(0L) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 0, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(0d), + WattsPerSquareMeter(0d), + Celsius(-5d), + MetersPerSecond(0d), + ), + Some(7200), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 0.toDateTime + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance( + qRunningHp + ) + } + + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe (-1).toDateTime + qDot should equalWithTolerance(0.0.asMegaWatt) + indoorTemperature should equalWithTolerance(20.asDegreeCelsius) + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe (-1).toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + energy should equalWithTolerance(0.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(0L))) + + /* TICK 6353 + House is fully heated up + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + House demand water : tba + ThermalStorage : requiredDemand = 10.44 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + Heat pump: stays on to serve storage demand + */ + + heatPumpAgent ! Activation(6353L) + + // Results of tick 6353 for hp + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 6353.toDateTime + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance( + qRunningHp + ) + } + + // Results of 0 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 0.toDateTime + qDot should equalWithTolerance(0.011.asMegaWatt) + indoorTemperature should equalWithTolerance( + 19.9999074074074.asDegreeCelsius + ) + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 0.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + energy should equalWithTolerance(0.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + // FIXME? Why next tick 6353? + scheduler.expectMessage(Completion(heatPumpAgent, Some(6353L))) + + /* TICK 7200 + New weather data (unchanged) incoming + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + House demand water : tba + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 7.85 kWh + DomesticWaterStorage : tba + Heat pump: stays on + */ + + heatPumpAgent ! Activation(7200L) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 7200L, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(1d), + WattsPerSquareMeter(1d), + Celsius(-5d), + MetersPerSecond(0d), + ), + Some(28800L), + ) + } + + // Results of 7200 for hp + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 7200.toDateTime + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance( + qRunningHp + ) + } + + // Results of 6353 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 6353.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 21.99992810459535.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 6353.toDateTime + qDot should equalWithTolerance(0.011.asMegaWatt) + energy should equalWithTolerance(0.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + // FIXME? Why next tick 7200? + scheduler.expectMessage(Completion(heatPumpAgent, Some(7200L))) + + /* TICK 7200 + Storage will be full + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + House demand water : tba + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + DomesticWaterStorage : tba + Heat pump: turned off + */ + + heatPumpAgent ! Activation(9770L) + + // Results of 9770 for hp + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 9770.toDateTime + hpResult.getP should equalWithTolerance(0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.asMegaVar) + } + + // Results of 7200 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 7200.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 21.9152283301339.asDegreeCelsius + ) + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 7200.toDateTime + qDot should equalWithTolerance(0.011.asMegaWatt) + energy should equalWithTolerance(0.002588055555555.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + // FIXME? Why next tick 9770? + scheduler.expectMessage(Completion(heatPumpAgent, Some(9770L))) + + /* TICK 28800 + House would reach lowerTempBoundary at tick 47518 + but now it's getting colder which should decrease inner temp of house faster + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 27.22 kWh + House demand water : tba + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + DomesticWaterStorage : tba + Heat pump: stays off + */ + + heatPumpAgent ! Activation(28800L) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 28800L, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(2d), + WattsPerSquareMeter(2d), + Celsius(-25d), + MetersPerSecond(0d), + ), + Some(34200L), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 28800.toDateTime + hpResult.getP should equalWithTolerance(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + } + + // Results of 9770 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 9770.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 21.65903523084334.asDegreeCelsius + ) + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 9770.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + energy should equalWithTolerance(0.01044.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(28800L))) + + /* TICK 31106 + House reach lowerTemperatureBoundary + House demand heating : requiredDemand = 15.0 kWh, additionalDemand = 30.00 kWh + House demand water : tba + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + DomesticWaterStorage : tba + Heat pump: stays off, demand should be covered by storage + */ + + heatPumpAgent ! Activation(31106L) + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 31106.toDateTime + hpResult.getP should equalWithTolerance(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.0.asMegaVar + ) + } + + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 28800.toDateTime + qDot should equalWithTolerance(0.0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 18.3704373032769.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 28800.toDateTime + qDot should equalWithTolerance(0.0.asMegaWatt) + energy should equalWithTolerance(0.01044.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(31106L))) + + /* TICK 34200 + Storage will be empty at tick 34706 + Additional trigger caused by (unchanged) weather data should not change this + House demand heating : requiredDemand = 9.72 kWh, additionalDemand = 24.72 kWh + House demand water : tba + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 8.97 kWh + DomesticWaterStorage : tba + Heat pump: stays off + */ + + heatPumpAgent ! Activation(34200L) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 34200, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(3d), + WattsPerSquareMeter(3d), + Celsius(-25d), + MetersPerSecond(0d), + ), + Some(50400L), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 34200.toDateTime + hpResult.getP should equalWithTolerance(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + } + + // Results of 31106 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 31106.toDateTime + qDot should equalWithTolerance(0.01044.asMegaWatt) + indoorTemperature should equalWithTolerance( + 18.00002164245703.asDegreeCelsius + ) + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 31106.toDateTime + qDot should equalWithTolerance((-0.01044).asMegaWatt) + energy should equalWithTolerance(0.01044.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(34200L))) + + /* TICK 34706 + Storage will be empty + House demand heating : requiredDemand = 8.87 kWh, additionalDemand = 23.87 kWh + House demand water : tba + ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + Heat pump: will be turned on - to serve the remaining heat demand of house (and refill storage later) + */ + + heatPumpAgent ! Activation(34706L) + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 34706.toDateTime + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance( + qRunningHp + ) + } + + // Results of 34200 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 34200.toDateTime + qDot should equalWithTolerance(0.01044.asMegaWatt) + indoorTemperature should equalWithTolerance( + 18.703619912969.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 34200.toDateTime + qDot should equalWithTolerance((-0.01044).asMegaWatt) + energy should equalWithTolerance( + 0.0014673999999999996.asMegaWattHour + ) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(34706L))) + + /* TICK 47690 + House will reach the upperTemperatureBoundary + House demand heating : requiredDemand = 0.00 kWh, additionalDemand = 0.00 kWh + House demand water : tba + ThermalStorage : requiredDemand = 10.44 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + Heat pump: stays on to refill the storage now + */ + + heatPumpAgent ! Activation(47690L) + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 47690.toDateTime + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance(qRunningHp) + } + + // Results of 34706 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 34706L.toDateTime + qDot should equalWithTolerance(0.011.asMegaWatt) + indoorTemperature should equalWithTolerance( + 18.81736942528025.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 34706L.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + energy should equalWithTolerance( + 0.asMegaWattHour + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(47690L))) + + /* TICK 50400 + New weather data: it's getting warmer again + House demand heating : requiredDemand = 0.00 kWh, additionalDemand = 0.00 kWh + House demand water : tba + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 2.16 kWh + DomesticWaterStorage : tba + Heat pump: stays on + */ + + heatPumpAgent ! Activation(50400L) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 50400L, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(4d), + WattsPerSquareMeter(4d), + Celsius(5d), + MetersPerSecond(0d), + ), + Some(151200L), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 50400.toDateTime + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance(qRunningHp) + } + + // Results of 47690 for house and storage + Range(0, 2) + .map { _ => + resultListener.expectMessageType[ResultEvent] + } + .foreach { case ResultEvent.ThermalResultEvent(thermalUnitResult) => + thermalUnitResult match { + case ThermalHouseResult( + time, + inputModel, + qDot, + indoorTemperature, + ) => + inputModel shouldBe typicalThermalHouse.getUuid + time shouldBe 47690.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 22.00001859336235.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 47690.toDateTime + qDot should equalWithTolerance(0.011.asMegaWatt) + energy should equalWithTolerance(0.asMegaWattHour) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + scheduler.expectMessage(Completion(heatPumpAgent, Some(50400L))) + } + } +} diff --git a/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala b/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala index 8e89cf7541..79e64e7a12 100644 --- a/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala +++ b/src/test/scala/edu/ie3/simona/agent/participant/HpAgentModelCalculationSpec.scala @@ -41,7 +41,8 @@ import edu.ie3.simona.ontology.messages.services.WeatherMessage.{ WeatherData, } import edu.ie3.simona.test.ParticipantAgentSpec -import edu.ie3.simona.test.common.model.participant.HpTestData +import edu.ie3.simona.test.common.DefaultTestData +import edu.ie3.simona.test.common.input.HpInputTestData import edu.ie3.simona.util.ConfigUtil import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK import edu.ie3.util.scala.quantities.{ @@ -61,7 +62,6 @@ import squants.thermal.Celsius import squants.{Dimensionless, Each} import java.io.File -import java.time.ZonedDateTime import java.util.concurrent.TimeUnit import scala.collection.SortedMap @@ -76,10 +76,11 @@ class HpAgentModelCalculationSpec """.stripMargin), ) ) - with HpTestData + with HpInputTestData with IntegrationSpecCommon - with PrivateMethodTester { - implicit val simulationStart: ZonedDateTime = defaultSimulationStart + with PrivateMethodTester + with DefaultTestData { + implicit val receiveTimeOut: Timeout = Timeout(10, TimeUnit.SECONDS) implicit val noReceiveTimeOut: Timeout = Timeout(1, TimeUnit.SECONDS) @@ -188,7 +189,7 @@ class HpAgentModelCalculationSpec ApparentPowerAndHeat, ]( inputModel = hpInput, - thermalGrid = thermalGrid, + thermalGrid = defaultThermalGrid, modelConfig = modelConfig, secondaryDataServices = services, simulationStartDate = defaultSimulationStart, @@ -250,7 +251,10 @@ class HpAgentModelCalculationSpec outputConfig, _, ) => - inputModel shouldBe WithHeatInputContainer(hpInput, thermalGrid) + inputModel shouldBe WithHeatInputContainer( + hpInput, + defaultThermalGrid, + ) modelConfig shouldBe modelConfig secondaryDataServices shouldBe services defaultSimulationStart shouldBe this.defaultSimulationStart @@ -270,7 +274,7 @@ class HpAgentModelCalculationSpec /* Expect a registration message */ weatherService.expectMsg( - RegisterForWeatherMessage(51.4843281, 7.4116482) + RegisterForWeatherMessage(52.02083574, 7.40110716) ) /* ... as well as corresponding state and state data */ @@ -371,7 +375,7 @@ class HpAgentModelCalculationSpec /* Expect a registration message */ weatherService.expectMsg( - RegisterForWeatherMessage(51.4843281, 7.4116482) + RegisterForWeatherMessage(52.02083574, 7.40110716) ) weatherService.send( hpAgent, diff --git a/src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala index 283b2f4171..8f35211486 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala @@ -16,6 +16,7 @@ import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseThreshold.{ import edu.ie3.simona.model.thermal.ThermalStorage.ThermalStorageState import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions import edu.ie3.simona.test.common.UnitSpec +import edu.ie3.simona.test.common.input.HpInputTestData import edu.ie3.util.scala.quantities.WattsPerKelvin import org.scalatest.prop.TableDrivenPropertyChecks import squants.energy.{KilowattHours, Kilowatts, Watts} @@ -25,7 +26,7 @@ import squants.{Kelvin, Power, Temperature} class HpModelSpec extends UnitSpec with TableDrivenPropertyChecks - with HpModelTestData { + with HpInputTestData { implicit val tempTolerance: Temperature = Kelvin(1e-3) implicit val powerTolerance: Power = Watts(1e-3) diff --git a/src/test/scala/edu/ie3/simona/test/common/input/EmInputTestData.scala b/src/test/scala/edu/ie3/simona/test/common/input/EmInputTestData.scala index 28cc5fcf15..c5f3cf8efe 100644 --- a/src/test/scala/edu/ie3/simona/test/common/input/EmInputTestData.scala +++ b/src/test/scala/edu/ie3/simona/test/common/input/EmInputTestData.scala @@ -27,7 +27,6 @@ import edu.ie3.datamodel.models.{OperationTime, StandardUnits} import edu.ie3.simona.config.SimonaConfig import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.model.participant.load.{LoadModelBehaviour, LoadReference} -import edu.ie3.simona.test.common.model.participant.HpTestData import edu.ie3.simona.util.ConfigUtil import edu.ie3.util.quantities.PowerSystemUnits._ import squants.energy.Kilowatts @@ -40,7 +39,7 @@ trait EmInputTestData extends NodeInputTestData with PvInputTestData with LoadInputTestData - with HpTestData { + with HpInputTestData { protected val emInput = new EmInput( UUID.randomUUID(), @@ -129,7 +128,7 @@ trait EmInputTestData "test hp", OperatorInput.NO_OPERATOR_ASSIGNED, OperationTime.notLimited(), - nodeInput, + nodeInputNoSlackNs04KvA, thermalBusInput, ReactivePowerCharacteristic.parse("cosPhiFixed:{(0.00,0.98)}"), emInput, diff --git a/src/test/scala/edu/ie3/simona/model/participant/HpModelTestData.scala b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala similarity index 51% rename from src/test/scala/edu/ie3/simona/model/participant/HpModelTestData.scala rename to src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala index 9e846e3eb5..a132151845 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/HpModelTestData.scala +++ b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala @@ -4,28 +4,24 @@ * Research group Distribution grid planning and operation */ -package edu.ie3.simona.model.participant +package edu.ie3.simona.test.common.input import edu.ie3.datamodel.models.input.system.HpInput import edu.ie3.datamodel.models.input.system.`type`.HpTypeInput import edu.ie3.datamodel.models.input.system.characteristic.CosPhiFixed import edu.ie3.datamodel.models.input.thermal.{ - ThermalBusInput, + CylindricalStorageInput, ThermalHouseInput, + ThermalStorageInput, } -import edu.ie3.datamodel.models.input.{NodeInput, OperatorInput} -import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils +import edu.ie3.datamodel.models.input.{OperatorInput, container} import edu.ie3.datamodel.models.{OperationTime, StandardUnits} +import edu.ie3.simona.model.participant.HpModel import edu.ie3.simona.model.participant.HpModel.HpRelevantData import edu.ie3.simona.model.participant.control.QControl import edu.ie3.simona.model.thermal.ThermalGrid.ThermalGridState import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseState -import edu.ie3.simona.model.thermal.{ - CylindricalThermalStorage, - ThermalGrid, - ThermalHouse, - ThermalStorage, -} +import edu.ie3.simona.model.thermal._ import edu.ie3.util.quantities.PowerSystemUnits import edu.ie3.util.scala.OperationInterval import squants.energy.{KilowattHours, Kilowatts} @@ -35,24 +31,12 @@ import tech.units.indriya.quantity.Quantities import tech.units.indriya.unit.Units import java.util.UUID +import scala.jdk.CollectionConverters.{SeqHasAsJava, _} -trait HpModelTestData { - private val thermalBus = new ThermalBusInput(UUID.randomUUID(), "thermal bus") - - private val nodeInput = new NodeInput( - UUID.randomUUID(), - "NS node", - OperatorInput.NO_OPERATOR_ASSIGNED, - OperationTime.notLimited(), - Quantities.getQuantity(1d, StandardUnits.VOLTAGE_MAGNITUDE), - false, - NodeInput.DEFAULT_GEO_POSITION, - GermanVoltageLevelUtils.LV, - 2, - ) +trait HpInputTestData extends NodeInputTestData with ThermalGridTestData { protected val hpTypeInput = new HpTypeInput( - UUID.randomUUID(), + UUID.fromString("9802bf35-2a4e-4ff5-be9b-cd9e6a78dcd6"), "HpTypeInput", Quantities.getQuantity(10000d, PowerSystemUnits.EURO), Quantities.getQuantity(200d, PowerSystemUnits.EURO_PER_MEGAWATTHOUR), @@ -62,12 +46,12 @@ trait HpModelTestData { ) protected val hpInputModel = new HpInput( - UUID.randomUUID(), + UUID.fromString("7832dea4-8703-4b37-8752-e67b86e957df"), "HpInput", OperatorInput.NO_OPERATOR_ASSIGNED, OperationTime.notLimited(), - nodeInput, - thermalBus, + nodeInputNoSlackNs04KvA, + thermalBusInput, new CosPhiFixed("cosPhiFixed:{(0.0,0.95)}"), null, hpTypeInput, @@ -83,6 +67,74 @@ trait HpModelTestData { Kilowatts(15d), thermalGrid, ) + protected val defaultThermalHouse = new ThermalHouseInput( + UUID.fromString("91940626-bdd0-41cf-96dd-47c94c86b20e"), + "thermal house", + thermalBusInput, + Quantities.getQuantity(0.325, StandardUnits.THERMAL_TRANSMISSION), + Quantities.getQuantity(75, StandardUnits.HEAT_CAPACITY), + Quantities.getQuantity(21.0, StandardUnits.TEMPERATURE), + Quantities.getQuantity(22.0, StandardUnits.TEMPERATURE), + Quantities.getQuantity(20.0, StandardUnits.TEMPERATURE), + ) + + protected val defaultThermalGrid = new container.ThermalGrid( + thermalBusInput, + Seq(defaultThermalHouse).asJava, + Seq.empty[ThermalStorageInput].asJava, + ) + + protected val typicalThermalHouse = new ThermalHouseInput( + UUID.fromString("74ac67b4-4743-416a-b731-1b5fe4a0a4e7"), + "thermal house", + thermalBusInput, + Quantities.getQuantity(0.1, StandardUnits.THERMAL_TRANSMISSION), + Quantities.getQuantity(7.5, StandardUnits.HEAT_CAPACITY), + Quantities.getQuantity(20.0, StandardUnits.TEMPERATURE), + Quantities.getQuantity(22.0, StandardUnits.TEMPERATURE), + Quantities.getQuantity(18.0, StandardUnits.TEMPERATURE), + ) + + protected val typicalThermalStorage: CylindricalStorageInput = + new CylindricalStorageInput( + UUID.fromString("4b8933dc-aeb6-4573-b8aa-59d577214150"), + "thermal storage", + thermalBusInput, + Quantities.getQuantity(300.0, Units.LITRE), + Quantities.getQuantity(0.0, Units.LITRE), + Quantities.getQuantity(60.0, StandardUnits.TEMPERATURE), + Quantities.getQuantity(30.0, StandardUnits.TEMPERATURE), + Quantities.getQuantity(1.16, StandardUnits.SPECIFIC_HEAT_CAPACITY), + ) + + protected val typicalThermalGrid = new container.ThermalGrid( + thermalBusInput, + Seq(typicalThermalHouse).asJava, + Set[ThermalStorageInput](typicalThermalStorage).asJava, + // Set.empty[ThermalStorageInput].asJava, + ) + + protected val typicalHpTypeInput = new HpTypeInput( + UUID.fromString("2829d5eb-352b-40df-a07f-735b65a0a7bd"), + "TypicalHpTypeInput", + Quantities.getQuantity(7500d, PowerSystemUnits.EURO), + Quantities.getQuantity(200d, PowerSystemUnits.EURO_PER_MEGAWATTHOUR), + Quantities.getQuantity(4, PowerSystemUnits.KILOVOLTAMPERE), + 0.95, + Quantities.getQuantity(11, PowerSystemUnits.KILOWATT), + ) + + protected val typicalHpInputModel = new HpInput( + UUID.fromString("1b5e928e-65a3-444c-b7f2-6a48af092224"), + "TypicalHpInput", + OperatorInput.NO_OPERATOR_ASSIGNED, + OperationTime.notLimited(), + nodeInputNoSlackNs04KvA, + thermalBusInput, + new CosPhiFixed("cosPhiFixed:{(0.0,0.95)}"), + null, + typicalHpTypeInput, + ) protected def thermalGrid( thermalHouse: ThermalHouse, @@ -94,18 +146,12 @@ trait HpModelTestData { None, ) - private val thermHouseUuid: UUID = - UUID.fromString("75a43a0f-7c20-45ca-9568-949b728804ca") - - private val thermalStorageUuid: UUID = - UUID.fromString("d57ddc54-48bd-4c59-babf-330c7ba71a74") - protected def thermalHouse( lowerTemperatureBoundary: Double, upperTemperatureBoundary: Double, ): ThermalHouse = ThermalHouse( new ThermalHouseInput( - thermHouseUuid, + UUID.fromString("75a43a0f-7c20-45ca-9568-949b728804ca"), "Thermal house", null, Quantities.getQuantity(1.0, StandardUnits.THERMAL_TRANSMISSION), @@ -120,11 +166,11 @@ trait HpModelTestData { ) protected def thermalStorage: ThermalStorage = CylindricalThermalStorage( - thermalStorageUuid, + UUID.fromString("d57ddc54-48bd-4c59-babf-330c7ba71a74"), "thermal storage", OperatorInput.NO_OPERATOR_ASSIGNED, OperationTime.notLimited(), - thermalBus, + thermalBusInput, KilowattHours(20d), KilowattHours(500d), Kilowatts(10d), diff --git a/src/test/scala/edu/ie3/simona/test/common/model/participant/HpTestData.scala b/src/test/scala/edu/ie3/simona/test/common/model/participant/HpTestData.scala deleted file mode 100644 index 76b1c3bafe..0000000000 --- a/src/test/scala/edu/ie3/simona/test/common/model/participant/HpTestData.scala +++ /dev/null @@ -1,83 +0,0 @@ -/* - * © 2022. TU Dortmund University, - * Institute of Energy Systems, Energy Efficiency and Energy Economics, - * Research group Distribution grid planning and operation - */ - -package edu.ie3.simona.test.common.model.participant - -import edu.ie3.datamodel.models.input.container.ThermalGrid -import edu.ie3.datamodel.models.{OperationTime, StandardUnits} -import edu.ie3.datamodel.models.input.{NodeInput, OperatorInput} -import edu.ie3.datamodel.models.input.system.HpInput -import edu.ie3.datamodel.models.input.system.`type`.HpTypeInput -import edu.ie3.datamodel.models.input.system.characteristic.ReactivePowerCharacteristic -import edu.ie3.datamodel.models.input.thermal.{ - ThermalBusInput, - ThermalHouseInput, - ThermalStorageInput, -} -import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils -import edu.ie3.simona.test.common.DefaultTestData -import tech.units.indriya.quantity.Quantities - -import java.util.UUID -import scala.jdk.CollectionConverters.SeqHasAsJava - -trait HpTestData extends DefaultTestData { - protected val nodeInput = new NodeInput( - UUID.fromString("d396cf12-5ede-41e0-b6c0-b8cadfdd5f13"), - "NS node", - OperatorInput.NO_OPERATOR_ASSIGNED, - OperationTime.notLimited(), - Quantities.getQuantity(1d, StandardUnits.VOLTAGE_MAGNITUDE), - false, - NodeInput.DEFAULT_GEO_POSITION, - GermanVoltageLevelUtils.LV, - 2, - ) - - protected val thermalBusInput = new ThermalBusInput( - UUID.fromString("48fa6e8d-c07f-45cd-9ad7-094a1f2a7489"), - "thermal bus", - ) - - protected val typeInput = new HpTypeInput( - UUID.fromString("9802bf35-2a4e-4ff5-be9b-cd9e6a78dcd6"), - "hp type", - Quantities.getQuantity(0.0, StandardUnits.CAPEX), - Quantities.getQuantity(0.0, StandardUnits.ENERGY_PRICE), - Quantities.getQuantity(15.0, StandardUnits.ACTIVE_POWER_IN), - 0.97, - Quantities.getQuantity(11.0, StandardUnits.ACTIVE_POWER_IN), - ) - - protected val hpInputModel = new HpInput( - UUID.fromString("7832dea4-8703-4b37-8752-e67b86e957df"), - "test hp", - OperatorInput.NO_OPERATOR_ASSIGNED, - OperationTime.notLimited(), - nodeInput, - thermalBusInput, - ReactivePowerCharacteristic.parse("cosPhiFixed:{(0.00,0.98)}"), - null, - typeInput, - ) - - protected val thermalHouse = new ThermalHouseInput( - UUID.fromString("91940626-bdd0-41cf-96dd-47c94c86b20e"), - "thermal house", - thermalBusInput, - Quantities.getQuantity(0.325, StandardUnits.THERMAL_TRANSMISSION), - Quantities.getQuantity(75, StandardUnits.HEAT_CAPACITY), - Quantities.getQuantity(21.0, StandardUnits.TEMPERATURE), - Quantities.getQuantity(22.0, StandardUnits.TEMPERATURE), - Quantities.getQuantity(20.0, StandardUnits.TEMPERATURE), - ) - - protected val thermalGrid = new ThermalGrid( - thermalBusInput, - Seq(thermalHouse).asJava, - Seq.empty[ThermalStorageInput].asJava, - ) -}