From bb2bcc423e1ec70c880247bf8db74e66e9b6c9f7 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 30 Jul 2024 11:15:02 +0200 Subject: [PATCH 01/27] fmt --- .../simona/model/thermal/ThermalGridWithHouseOnlySpec.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala index ac96c4c541..de9d4c9a23 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -73,7 +73,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { "determining the energy demand" should { "exactly be the demand of the house" in { - val tick = 10800 // after three house + val tick = 10800 // after three hours val houseDemand = thermalHouse.energyDemand( tick, testGridambientTemperature, @@ -126,7 +126,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { } "not withdraw energy from the house, if actual consumption is given" in { - val tick = 0L // after three house + val tick = 0L // after three hours val gridState = ThermalGrid.startingState(thermalGrid) val (updatedGridState, reachedThreshold) = From 0539bd5a28806699d1706f1e41c70a6c0f1892cf Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 31 Jul 2024 11:12:38 +0200 Subject: [PATCH 02/27] use should approximate for HpModelSpec --- CHANGELOG.md | 1 + .../HpAgentModelCalculationSpec.scala | 22 +++-- .../model/participant/HpModelSpec.scala | 3 +- .../test/common/input/EmInputTestData.scala | 5 +- .../common/input/HpInputTestData.scala} | 61 +++++++------- .../common/model/participant/HpTestData.scala | 83 ------------------- 6 files changed, 50 insertions(+), 125 deletions(-) rename src/test/scala/edu/ie3/simona/{model/participant/HpModelTestData.scala => test/common/input/HpInputTestData.scala} (71%) delete mode 100644 src/test/scala/edu/ie3/simona/test/common/model/participant/HpTestData.scala diff --git a/CHANGELOG.md b/CHANGELOG.md index 75964bde00..88eb6971e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rewrote FixedLoadModelTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - 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) +- Merged `HpModelTestData` with `HpTestData` to `HpInputTestData` [#872](https://github.com/ie3-institute/simona/issues/872) ### Fixed - Removed a repeated line in the documentation of vn_simona config [#658](https://github.com/ie3-institute/simona/issues/658) 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 ef2e082265..f803502bfb 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 71% 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 cbbe51ba9e..f58e546c48 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,7 +4,7 @@ * 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 @@ -12,10 +12,11 @@ import edu.ie3.datamodel.models.input.system.characteristic.CosPhiFixed import edu.ie3.datamodel.models.input.thermal.{ ThermalBusInput, 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 @@ -35,24 +36,16 @@ 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 { + protected val thermalBusInput = new ThermalBusInput( + UUID.fromString("48fa6e8d-c07f-45cd-9ad7-094a1f2a7489"), + "thermal bus", ) 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 +55,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 +76,22 @@ 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 def thermalGrid( thermalHouse: ThermalHouse, @@ -93,18 +102,12 @@ trait HpModelTestData { thermalStorage, ) - 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), @@ -119,11 +122,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, - ) -} From 83e755178e61633cbaabcf9120f7976d8f74cb84 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 31 Jul 2024 11:12:38 +0200 Subject: [PATCH 03/27] merge HpTestData and HpModelTestData to HpInputTestData --- CHANGELOG.md | 1 + .../HpAgentModelCalculationSpec.scala | 22 +++-- .../model/participant/HpModelSpec.scala | 3 +- .../test/common/input/EmInputTestData.scala | 5 +- .../common/input/HpInputTestData.scala} | 61 +++++++------- .../common/model/participant/HpTestData.scala | 83 ------------------- 6 files changed, 50 insertions(+), 125 deletions(-) rename src/test/scala/edu/ie3/simona/{model/participant/HpModelTestData.scala => test/common/input/HpInputTestData.scala} (71%) delete mode 100644 src/test/scala/edu/ie3/simona/test/common/model/participant/HpTestData.scala diff --git a/CHANGELOG.md b/CHANGELOG.md index 75964bde00..88eb6971e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rewrote FixedLoadModelTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - 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) +- Merged `HpModelTestData` with `HpTestData` to `HpInputTestData` [#872](https://github.com/ie3-institute/simona/issues/872) ### Fixed - Removed a repeated line in the documentation of vn_simona config [#658](https://github.com/ie3-institute/simona/issues/658) 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 ef2e082265..f803502bfb 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 71% 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 cbbe51ba9e..f58e546c48 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,7 +4,7 @@ * 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 @@ -12,10 +12,11 @@ import edu.ie3.datamodel.models.input.system.characteristic.CosPhiFixed import edu.ie3.datamodel.models.input.thermal.{ ThermalBusInput, 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 @@ -35,24 +36,16 @@ 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 { + protected val thermalBusInput = new ThermalBusInput( + UUID.fromString("48fa6e8d-c07f-45cd-9ad7-094a1f2a7489"), + "thermal bus", ) 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 +55,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 +76,22 @@ 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 def thermalGrid( thermalHouse: ThermalHouse, @@ -93,18 +102,12 @@ trait HpModelTestData { thermalStorage, ) - 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), @@ -119,11 +122,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, - ) -} From ea362a953096f7e55458498658cfb5817a54df7d Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 31 Jul 2024 12:43:13 +0200 Subject: [PATCH 04/27] refactor test data for thermalBusInput --- .../model/thermal/ThermalGridTestData.scala | 4 ++-- .../ThermalGridWithHouseAndStorageSpec.scala | 16 ++++++++-------- .../thermal/ThermalGridWithHouseOnlySpec.scala | 16 ++++++++-------- .../thermal/ThermalGridWithStorageOnlySpec.scala | 12 ++++++------ .../test/common/input/HpInputTestData.scala | 14 ++------------ 5 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala index a7af090fb6..6011c6caf2 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala @@ -16,12 +16,12 @@ import java.util.UUID trait ThermalGridTestData { protected val thermalBusInput = new ThermalBusInput( - UUID.randomUUID(), + UUID.fromString("48fa6e8d-c07f-45cd-9ad7-094a1f2a7489"), "Thermal Bus", OperatorInput.NO_OPERATOR_ASSIGNED, OperationTime.notLimited(), ) - protected val testGridambientTemperature: Temperature = Celsius(12d) + protected val testGridAmbientTemperature: Temperature = Celsius(12d) protected val testGridQDotInfeed: Power = Kilowatts(15d) protected val testGridQDotConsumption: Power = Kilowatts(-42d) protected val testGridQDotConsumptionHigh: Power = Kilowatts(-200d) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala index 6955b3c705..e90edcb0a3 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -98,7 +98,7 @@ class ThermalGridWithHouseAndStorageSpec val gridDemand = thermalGrid.energyDemand( tick, - testGridambientTemperature, + testGridAmbientTemperature, ThermalGrid.startingState(thermalGrid), ) @@ -114,7 +114,7 @@ class ThermalGridWithHouseAndStorageSpec val startingState = ThermalGrid.startingState(thermalGrid) val gridDemand = thermalGrid.energyDemand( tick, - testGridambientTemperature, + testGridAmbientTemperature, startingState.copy(houseState = startingState.houseState.map( _.copy(innerTemperature = Celsius(16d)) @@ -132,7 +132,7 @@ class ThermalGridWithHouseAndStorageSpec val startingState = ThermalGrid.startingState(thermalGrid) val gridDemand = thermalGrid.energyDemand( tick, - testGridambientTemperature, + testGridAmbientTemperature, startingState.copy(houseState = startingState.houseState.map( _.copy(innerTemperature = Celsius(3d)) @@ -164,7 +164,7 @@ class ThermalGridWithHouseAndStorageSpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleConsumption( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, externalQDot, ) @@ -200,7 +200,7 @@ class ThermalGridWithHouseAndStorageSpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleConsumption( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, externalQDot, ) @@ -253,7 +253,7 @@ class ThermalGridWithHouseAndStorageSpec maybeStorageState, maybeHouseState.map(_._1), None, - testGridambientTemperature, + testGridAmbientTemperature, testGridQDotConsumption, ) match { case (maybeRevisedHouseState, maybeRevisedStorageState) => @@ -486,7 +486,7 @@ class ThermalGridWithHouseAndStorageSpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleInfeed( tick, - testGridambientTemperature, + testGridAmbientTemperature, initialGridState, externalQDot, ) @@ -531,7 +531,7 @@ class ThermalGridWithHouseAndStorageSpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleInfeed( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, externalQDot, ) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala index ac96c4c541..99ed500efb 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -76,13 +76,13 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { val tick = 10800 // after three house val houseDemand = thermalHouse.energyDemand( tick, - testGridambientTemperature, + testGridAmbientTemperature, expectedHouseStartingState, ) val gridDemand = thermalGrid.energyDemand( tick, - testGridambientTemperature, + testGridAmbientTemperature, ThermalGrid.startingState(thermalGrid), ) @@ -105,7 +105,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleConsumption( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, externalQDot, ) @@ -132,7 +132,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleConsumption( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, testGridQDotConsumption, ) @@ -166,7 +166,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleInfeed( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, testGridQDotInfeed, ) @@ -192,7 +192,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { thermalGrid.updateState( 0L, ThermalGrid.startingState(thermalGrid), - testGridambientTemperature, + testGridAmbientTemperature, testGridQDotInfeed, ) match { case ( @@ -214,7 +214,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { thermalGrid.updateState( 0L, ThermalGrid.startingState(thermalGrid), - testGridambientTemperature, + testGridAmbientTemperature, testGridQDotConsumption, ) match { case ( @@ -236,7 +236,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { thermalGrid.updateState( 0L, ThermalGrid.startingState(thermalGrid), - testGridambientTemperature, + testGridAmbientTemperature, Megawatts(0d), ) match { case ( diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala index fe4276909f..7455f282ae 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -82,7 +82,7 @@ class ThermalGridWithStorageOnlySpec val gridDemand = thermalGrid.energyDemand( tick, - testGridambientTemperature, + testGridAmbientTemperature, ThermalGrid.startingState(thermalGrid), ) @@ -114,7 +114,7 @@ class ThermalGridWithStorageOnlySpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleConsumption( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, testGridQDotConsumptionHigh, ) @@ -146,7 +146,7 @@ class ThermalGridWithStorageOnlySpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleInfeed( tick, - testGridambientTemperature, + testGridAmbientTemperature, gridState, testGridQDotInfeed, ) @@ -170,7 +170,7 @@ class ThermalGridWithStorageOnlySpec val (updatedState, nextThreshold) = thermalGrid.updateState( 0L, ThermalGrid.startingState(thermalGrid), - testGridambientTemperature, + testGridAmbientTemperature, testGridQDotInfeed, ) @@ -202,7 +202,7 @@ class ThermalGridWithStorageOnlySpec ) ) ), - testGridambientTemperature, + testGridAmbientTemperature, testGridQDotConsumptionHigh, ) match { case ( @@ -224,7 +224,7 @@ class ThermalGridWithStorageOnlySpec val updatedState = thermalGrid.updateState( 0L, ThermalGrid.startingState(thermalGrid), - testGridambientTemperature, + testGridAmbientTemperature, Kilowatts(0d), ) updatedState match { diff --git a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala index f58e546c48..2611073a1c 100644 --- a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala +++ b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala @@ -10,7 +10,6 @@ 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, ThermalHouseInput, ThermalStorageInput, } @@ -21,12 +20,7 @@ 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} @@ -38,11 +32,7 @@ import tech.units.indriya.unit.Units import java.util.UUID import scala.jdk.CollectionConverters.SeqHasAsJava -trait HpInputTestData extends NodeInputTestData { - protected val thermalBusInput = new ThermalBusInput( - UUID.fromString("48fa6e8d-c07f-45cd-9ad7-094a1f2a7489"), - "thermal bus", - ) +trait HpInputTestData extends NodeInputTestData with ThermalGridTestData { protected val hpTypeInput = new HpTypeInput( UUID.fromString("9802bf35-2a4e-4ff5-be9b-cd9e6a78dcd6"), From 59d70affc0f3f6f8f5a971892677ad55d9c748c4 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 31 Jul 2024 12:45:36 +0200 Subject: [PATCH 05/27] setup framework for ThermalGridIT --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala 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..cea78a108c --- /dev/null +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -0,0 +1,309 @@ +/* + * © 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.datamodel.models.result.system.EmResult +import edu.ie3.simona.agent.EnvironmentRefs +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.ParticipantResultEvent +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 [[GridAgent]] in center position should + * be able to do if the DBFSAlgorithm is used. The scheduler, the weather + * service as well as the inferior and superior [[GridAgent]] s are simulated + * by the TestKit. By now this test does NOT cover interactions with generation + * or load asset agents due to unavailability during test development. Hence it + * would make sense to extend this test in the future to include asset agent + * interaction or cover this behaviour by another (integration) test! + */ +class ThermalGridIT + extends ScalaTestWithActorTestKit + with ThermalHouseTestData + with AnyWordSpecLike + with should.Matchers + with EmInputTestData + with MockitoSugar + with DefaultTestData +// with TestSpawnerTyped + { + private implicit val classicSystem: ActorSystem = system.toClassic + protected implicit val simulationStartDate: ZonedDateTime = + TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z") + + val scheduler: TestProbe[SchedulerMessage] = TestProbe("scheduler") + val runtimeEvents: TestProbe[RuntimeEvent] = + TestProbe("runtimeEvents") + val primaryServiceProxy = + TestProbe[ServiceMessage]("PrimaryServiceProxy") + + val weatherService = TestProbe[ServiceMessage]("WeatherService") + + private val environmentRefs = EnvironmentRefs( + scheduler = scheduler.ref, + runtimeEventListener = runtimeEvents.ref, + primaryServiceProxy = primaryServiceProxy.ref.toClassic, + weather = weatherService.ref.toClassic, + evDataService = None, + ) + + 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( + hpInputModel, + defaultThermalGrid, + HpRuntimeConfig( + calculateMissingReactivePowerWithModel = true, + 1.0, + List.empty[String], + ), + primaryServiceProxy.ref.toClassic, + Iterable(ActorWeatherService(weatherService.ref.toClassic)), + defaultSimulationStart, + defaultSimulationEnd, + defaultResolution, + simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, + defaultOutputConfig, + None, + ), + listener = Iterable(resultListener.ref.toClassic), + ), + "HeatPumpAgent1", + ) + + scheduler.expectNoMessage() + + /* INIT */ + + // heat pump + heatPumpAgent ! Activation(INIT_SIM_TICK) + + primaryServiceProxy.expectMessage( + PrimaryServiceRegistrationMessage(adaptedHpInputModel.getUuid) + ) + heatPumpAgent ! RegistrationFailedMessage( + primaryServiceProxy.ref.toClassic + ) + + weatherService.expectMessage( + RegisterForWeatherMessage( + hpInputModel.getNode.getGeoPosition.getY, + hpInputModel.getNode.getGeoPosition.getX, + ) + ) + + heatPumpAgent ! RegistrationSuccessfulMessage( + weatherService.ref.toClassic, + Some(0L), + ) + + scheduler.expectMessage(Completion(heatPumpAgent)) + + val weatherDependentAgents = Seq(heatPumpAgent) + + /* TICK 0 + LOAD: 0.000269 MW + PV: -0.005685 MW + Heat pump: off, can be turned on or stay off + -> set point ~3.5 kW (bigger than 50 % rated apparent power): turned on + -> remaining -0.000566 MW + */ + + heatPumpAgent ! Activation(0) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 0, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(400d), + WattsPerSquareMeter(200d), + Celsius(0d), + MetersPerSecond(0d), + ), + Some(7200), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(emResult: EmResult) => + emResult.getInputModel shouldBe emInput.getUuid + emResult.getTime shouldBe 0.toDateTime + emResult.getP should equalWithTolerance( + (-0.000566087824).asMegaWatt + ) + emResult.getQ should equalWithTolerance(0.001073120041.asMegaVar) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(7200))) + + /* TICK 7200 + LOAD: 0.000269 MW (unchanged) + PV: -0.003797 MW + Heat pump: running (turned on from last request), can also be turned off + -> set point ~3.5 kW (bigger than 50 % rated apparent power): stays turned on with unchanged state + -> remaining 0 MW + */ + + heatPumpAgent ! Activation(7200) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 7200, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(300d), + WattsPerSquareMeter(500d), + Celsius(0d), + MetersPerSecond(0d), + ), + Some(14400), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(emResult: EmResult) => + emResult.getInputModel shouldBe emInput.getUuid + emResult.getTime shouldBe 7200.toDateTime + emResult.getP should equalWithTolerance(0.00132184544484.asMegaWatt) + emResult.getQ should equalWithTolerance(0.001073120041.asMegaVar) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(14400))) + + /* TICK 14400 + LOAD: 0.000269 MW (unchanged) + PV: -0.000066 MW + Heat pump: Is still running, can still be turned off + -> flex signal is 0 MW: Heat pump is turned off + */ + + heatPumpAgent ! Activation(14400) + + // it got cloudy now... + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 14400, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(5d), + WattsPerSquareMeter(5d), + Celsius(0d), + MetersPerSecond(0d), + ), + Some(21600), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(emResult: EmResult) => + emResult.getInputModel shouldBe emInput.getUuid + emResult.getTime shouldBe 14400L.toDateTime + emResult.getP should equalWithTolerance(0.000202956264.asMegaWatt) + emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(21600))) + + /* TICK 21600 + LOAD: 0.000269 MW (unchanged) + PV: -0.000032 MW + Heat pump: Is not running, can run or stay off + -> flex signal is 0 MW: Heat pump is turned off + */ + + heatPumpAgent ! Activation(21600) + + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 21600, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(5d), + WattsPerSquareMeter(5d), + Celsius(0d), + MetersPerSecond(0d), + ), + Some(28800), + ) + } + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(emResult: EmResult) => + emResult.getInputModel shouldBe emInput.getUuid + emResult.getTime shouldBe 21600.toDateTime + emResult.getP should equalWithTolerance(0.0002367679996.asMegaWatt) + emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(28665))) + + /* TICK 28666 + LOAD: 0.000269 MW (unchanged) + PV: -0.000032 MW (unchanged) + Heat pump: Is turned on again and cannot be turned off + -> flex signal is no control -> 0.00485 MW + */ + + heatPumpAgent ! Activation(28665) + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(emResult: EmResult) => + emResult.getInputModel shouldBe emInput.getUuid + emResult.getTime shouldBe 28665.toDateTime + emResult.getP should equalWithTolerance(0.0050867679996.asMegaWatt) + emResult.getQ should equalWithTolerance(0.001073120040.asMegaVar) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(28800))) + } + } +} From 53499008d928d19a10ea2dcf3cce8d1750da11c9 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 1 Aug 2024 09:24:16 +0200 Subject: [PATCH 06/27] using updatedState for energyDemand --- .../edu/ie3/simona/model/thermal/ThermalGrid.scala | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala index 2dba440bdc..d1253c2b2b 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -72,16 +72,12 @@ final case class ThermalGrid( if ( updatedState._1.innerTemperature < thermalHouse.targetTemperature ) { - house - .zip(state.houseState) - .map { case (house, state) => - house.energyDemand( + thermalHouse.energyDemand( tick, ambientTemperature, - state, + updatedState._1, ) - } - .getOrElse(ThermalEnergyDemand.noDemand) + } else { ThermalEnergyDemand.noDemand } From ad2bac95b2ded59f81c34bea8949b34bbe637a28 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 1 Aug 2024 09:52:20 +0200 Subject: [PATCH 07/27] fmt --- .../scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala index d1253c2b2b..521ed84099 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -73,10 +73,10 @@ final case class ThermalGrid( updatedState._1.innerTemperature < thermalHouse.targetTemperature ) { thermalHouse.energyDemand( - tick, - ambientTemperature, + tick, + ambientTemperature, updatedState._1, - ) + ) } else { ThermalEnergyDemand.noDemand From d85279a6620488e8dad86e3b92e591f91286a213 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 1 Aug 2024 10:14:45 +0200 Subject: [PATCH 08/27] codacy --- .../ie3/simona/model/thermal/ThermalGrid.scala | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala index 521ed84099..d1a2909dfa 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -63,19 +63,20 @@ final case class ThermalGrid( val houseDemand = house.zip(state.houseState).headOption match { case Some((thermalHouse, lastHouseState)) => - val updatedState = thermalHouse.determineState( - tick, - lastHouseState, - ambientTemperature, - lastHouseState.qDot, - ) + val (updatedHouseState, updatedStorageState) = + thermalHouse.determineState( + tick, + lastHouseState, + ambientTemperature, + lastHouseState.qDot, + ) if ( - updatedState._1.innerTemperature < thermalHouse.targetTemperature + updatedHouseState.innerTemperature < thermalHouse.targetTemperature ) { thermalHouse.energyDemand( tick, ambientTemperature, - updatedState._1, + updatedHouseState, ) } else { From 4b2e6437dab5810566ae67a4c6c7e68bfec9becf Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sun, 4 Aug 2024 13:32:39 +0200 Subject: [PATCH 09/27] create thermalGridIT testframe --- .../ParticipantAgentFundamentals.scala | 13 +- .../edu/ie3/simona/event/ResultEvent.scala | 9 +- .../ie3/simona/agent/grid/ThermalGridIT.scala | 207 ++++++++---------- 3 files changed, 110 insertions(+), 119 deletions(-) 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..d6bf1524bb 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -13,7 +13,10 @@ import edu.ie3.datamodel.models.result.system.{ FlexOptionsResult, SystemParticipantResult, } -import edu.ie3.datamodel.models.result.thermal.ThermalUnitResult +import edu.ie3.datamodel.models.result.thermal.{ + ThermalHouseResult, + ThermalUnitResult, +} import edu.ie3.simona.agent.ValueStore import edu.ie3.simona.agent.grid.GridAgentMessages.{ AssetPowerChangedMessage, @@ -54,7 +57,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 +1942,11 @@ protected trait ParticipantAgentFundamentals[ def buildResultEvent[R <: ResultEntity]( result: R ): Option[ResultEvent] = result match { - case thermalResult: ThermalUnitResult => - Some(ThermalResultEvent(thermalResult)) + case thermalHouseResult: ThermalHouseResult => + Some(ResultEvent.ThermalHouseResultEvent(thermalHouseResult)) + 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..3af3b1bb08 100644 --- a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala +++ b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala @@ -16,7 +16,10 @@ import edu.ie3.datamodel.models.result.system.{ FlexOptionsResult, SystemParticipantResult, } -import edu.ie3.datamodel.models.result.thermal.ThermalUnitResult +import edu.ie3.datamodel.models.result.thermal.{ + ThermalHouseResult, + ThermalUnitResult, +} import edu.ie3.simona.agent.grid.GridResultsSupport.PartialTransformer3wResult import edu.ie3.simona.event.listener.ResultEventListener @@ -44,6 +47,10 @@ object ResultEvent { thermalResult: ThermalUnitResult ) extends ResultEvent + final case class ThermalHouseResultEvent( + thermalHouseResult: ThermalHouseResult + ) extends ResultEvent + /** 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/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index cea78a108c..62a56c8d62 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -6,13 +6,16 @@ package edu.ie3.simona.agent.grid -import edu.ie3.datamodel.models.result.system.EmResult import edu.ie3.simona.agent.EnvironmentRefs 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.ParticipantResultEvent +import edu.ie3.simona.event.ResultEvent.{ + ParticipantResultEvent, + ThermalHouseResultEvent, +} +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 @@ -73,6 +76,17 @@ class ThermalGridIT 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] = @@ -107,11 +121,11 @@ class ThermalGridIT ), primaryServiceProxy.ref.toClassic, Iterable(ActorWeatherService(weatherService.ref.toClassic)), - defaultSimulationStart, - defaultSimulationEnd, - defaultResolution, + simulationStartDate, + simulationEndDate, + resolution, simonaConfig.simona.runtime.participant.requestVoltageDeviationThreshold, - defaultOutputConfig, + outputConfigOn, None, ), listener = Iterable(resultListener.ref.toClassic), @@ -144,28 +158,31 @@ class ThermalGridIT weatherService.ref.toClassic, Some(0L), ) + val weatherDependentAgents = Seq(heatPumpAgent) - scheduler.expectMessage(Completion(heatPumpAgent)) + // scheduler.expectMessage(Completion(heatPumpAgent,Some(0L))) - val weatherDependentAgents = Seq(heatPumpAgent) + // weatherService ! Activation(0L) /* TICK 0 - LOAD: 0.000269 MW - PV: -0.005685 MW + House demand heating : + House demand water : + ThermalStorage : + DomesticWaterStorage : + Heat pump: off, can be turned on or stay off -> set point ~3.5 kW (bigger than 50 % rated apparent power): turned on - -> remaining -0.000566 MW */ - - heatPumpAgent ! Activation(0) + // scheduler ! ScheduleActivation(heatPumpAgent, 0L) + // heatPumpAgent ! Activation(0L) weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 0, weatherService.ref.toClassic, WeatherData( - WattsPerSquareMeter(400d), - WattsPerSquareMeter(200d), + WattsPerSquareMeter(0d), + WattsPerSquareMeter(0d), Celsius(0d), MetersPerSecond(0d), ), @@ -173,137 +190,99 @@ class ThermalGridIT ) } - resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(emResult: EmResult) => - emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 0.toDateTime - emResult.getP should equalWithTolerance( - (-0.000566087824).asMegaWatt - ) - emResult.getQ should equalWithTolerance(0.001073120041.asMegaVar) - } + scheduler.expectMessage(Completion(heatPumpAgent, Some(0L))) - scheduler.expectMessage(Completion(heatPumpAgent, Some(7200))) + heatPumpAgent ! Activation(7200L) - /* TICK 7200 - LOAD: 0.000269 MW (unchanged) - PV: -0.003797 MW - Heat pump: running (turned on from last request), can also be turned off - -> set point ~3.5 kW (bigger than 50 % rated apparent power): stays turned on with unchanged state - -> remaining 0 MW - */ + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe hpInputModel.getUuid + hpResult.getTime shouldBe 7200.toDateTime + hpResult.getP should equalWithTolerance(0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.asMegaVar) + } - heatPumpAgent ! Activation(7200) + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe defaultThermalHouse.getUuid + thermalHouseResult.getTime shouldBe (-1).toDateTime + thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 21.asDegreeCelsius + ) + } weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( - 7200, + 7200L, weatherService.ref.toClassic, WeatherData( - WattsPerSquareMeter(300d), - WattsPerSquareMeter(500d), - Celsius(0d), - MetersPerSecond(0d), + WattsPerSquareMeter(1d), + WattsPerSquareMeter(1d), + Celsius(1d), + MetersPerSecond(1d), ), Some(14400), ) } - resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(emResult: EmResult) => - emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 7200.toDateTime - emResult.getP should equalWithTolerance(0.00132184544484.asMegaWatt) - emResult.getQ should equalWithTolerance(0.001073120041.asMegaVar) - } - - scheduler.expectMessage(Completion(heatPumpAgent, Some(14400))) - - /* TICK 14400 - LOAD: 0.000269 MW (unchanged) - PV: -0.000066 MW - Heat pump: Is still running, can still be turned off - -> flex signal is 0 MW: Heat pump is turned off - */ + scheduler.expectMessage(Completion(heatPumpAgent, Some(7200L))) - heatPumpAgent ! Activation(14400) - - // it got cloudy now... - weatherDependentAgents.foreach { - _ ! ProvideWeatherMessage( - 14400, - weatherService.ref.toClassic, - WeatherData( - WattsPerSquareMeter(5d), - WattsPerSquareMeter(5d), - Celsius(0d), - MetersPerSecond(0d), - ), - Some(21600), - ) - } + heatPumpAgent ! Activation(14400L) resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(emResult: EmResult) => - emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 14400L.toDateTime - emResult.getP should equalWithTolerance(0.000202956264.asMegaWatt) - emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe hpInputModel.getUuid + hpResult.getTime shouldBe 14400.toDateTime + hpResult.getP should equalWithTolerance(0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.asMegaVar) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(21600))) - - /* TICK 21600 - LOAD: 0.000269 MW (unchanged) - PV: -0.000032 MW - Heat pump: Is not running, can run or stay off - -> flex signal is 0 MW: Heat pump is turned off - */ - - heatPumpAgent ! Activation(21600) + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe defaultThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 7200.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 20.81797472222.asDegreeCelsius + ) + } weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( - 21600, + 14400L, weatherService.ref.toClassic, WeatherData( - WattsPerSquareMeter(5d), - WattsPerSquareMeter(5d), - Celsius(0d), - MetersPerSecond(0d), + WattsPerSquareMeter(2d), + WattsPerSquareMeter(2d), + Celsius(2d), + MetersPerSecond(2d), ), - Some(28800), + Some(21600), ) } - resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(emResult: EmResult) => - emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 21600.toDateTime - emResult.getP should equalWithTolerance(0.0002367679996.asMegaWatt) - emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) - } - - scheduler.expectMessage(Completion(heatPumpAgent, Some(28665))) - - /* TICK 28666 - LOAD: 0.000269 MW (unchanged) - PV: -0.000032 MW (unchanged) - Heat pump: Is turned on again and cannot be turned off - -> flex signal is no control -> 0.00485 MW - */ + scheduler.expectMessage(Completion(heatPumpAgent, Some(14400L))) - heatPumpAgent ! Activation(28665) + heatPumpAgent ! Activation(21600L) resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(emResult: EmResult) => - emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 28665.toDateTime - emResult.getP should equalWithTolerance(0.0050867679996.asMegaWatt) - emResult.getQ should equalWithTolerance(0.001073120040.asMegaVar) + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe hpInputModel.getUuid + hpResult.getTime shouldBe 21600.toDateTime + hpResult.getP should equalWithTolerance(0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.asMegaVar) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(28800))) + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe defaultThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 14400.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 20.6375522746296.asDegreeCelsius + ) + } } } } From a0ecdb6589621cbacfbbe6d8767ec4c2b5b3ebc9 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sun, 4 Aug 2024 13:33:20 +0200 Subject: [PATCH 10/27] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 981b8b301e..80908bf866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Implementation of StorageAgent [#309](https://github.com/ie3-institute/simona/issues/309) - 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) +- 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) From 3635241fc8896b1b8d5a685129fcb9fa0ddf987e Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 11:55:19 +0200 Subject: [PATCH 11/27] Provide actual ambient temperature of tick to HpModel when calculate state --- CHANGELOG.md | 1 + src/main/scala/edu/ie3/simona/model/participant/HpModel.scala | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 468de1d410..8f22e318f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,6 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed result output for thermal houses and cylindrical storages [#844](https://github.com/ie3-institute/simona/issues/844) - Fixed FixedFeedModelSpec [#861](https://github.com/ie3-institute/simona/issues/861) - Fixing duration calculation in result events [#801](https://github.com/ie3-institute/simona/issues/801) +- 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/model/participant/HpModel.scala b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala index 7af9279611..cb2375db42 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -184,7 +184,7 @@ final case class HpModel( thermalGrid.updateState( relevantData.currentTick, state.thermalGridState, - state.ambientTemperature.getOrElse(relevantData.ambientTemperature), + relevantData.ambientTemperature, newThermalPower, ) From 5ba6f591d99bf1b3318c6f15acb6bffefc35c60b Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 12:00:37 +0200 Subject: [PATCH 12/27] fmt --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f22e318f0..e9d873f5e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,7 +88,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed result output for thermal houses and cylindrical storages [#844](https://github.com/ie3-institute/simona/issues/844) - Fixed FixedFeedModelSpec [#861](https://github.com/ie3-institute/simona/issues/861) - Fixing duration calculation in result events [#801](https://github.com/ie3-institute/simona/issues/801) -- Provide actual ambient temperature of tick to HpModel when calculate state [#882](https://github.com/ie3-institute/simona/issues/882) +- 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 From bdf4c9d5ac7e0745afd90aaf9b3311e9b5fe3507 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 12:08:40 +0200 Subject: [PATCH 13/27] introduce storage in HpInputTestData --- .../ParticipantAgentFundamentals.scala | 3 + .../edu/ie3/simona/event/ResultEvent.scala | 9 +++ .../ie3/simona/agent/grid/ThermalGridIT.scala | 17 +++--- .../test/common/input/HpInputTestData.scala | 55 ++++++++++++++++++- 4 files changed, 75 insertions(+), 9 deletions(-) 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 d6bf1524bb..2b2fe3564f 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -14,6 +14,7 @@ import edu.ie3.datamodel.models.result.system.{ SystemParticipantResult, } import edu.ie3.datamodel.models.result.thermal.{ + CylindricalStorageResult, ThermalHouseResult, ThermalUnitResult, } @@ -1942,6 +1943,8 @@ protected trait ParticipantAgentFundamentals[ def buildResultEvent[R <: ResultEntity]( result: R ): Option[ResultEvent] = result match { + case thermalStorageResult: CylindricalStorageResult => + Some(ResultEvent.CylindricalStorageResultEvent(thermalStorageResult)) case thermalHouseResult: ThermalHouseResult => Some(ResultEvent.ThermalHouseResultEvent(thermalHouseResult)) case thermalUnitResult: ThermalUnitResult => diff --git a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala index 3af3b1bb08..704f37aed3 100644 --- a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala +++ b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala @@ -18,6 +18,7 @@ import edu.ie3.datamodel.models.result.system.{ } import edu.ie3.datamodel.models.result.thermal.{ ThermalHouseResult, + ThermalStorageResult, ThermalUnitResult, } import edu.ie3.simona.agent.grid.GridResultsSupport.PartialTransformer3wResult @@ -51,6 +52,14 @@ object ResultEvent { thermalHouseResult: ThermalHouseResult ) extends ResultEvent + final case class ThermalStorageResultEvent( + thermalStorageResult: ThermalStorageResult + ) extends ResultEvent + + final case class CylindricalStorageResultEvent( + thermalStorageResult: ThermalStorageResult + ) extends ResultEvent + /** 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/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 62a56c8d62..5e7cbf164f 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -12,6 +12,7 @@ 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.{ + CylindricalStorageResultEvent, ParticipantResultEvent, ThermalHouseResultEvent, } @@ -112,8 +113,8 @@ class ThermalGridIT new HpAgent( scheduler = scheduler.ref.toClassic, initStateData = ParticipantInitializeStateData( - hpInputModel, - defaultThermalGrid, + typicalHpInputModel, + typicalThermalGrid, HpRuntimeConfig( calculateMissingReactivePowerWithModel = true, 1.0, @@ -141,7 +142,7 @@ class ThermalGridIT heatPumpAgent ! Activation(INIT_SIM_TICK) primaryServiceProxy.expectMessage( - PrimaryServiceRegistrationMessage(adaptedHpInputModel.getUuid) + PrimaryServiceRegistrationMessage(typicalHpInputModel.getUuid) ) heatPumpAgent ! RegistrationFailedMessage( primaryServiceProxy.ref.toClassic @@ -149,8 +150,8 @@ class ThermalGridIT weatherService.expectMessage( RegisterForWeatherMessage( - hpInputModel.getNode.getGeoPosition.getY, - hpInputModel.getNode.getGeoPosition.getX, + typicalHpInputModel.getNode.getGeoPosition.getY, + typicalHpInputModel.getNode.getGeoPosition.getX, ) ) @@ -196,7 +197,7 @@ class ThermalGridIT resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => - hpResult.getInputModel shouldBe hpInputModel.getUuid + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 7200.toDateTime hpResult.getP should equalWithTolerance(0.asMegaWatt) hpResult.getQ should equalWithTolerance(0.asMegaVar) @@ -204,7 +205,7 @@ class ThermalGridIT resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe defaultThermalHouse.getUuid + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid thermalHouseResult.getTime shouldBe (-1).toDateTime thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( @@ -240,7 +241,7 @@ class ThermalGridIT resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe defaultThermalHouse.getUuid + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid thermalHouseResult.getTime shouldBe 7200.toDateTime thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( diff --git a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala index 2611073a1c..3468adc96d 100644 --- a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala +++ b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala @@ -10,6 +10,7 @@ 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.{ + CylindricalStorageInput, ThermalHouseInput, ThermalStorageInput, } @@ -30,7 +31,7 @@ import tech.units.indriya.quantity.Quantities import tech.units.indriya.unit.Units import java.util.UUID -import scala.jdk.CollectionConverters.SeqHasAsJava +import scala.jdk.CollectionConverters.{SeqHasAsJava, _} trait HpInputTestData extends NodeInputTestData with ThermalGridTestData { @@ -83,6 +84,58 @@ trait HpInputTestData extends NodeInputTestData with ThermalGridTestData { 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, thermalStorage: Option[ThermalStorage] = None, From 1a4bde854e9b7c9c14e708779be347f8ab0bfe26 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 12:08:48 +0200 Subject: [PATCH 14/27] resolve merge conflict --- .../ThermalGridWithHouseAndStorageSpec.scala | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala index 674d7a0ee7..ecbf8e18d7 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -127,23 +127,6 @@ class ThermalGridWithHouseAndStorageSpec storageDemand.required should approximate(KilowattHours(345d)) storageDemand.possible should approximate(KilowattHours(920d)) } - - "consider stored energy to reduce house demand if stored energy is not enough" in { - val tick = 10800 // after three hours - - val startingState = ThermalGrid.startingState(thermalGrid) - val gridDemand = thermalGrid.energyDemand( - tick, - testGridAmbientTemperature, - startingState.copy(houseState = - startingState.houseState.map( - _.copy(innerTemperature = Celsius(3d)) - ) - ), - ) - gridDemand.required should approximate(KilowattHours(8.64987499999)) - gridDemand.possible should approximate(KilowattHours(1418.64987499999)) - } } "handling thermal energy consumption from grid" should { From 97a4577571e04b8d9b274408f8bab82691afeb77 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 12:09:03 +0200 Subject: [PATCH 15/27] update ThermalGridIT --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 166 +++++++++++++++--- 1 file changed, 140 insertions(+), 26 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 5e7cbf164f..884823a548 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -184,7 +184,7 @@ class ThermalGridIT WeatherData( WattsPerSquareMeter(0d), WattsPerSquareMeter(0d), - Celsius(0d), + Celsius(-5d), MetersPerSecond(0d), ), Some(7200), @@ -199,8 +199,10 @@ class ThermalGridIT case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 7200.toDateTime - hpResult.getP should equalWithTolerance(0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.asMegaVar) + hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.0012489995996796802.asMegaVar + ) } resultListener.expectMessageType[ThermalHouseResultEvent] match { @@ -209,7 +211,17 @@ class ThermalGridIT thermalHouseResult.getTime shouldBe (-1).toDateTime thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 21.asDegreeCelsius + 20.asDegreeCelsius + ) + } + + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe (-1).toDateTime + thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.asMegaWattHour ) } @@ -220,68 +232,170 @@ class ThermalGridIT WeatherData( WattsPerSquareMeter(1d), WattsPerSquareMeter(1d), - Celsius(1d), - MetersPerSecond(1d), + Celsius(-5d), + MetersPerSecond(0d), ), - Some(14400), + Some(28800), ) } + // FIXME? Why next tick 7200? scheduler.expectMessage(Completion(heatPumpAgent, Some(7200L))) - heatPumpAgent ! Activation(14400L) + // House reaches upperTempBoundary + heatPumpAgent ! Activation(15605L) + // Results of 7200 resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => - hpResult.getInputModel shouldBe hpInputModel.getUuid - hpResult.getTime shouldBe 14400.toDateTime - hpResult.getP should equalWithTolerance(0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.asMegaVar) + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 15605.toDateTime + hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.0012489995996796802.asMegaVar + ) } resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid thermalHouseResult.getTime shouldBe 7200.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance( + 0.011.asMegaWatt + ) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 19.3332407407407.asDegreeCelsius + ) + } + + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 7200.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.asMegaWattHour + ) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(19022L))) + + // Tick where Storage will be full + heatPumpAgent ! Activation(19022L) + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 19022.toDateTime + hpResult.getP should equalWithTolerance(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + } + + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 15605.toDateTime thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 20.81797472222.asDegreeCelsius + 22.0000152280521.asDegreeCelsius + ) + } + + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 15605.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance( + 0.011.asMegaWatt + ) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.asMegaWattHour ) } + scheduler.expectMessage(Completion(heatPumpAgent, Some(28800L))) + + // house reaches lowerTempBoundary at tick 56074 + // but now it's getting colder which should would cool the house faster + weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( - 14400L, + 28800L, weatherService.ref.toClassic, WeatherData( WattsPerSquareMeter(2d), WattsPerSquareMeter(2d), - Celsius(2d), - MetersPerSecond(2d), + Celsius(-25d), + MetersPerSecond(0d), ), - Some(21600), + Some(51200), ) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(14400L))) + heatPumpAgent ! Activation(28800L) + 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) + } - heatPumpAgent ! Activation(21600L) + // results of 19022 where storage got full charged + // house cooled a bit since the thermal infeed got into the storage + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 19022.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 21.6583150353326.asDegreeCelsius + ) + } + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 19022.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance( + 0.0.asMegaWatt + ) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.01044.asMegaWattHour + ) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(40620L))) + + heatPumpAgent ! Activation(56074) resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => - hpResult.getInputModel shouldBe hpInputModel.getUuid - hpResult.getTime shouldBe 21600.toDateTime - hpResult.getP should equalWithTolerance(0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.asMegaVar) + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 28800.toDateTime + hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.0012489995996796802.asMegaVar + ) } resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe defaultThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 14400.toDateTime + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 28800.toDateTime thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 20.6375522746296.asDegreeCelsius + 26.18658148148146.asDegreeCelsius + ) + } + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 28800.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance( + 0.0.asMegaWatt + ) + thermalStorageResult.getEnergy should equalWithTolerance( + 19.3332407407407.asKiloWattHour ) } } From 11c8acbe18252e41cc559bbd260991625f9ce16e Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 14:36:46 +0200 Subject: [PATCH 16/27] further update ThermalGridIT --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 236 ++++++++++++++---- 1 file changed, 184 insertions(+), 52 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 884823a548..74aaa2fec8 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -175,7 +175,7 @@ class ThermalGridIT -> set point ~3.5 kW (bigger than 50 % rated apparent power): turned on */ // scheduler ! ScheduleActivation(heatPumpAgent, 0L) - // heatPumpAgent ! Activation(0L) + heatPumpAgent ! Activation(0L) weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( @@ -191,14 +191,10 @@ class ThermalGridIT ) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(0L))) - - heatPumpAgent ! Activation(7200L) - resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid - hpResult.getTime shouldBe 7200.toDateTime + hpResult.getTime shouldBe 0.toDateTime hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) hpResult.getQ should equalWithTolerance( 0.0012489995996796802.asMegaVar @@ -225,6 +221,50 @@ class ThermalGridIT ) } + scheduler.expectMessage(Completion(heatPumpAgent, Some(0L))) + + // House is fully heated up + heatPumpAgent ! Activation(6353L) + + // Results of 6353 for hp + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 6353.toDateTime + hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.0012489995996796802.asMegaVar + ) + } + + // Results of 0 for house and storage + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 0.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance( + 0.011.asMegaWatt + ) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 19.9999074074074.asDegreeCelsius + ) + } + + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 0.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.asMegaWattHour + ) + } + // FIXME? Why next tick 6353? + scheduler.expectMessage(Completion(heatPumpAgent, Some(6353L))) + + heatPumpAgent ! Activation(7200L) + + // weather update (unchanged) weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 7200L, @@ -235,89 +275,91 @@ class ThermalGridIT Celsius(-5d), MetersPerSecond(0d), ), - Some(28800), + Some(28800L), ) } - // FIXME? Why next tick 7200? - scheduler.expectMessage(Completion(heatPumpAgent, Some(7200L))) - - // House reaches upperTempBoundary - heatPumpAgent ! Activation(15605L) - - // Results of 7200 + // Results of 7200 for hp resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid - hpResult.getTime shouldBe 15605.toDateTime + hpResult.getTime shouldBe 7200.toDateTime hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) hpResult.getQ should equalWithTolerance( 0.0012489995996796802.asMegaVar ) } + // Results of 6353 for house and storage resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 7200.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance( - 0.011.asMegaWatt - ) + thermalHouseResult.getTime shouldBe 6353.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance(0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 19.3332407407407.asDegreeCelsius + 21.99992810459535.asDegreeCelsius ) } resultListener.expectMessageType[CylindricalStorageResultEvent] match { case CylindricalStorageResultEvent(thermalStorageResult) => thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 7200.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) + thermalStorageResult.getTime shouldBe 6353.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance( + 0.011.asMegaWatt + ) thermalStorageResult.getEnergy should equalWithTolerance( 0.asMegaWattHour ) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(19022L))) + // FIXME? Why next tick 7200? + scheduler.expectMessage(Completion(heatPumpAgent, Some(7200L))) - // Tick where Storage will be full - heatPumpAgent ! Activation(19022L) + // Tick where storage will be full + heatPumpAgent ! Activation(9770L) + // Results of 9770 for hp resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid - hpResult.getTime shouldBe 19022.toDateTime - hpResult.getP should equalWithTolerance(0.0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + hpResult.getTime shouldBe 9770.toDateTime + hpResult.getP should equalWithTolerance(0.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.asMegaVar + ) } + // Results of 7200 for house and storage resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 15605.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) + thermalHouseResult.getTime shouldBe 7200.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance( + 0.asMegaWatt + ) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 22.0000152280521.asDegreeCelsius + 21.9152283301339.asDegreeCelsius ) } resultListener.expectMessageType[CylindricalStorageResultEvent] match { case CylindricalStorageResultEvent(thermalStorageResult) => thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 15605.toDateTime + thermalStorageResult.getTime shouldBe 7200.toDateTime thermalStorageResult.getqDot() should equalWithTolerance( 0.011.asMegaWatt ) thermalStorageResult.getEnergy should equalWithTolerance( - 0.asMegaWattHour + 0.002588055555555.asMegaWattHour ) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(28800L))) - - // house reaches lowerTempBoundary at tick 56074 - // but now it's getting colder which should would cool the house faster + // FIXME? Why next tick 9770? + scheduler.expectMessage(Completion(heatPumpAgent, Some(9770L))) + // house would reach lowerTempBoundary at tick 47518 + // but now it's getting colder which should decrease inner temp of house faster weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 28800L, @@ -328,7 +370,7 @@ class ThermalGridIT Celsius(-25d), MetersPerSecond(0d), ), - Some(51200), + Some(50400L), ) } @@ -341,37 +383,37 @@ class ThermalGridIT hpResult.getQ should equalWithTolerance(0.0.asMegaVar) } - // results of 19022 where storage got full charged - // house cooled a bit since the thermal infeed got into the storage + // Results of 9770 for house and storage resultListener.expectMessageType[ThermalHouseResultEvent] match { case ThermalHouseResultEvent(thermalHouseResult) => thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 19022.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) + thermalHouseResult.getTime shouldBe 9770.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance( + 0.asMegaWatt + ) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 21.6583150353326.asDegreeCelsius + 21.65903523084334.asDegreeCelsius ) } + resultListener.expectMessageType[CylindricalStorageResultEvent] match { case CylindricalStorageResultEvent(thermalStorageResult) => thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 19022.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance( - 0.0.asMegaWatt - ) + thermalStorageResult.getTime shouldBe 9770.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) thermalStorageResult.getEnergy should equalWithTolerance( 0.01044.asMegaWattHour ) } - scheduler.expectMessage(Completion(heatPumpAgent, Some(40620L))) + scheduler.expectMessage(Completion(heatPumpAgent, Some(28800L))) - heatPumpAgent ! Activation(56074) + heatPumpAgent ! Activation(31106L) resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid - hpResult.getTime shouldBe 28800.toDateTime + hpResult.getTime shouldBe 31106.toDateTime hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) hpResult.getQ should equalWithTolerance( 0.0012489995996796802.asMegaVar @@ -384,7 +426,7 @@ class ThermalGridIT thermalHouseResult.getTime shouldBe 28800.toDateTime thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 26.18658148148146.asDegreeCelsius + 18.3704373032769.asDegreeCelsius ) } resultListener.expectMessageType[CylindricalStorageResultEvent] match { @@ -395,9 +437,99 @@ class ThermalGridIT 0.0.asMegaWatt ) thermalStorageResult.getEnergy should equalWithTolerance( - 19.3332407407407.asKiloWattHour + 0.01044.asMegaWattHour + ) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(31106))) + + heatPumpAgent ! Activation(47225L) + + resultListener.expectMessageType[ParticipantResultEvent] match { + case ParticipantResultEvent(hpResult) => + hpResult.getInputModel shouldBe typicalHpInputModel.getUuid + hpResult.getTime shouldBe 47225.toDateTime + hpResult.getP should equalWithTolerance(0.asMegaWatt) + hpResult.getQ should equalWithTolerance( + 0.asMegaVar + ) + } + + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 31106.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance( + 0.011.asMegaWatt + ) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 18.00002164245703.asDegreeCelsius + ) + } + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 31106.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance( + 0.0.asMegaWatt + ) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.01044.asMegaWattHour ) } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) + + heatPumpAgent ! Activation(50400L) + + // it's getting warmer again + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 50400L, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(3d), + WattsPerSquareMeter(3d), + 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(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + } + + // results of tick 47225 where house reached the upper boundary + // should be heated by using thermal energy from the storage FIXME + resultListener.expectMessageType[ThermalHouseResultEvent] match { + case ThermalHouseResultEvent(thermalHouseResult) => + thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid + thermalHouseResult.getTime shouldBe 47225.toDateTime + thermalHouseResult.getqDot() should equalWithTolerance(0.asMegaWatt) + thermalHouseResult.getIndoorTemperature should equalWithTolerance( + 21.99992035040234.asDegreeCelsius + ) + } + resultListener.expectMessageType[CylindricalStorageResultEvent] match { + case CylindricalStorageResultEvent(thermalStorageResult) => + thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid + thermalStorageResult.getTime shouldBe 47225.toDateTime + thermalStorageResult.getqDot() should equalWithTolerance( + 0.0.asMegaWatt + ) + thermalStorageResult.getEnergy should equalWithTolerance( + 0.01044.asMegaWattHour + ) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(50400L))) + } } } From b21bbc3603dfc82f2e3641e309cdaa9f412fa607 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 14:45:01 +0200 Subject: [PATCH 17/27] update changelog --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f647430a99..195cc49156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,10 +90,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed result output for thermal houses and cylindrical storages [#844](https://github.com/ie3-institute/simona/issues/844) - Fixed FixedFeedModelSpec [#861](https://github.com/ie3-institute/simona/issues/861) - Fixing duration calculation in result events [#801](https://github.com/ie3-institute/simona/issues/801) -- Provide actual ambient temperature of tick to HpModel when calculate state [#882](https://github.com/ie3-institute/simona/issues/882) - 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) -- Fixed Hp results leading to overheating house and other effects [#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 From b14f4ab8c11946c1215f934b90d127a2f093029e Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 5 Aug 2024 17:12:16 +0200 Subject: [PATCH 18/27] refactor tests for result events within ThermalGridIT --- .../ParticipantAgentFundamentals.scala | 10 +- .../edu/ie3/simona/event/ResultEvent.scala | 63 +- .../ie3/simona/agent/grid/ThermalGridIT.scala | 541 ++++++++++-------- .../ThermalGridWithHouseOnlySpec.scala | 4 +- 4 files changed, 368 insertions(+), 250 deletions(-) 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 2b2fe3564f..860881a535 100644 --- a/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala +++ b/src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala @@ -13,11 +13,7 @@ import edu.ie3.datamodel.models.result.system.{ FlexOptionsResult, SystemParticipantResult, } -import edu.ie3.datamodel.models.result.thermal.{ - CylindricalStorageResult, - ThermalHouseResult, - ThermalUnitResult, -} +import edu.ie3.datamodel.models.result.thermal.ThermalUnitResult import edu.ie3.simona.agent.ValueStore import edu.ie3.simona.agent.grid.GridAgentMessages.{ AssetPowerChangedMessage, @@ -1943,10 +1939,6 @@ protected trait ParticipantAgentFundamentals[ def buildResultEvent[R <: ResultEntity]( result: R ): Option[ResultEvent] = result match { - case thermalStorageResult: CylindricalStorageResult => - Some(ResultEvent.CylindricalStorageResultEvent(thermalStorageResult)) - case thermalHouseResult: ThermalHouseResult => - Some(ResultEvent.ThermalHouseResultEvent(thermalHouseResult)) case thermalUnitResult: ThermalUnitResult => Some(ResultEvent.ThermalResultEvent(thermalUnitResult)) diff --git a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala index 704f37aed3..a1a765d977 100644 --- a/src/main/scala/edu/ie3/simona/event/ResultEvent.scala +++ b/src/main/scala/edu/ie3/simona/event/ResultEvent.scala @@ -17,12 +17,17 @@ import edu.ie3.datamodel.models.result.system.{ SystemParticipantResult, } import edu.ie3.datamodel.models.result.thermal.{ + CylindricalStorageResult, ThermalHouseResult, - ThermalStorageResult, 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 @@ -48,17 +53,53 @@ object ResultEvent { thermalResult: ThermalUnitResult ) extends ResultEvent - final case class ThermalHouseResultEvent( - thermalHouseResult: ThermalHouseResult - ) 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 + } + } + } - final case class ThermalStorageResultEvent( - thermalStorageResult: ThermalStorageResult - ) extends ResultEvent - - final case class CylindricalStorageResultEvent( - thermalStorageResult: ThermalStorageResult - ) extends ResultEvent + 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 diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 74aaa2fec8..57ec95f627 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -6,15 +6,14 @@ package edu.ie3.simona.agent.grid -import edu.ie3.simona.agent.EnvironmentRefs 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.{ - CylindricalStorageResultEvent, + CylindricalThermalStorageResult, ParticipantResultEvent, - ThermalHouseResultEvent, + ThermalHouseResult, } import edu.ie3.simona.event.notifier.NotifierConfig import edu.ie3.simona.event.{ResultEvent, RuntimeEvent} @@ -56,13 +55,8 @@ import squants.thermal.Celsius import java.time.ZonedDateTime import scala.language.postfixOps -/** Test to ensure the functions that a [[GridAgent]] in center position should - * be able to do if the DBFSAlgorithm is used. The scheduler, the weather - * service as well as the inferior and superior [[GridAgent]] s are simulated - * by the TestKit. By now this test does NOT cover interactions with generation - * or load asset agents due to unavailability during test development. Hence it - * would make sense to extend this test in the future to include asset agent - * interaction or cover this behaviour by another (integration) test! +/** Test to ensure the functions that a thermal grid and its connected assets is + * capable. */ class ThermalGridIT extends ScalaTestWithActorTestKit @@ -71,9 +65,7 @@ class ThermalGridIT with should.Matchers with EmInputTestData with MockitoSugar - with DefaultTestData -// with TestSpawnerTyped - { + with DefaultTestData { private implicit val classicSystem: ActorSystem = system.toClassic protected implicit val simulationStartDate: ZonedDateTime = TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z") @@ -97,14 +89,6 @@ class ThermalGridIT val weatherService = TestProbe[ServiceMessage]("WeatherService") - private val environmentRefs = EnvironmentRefs( - scheduler = scheduler.ref, - runtimeEventListener = runtimeEvents.ref, - primaryServiceProxy = primaryServiceProxy.ref.toClassic, - weather = weatherService.ref.toClassic, - evDataService = None, - ) - 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 { @@ -161,10 +145,6 @@ class ThermalGridIT ) val weatherDependentAgents = Seq(heatPumpAgent) - // scheduler.expectMessage(Completion(heatPumpAgent,Some(0L))) - - // weatherService ! Activation(0L) - /* TICK 0 House demand heating : House demand water : @@ -174,7 +154,7 @@ class ThermalGridIT Heat pump: off, can be turned on or stay off -> set point ~3.5 kW (bigger than 50 % rated apparent power): turned on */ - // scheduler ! ScheduleActivation(heatPumpAgent, 0L) + heatPumpAgent ! Activation(0L) weatherDependentAgents.foreach { @@ -201,25 +181,38 @@ class ThermalGridIT ) } - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe (-1).toDateTime - thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 20.asDegreeCelsius - ) - } - - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe (-1).toDateTime - thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.asMegaWattHour - ) - } + 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))) @@ -238,27 +231,41 @@ class ThermalGridIT } // Results of 0 for house and storage - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 0.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance( - 0.011.asMegaWatt - ) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 19.9999074074074.asDegreeCelsius - ) - } + 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" + ) + } + } - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 0.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.asMegaWattHour - ) - } // FIXME? Why next tick 6353? scheduler.expectMessage(Completion(heatPumpAgent, Some(6353L))) @@ -291,27 +298,41 @@ class ThermalGridIT } // Results of 6353 for house and storage - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 6353.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance(0.asMegaWatt) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 21.99992810459535.asDegreeCelsius - ) - } - - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 6353.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance( - 0.011.asMegaWatt - ) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.asMegaWattHour - ) - } + 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))) @@ -325,35 +346,44 @@ class ThermalGridIT hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 9770.toDateTime hpResult.getP should equalWithTolerance(0.asMegaWatt) - hpResult.getQ should equalWithTolerance( - 0.asMegaVar - ) + hpResult.getQ should equalWithTolerance(0.asMegaVar) } // Results of 7200 for house and storage - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 7200.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance( - 0.asMegaWatt - ) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 21.9152283301339.asDegreeCelsius - ) - } - - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 7200.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance( - 0.011.asMegaWatt - ) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.002588055555555.asMegaWattHour - ) - } + 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))) @@ -384,27 +414,40 @@ class ThermalGridIT } // Results of 9770 for house and storage - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 9770.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance( - 0.asMegaWatt - ) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 21.65903523084334.asDegreeCelsius - ) - } - - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 9770.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance(0.asMegaWatt) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.01044.asMegaWattHour - ) - } + 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))) @@ -420,26 +463,41 @@ class ThermalGridIT ) } - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 28800.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance(0.0.asMegaWatt) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 18.3704373032769.asDegreeCelsius - ) - } - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 28800.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance( - 0.0.asMegaWatt - ) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.01044.asMegaWattHour - ) - } + 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(31106))) @@ -455,81 +513,108 @@ class ThermalGridIT ) } - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 31106.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance( - 0.011.asMegaWatt - ) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 18.00002164245703.asDegreeCelsius - ) - } - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 31106.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance( - 0.0.asMegaWatt - ) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.01044.asMegaWattHour - ) - } - - scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) - - heatPumpAgent ! Activation(50400L) - - // it's getting warmer again - weatherDependentAgents.foreach { - _ ! ProvideWeatherMessage( - 50400L, - weatherService.ref.toClassic, - WeatherData( - WattsPerSquareMeter(3d), - WattsPerSquareMeter(3d), - 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(0.0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.0.asMegaVar) - } - - // results of tick 47225 where house reached the upper boundary - // should be heated by using thermal energy from the storage FIXME - resultListener.expectMessageType[ThermalHouseResultEvent] match { - case ThermalHouseResultEvent(thermalHouseResult) => - thermalHouseResult.getInputModel shouldBe typicalThermalHouse.getUuid - thermalHouseResult.getTime shouldBe 47225.toDateTime - thermalHouseResult.getqDot() should equalWithTolerance(0.asMegaWatt) - thermalHouseResult.getIndoorTemperature should equalWithTolerance( - 21.99992035040234.asDegreeCelsius - ) - } - resultListener.expectMessageType[CylindricalStorageResultEvent] match { - case CylindricalStorageResultEvent(thermalStorageResult) => - thermalStorageResult.getInputModel shouldBe typicalThermalStorage.getUuid - thermalStorageResult.getTime shouldBe 47225.toDateTime - thermalStorageResult.getqDot() should equalWithTolerance( - 0.0.asMegaWatt - ) - thermalStorageResult.getEnergy should equalWithTolerance( - 0.01044.asMegaWattHour - ) - } - - scheduler.expectMessage(Completion(heatPumpAgent, Some(50400L))) - + 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.011.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.0.asMegaWatt + ) + energy should equalWithTolerance( + 0.01044.asMegaWattHour + ) + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) + + heatPumpAgent ! Activation(50400L) + + // it's getting warmer again + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 50400L, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(3d), + WattsPerSquareMeter(3d), + 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(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + } + + // results of tick 47225 where house reached the upper boundary + // should be heated by using thermal energy from the storage FIXME + + 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 47225.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 21.99992035040234.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 47225.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(50400L))) + } } } } diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala index 5951473957..1301eb01b9 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -14,7 +14,7 @@ import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseThreshold.{ HouseTemperatureUpperBoundaryReached, } import edu.ie3.simona.test.common.UnitSpec -import squants.energy.{KilowattHours, Kilowatts, Megawatts, WattHours, Watts} +import squants.energy._ import squants.thermal.Celsius import squants.{Energy, Power, Temperature} @@ -74,7 +74,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { "determining the energy demand" should { "exactly be the demand of the house" in { val tick = 10800 // after three hours - val houseDemand = thermalHouse.energyDemand( + val expectedHouseDemand = thermalHouse.energyDemand( tick, testGridAmbientTemperature, expectedHouseStartingState, From cecd940f49ea1f11a62152815009d681c1bd5fe0 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 7 Aug 2024 09:45:33 +0200 Subject: [PATCH 19/27] fixed ThermalGridIT --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 128 +++++++++--------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 57ec95f627..8878c5ff23 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -547,74 +547,74 @@ class ThermalGridIT 0.01044.asMegaWattHour ) } + } - scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) - - heatPumpAgent ! Activation(50400L) - - // it's getting warmer again - weatherDependentAgents.foreach { - _ ! ProvideWeatherMessage( - 50400L, - weatherService.ref.toClassic, - WeatherData( - WattsPerSquareMeter(3d), - WattsPerSquareMeter(3d), - Celsius(5d), - MetersPerSecond(0d), - ), - Some(151200L), - ) - } + scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) - resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(hpResult) => - hpResult.getInputModel shouldBe typicalHpInputModel.getUuid - hpResult.getTime shouldBe 50400.toDateTime - hpResult.getP should equalWithTolerance(0.0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.0.asMegaVar) - } + heatPumpAgent ! Activation(50400L) + + // it's getting warmer again + weatherDependentAgents.foreach { + _ ! ProvideWeatherMessage( + 50400L, + weatherService.ref.toClassic, + WeatherData( + WattsPerSquareMeter(3d), + WattsPerSquareMeter(3d), + 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(0.0.asMegaWatt) + hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + } + + // results of tick 47225 where house reached the upper boundary + // should be heated by using thermal energy from the storage FIXME - // results of tick 47225 where house reached the upper boundary - // should be heated by using thermal energy from the storage FIXME - - 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 47225.toDateTime - qDot should equalWithTolerance(0.asMegaWatt) - indoorTemperature should equalWithTolerance( - 21.99992035040234.asDegreeCelsius - ) - - case CylindricalThermalStorageResult( - time, - inputModel, - qDot, - energy, - ) => - inputModel shouldBe typicalThermalStorage.getUuid - time shouldBe 47225.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(50400L))) + 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 47225.toDateTime + qDot should equalWithTolerance(0.asMegaWatt) + indoorTemperature should equalWithTolerance( + 21.99992035040234.asDegreeCelsius + ) + + case CylindricalThermalStorageResult( + time, + inputModel, + qDot, + energy, + ) => + inputModel shouldBe typicalThermalStorage.getUuid + time shouldBe 47225.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(50400L))) } } } From 6f116662523cbb013bf987d39f6599e41d582349 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 7 Aug 2024 16:25:55 +0200 Subject: [PATCH 20/27] ThermalGridIT till tick 31106 --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 114 +++++++++++++++--- .../test/common/input/HpInputTestData.scala | 2 +- 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 8878c5ff23..d034a610d1 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -146,14 +146,16 @@ class ThermalGridIT val weatherDependentAgents = Seq(heatPumpAgent) /* TICK 0 - House demand heating : - House demand water : - ThermalStorage : - DomesticWaterStorage : - Heat pump: off, can be turned on or stay off - -> set point ~3.5 kW (bigger than 50 % rated apparent power): turned on - */ + Start of Simulation + + House demand heating : requiredDemand = 0.0 kWh, additionalDemand ~ 15 kWh + House demand water : tba + ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + + Heat pump: on - to serve the storage demand, but will heat up the house first + */ heatPumpAgent ! Activation(0L) @@ -216,10 +218,21 @@ class ThermalGridIT scheduler.expectMessage(Completion(heatPumpAgent, Some(0L))) - // House is fully heated up + + /* TICK 6353 + House is fully heated up + + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + House demand water : tba + ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + + Heat pump: on - to serve storage demand + */ + heatPumpAgent ! Activation(6353L) - // Results of 6353 for hp + // Results of tick 6353 for hp resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid @@ -269,9 +282,21 @@ class ThermalGridIT // 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 = 2.63 kWh, additionalDemand = 7.85 kWh + DomesticWaterStorage : tba + +Heat pump: on +*/ + + heatPumpAgent ! Activation(7200L) - // weather update (unchanged) + weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 7200L, @@ -337,7 +362,17 @@ class ThermalGridIT // FIXME? Why next tick 7200? scheduler.expectMessage(Completion(heatPumpAgent, Some(7200L))) - // Tick where storage will be full + /* 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: off +*/ + heatPumpAgent ! Activation(9770L) // Results of 9770 for hp @@ -388,8 +423,20 @@ class ThermalGridIT // FIXME? Why next tick 9770? scheduler.expectMessage(Completion(heatPumpAgent, Some(9770L))) - // house would reach lowerTempBoundary at tick 47518 - // but now it's getting colder which should decrease inner temp of house faster + heatPumpAgent ! Activation(28800L) + + /* 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: off +*/ + weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 28800L, @@ -404,7 +451,7 @@ class ThermalGridIT ) } - heatPumpAgent ! Activation(28800L) + resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid @@ -451,6 +498,19 @@ class ThermalGridIT scheduler.expectMessage(Completion(heatPumpAgent, Some(28800L))) + /* TICK 31106 + +? + + + 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: on +*/ + heatPumpAgent ! Activation(31106L) resultListener.expectMessageType[ParticipantResultEvent] match { @@ -501,6 +561,18 @@ class ThermalGridIT scheduler.expectMessage(Completion(heatPumpAgent, Some(31106))) + /* TICK 47225 + +? + +House demand heating : +House demand water : tba +ThermalStorage : empty +DomesticWaterStorage : tba + +Heat pump: on +*/ + heatPumpAgent ! Activation(47225L) resultListener.expectMessageType[ParticipantResultEvent] match { @@ -551,9 +623,21 @@ class ThermalGridIT scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) + /* TICK 50400 + +New weather data: it's getting warmer again + +House demand heating : +House demand water : tba +ThermalStorage : empty +DomesticWaterStorage : tba + +Heat pump: on +*/ + heatPumpAgent ! Activation(50400L) - // it's getting warmer again + weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 50400L, diff --git a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala index 3468adc96d..bda08d6ed1 100644 --- a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala +++ b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala @@ -100,7 +100,7 @@ trait HpInputTestData extends NodeInputTestData with ThermalGridTestData { UUID.fromString("4b8933dc-aeb6-4573-b8aa-59d577214150"), "thermal storage", thermalBusInput, - Quantities.getQuantity(300.0, Units.LITRE), + Quantities.getQuantity(1300.0, Units.LITRE), Quantities.getQuantity(0.0, Units.LITRE), Quantities.getQuantity(60.0, StandardUnits.TEMPERATURE), Quantities.getQuantity(30.0, StandardUnits.TEMPERATURE), From 97e3bd8ee112132fa5bab3da5cd2046b6981e049 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 7 Aug 2024 19:01:17 +0200 Subject: [PATCH 21/27] refator HpModel.operatesInNextState, enrich energyDemand method of ThermalGrid to deliver updatedThermalState --- .../simona/model/participant/HpModel.scala | 56 ++++++++++++------- .../simona/model/thermal/ThermalGrid.scala | 42 ++++++++------ .../ThermalGridWithHouseAndStorageSpec.scala | 43 +++++++++----- .../ThermalGridWithHouseOnlySpec.scala | 17 ++++-- .../ThermalGridWithStorageOnlySpec.scala | 13 +++-- 5 files changed, 109 insertions(+), 62 deletions(-) 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 02c23a148d..239e27fa1e 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -22,7 +22,7 @@ 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.Kilowatts +import squants.energy.{KilowattHours, Kilowatts} import squants.{Power, Temperature} import java.time.ZonedDateTime @@ -153,14 +153,22 @@ final case class HpModel( state: HpState, relevantData: HpRelevantData, ): (Boolean, ThermalEnergyDemand, ThermalEnergyDemand) = { - val (demandHouse, demandStorage) = thermalGrid.energyDemand( - relevantData.currentTick, - relevantData.ambientTemperature, - state.thermalGridState, - ) + val (demandHouse, demandStorage, updatedState) = + thermalGrid.energyDemandAndUpdatedState( + relevantData.currentTick, + relevantData.ambientTemperature, + state.thermalGridState, + ) + implicit val tolerance = KilowattHours(1e-3) + val noStorageOrStorageIsEmpty: Boolean = + updatedState.storageState.isEmpty || updatedState.storageState.exists( + _.storedEnergy =~ zeroKWH + ) + + val turnHpOn: Boolean = { + (demandHouse.hasRequiredDemand && noStorageOrStorageIsEmpty) || demandStorage.hasRequiredDemand || (state.isRunning && demandHouse.hasAdditionalDemand) || (state.isRunning && demandStorage.hasAdditionalDemand) - val turnHpOn = - demandHouse.hasRequiredDemand || demandStorage.hasRequiredDemand || (state.isRunning && demandHouse.hasAdditionalDemand) || (state.isRunning && demandStorage.hasAdditionalDemand) + } ( turnHpOn, @@ -225,26 +233,30 @@ final case class HpModel( lastState: HpState, ): ProvideFlexOptions = { /* Determine the operating state in the given tick */ - val updatedState = determineState(lastState, data) + val updatedHpState: HpState = determineState(lastState, data) /* Determine the options we have */ - val (thermalEnergyDemandHouse, thermalEnergyDemandStorge) = - thermalGrid.energyDemand( + val ( + thermalEnergyDemandHouse, + thermalEnergyDemandStorage, + updatedThermalGridState, + ) = + thermalGrid.energyDemandAndUpdatedState( data.currentTick, data.ambientTemperature, lastState.thermalGridState, ) val canOperate = thermalEnergyDemandHouse.hasRequiredDemand || thermalEnergyDemandHouse.hasAdditionalDemand || - thermalEnergyDemandStorge.hasRequiredDemand || thermalEnergyDemandStorge.hasAdditionalDemand + thermalEnergyDemandStorage.hasRequiredDemand || thermalEnergyDemandStorage.hasAdditionalDemand val canBeOutOfOperation = - !thermalEnergyDemandHouse.hasRequiredDemand && !thermalEnergyDemandStorge.hasRequiredDemand + !thermalEnergyDemandHouse.hasRequiredDemand && !thermalEnergyDemandStorage.hasRequiredDemand val lowerBoundary = if (canBeOutOfOperation) zeroKW else - updatedState.activePower + updatedHpState.activePower val upperBoundary = if (canOperate) sRated * cosPhiRated @@ -253,7 +265,7 @@ final case class HpModel( ProvideMinMaxFlexOptions( uuid, - updatedState.activePower, + updatedHpState.activePower, lowerBoundary, upperBoundary, ) @@ -284,14 +296,18 @@ final case class HpModel( /* If the setpoint value is above 50 % of the electrical power, turn on the heat pump otherwise turn it off */ val turnOn = setPower > (sRated * cosPhiRated * 0.5) - val (thermalEnergyDemandHouse, thermalEnergyDemandStorage) = - thermalGrid.energyDemand( + val ( + thermalEnergyDemandHouse, + thermalEnergyDemandStorage, + updatedThermalGridState, + ) = + thermalGrid.energyDemandAndUpdatedState( data.currentTick, data.ambientTemperature, lastState.thermalGridState, ) - val updatedState = + val updatedHpState: HpState = calcState( lastState, data, @@ -301,10 +317,10 @@ final case class HpModel( ) ( - updatedState, + updatedHpState, FlexChangeIndicator( changesAtNextActivation = true, - updatedState.maybeThermalThreshold.map(_.tick), + updatedHpState.maybeThermalThreshold.map(_.tick), ), ) } diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala index 4c4fd24d5e..2aa3e9db7a 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -43,7 +43,7 @@ final case class ThermalGrid( ) extends LazyLogging { /** Determine the energy demand of the total grid at the given instance in - * time + * time and returns it including the updatedState * * @param tick * Questioned instance in time @@ -52,16 +52,17 @@ final case class ThermalGrid( * @param state * Currently applicable state of the thermal grid * @return - * The total energy demand of the house and the storage + * The total energy demand of the house and the storage and an updated + * [[ThermalGridState]] */ - def energyDemand( + def energyDemandAndUpdatedState( tick: Long, ambientTemperature: Temperature, state: ThermalGridState, - ): (ThermalEnergyDemand, ThermalEnergyDemand) = { + ): (ThermalEnergyDemand, ThermalEnergyDemand, ThermalGridState) = { /* First get the energy demand of the houses but only if inner temperature is below target temperature */ - val houseDemand = + val (houseDemand, updatedHouseState) = house.zip(state.houseState).headOption match { case Some((thermalHouse, lastHouseState)) => val (updatedHouseState, updatedStorageState) = @@ -74,22 +75,25 @@ final case class ThermalGrid( if ( updatedHouseState.innerTemperature < thermalHouse.targetTemperature ) { - thermalHouse.energyDemand( - tick, - ambientTemperature, - updatedHouseState, + ( + thermalHouse.energyDemand( + tick, + ambientTemperature, + updatedHouseState, + ), + Some(updatedHouseState), ) } else { - ThermalEnergyDemand.noDemand + (ThermalEnergyDemand.noDemand, Some(updatedHouseState)) } case None => - ThermalEnergyDemand.noDemand + (ThermalEnergyDemand.noDemand, None) } /* Then go over the storages, see what they can provide and what they might be able to charge */ - val storageDemand = { + val (storageDemand, updatedStorageState) = { storage .zip(state.storageState) @@ -106,13 +110,18 @@ final case class ThermalGrid( } val storagePossible = storage.getMaxEnergyThreshold - storedEnergy - ThermalEnergyDemand( - storageRequired, - storagePossible, + ( + ThermalEnergyDemand( + storageRequired, + storagePossible, + ), + Some(updatedStorageState), ) + } .getOrElse( - ThermalEnergyDemand(zeroMWH, zeroMWH) + ThermalEnergyDemand(zeroMWH, zeroMWH), + None, ) } @@ -125,6 +134,7 @@ final case class ThermalGrid( storageDemand.required, storageDemand.possible, ), + ThermalGridState(updatedHouseState, updatedStorageState), ) } diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala index ecbf8e18d7..ad8749442f 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -96,36 +96,49 @@ class ThermalGridWithHouseAndStorageSpec "deliver the house demand (no demand) with added flexibility by storage" in { val tick = 10800 // after three hours - val (houseDemand, storageDemand) = thermalGrid.energyDemand( - tick, - testGridAmbientTemperature, - ThermalGrid.startingState(thermalGrid), - ) - + val (houseDemand, storageDemand, updatedThermalGridState) = + thermalGrid.energyDemandAndUpdatedState( + tick, + testGridAmbientTemperature, + ThermalGrid.startingState(thermalGrid), + ) houseDemand.required should approximate(KilowattHours(0d)) houseDemand.possible should approximate(KilowattHours(31.05009722d)) storageDemand.required should approximate(KilowattHours(345d)) storageDemand.possible should approximate(KilowattHours(920d)) + updatedThermalGridState.houseState shouldBe Some( + ThermalHouseState(10800, Kelvin(292.0799935185185), Kilowatts(0d)) + ) + updatedThermalGridState.storageState shouldBe Some( + ThermalStorageState(10800, KilowattHours(230d), Kilowatts(0d)) + ) } "deliver the correct house and storage demand" in { val tick = 10800 // after three hours val startingState = ThermalGrid.startingState(thermalGrid) - val (houseDemand, storageDemand) = thermalGrid.energyDemand( - tick, - testGridAmbientTemperature, - startingState.copy(houseState = - startingState.houseState.map( - _.copy(innerTemperature = Celsius(16d)) - ) - ), - ) + val (houseDemand, storageDemand, updatedThermalGridState) = + thermalGrid.energyDemandAndUpdatedState( + tick, + testGridAmbientTemperature, + startingState.copy(houseState = + startingState.houseState.map( + _.copy(innerTemperature = Celsius(16d)) + ) + ), + ) houseDemand.required should approximate(KilowattHours(45.6000555)) houseDemand.possible should approximate(KilowattHours(75.600055555)) storageDemand.required should approximate(KilowattHours(345d)) storageDemand.possible should approximate(KilowattHours(920d)) + updatedThermalGridState.houseState shouldBe Some( + ThermalHouseState(10800, Celsius(15.959996296296296), Kilowatts(0d)) + ) + updatedThermalGridState.storageState shouldBe Some( + ThermalStorageState(10800, KilowattHours(230d), Kilowatts(0d)) + ) } } diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala index 1301eb01b9..20c785d1a8 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -16,7 +16,7 @@ import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseThreshold.{ import edu.ie3.simona.test.common.UnitSpec import squants.energy._ import squants.thermal.Celsius -import squants.{Energy, Power, Temperature} +import squants.{Energy, Kelvin, Power, Temperature} import scala.jdk.CollectionConverters._ @@ -80,16 +80,21 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { expectedHouseStartingState, ) - val (houseDemand, storageDemand) = thermalGrid.energyDemand( - tick, - testGridAmbientTemperature, - ThermalGrid.startingState(thermalGrid), - ) + val (houseDemand, storageDemand, updatedThermalGridState) = + thermalGrid.energyDemandAndUpdatedState( + tick, + testGridAmbientTemperature, + ThermalGrid.startingState(thermalGrid), + ) houseDemand.required should approximate(expectedHouseDemand.required) houseDemand.possible should approximate(expectedHouseDemand.possible) storageDemand.required should approximate(KilowattHours(0d)) storageDemand.possible should approximate(KilowattHours(0d)) + updatedThermalGridState.houseState shouldBe Some( + ThermalHouseState(10800, Kelvin(292.0799935185185), Kilowatts(0d)) + ) + updatedThermalGridState.storageState shouldBe None } } diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala index 7bc330b166..3dc257ba74 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -80,16 +80,19 @@ class ThermalGridWithStorageOnlySpec "deliver the capabilities of the storage" in { val tick = 10800 // after three hours - val (houseDemand, storageDemand) = thermalGrid.energyDemand( - tick, - testGridAmbientTemperature, - ThermalGrid.startingState(thermalGrid), - ) + val (houseDemand, storageDemand, updatedThermalGridState) = + thermalGrid.energyDemandAndUpdatedState( + tick, + testGridAmbientTemperature, + ThermalGrid.startingState(thermalGrid), + ) houseDemand.required should approximate(KilowattHours(0d)) houseDemand.possible should approximate(KilowattHours(0d)) storageDemand.required should approximate(KilowattHours(345d)) storageDemand.possible should approximate(KilowattHours(920d)) + updatedThermalGridState.houseState shouldBe None + Some(ThermalStorageState(10800, KilowattHours(230d), Kilowatts(0d))) } } From 26b22c0d3adf4122a1323a6cad69b9b759cf8d43 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 7 Aug 2024 21:21:23 +0200 Subject: [PATCH 22/27] fmt --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 154 ++++++++---------- 1 file changed, 64 insertions(+), 90 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index d034a610d1..a1269c2571 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -118,6 +118,9 @@ class ThermalGridIT "HeatPumpAgent1", ) + val pRunningHp = 0.0038.asMegaWatt + val qRunningHp = 0.0012489995996796802.asMegaVar + scheduler.expectNoMessage() /* INIT */ @@ -146,16 +149,13 @@ class ThermalGridIT 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 = 5.22 kWh, additionalDemand = 10.44 kWh - DomesticWaterStorage : tba - - Heat pump: on - to serve the storage demand, but will heat up the house first - */ + House demand heating : requiredDemand = 0.0 kWh, additionalDemand ~ 15 kWh + House demand water : tba + ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + Heat pump: on - to serve the storage demand, but will heat up the house first + */ heatPumpAgent ! Activation(0L) @@ -177,9 +177,9 @@ class ThermalGridIT case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 0.toDateTime - hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getP should equalWithTolerance(pRunningHp) hpResult.getQ should equalWithTolerance( - 0.0012489995996796802.asMegaVar + qRunningHp ) } @@ -218,17 +218,14 @@ class ThermalGridIT 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 = 5.22 kWh, additionalDemand = 10.44 kWh - DomesticWaterStorage : tba - + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + House demand water : tba + ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba Heat pump: on - to serve storage demand - */ + */ heatPumpAgent ! Activation(6353L) @@ -237,9 +234,9 @@ class ThermalGridIT case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 6353.toDateTime - hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getP should equalWithTolerance(pRunningHp) hpResult.getQ should equalWithTolerance( - 0.0012489995996796802.asMegaVar + qRunningHp ) } @@ -283,20 +280,16 @@ class ThermalGridIT 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 = 2.63 kWh, additionalDemand = 7.85 kWh - DomesticWaterStorage : tba - -Heat pump: on -*/ - + New weather data (unchanged) incoming + House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh + House demand water : tba + ThermalStorage : requiredDemand = 2.63 kWh, additionalDemand = 7.85 kWh + DomesticWaterStorage : tba + Heat pump: on + */ heatPumpAgent ! Activation(7200L) - weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 7200L, @@ -316,9 +309,9 @@ Heat pump: on case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 7200.toDateTime - hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getP should equalWithTolerance(pRunningHp) hpResult.getQ should equalWithTolerance( - 0.0012489995996796802.asMegaVar + qRunningHp ) } @@ -363,15 +356,13 @@ Heat pump: on 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: off -*/ + 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: off + */ heatPumpAgent ! Activation(9770L) @@ -423,19 +414,17 @@ Heat pump: off // FIXME? Why next tick 9770? scheduler.expectMessage(Completion(heatPumpAgent, Some(9770L))) - heatPumpAgent ! Activation(28800L) - /* 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: off + */ - 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: off -*/ + heatPumpAgent ! Activation(28800L) weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( @@ -451,7 +440,6 @@ Heat pump: off ) } - resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid @@ -499,17 +487,13 @@ Heat pump: off scheduler.expectMessage(Completion(heatPumpAgent, Some(28800L))) /* TICK 31106 - -? - - - 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: on -*/ + 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: off, demand should be covered by storage + */ heatPumpAgent ! Activation(31106L) @@ -562,16 +546,13 @@ Heat pump: on scheduler.expectMessage(Completion(heatPumpAgent, Some(31106))) /* TICK 47225 - -? - -House demand heating : -House demand water : tba -ThermalStorage : empty -DomesticWaterStorage : tba - -Heat pump: on -*/ + ? + House demand heating : + House demand water : tba + ThermalStorage : empty + DomesticWaterStorage : tba + Heat pump: on + */ heatPumpAgent ! Activation(47225L) @@ -579,10 +560,8 @@ Heat pump: on case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 47225.toDateTime - hpResult.getP should equalWithTolerance(0.asMegaWatt) - hpResult.getQ should equalWithTolerance( - 0.asMegaVar - ) + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance(qRunningHp) } Range(0, 2) @@ -624,20 +603,16 @@ Heat pump: on scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) /* TICK 50400 - -New weather data: it's getting warmer again - -House demand heating : -House demand water : tba -ThermalStorage : empty -DomesticWaterStorage : tba - -Heat pump: on -*/ + New weather data: it's getting warmer again + House demand heating : + House demand water : tba + ThermalStorage : empty + DomesticWaterStorage : tba + Heat pump: on + */ heatPumpAgent ! Activation(50400L) - weatherDependentAgents.foreach { _ ! ProvideWeatherMessage( 50400L, @@ -662,7 +637,6 @@ Heat pump: on // results of tick 47225 where house reached the upper boundary // should be heated by using thermal energy from the storage FIXME - Range(0, 2) .map { _ => resultListener.expectMessageType[ResultEvent] From 6f220a9594bc04c4fdfec6e16a58585b6935cee2 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 7 Aug 2024 21:22:05 +0200 Subject: [PATCH 23/27] handle case where thermal storage heat the house and we get activated inbetween by new weather data --- .../edu/ie3/simona/model/participant/HpModel.scala | 13 +++++++++---- .../edu/ie3/simona/model/thermal/ThermalGrid.scala | 9 ++++++--- .../simona/test/common/input/HpInputTestData.scala | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) 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 239e27fa1e..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,9 +20,8 @@ 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.{KilowattHours, Kilowatts} +import squants.energy.{Energy, KilowattHours, Kilowatts} import squants.{Power, Temperature} import java.time.ZonedDateTime @@ -159,7 +158,7 @@ final case class HpModel( relevantData.ambientTemperature, state.thermalGridState, ) - implicit val tolerance = KilowattHours(1e-3) + implicit val tolerance: Energy = KilowattHours(1e-3) val noStorageOrStorageIsEmpty: Boolean = updatedState.storageState.isEmpty || updatedState.storageState.exists( _.storedEnergy =~ zeroKWH @@ -201,10 +200,16 @@ final case class HpModel( houseDemand: ThermalEnergyDemand, storageDemand: ThermalEnergyDemand, ): HpState = { + val lastStateStorageqDot = state.thermalGridState.storageState + .map(_.qDot) + .getOrElse(zeroKW) + val (newActivePower, newThermalPower) = if (isRunning) (pRated, pThermal) - else (DefaultQuantities.zeroKW, DefaultQuantities.zeroKW) + else if (lastStateStorageqDot < zeroKW) + (zeroKW, lastStateStorageqDot * (-1)) + else (zeroKW, zeroKW) /* Push thermal energy to the thermal grid and get its updated state in return */ val (thermalGridState, maybeThreshold) = diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala index 2aa3e9db7a..9ca3bc9d18 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -219,7 +219,9 @@ final case class ThermalGrid( val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse(tick, ambientTemperature, state, qDotHouseLastState) val (updatedStorageState, thermalStorageThreshold) = - if (remainingQDotHouse > qDotStorageLastState) { + if ( + qDotStorageLastState >= zeroKW && remainingQDotHouse > qDotStorageLastState + ) { handleInfeedStorage( tick, ambientTemperature, @@ -336,8 +338,9 @@ final case class ThermalGrid( } } - /** Handles the case, when the storage has heat demand and will be filled up - * here. + /** Handles the cases, when the storage has heat demand and will be filled up + * here (positive qDot) or will be return its stored energy into the thermal + * grid (negative qDot). * @param tick * Current tick * @param ambientTemperature diff --git a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala index bda08d6ed1..3468adc96d 100644 --- a/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala +++ b/src/test/scala/edu/ie3/simona/test/common/input/HpInputTestData.scala @@ -100,7 +100,7 @@ trait HpInputTestData extends NodeInputTestData with ThermalGridTestData { UUID.fromString("4b8933dc-aeb6-4573-b8aa-59d577214150"), "thermal storage", thermalBusInput, - Quantities.getQuantity(1300.0, Units.LITRE), + Quantities.getQuantity(300.0, Units.LITRE), Quantities.getQuantity(0.0, Units.LITRE), Quantities.getQuantity(60.0, StandardUnits.TEMPERATURE), Quantities.getQuantity(30.0, StandardUnits.TEMPERATURE), From ab527154d196de7a786e8d0af5dc5bd2305c7cee Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 7 Aug 2024 21:24:46 +0200 Subject: [PATCH 24/27] adapt ThermalGridIT to changes for case storage heat house --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 151 +++++++++++++++++- 1 file changed, 143 insertions(+), 8 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index a1269c2571..3bde8e016c 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -436,7 +436,7 @@ class ThermalGridIT Celsius(-25d), MetersPerSecond(0d), ), - Some(50400L), + Some(34200L), ) } @@ -501,9 +501,9 @@ class ThermalGridIT case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 31106.toDateTime - hpResult.getP should equalWithTolerance(0.0038.asMegaWatt) + hpResult.getP should equalWithTolerance(0.0.asMegaWatt) hpResult.getQ should equalWithTolerance( - 0.0012489995996796802.asMegaVar + 0.0.asMegaVar ) } @@ -543,7 +543,141 @@ class ThermalGridIT } } - scheduler.expectMessage(Completion(heatPumpAgent, Some(31106))) + 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 + even when energy in storage is below 50% SoC FIXME: THIS IS NOT WORKING YET! + 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: 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 = 15.0 kWh, additionalDemand = 30.00 kWh + House demand water : tba + ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + DomesticWaterStorage : tba + Heat pump: off, demand should be covered by storage + */ + + 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 + ) + } + + 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.29428672391876.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.0066874000000000005.asMegaWattHour + ) + case _ => + fail( + "Expected a ThermalHouseResult and a ThermalStorageResult but got something else" + ) + } + } + + scheduler.expectMessage(Completion(heatPumpAgent, Some(34706L))) /* TICK 47225 ? @@ -554,6 +688,7 @@ class ThermalGridIT Heat pump: on */ + //FIXME heatPumpAgent ! Activation(47225L) resultListener.expectMessageType[ParticipantResultEvent] match { @@ -577,7 +712,7 @@ class ThermalGridIT indoorTemperature, ) => inputModel shouldBe typicalThermalHouse.getUuid - time shouldBe 31106.toDateTime + time shouldBe 34706L.toDateTime qDot should equalWithTolerance(0.011.asMegaWatt) indoorTemperature should equalWithTolerance( 18.00002164245703.asDegreeCelsius @@ -590,7 +725,7 @@ class ThermalGridIT energy, ) => inputModel shouldBe typicalThermalStorage.getUuid - time shouldBe 31106.toDateTime + time shouldBe 34706L.toDateTime qDot should equalWithTolerance( 0.0.asMegaWatt ) @@ -618,8 +753,8 @@ class ThermalGridIT 50400L, weatherService.ref.toClassic, WeatherData( - WattsPerSquareMeter(3d), - WattsPerSquareMeter(3d), + WattsPerSquareMeter(4d), + WattsPerSquareMeter(4d), Celsius(5d), MetersPerSecond(0d), ), From 264210a1baed6ad6d66c1a8472a0dfa9a0b5ebad Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 8 Aug 2024 13:55:55 +0200 Subject: [PATCH 25/27] update tests to thermalStorage with zero storageMinimumLvl --- .../ThermalGridWithHouseAndStorageSpec.scala | 26 +++++----- .../ThermalGridWithStorageOnlySpec.scala | 49 ++++++++++++++----- .../thermal/ThermalStorageTestData.scala | 2 +- 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala index ad8749442f..eef4cd8fdf 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -104,13 +104,13 @@ class ThermalGridWithHouseAndStorageSpec ) houseDemand.required should approximate(KilowattHours(0d)) houseDemand.possible should approximate(KilowattHours(31.05009722d)) - storageDemand.required should approximate(KilowattHours(345d)) - storageDemand.possible should approximate(KilowattHours(920d)) + storageDemand.required should approximate(KilowattHours(1150d)) + storageDemand.possible should approximate(KilowattHours(1150d)) updatedThermalGridState.houseState shouldBe Some( ThermalHouseState(10800, Kelvin(292.0799935185185), Kilowatts(0d)) ) updatedThermalGridState.storageState shouldBe Some( - ThermalStorageState(10800, KilowattHours(230d), Kilowatts(0d)) + ThermalStorageState(10800, KilowattHours(0d), Kilowatts(0d)) ) } @@ -131,13 +131,13 @@ class ThermalGridWithHouseAndStorageSpec houseDemand.required should approximate(KilowattHours(45.6000555)) houseDemand.possible should approximate(KilowattHours(75.600055555)) - storageDemand.required should approximate(KilowattHours(345d)) - storageDemand.possible should approximate(KilowattHours(920d)) + storageDemand.required should approximate(KilowattHours(1150d)) + storageDemand.possible should approximate(KilowattHours(1150d)) updatedThermalGridState.houseState shouldBe Some( ThermalHouseState(10800, Celsius(15.959996296296296), Kilowatts(0d)) ) updatedThermalGridState.storageState shouldBe Some( - ThermalStorageState(10800, KilowattHours(230d), Kilowatts(0d)) + ThermalStorageState(10800, KilowattHours(0d), Kilowatts(0d)) ) } } @@ -187,7 +187,7 @@ class ThermalGridWithHouseAndStorageSpec "take energy from storage, if there is actual consumption" in { val tick = 0L val initialGridState = ThermalGrid.startingState(thermalGrid) - val initialLoading = KilowattHours(430d) + val initialLoading = KilowattHours(200d) val gridState = initialGridState.copy(storageState = initialGridState.storageState.map(storageState => storageState.copy(storedEnergy = initialLoading) @@ -364,7 +364,7 @@ class ThermalGridWithHouseAndStorageSpec ( ThermalStorageState( tick, - KilowattHours(50d), + KilowattHours(0d), testGridQDotInfeed, ), Some(StorageEmpty(tick)), @@ -406,7 +406,7 @@ class ThermalGridWithHouseAndStorageSpec ( ThermalStorageState( tick, - KilowattHours(250d), + KilowattHours(20d), testGridQDotInfeed, ), None, @@ -427,7 +427,7 @@ class ThermalGridWithHouseAndStorageSpec val formerStorageState = Some( ThermalStorageState( 0L, - KilowattHours(300d), + KilowattHours(70d), Kilowatts(-50d), ) ) @@ -463,8 +463,8 @@ class ThermalGridWithHouseAndStorageSpec thermalStorage.chargingPower * (-1) ) - houseColdTick shouldBe 3718L - storageEmptyTick shouldBe 3678L + houseColdTick shouldBe 3695L + storageEmptyTick shouldBe 3663L case _ => fail("Revision of states failed") } } @@ -559,7 +559,7 @@ class ThermalGridWithHouseAndStorageSpec case _ => fail("Thermal grid state has been calculated wrong.") } reachedThreshold shouldBe Some( - StorageFull(220800L) + StorageFull(276000L) ) } } diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala index 3dc257ba74..37e8cb423b 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -89,10 +89,35 @@ class ThermalGridWithStorageOnlySpec houseDemand.required should approximate(KilowattHours(0d)) houseDemand.possible should approximate(KilowattHours(0d)) - storageDemand.required should approximate(KilowattHours(345d)) - storageDemand.possible should approximate(KilowattHours(920d)) + storageDemand.required should approximate(KilowattHours(1150d)) + storageDemand.possible should approximate(KilowattHours(1150d)) updatedThermalGridState.houseState shouldBe None - Some(ThermalStorageState(10800, KilowattHours(230d), Kilowatts(0d))) + updatedThermalGridState.storageState shouldBe Some( + ThermalStorageState(10800, KilowattHours(0d), Kilowatts(0d)) + ) + } + + "deliver the capabilities of a half full storage" in { + val tick = 10800 // after three hours + + val (houseDemand, storageDemand, updatedThermalGridState) = + thermalGrid.energyDemandAndUpdatedState( + tick, + testGridAmbientTemperature, + ThermalGridState( + None, + Some(ThermalStorageState(0L, KilowattHours(575d), Kilowatts(0d))), + ), + ) + + houseDemand.required should approximate(KilowattHours(0d)) + houseDemand.possible should approximate(KilowattHours(0d)) + storageDemand.required should approximate(KilowattHours(0d)) + storageDemand.possible should approximate(KilowattHours(575d)) + updatedThermalGridState.houseState shouldBe None + updatedThermalGridState.storageState shouldBe Some( + ThermalStorageState(10800L, KilowattHours(575d), Kilowatts(0d)) + ) } } @@ -110,7 +135,7 @@ class ThermalGridWithStorageOnlySpec Some( ThermalStorageState( 0L, - KilowattHours(430d), + KilowattHours(200d), Kilowatts(0d), ) ) @@ -130,7 +155,7 @@ class ThermalGridWithStorageOnlySpec Some(ThermalStorageState(tick, storedEnergy, qDot)), ) => tick shouldBe 0L - storedEnergy should approximate(KilowattHours(430d)) + storedEnergy should approximate(KilowattHours(200d)) qDot should approximate(testGridQDotConsumptionHigh) case _ => fail("Thermal grid state has been calculated wrong.") } @@ -164,11 +189,11 @@ class ThermalGridWithStorageOnlySpec Some(ThermalStorageState(tick, storedEnergy, qDot)), ) => tick shouldBe 0L - storedEnergy should approximate(KilowattHours(230d)) + storedEnergy should approximate(KilowattHours(0d)) qDot should approximate(testGridQDotInfeed) case _ => fail("Thermal grid state has been calculated wrong.") } - reachedThreshold shouldBe Some(StorageFull(220800L)) + reachedThreshold shouldBe Some(StorageFull(276000L)) } } @@ -183,7 +208,7 @@ class ThermalGridWithStorageOnlySpec thermalDemand, ) - nextThreshold shouldBe Some(StorageFull(220800L)) + nextThreshold shouldBe Some(StorageFull(276000L)) updatedState match { case ThermalGridState( @@ -191,7 +216,7 @@ class ThermalGridWithStorageOnlySpec Some(ThermalStorageState(tick, storedEnergy, qDot)), ) => tick shouldBe 0L - storedEnergy should approximate(KilowattHours(230d)) + storedEnergy should approximate(KilowattHours(0d)) qDot should approximate(testGridQDotInfeed) case _ => fail("Thermal grid state updated failed") } @@ -206,7 +231,7 @@ class ThermalGridWithStorageOnlySpec Some( ThermalStorageState( 0L, - KilowattHours(430d), + KilowattHours(200d), Kilowatts(0d), ) ) @@ -224,7 +249,7 @@ class ThermalGridWithStorageOnlySpec Some(StorageEmpty(thresholdTick)), ) => tick shouldBe 0L - storedEnergy should approximate(KilowattHours(430d)) + storedEnergy should approximate(KilowattHours(200d)) qDot should approximate(testGridQDotConsumptionHigh) thresholdTick shouldBe 3600L case _ => fail("Thermal grid state updated failed") @@ -249,7 +274,7 @@ class ThermalGridWithStorageOnlySpec None, ) => tick shouldBe 0L - storedEnergy should approximate(KilowattHours(230d)) + storedEnergy should approximate(KilowattHours(0d)) qDot should approximate(Megawatts(0d)) case _ => fail("Thermal grid state updated failed") diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalStorageTestData.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalStorageTestData.scala index b5434bbb17..2360fb6efc 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalStorageTestData.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalStorageTestData.scala @@ -25,7 +25,7 @@ trait ThermalStorageTestData extends ThermalGridTestData { "TestThermalBus", ), getQuantity(100, StandardUnits.VOLUME), - getQuantity(20, StandardUnits.VOLUME), + getQuantity(0, StandardUnits.VOLUME), getQuantity(30, StandardUnits.TEMPERATURE), getQuantity(40, StandardUnits.TEMPERATURE), getQuantity(1.15, StandardUnits.SPECIFIC_HEAT_CAPACITY), From 701aaf5b2deccb0159ab56432288cf59e321ea28 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 8 Aug 2024 17:58:39 +0200 Subject: [PATCH 26/27] fix thermal storage recharging condition --- .../edu/ie3/simona/model/thermal/ThermalGrid.scala | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala index 9ca3bc9d18..e556bc0133 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -102,12 +102,14 @@ final case class ThermalGrid( storage.updateState(tick, state.qDot, state)._1 val storedEnergy = updatedStorageState.storedEnergy val soc = storedEnergy / storage.getMaxEnergyThreshold - val storageRequired = - if (soc < 0.5) { - storage.getMaxEnergyThreshold * 0.5 - storedEnergy + val storageRequired = { + if (soc == 0d) { + storage.getMaxEnergyThreshold - storedEnergy + } else { zeroMWH } + } val storagePossible = storage.getMaxEnergyThreshold - storedEnergy ( @@ -215,7 +217,9 @@ final case class ThermalGrid( ) } - if (qDotHouseLastState > zeroKW | qDotStorageLastState > zeroKW) { + if ( + (qDotHouseLastState > zeroKW && qDotHouseLastState == qDot) | qDotStorageLastState > zeroKW + ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse(tick, ambientTemperature, state, qDotHouseLastState) val (updatedStorageState, thermalStorageThreshold) = From 14d2b05c701a5e6b392e09c08b27df3bb0edd3be Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 8 Aug 2024 18:00:53 +0200 Subject: [PATCH 27/27] finalise ThermalGridIT --- .../ie3/simona/agent/grid/ThermalGridIT.scala | 83 +++++++++---------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala index 3bde8e016c..9fe31484e7 100644 --- a/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/grid/ThermalGridIT.scala @@ -152,9 +152,9 @@ class ThermalGridIT Start of Simulation House demand heating : requiredDemand = 0.0 kWh, additionalDemand ~ 15 kWh House demand water : tba - ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + ThermalStorage : requiredDemand = 10.44 kWh, additionalDemand = 10.44 kWh DomesticWaterStorage : tba - Heat pump: on - to serve the storage demand, but will heat up the house first + Heat pump: turned on - to serve the storage demand, but will heat up the house first */ heatPumpAgent ! Activation(0L) @@ -222,9 +222,9 @@ class ThermalGridIT House is fully heated up House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh House demand water : tba - ThermalStorage : requiredDemand = 5.22 kWh, additionalDemand = 10.44 kWh + ThermalStorage : requiredDemand = 10.44 kWh, additionalDemand = 10.44 kWh DomesticWaterStorage : tba - Heat pump: on - to serve storage demand + Heat pump: stays on to serve storage demand */ heatPumpAgent ! Activation(6353L) @@ -283,9 +283,9 @@ class ThermalGridIT New weather data (unchanged) incoming House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh House demand water : tba - ThermalStorage : requiredDemand = 2.63 kWh, additionalDemand = 7.85 kWh + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 7.85 kWh DomesticWaterStorage : tba - Heat pump: on + Heat pump: stays on */ heatPumpAgent ! Activation(7200L) @@ -361,7 +361,7 @@ class ThermalGridIT House demand water : tba ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh DomesticWaterStorage : tba - Heat pump: off + Heat pump: turned off */ heatPumpAgent ! Activation(9770L) @@ -421,7 +421,7 @@ class ThermalGridIT House demand water : tba ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh DomesticWaterStorage : tba - Heat pump: off + Heat pump: stays off */ heatPumpAgent ! Activation(28800L) @@ -492,7 +492,7 @@ class ThermalGridIT House demand water : tba ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh DomesticWaterStorage : tba - Heat pump: off, demand should be covered by storage + Heat pump: stays off, demand should be covered by storage */ heatPumpAgent ! Activation(31106L) @@ -548,12 +548,11 @@ class ThermalGridIT /* TICK 34200 Storage will be empty at tick 34706 Additional trigger caused by (unchanged) weather data should not change this - even when energy in storage is below 50% SoC FIXME: THIS IS NOT WORKING YET! - House demand heating : requiredDemand = 0.0 kWh, additionalDemand = 27.22 kWh ??? + House demand heating : requiredDemand = 9.72 kWh, additionalDemand = 24.72 kWh House demand water : tba - ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 0.0 kWh ??? + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 8.97 kWh DomesticWaterStorage : tba - Heat pump: off + Heat pump: stays off */ heatPumpAgent ! Activation(34200L) @@ -620,11 +619,11 @@ class ThermalGridIT /* TICK 34706 Storage will be empty - House demand heating : requiredDemand = 15.0 kWh, additionalDemand = 30.00 kWh + 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: off, demand should be covered by storage + Heat pump: will be turned on - to serve the remaining heat demand of house (and refill storage later) */ heatPumpAgent ! Activation(34706L) @@ -639,6 +638,7 @@ class ThermalGridIT ) } + // Results of 34200 for house and storage Range(0, 2) .map { _ => resultListener.expectMessageType[ResultEvent] @@ -655,7 +655,7 @@ class ThermalGridIT time shouldBe 34200.toDateTime qDot should equalWithTolerance(0.01044.asMegaWatt) indoorTemperature should equalWithTolerance( - 18.29428672391876.asDegreeCelsius + 18.703619912969.asDegreeCelsius ) case CylindricalThermalStorageResult( @@ -668,7 +668,7 @@ class ThermalGridIT time shouldBe 34200.toDateTime qDot should equalWithTolerance((-0.01044).asMegaWatt) energy should equalWithTolerance( - 0.0066874000000000005.asMegaWattHour + 0.0014673999999999996.asMegaWattHour ) case _ => fail( @@ -679,26 +679,26 @@ class ThermalGridIT scheduler.expectMessage(Completion(heatPumpAgent, Some(34706L))) - /* TICK 47225 - ? - House demand heating : + /* TICK 47690 + House will reach the upperTemperatureBoundary + House demand heating : requiredDemand = 0.00 kWh, additionalDemand = 0.00 kWh House demand water : tba - ThermalStorage : empty + ThermalStorage : requiredDemand = 10.44 kWh, additionalDemand = 10.44 kWh DomesticWaterStorage : tba - Heat pump: on + Heat pump: stays on to refill the storage now */ - //FIXME - heatPumpAgent ! Activation(47225L) + heatPumpAgent ! Activation(47690L) resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid - hpResult.getTime shouldBe 47225.toDateTime + 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] @@ -715,7 +715,7 @@ class ThermalGridIT time shouldBe 34706L.toDateTime qDot should equalWithTolerance(0.011.asMegaWatt) indoorTemperature should equalWithTolerance( - 18.00002164245703.asDegreeCelsius + 18.81736942528025.asDegreeCelsius ) case CylindricalThermalStorageResult( @@ -726,24 +726,22 @@ class ThermalGridIT ) => inputModel shouldBe typicalThermalStorage.getUuid time shouldBe 34706L.toDateTime - qDot should equalWithTolerance( - 0.0.asMegaWatt - ) + qDot should equalWithTolerance(0.asMegaWatt) energy should equalWithTolerance( - 0.01044.asMegaWattHour + 0.asMegaWattHour ) } } - scheduler.expectMessage(Completion(heatPumpAgent, Some(47225))) + scheduler.expectMessage(Completion(heatPumpAgent, Some(47690L))) /* TICK 50400 New weather data: it's getting warmer again - House demand heating : + House demand heating : requiredDemand = 0.00 kWh, additionalDemand = 0.00 kWh House demand water : tba - ThermalStorage : empty + ThermalStorage : requiredDemand = 0.0 kWh, additionalDemand = 2.16 kWh DomesticWaterStorage : tba - Heat pump: on + Heat pump: stays on */ heatPumpAgent ! Activation(50400L) @@ -766,12 +764,11 @@ class ThermalGridIT case ParticipantResultEvent(hpResult) => hpResult.getInputModel shouldBe typicalHpInputModel.getUuid hpResult.getTime shouldBe 50400.toDateTime - hpResult.getP should equalWithTolerance(0.0.asMegaWatt) - hpResult.getQ should equalWithTolerance(0.0.asMegaVar) + hpResult.getP should equalWithTolerance(pRunningHp) + hpResult.getQ should equalWithTolerance(qRunningHp) } - // results of tick 47225 where house reached the upper boundary - // should be heated by using thermal energy from the storage FIXME + // Results of 47690 for house and storage Range(0, 2) .map { _ => resultListener.expectMessageType[ResultEvent] @@ -785,10 +782,10 @@ class ThermalGridIT indoorTemperature, ) => inputModel shouldBe typicalThermalHouse.getUuid - time shouldBe 47225.toDateTime + time shouldBe 47690.toDateTime qDot should equalWithTolerance(0.asMegaWatt) indoorTemperature should equalWithTolerance( - 21.99992035040234.asDegreeCelsius + 22.00001859336235.asDegreeCelsius ) case CylindricalThermalStorageResult( @@ -798,9 +795,9 @@ class ThermalGridIT energy, ) => inputModel shouldBe typicalThermalStorage.getUuid - time shouldBe 47225.toDateTime - qDot should equalWithTolerance(0.0.asMegaWatt) - energy should equalWithTolerance(0.01044.asMegaWattHour) + 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"