From 64a67ecd5379a9d9d525902168d1ddebd499241c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 24 Aug 2024 10:32:58 +0200 Subject: [PATCH 01/63] Refactoring of ThermalGrid.handleInfeed to fix thermal storage recharge correctly when empty --- CHANGELOG.md | 1 + .../simona/model/participant/HpModel.scala | 7 + .../simona/model/thermal/ThermalGrid.scala | 334 ++++++++++++++---- .../edu/ie3/simona/agent/em/EmAgentIT.scala | 16 +- .../model/thermal/ThermalGridTestData.scala | 4 + .../ThermalGridWithHouseAndStorageSpec.scala | 8 +- .../ThermalGridWithHouseOnlySpec.scala | 12 + .../ThermalGridWithStorageOnlySpec.scala | 12 + .../test/common/input/EmInputTestData.scala | 2 +- 9 files changed, 317 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74bc169d92..3f51e98bd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -106,6 +106,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix activation of Hp when not under control of an EM [#922](https://github.com/ie3-institute/simona/issues/922) - Fixed ThermalStorageResults having multiple entries [#924](https://github.com/ie3-institute/simona/issues/924) - Fix determineState of ThermalHouse [#926](https://github.com/ie3-institute/simona/issues/926) +- Refactoring of `ThermalGrid.handleInfeed` to fix thermal storage recharge correctly when empty [#930](https://github.com/ie3-institute/simona/issues/930) ## [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 569bd48c10..7e2da343fe 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -217,6 +217,10 @@ final case class HpModel( * data of heat pump including state of the heat pump * @param isRunning * determines whether the heat pump is running or not + * @param houseDemand + * determines if the thermal house has heat demand + * @param storageDemand + * determines if the thermal storage has heat demand * @return * next [[HpState]] */ @@ -245,7 +249,10 @@ final case class HpModel( state.thermalGridState, state.ambientTemperature.getOrElse(relevantData.ambientTemperature), relevantData.ambientTemperature, + isRunning, newThermalPower, + houseDemand, + storageDemand, ) HpState( 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 28d299d67e..bd63a8030b 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -146,6 +146,7 @@ final case class ThermalGrid( } /** Update the current state of the grid + * * @param tick * Instance in time * @param state @@ -154,8 +155,14 @@ final case class ThermalGrid( * Ambient temperature until this tick * @param ambientTemperature * Actual ambient temperature + * @param isRunning + * determines whether the heat pump is running or not * @param qDot * Thermal energy balance + * @param houseDemand + * determines if the thermal house has heat demand + * @param storageDemand + * determines if the thermal storage has heat demand * @return * The updated state of the grid */ @@ -164,9 +171,21 @@ final case class ThermalGrid( state: ThermalGridState, lastAmbientTemperature: Temperature, ambientTemperature: Temperature, + isRunning: Boolean, qDot: Power, + houseDemand: Boolean, + storageDemand: Boolean, ): (ThermalGridState, Option[ThermalThreshold]) = if (qDot > zeroKW) - handleInfeed(tick, lastAmbientTemperature, ambientTemperature, state, qDot) + handleInfeed( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + isRunning, + qDot, + houseDemand, + storageDemand, + ) else handleConsumption( tick, @@ -176,8 +195,9 @@ final case class ThermalGrid( qDot, ) - /** Handles the case, when a grid has infeed. First, heat up all the houses to - * their maximum temperature, then fill up the storages + /** Handles the case, when a grid has infeed. Depending which entity has some + * heat demand the house or the storage will be heated up / filled up. + * * @param tick * Current tick * @param lastAmbientTemperature @@ -186,8 +206,14 @@ final case class ThermalGrid( * Actual ambient temperature * @param state * Current state of the houses + * @param isRunning + * determines whether the heat pump is running or not * @param qDot * Infeed to the grid + * @param houseDemand + * determines if the thermal house has heat demand + * @param storageDemand + * determines if the thermal storage has heat demand * @return * Updated thermal grid state */ @@ -196,41 +222,221 @@ final case class ThermalGrid( lastAmbientTemperature: Temperature, ambientTemperature: Temperature, state: ThermalGridState, + isRunning: Boolean, qDot: Power, - ): (ThermalGridState, Option[ThermalThreshold]) = - house.zip(state.houseState) match { - case Some((thermalHouse, lastHouseState)) => - /* Set thermal power exchange with storage to zero */ - // TODO: We would need to issue a storage result model here... - val updatedStorageState = storage.zip(state.storageState) match { - case Some((thermalStorage, storageState)) => - Some( - thermalStorage - .updateState( - tick, - zeroKW, - storageState, - ) - ._1 - ) - case _ => state.storageState + houseDemand: Boolean, + heatStorageDemand: Boolean, + ): (ThermalGridState, Option[ThermalThreshold]) = { + // TODO: We would need to issue a storage result model here... + + /* Consider the action in the last state */ + val (qDotHouseLastState, qDotStorageLastState) = state match { + case ThermalGridState(Some(houseState), Some(storageState)) => + (houseState.qDot, storageState.qDot) + case ThermalGridState(Some(houseState), None) => (houseState.qDot, zeroKW) + case ThermalGridState(None, Some(storageState)) => + (zeroKW, storageState.qDot) + case _ => + throw new InconsistentStateException( + "There should be at least a house or a storage state." + ) + } + + if ( + (qDotHouseLastState > zeroKW && !(qDotStorageLastState < zeroKW)) | (qDotStorageLastState > zeroKW & heatStorageDemand) + ) { + val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = + handleInfeedHouse( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDotHouseLastState, + ) + val (updatedStorageState, thermalStorageThreshold) = + if ( + qDotStorageLastState >= zeroKW && remainingQDotHouse > qDotStorageLastState + ) { + handleInfeedStorage( + tick, + state, + remainingQDotHouse, + ) + } else { + handleInfeedStorage( + tick, + state, + qDotStorageLastState, + ) } - val (updatedHouseState, maybeHouseThreshold) = - thermalHouse.determineState( + val nextThreshold = determineMostRecentThreshold( + thermalHouseThreshold, + thermalStorageThreshold, + ) + ( + state.copy( + houseState = updatedHouseState, + storageState = updatedStorageState, + ), + nextThreshold, + ) + } + // Handle edge case where house get heated from storage and HP will be activated in between + else if ((qDotHouseLastState > zeroKW && qDotStorageLastState < zeroKW)) { + if (isRunning) { + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDot, + zeroKW, + ) + } else { + + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDotHouseLastState, + qDotStorageLastState, + ) + } + } else { + + (houseDemand, heatStorageDemand) match { + + case (true, _) => + // house first then heatStorage after heating House + handleCases( tick, - lastHouseState, lastAmbientTemperature, ambientTemperature, + state, qDot, + zeroKW, ) + case (false, true) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + zeroKW, + qDot, + ) + + case (false, false) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + zeroKW, + zeroKW, + ) + case _ => + throw new InconsistentStateException( + "There should be at least a house or a storage state." + ) + } + } + } + + /** Handles the different cases, of thermal flows from and into the thermal + * grid. + * + * @param tick + * Current tick + * @param lastAmbientTemperature + * Ambient temperature until this tick + * @param ambientTemperature + * actual ambient temperature + * @param state + * Current state of the thermal grid + * @param qDotHouse + * Infeed to the house + * @param qDotStorage + * Infeed to the heat storage + * @return + * Updated thermal grid state and the next threshold if there is one + */ + private def handleCases( + tick: Long, + lastAmbientTemperature: Temperature, + ambientTemperature: Temperature, + state: ThermalGridState, + qDotHouse: Power, + qDotHeatStorage: Power, + ): (ThermalGridState, Option[ThermalThreshold]) = { + // FIXME: Is there any case where we get back some remainingQDotHouse? + val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = + handleInfeedHouse( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDotHouse, + ) + + val (updatedStorageState, thermalStorageThreshold) = + handleInfeedStorage(tick, state, qDotHeatStorage) + + val nextThreshold = determineMostRecentThreshold( + thermalHouseThreshold, + thermalStorageThreshold, + ) + + ( + state.copy( + houseState = updatedHouseState, + storageState = updatedStorageState, + ), + nextThreshold, + ) + } + + /** Handles the case, when the house has heat demand and will be heated up + * here. + * + * @param tick + * Current tick + * @param lastAmbientTemperature + * Ambient temperature until this tick + * @param ambientTemperature + * actual ambient temperature + * @param state + * Current state of the houses + * @param qDot + * Infeed to the grid + * @return + * Updated thermal house state, a ThermalThreshold and the remaining qDot + */ + private def handleInfeedHouse( + tick: Long, + lastAmbientTemperature: Temperature, + ambientTemperature: Temperature, + state: ThermalGridState, + qDot: Power, + ): (Option[ThermalHouseState], Option[ThermalThreshold], Power) = { + (house, state.houseState) match { + case (Some(thermalHouse), Some(lastHouseState)) => + val (newState, threshold) = thermalHouse.determineState( + tick, + lastHouseState, + lastAmbientTemperature, + ambientTemperature, + qDot, + ) + /* Check if house can handle the thermal feed in */ if ( thermalHouse.isInnerTemperatureTooHigh( - updatedHouseState.innerTemperature + newState.innerTemperature ) ) { - /* The house is already heated up fully, set back the infeed and put it into storage, if available */ val (fullHouseState, maybeFullHouseThreshold) = thermalHouse.determineState( tick, @@ -239,54 +445,44 @@ final case class ThermalGrid( ambientTemperature, zeroKW, ) - storage.zip(updatedStorageState) match { - case Some((thermalStorage, storageState)) => - val (updatedStorageState, maybeStorageThreshold) = - thermalStorage.updateState(tick, qDot, storageState) - - /* Both house and storage are updated. Determine what reaches the next threshold */ - val nextThreshold = determineMostRecentThreshold( - maybeFullHouseThreshold, - maybeStorageThreshold, - ) - - ( - state.copy( - houseState = Some(fullHouseState), - storageState = Some(updatedStorageState), - ), - nextThreshold, - ) - case None => - /* There is no storage, house determines the next activation */ - ( - state.copy(houseState = Some(fullHouseState)), - maybeFullHouseThreshold, - ) - } + (Some(fullHouseState), maybeFullHouseThreshold, qDot) } else { - /* The house can handle the infeed */ - ( - state.copy(houseState = Some(updatedHouseState)), - maybeHouseThreshold, - ) + (Some(newState), threshold, zeroKW) } + case _ => (None, None, zeroKW) + } + } - case None => - storage.zip(state.storageState) match { - case Some((thermalStorage, storageState)) => - val (updatedStorageState, maybeStorageThreshold) = - thermalStorage.updateState(tick, qDot, storageState) - ( - state.copy(storageState = Some(updatedStorageState)), - maybeStorageThreshold, - ) - case None => - throw new InconsistentStateException( - "A thermal grid has to contain either at least a house or a storage." - ) - } + /** 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 + * Ambient temperature + * @param state + * Current state of the houses + * @param qDot + * Infeed to the grid + * @return + * Updated thermal grid state + */ + private def handleInfeedStorage( + tick: Long, + state: ThermalGridState, + qDot: Power, + ): (Option[ThermalStorageState], Option[ThermalThreshold]) = { + (storage, state.storageState) match { + case (Some(thermalStorage), Some(lastStorageState)) => + val (newState, threshold) = thermalStorage.updateState( + tick, + qDot, + lastStorageState, + ) + (Some(newState), threshold) + case _ => (None, None) } + } private def determineMostRecentThreshold( maybeHouseThreshold: Option[ThermalThreshold], diff --git a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala index 09f6acb019..be1cee377f 100644 --- a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala @@ -680,7 +680,7 @@ class EmAgentIT Celsius(0d), MetersPerSecond(0d), ), - Some(28800), + Some(56000), ) } @@ -692,26 +692,26 @@ class EmAgentIT emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) } - scheduler.expectMessage(Completion(emAgentActivation, Some(28665))) + scheduler.expectMessage(Completion(emAgentActivation, Some(44398))) - /* TICK 28666 + /* TICK 44398 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 */ - emAgentActivation ! Activation(28665) + emAgentActivation ! Activation(44398) 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) + emResult.getTime shouldBe 44398.toDateTime + emResult.getP should equalWithTolerance(0.005086768.asMegaWatt) + emResult.getQ should equalWithTolerance(0.00107312004.asMegaVar) } - scheduler.expectMessage(Completion(emAgentActivation, Some(28800))) + scheduler.expectMessage(Completion(emAgentActivation, Some(56000))) } } 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 6011c6caf2..0a016d4566 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala @@ -25,4 +25,8 @@ trait ThermalGridTestData { protected val testGridQDotInfeed: Power = Kilowatts(15d) protected val testGridQDotConsumption: Power = Kilowatts(-42d) protected val testGridQDotConsumptionHigh: Power = Kilowatts(-200d) + protected val noThermalDemand: Boolean = false + protected val thermalDemand: Boolean = true + protected val isRunning: Boolean = true + protected val isNotRunning: Boolean = false } 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 1ea45a656d..b2b732ae0e 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -496,7 +496,10 @@ class ThermalGridWithHouseAndStorageSpec testGridAmbientTemperature, testGridAmbientTemperature, initialGridState, + isNotRunning, externalQDot, + thermalDemand, + noThermalDemand, ) updatedGridState match { @@ -510,7 +513,7 @@ class ThermalGridWithHouseAndStorageSpec innerTemperature should approximate(Celsius(18.9999d)) qDotHouse should approximate(externalQDot) - storageTick shouldBe -1L + storageTick shouldBe 0L storedEnergy should approximate( initialGridState.storageState .map(_.storedEnergy) @@ -542,7 +545,10 @@ class ThermalGridWithHouseAndStorageSpec testGridAmbientTemperature, testGridAmbientTemperature, gridState, + isNotRunning, externalQDot, + noThermalDemand, + thermalDemand, ) updatedGridState match { 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 eb447d0fc4..4ecbfc819b 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -179,7 +179,10 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { testGridAmbientTemperature, testGridAmbientTemperature, gridState, + isNotRunning, testGridQDotInfeed, + thermalDemand, + noThermalDemand, ) updatedGridState match { @@ -205,7 +208,10 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { ThermalGrid.startingState(thermalGrid), testGridAmbientTemperature, testGridAmbientTemperature, + isRunning, testGridQDotInfeed, + thermalDemand, + noThermalDemand, ) match { case ( ThermalGridState( @@ -228,7 +234,10 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { ThermalGrid.startingState(thermalGrid), testGridAmbientTemperature, testGridAmbientTemperature, + isNotRunning, testGridQDotConsumption, + thermalDemand, + noThermalDemand, ) match { case ( ThermalGridState( @@ -251,7 +260,10 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { ThermalGrid.startingState(thermalGrid), testGridAmbientTemperature, testGridAmbientTemperature, + isNotRunning, Megawatts(0d), + thermalDemand, + noThermalDemand, ) match { case ( ThermalGridState( 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 93a45e3180..c1ded4c6dc 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -182,7 +182,10 @@ class ThermalGridWithStorageOnlySpec testGridAmbientTemperature, testGridAmbientTemperature, gridState, + isNotRunning, testGridQDotInfeed, + noThermalDemand, + thermalDemand, ) updatedGridState match { @@ -206,7 +209,10 @@ class ThermalGridWithStorageOnlySpec ThermalGrid.startingState(thermalGrid), testGridAmbientTemperature, testGridAmbientTemperature, + isRunning, testGridQDotInfeed, + noThermalDemand, + thermalDemand, ) nextThreshold shouldBe Some(StorageFull(276000L)) @@ -239,7 +245,10 @@ class ThermalGridWithStorageOnlySpec ), testGridAmbientTemperature, testGridAmbientTemperature, + isRunning, testGridQDotConsumptionHigh, + thermalDemand, + noThermalDemand, ) match { case ( ThermalGridState( @@ -262,7 +271,10 @@ class ThermalGridWithStorageOnlySpec ThermalGrid.startingState(thermalGrid), testGridAmbientTemperature, testGridAmbientTemperature, + isRunning, Kilowatts(0d), + noThermalDemand, + noThermalDemand, ) updatedState match { case ( 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 c5f3cf8efe..9c5abd30de 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 @@ -140,7 +140,7 @@ trait EmInputTestData UUID.fromString("91940626-bdd0-41cf-96dd-47c94c86b20e"), "thermal house", thermalBusInput, - Quantities.getQuantity(0.325, StandardUnits.THERMAL_TRANSMISSION), + Quantities.getQuantity(0.15, StandardUnits.THERMAL_TRANSMISSION), Quantities.getQuantity(75, StandardUnits.HEAT_CAPACITY), Quantities.getQuantity(20.3, StandardUnits.TEMPERATURE), Quantities.getQuantity(22.0, StandardUnits.TEMPERATURE), From a669b5bb5caad4d0da12da3df0432c3ca7a0152f Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 15:14:32 +0100 Subject: [PATCH 02/63] remove double entry in changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 201736009b..ae3049db15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,7 +130,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix power flow calculation with em agents [#962](https://github.com/ie3-institute/simona/issues/962) - Fix scheduling at Evcs with more than one Ev at a time without Em [#787](https://github.com/ie3-institute/simona/issues/787) - Fix CheckWindow duration [#921](https://github.com/ie3-institute/simona/issues/921) -- Fixed ThermalStorageResults having multiple entries [#924](https://github.com/ie3-institute/simona/issues/924) - Fix filter for thermal result checking for lastTick not for currentTick [#1008](https://github.com/ie3-institute/simona/issues/1008) - Fixed `CHANGELOG` entry for issue ([#103](https://github.com/ie3-institute/simona/issues/103)) [#941](https://github.com/ie3-institute/simona/issues/941) - Refactoring of `ThermalGrid.handleInfeed` to fix thermal storage recharge correctly when empty [#930](https://github.com/ie3-institute/simona/issues/930) From 78845417a5343532013e3f725ae4d2938de731d1 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 15:16:24 +0100 Subject: [PATCH 03/63] Revert "remove double entry in changelog" This reverts commit a669b5bb5caad4d0da12da3df0432c3ca7a0152f. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae3049db15..201736009b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -130,6 +130,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix power flow calculation with em agents [#962](https://github.com/ie3-institute/simona/issues/962) - Fix scheduling at Evcs with more than one Ev at a time without Em [#787](https://github.com/ie3-institute/simona/issues/787) - Fix CheckWindow duration [#921](https://github.com/ie3-institute/simona/issues/921) +- Fixed ThermalStorageResults having multiple entries [#924](https://github.com/ie3-institute/simona/issues/924) - Fix filter for thermal result checking for lastTick not for currentTick [#1008](https://github.com/ie3-institute/simona/issues/1008) - Fixed `CHANGELOG` entry for issue ([#103](https://github.com/ie3-institute/simona/issues/103)) [#941](https://github.com/ie3-institute/simona/issues/941) - Refactoring of `ThermalGrid.handleInfeed` to fix thermal storage recharge correctly when empty [#930](https://github.com/ie3-institute/simona/issues/930) From 86b3256c41ea8e140cccedd0684c7745fbade8c9 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 15:16:48 +0100 Subject: [PATCH 04/63] remove correct double entry in changelog --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 201736009b..1c7137c826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -122,7 +122,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 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) - Handle MobSim requests for current prices [#892](https://github.com/ie3-institute/simona/issues/892) -- Fixed ThermalStorageResults having multiple entries [#924](https://github.com/ie3-institute/simona/issues/924) - Fix determineState of ThermalHouse [#926](https://github.com/ie3-institute/simona/issues/926) - Fix activation of Hp when not under control of an EM [#922](https://github.com/ie3-institute/simona/issues/922) - Fix expected secondaryData in baseStateData [#955](https://github.com/ie3-institute/simona/issues/955) From f4fa8108db07bbfaf3cc68690d2cc5a53ba80c30 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 15:38:09 +0100 Subject: [PATCH 05/63] reintroduce demand booleans indicating demand when handle thermal infeed --- .../simona/model/participant/HpModel.scala | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 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 c64e677ad6..52e1462681 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -143,7 +143,7 @@ final case class HpModel( ) // Determining the operation point and limitations at this tick - val (turnOn, canOperate, canBeOutOfOperation) = + val (turnOn, canOperate, canBeOutOfOperation, houseDemand, storageDemand) = operatesInNextState( lastHpState, currentThermalGridState, @@ -154,7 +154,7 @@ final case class HpModel( // Updating the HpState val updatedState = - calcState(lastHpState, relevantData, turnOn) + calcState(lastHpState, relevantData, turnOn, houseDemand, storageDemand) (canOperate, canBeOutOfOperation, updatedState) } @@ -176,7 +176,8 @@ final case class HpModel( * ThermalEnergyDemand of the thermal storage * @return * boolean defining if heat pump runs in next time step, if it can be in - * operation and can be out of operation + * operation and can be out of operation plus the demand of house and + * storage */ private def operatesInNextState( lastState: HpState, @@ -184,7 +185,7 @@ final case class HpModel( relevantData: HpRelevantData, demandHouse: ThermalEnergyDemand, demandThermalStorage: ThermalEnergyDemand, - ): (Boolean, Boolean, Boolean) = { + ): (Boolean, Boolean, Boolean, Boolean, Boolean) = { val ( houseHasDemand, @@ -206,7 +207,13 @@ final case class HpModel( val canBeOutOfOperation = !(demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) - (turnHpOn, canOperate, canBeOutOfOperation) + ( + turnHpOn, + canOperate, + canBeOutOfOperation, + houseHasDemand, + heatStorageHasDemand, + ) } /** This method will return booleans whether there is a heat demand of house @@ -268,6 +275,8 @@ final case class HpModel( lastState: HpState, relevantData: HpRelevantData, isRunning: Boolean, + houseDemand: Boolean, + storageDemand: Boolean, ): HpState = { val lastStateStorageQDot = lastState.thermalGridState.storageState .map(_.qDot) @@ -353,13 +362,38 @@ final case class HpModel( lastState: HpState, setPower: Power, ): (HpState, FlexChangeIndicator) = { - /* If the setpoint value is above 50 % of the electrical power, turn on the heat pump otherwise turn it off */ + /* If the set point 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, + updatedThermalGridState, + ) = + thermalGrid.energyDemandAndUpdatedState( + data.currentTick, + lastState.ambientTemperature.getOrElse(data.ambientTemperature), + data.ambientTemperature, + lastState.thermalGridState, + ) + + val ( + houseDemand, + heatStorageDemand, + _, + ) = determineDemandBooleans( + lastState, + updatedThermalGridState, + thermalEnergyDemandHouse, + thermalEnergyDemandStorage, + ) + val updatedHpState = calcState( lastState, data, turnOn, + houseDemand, + heatStorageDemand, ) ( From 963670c1013283559080bbc96256d9ff02a28cf0 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 15:49:21 +0100 Subject: [PATCH 06/63] add some scala doc --- .../edu/ie3/simona/model/thermal/ThermalGrid.scala | 10 ++++++++++ 1 file changed, 10 insertions(+) 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 cd2c19691c..b59663a783 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -485,6 +485,16 @@ final case class ThermalGrid( } } + /** Determines the most recent threshold of two given input thresholds + * + * @param maybeHouseThreshold + * Option of a possible next threshold of the thermal house + * @param maybeStorageThreshold + * Option of a possible next threshold of the thermal storage + * @return + * The next threshold + */ + private def determineMostRecentThreshold( maybeHouseThreshold: Option[ThermalThreshold], maybeStorageThreshold: Option[ThermalThreshold], From bfd633b6e7194f2ffe8de6f9ac59c3927d4e4a65 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 15:54:32 +0100 Subject: [PATCH 07/63] handle sonar code smell --- .../ie3/simona/model/thermal/ThermalGrid.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 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 b59663a783..82b9e9535c 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -244,7 +244,7 @@ final case class ThermalGrid( } if ( - (qDotHouseLastState > zeroKW && !(qDotStorageLastState < zeroKW)) | (qDotStorageLastState > zeroKW & heatStorageDemand) + (qDotHouseLastState >= zeroKW && !(qDotStorageLastState >= zeroKW)) | (qDotStorageLastState >= zeroKW & heatStorageDemand) ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( @@ -486,14 +486,14 @@ final case class ThermalGrid( } /** Determines the most recent threshold of two given input thresholds - * - * @param maybeHouseThreshold - * Option of a possible next threshold of the thermal house - * @param maybeStorageThreshold - * Option of a possible next threshold of the thermal storage - * @return - * The next threshold - */ + * + * @param maybeHouseThreshold + * Option of a possible next threshold of the thermal house + * @param maybeStorageThreshold + * Option of a possible next threshold of the thermal storage + * @return + * The next threshold + */ private def determineMostRecentThreshold( maybeHouseThreshold: Option[ThermalThreshold], From 9eee88668b0bab34914708d075170411092faac9 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 16:07:48 +0100 Subject: [PATCH 08/63] Revert "handle sonar code smell" This reverts commit bfd633b6e7194f2ffe8de6f9ac59c3927d4e4a65. --- .../ie3/simona/model/thermal/ThermalGrid.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 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 82b9e9535c..b59663a783 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -244,7 +244,7 @@ final case class ThermalGrid( } if ( - (qDotHouseLastState >= zeroKW && !(qDotStorageLastState >= zeroKW)) | (qDotStorageLastState >= zeroKW & heatStorageDemand) + (qDotHouseLastState > zeroKW && !(qDotStorageLastState < zeroKW)) | (qDotStorageLastState > zeroKW & heatStorageDemand) ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( @@ -486,14 +486,14 @@ final case class ThermalGrid( } /** Determines the most recent threshold of two given input thresholds - * - * @param maybeHouseThreshold - * Option of a possible next threshold of the thermal house - * @param maybeStorageThreshold - * Option of a possible next threshold of the thermal storage - * @return - * The next threshold - */ + * + * @param maybeHouseThreshold + * Option of a possible next threshold of the thermal house + * @param maybeStorageThreshold + * Option of a possible next threshold of the thermal storage + * @return + * The next threshold + */ private def determineMostRecentThreshold( maybeHouseThreshold: Option[ThermalThreshold], From 122cb6991bf069c948024c7ad330d2c1d93dc0fe Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 14 Nov 2024 16:11:37 +0100 Subject: [PATCH 09/63] handle sonar code smell --- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b59663a783..6b1af8ac04 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -244,7 +244,7 @@ final case class ThermalGrid( } if ( - (qDotHouseLastState > zeroKW && !(qDotStorageLastState < zeroKW)) | (qDotStorageLastState > zeroKW & heatStorageDemand) + (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW & heatStorageDemand) ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( From eba3b89c350226b3cb3df4492ee8c3cf189865c2 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 15 Nov 2024 08:17:35 +0100 Subject: [PATCH 10/63] fmt --- .../ie3/simona/model/thermal/ThermalGrid.scala | 16 ++++++++-------- 1 file changed, 8 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 6b1af8ac04..fe90773420 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -486,14 +486,14 @@ final case class ThermalGrid( } /** Determines the most recent threshold of two given input thresholds - * - * @param maybeHouseThreshold - * Option of a possible next threshold of the thermal house - * @param maybeStorageThreshold - * Option of a possible next threshold of the thermal storage - * @return - * The next threshold - */ + * + * @param maybeHouseThreshold + * Option of a possible next threshold of the thermal house + * @param maybeStorageThreshold + * Option of a possible next threshold of the thermal storage + * @return + * The next threshold + */ private def determineMostRecentThreshold( maybeHouseThreshold: Option[ThermalThreshold], From 1f6311fe7f0a0da1434e8fd604a503bdfc2c821f Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 15 Nov 2024 08:26:51 +0100 Subject: [PATCH 11/63] fix scala doc --- .../scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 6 ++---- 1 file changed, 2 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 fe90773420..b20742d5b6 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -213,7 +213,7 @@ final case class ThermalGrid( * Infeed to the grid * @param houseDemand * determines if the thermal house has heat demand - * @param storageDemand + * @param heatStorageDemand * determines if the thermal storage has heat demand * @return * Updated thermal grid state @@ -360,7 +360,7 @@ final case class ThermalGrid( * Current state of the thermal grid * @param qDotHouse * Infeed to the house - * @param qDotStorage + * @param qDotHeatStorage * Infeed to the heat storage * @return * Updated thermal grid state and the next threshold if there is one @@ -459,8 +459,6 @@ final case class ThermalGrid( * grid (negative qDot). * @param tick * Current tick - * @param ambientTemperature - * Ambient temperature * @param state * Current state of the houses * @param qDot From 95d0562cb88694ba44145dd968307f7c5c850f8e Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 15 Nov 2024 11:12:20 +0100 Subject: [PATCH 12/63] refactor demand booleans of thermal units into ThermalDemandIndicator class --- .../simona/model/participant/HpModel.scala | 46 +++++++++---------- .../simona/model/thermal/ThermalGrid.scala | 41 ++++++++++------- .../model/thermal/ThermalGridTestData.scala | 9 +++- .../ThermalGridWithHouseAndStorageSpec.scala | 6 +-- .../ThermalGridWithHouseOnlySpec.scala | 12 ++--- .../ThermalGridWithStorageOnlySpec.scala | 10 ++-- 6 files changed, 62 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 52e1462681..a7a585820b 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -12,6 +12,7 @@ import edu.ie3.simona.model.SystemComponent import edu.ie3.simona.model.participant.HpModel.{HpRelevantData, HpState} import edu.ie3.simona.model.participant.control.QControl import edu.ie3.simona.model.thermal.ThermalGrid.{ + ThermalDemandIndicator, ThermalEnergyDemand, ThermalGridState, } @@ -143,7 +144,7 @@ final case class HpModel( ) // Determining the operation point and limitations at this tick - val (turnOn, canOperate, canBeOutOfOperation, houseDemand, storageDemand) = + val (turnOn, canOperate, canBeOutOfOperation, demandIndicator) = operatesInNextState( lastHpState, currentThermalGridState, @@ -154,7 +155,7 @@ final case class HpModel( // Updating the HpState val updatedState = - calcState(lastHpState, relevantData, turnOn, houseDemand, storageDemand) + calcState(lastHpState, relevantData, turnOn, demandIndicator) (canOperate, canBeOutOfOperation, updatedState) } @@ -176,8 +177,8 @@ final case class HpModel( * ThermalEnergyDemand of the thermal storage * @return * boolean defining if heat pump runs in next time step, if it can be in - * operation and can be out of operation plus the demand of house and - * storage + * operation and can be out of operation plus the + * [[ThermalDemandIndicator]] of the thermal units */ private def operatesInNextState( lastState: HpState, @@ -185,11 +186,10 @@ final case class HpModel( relevantData: HpRelevantData, demandHouse: ThermalEnergyDemand, demandThermalStorage: ThermalEnergyDemand, - ): (Boolean, Boolean, Boolean, Boolean, Boolean) = { + ): (Boolean, Boolean, Boolean, ThermalDemandIndicator) = { val ( - houseHasDemand, - heatStorageHasDemand, + demandIndicator, noThermalStorageOrThermalStorageIsEmpty, ) = determineDemandBooleans( lastState, @@ -198,8 +198,8 @@ final case class HpModel( demandThermalStorage, ) - val turnHpOn: Boolean = - houseHasDemand || heatStorageHasDemand + val turnHpOn = + demandIndicator.houseDemand || demandIndicator.heatStorageDemand val canOperate = demandHouse.hasRequiredDemand || demandHouse.hasAdditionalDemand || @@ -211,8 +211,7 @@ final case class HpModel( turnHpOn, canOperate, canBeOutOfOperation, - houseHasDemand, - heatStorageHasDemand, + demandIndicator, ) } @@ -239,7 +238,7 @@ final case class HpModel( updatedGridState: ThermalGridState, demandHouse: ThermalEnergyDemand, demandThermalStorage: ThermalEnergyDemand, - ): (Boolean, Boolean, Boolean) = { + ): (ThermalDemandIndicator, Boolean) = { implicit val tolerance: Energy = KilowattHours(1e-3) val noThermalStorageOrThermalStorageIsEmpty: Boolean = updatedGridState.storageState.isEmpty || updatedGridState.storageState @@ -251,7 +250,9 @@ final case class HpModel( (demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) || (lastHpState.isRunning && demandHouse.hasAdditionalDemand) val heatStorageDemand = demandThermalStorage.hasRequiredDemand || (lastHpState.isRunning && demandThermalStorage.hasAdditionalDemand) - (houseDemand, heatStorageDemand, noThermalStorageOrThermalStorageIsEmpty) + + val demandIndicator = ThermalDemandIndicator(houseDemand, heatStorageDemand) + (demandIndicator, noThermalStorageOrThermalStorageIsEmpty) } /** Calculate state depending on whether heat pump is needed or not. Also @@ -264,10 +265,9 @@ final case class HpModel( * data of heat pump including state of the heat pump * @param isRunning * determines whether the heat pump is running or not - * @param houseDemand - * determines if the thermal house has heat demand - * @param storageDemand - * determines if the thermal storage has heat demand + * @param demandIndicator + * determines if the thermal units (house, storage) having some heat demand + * or not * @return * next [[HpState]] */ @@ -275,8 +275,7 @@ final case class HpModel( lastState: HpState, relevantData: HpRelevantData, isRunning: Boolean, - houseDemand: Boolean, - storageDemand: Boolean, + demandIndicator: ThermalDemandIndicator, ): HpState = { val lastStateStorageQDot = lastState.thermalGridState.storageState .map(_.qDot) @@ -298,8 +297,7 @@ final case class HpModel( relevantData.ambientTemperature, isRunning, newThermalPower, - houseDemand, - storageDemand, + demandIndicator, ) HpState( @@ -378,8 +376,7 @@ final case class HpModel( ) val ( - houseDemand, - heatStorageDemand, + demandIndicator, _, ) = determineDemandBooleans( lastState, @@ -392,8 +389,7 @@ final case class HpModel( lastState, data, turnOn, - houseDemand, - heatStorageDemand, + demandIndicator, ) ( 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 b20742d5b6..8e603fe512 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -15,6 +15,7 @@ import edu.ie3.datamodel.models.result.thermal.{ } import edu.ie3.simona.exceptions.agent.InconsistentStateException import edu.ie3.simona.model.thermal.ThermalGrid.{ + ThermalDemandIndicator, ThermalEnergyDemand, ThermalGridState, } @@ -160,10 +161,9 @@ final case class ThermalGrid( * determines whether the heat pump is running or not * @param qDot * Thermal energy balance - * @param houseDemand - * determines if the thermal house has heat demand - * @param storageDemand - * determines if the thermal storage has heat demand + * @param demandIndicator + * determines if the thermal units (house, storage) having some heat demand + * or not * @return * The updated state of the grid */ @@ -174,8 +174,7 @@ final case class ThermalGrid( ambientTemperature: Temperature, isRunning: Boolean, qDot: Power, - houseDemand: Boolean, - storageDemand: Boolean, + demandIndicator: ThermalDemandIndicator, ): (ThermalGridState, Option[ThermalThreshold]) = if (qDot > zeroKW) handleInfeed( tick, @@ -184,8 +183,7 @@ final case class ThermalGrid( state, isRunning, qDot, - houseDemand, - storageDemand, + demandIndicator, ) else handleConsumption( @@ -211,10 +209,9 @@ final case class ThermalGrid( * determines whether the heat pump is running or not * @param qDot * Infeed to the grid - * @param houseDemand - * determines if the thermal house has heat demand - * @param heatStorageDemand - * determines if the thermal storage has heat demand + * @param demandIndicator + * determines if the thermal units (house, storage) having some heat demand + * or not * @return * Updated thermal grid state */ @@ -225,8 +222,7 @@ final case class ThermalGrid( state: ThermalGridState, isRunning: Boolean, qDot: Power, - houseDemand: Boolean, - heatStorageDemand: Boolean, + demandIndicator: ThermalDemandIndicator, ): (ThermalGridState, Option[ThermalThreshold]) = { // TODO: We would need to issue a storage result model here... @@ -244,7 +240,7 @@ final case class ThermalGrid( } if ( - (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW & heatStorageDemand) + (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW & demandIndicator.heatStorageDemand) ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( @@ -307,7 +303,7 @@ final case class ThermalGrid( } } else { - (houseDemand, heatStorageDemand) match { + (demandIndicator.houseDemand, demandIndicator.heatStorageDemand) match { case (true, _) => // house first then heatStorage after heating House @@ -742,6 +738,19 @@ object ThermalGrid { thermalGrid.storage.map(_.startingState), ) + /** Wraps booleans indicating the demand of thermal units (thermal house, + * thermal storage). + * + * @param houseDemand + * Boolean indicating the demand of the thermal house + * @param heatStorageDemand + * Boolean indicating the demand of the thermal heat storage + */ + final case class ThermalDemandIndicator private ( + houseDemand: Boolean, + heatStorageDemand: Boolean, + ) + /** Defines the thermal energy demand of a thermal grid. It comprises the * absolutely required energy demand to reach the target state as well as an * energy, that can be handled. The possible energy always has to be greater 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 0a016d4566..21f27b1892 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala @@ -9,6 +9,7 @@ package edu.ie3.simona.model.thermal import edu.ie3.datamodel.models.OperationTime import edu.ie3.datamodel.models.input.OperatorInput import edu.ie3.datamodel.models.input.thermal.ThermalBusInput +import edu.ie3.simona.model.thermal.ThermalGrid.ThermalDemandIndicator import squants.energy.{Kilowatts, Power} import squants.thermal.{Celsius, Temperature} @@ -25,8 +26,12 @@ trait ThermalGridTestData { protected val testGridQDotInfeed: Power = Kilowatts(15d) protected val testGridQDotConsumption: Power = Kilowatts(-42d) protected val testGridQDotConsumptionHigh: Power = Kilowatts(-200d) - protected val noThermalDemand: Boolean = false - protected val thermalDemand: Boolean = true + protected val noThermalDemand: ThermalDemandIndicator = + ThermalDemandIndicator(false, false) + protected val onlyThermalDemandOfHouse: ThermalDemandIndicator = + ThermalDemandIndicator(true, false) + protected val onlyThermalDemandOfHeatStorage: ThermalDemandIndicator = + ThermalDemandIndicator(false, true) protected val isRunning: Boolean = true protected val isNotRunning: Boolean = false } 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 b2b732ae0e..ce58b6a52a 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -498,8 +498,7 @@ class ThermalGridWithHouseAndStorageSpec initialGridState, isNotRunning, externalQDot, - thermalDemand, - noThermalDemand, + onlyThermalDemandOfHouse, ) updatedGridState match { @@ -547,8 +546,7 @@ class ThermalGridWithHouseAndStorageSpec gridState, isNotRunning, externalQDot, - noThermalDemand, - thermalDemand, + onlyThermalDemandOfHeatStorage, ) updatedGridState match { 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 4ecbfc819b..39a614e92c 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -181,8 +181,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { gridState, isNotRunning, testGridQDotInfeed, - thermalDemand, - noThermalDemand, + onlyThermalDemandOfHouse, ) updatedGridState match { @@ -210,8 +209,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { testGridAmbientTemperature, isRunning, testGridQDotInfeed, - thermalDemand, - noThermalDemand, + onlyThermalDemandOfHouse, ) match { case ( ThermalGridState( @@ -236,8 +234,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { testGridAmbientTemperature, isNotRunning, testGridQDotConsumption, - thermalDemand, - noThermalDemand, + onlyThermalDemandOfHouse, ) match { case ( ThermalGridState( @@ -262,8 +259,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { testGridAmbientTemperature, isNotRunning, Megawatts(0d), - thermalDemand, - noThermalDemand, + onlyThermalDemandOfHouse, ) match { case ( ThermalGridState( 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 c1ded4c6dc..c2c1880fef 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -184,8 +184,7 @@ class ThermalGridWithStorageOnlySpec gridState, isNotRunning, testGridQDotInfeed, - noThermalDemand, - thermalDemand, + onlyThermalDemandOfHeatStorage, ) updatedGridState match { @@ -211,8 +210,7 @@ class ThermalGridWithStorageOnlySpec testGridAmbientTemperature, isRunning, testGridQDotInfeed, - noThermalDemand, - thermalDemand, + onlyThermalDemandOfHeatStorage, ) nextThreshold shouldBe Some(StorageFull(276000L)) @@ -247,8 +245,7 @@ class ThermalGridWithStorageOnlySpec testGridAmbientTemperature, isRunning, testGridQDotConsumptionHigh, - thermalDemand, - noThermalDemand, + onlyThermalDemandOfHouse, ) match { case ( ThermalGridState( @@ -274,7 +271,6 @@ class ThermalGridWithStorageOnlySpec isRunning, Kilowatts(0d), noThermalDemand, - noThermalDemand, ) updatedState match { case ( From 7341e10ac9e99eb80fb765ce6424be51557a13d5 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 15 Nov 2024 14:09:46 +0100 Subject: [PATCH 13/63] remove unnecessary value --- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 3 +-- 1 file changed, 1 insertion(+), 2 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 b74c8ffa04..f50b493b9c 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -369,8 +369,7 @@ final case class ThermalGrid( qDotHouse: Power, qDotHeatStorage: Power, ): (ThermalGridState, Option[ThermalThreshold]) = { - // FIXME: Is there any case where we get back some remainingQDotHouse? - val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = + val (updatedHouseState, thermalHouseThreshold, _) = handleInfeedHouse( tick, lastAmbientTemperature, From debae480c15738ce24e34f4f5d72c82e0c96742c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 22 Nov 2024 17:01:34 +0100 Subject: [PATCH 14/63] refactoring thermal demand indicators --- .../simona/model/participant/HpModel.scala | 88 ++++++------------- .../simona/model/thermal/ThermalGrid.scala | 62 ++++++------- .../model/participant/HpModelSpec.scala | 2 +- .../model/thermal/ThermalGridTestData.scala | 29 ++++-- .../ThermalGridWithHouseAndStorageSpec.scala | 11 ++- .../ThermalGridWithHouseOnlySpec.scala | 7 +- .../ThermalGridWithStorageOnlySpec.scala | 8 +- 7 files changed, 100 insertions(+), 107 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 3400fa15c8..76e9f24651 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -12,8 +12,7 @@ import edu.ie3.simona.model.SystemComponent import edu.ie3.simona.model.participant.HpModel.{HpRelevantData, HpState} import edu.ie3.simona.model.participant.control.QControl import edu.ie3.simona.model.thermal.ThermalGrid.{ - ThermalDemandIndicator, - ThermalEnergyDemand, + ThermalDemandWrapper, ThermalGridState, } import edu.ie3.simona.model.thermal.{ThermalGrid, ThermalThreshold} @@ -133,7 +132,7 @@ final case class HpModel( ): (Boolean, Boolean, HpState) = { // Use lastHpState and relevantData to update state of thermalGrid to the current tick - val (demandHouse, demandThermalStorage, currentThermalGridState) = + val (thermalDemandWrapper, currentThermalGridState) = thermalGrid.energyDemandAndUpdatedState( relevantData.currentTick, lastHpState.ambientTemperature.getOrElse( @@ -144,18 +143,17 @@ final case class HpModel( ) // Determining the operation point and limitations at this tick - val (turnOn, canOperate, canBeOutOfOperation, demandIndicator) = + val (turnOn, canOperate, canBeOutOfOperation) = operatesInNextState( lastHpState, currentThermalGridState, relevantData, - demandHouse, - demandThermalStorage, + thermalDemandWrapper, ) // Updating the HpState val updatedState = - calcState(lastHpState, relevantData, turnOn, demandIndicator) + calcState(lastHpState, relevantData, turnOn, thermalDemandWrapper) (canOperate, canBeOutOfOperation, updatedState) } @@ -171,35 +169,30 @@ final case class HpModel( * to current tick updated state of the thermalGrid * @param relevantData * Relevant (external) data - * @param demandHouse - * ThermalEnergyDemand of the house - * @param demandThermalStorage - * ThermalEnergyDemand of the thermal storage + * @param thermalDemands + * ThermalEnergyDemand of the house and the thermal storage * @return * boolean defining if heat pump runs in next time step, if it can be in - * operation and can be out of operation plus the - * [[ThermalDemandIndicator]] of the thermal units + * operation and can be out of operation */ private def operatesInNextState( lastState: HpState, currentThermalGridState: ThermalGridState, relevantData: HpRelevantData, - demandHouse: ThermalEnergyDemand, - demandThermalStorage: ThermalEnergyDemand, - ): (Boolean, Boolean, Boolean, ThermalDemandIndicator) = { + thermalDemands: ThermalDemandWrapper, + ): (Boolean, Boolean, Boolean) = { - val ( - demandIndicator, - noThermalStorageOrThermalStorageIsEmpty, - ) = determineDemandBooleans( + val demandHouse = thermalDemands.houseDemand + val demandThermalStorage = thermalDemands.heatStorageDemand + + val noThermalStorageOrThermalStorageIsEmpty = determineThermalStorageStatus( lastState, currentThermalGridState, - demandHouse, - demandThermalStorage, ) val turnHpOn = - demandIndicator.houseDemand || demandIndicator.heatStorageDemand + (demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) || + demandThermalStorage.hasRequiredDemand || (demandThermalStorage.hasAdditionalDemand && lastState.isRunning) val canOperate = demandHouse.hasRequiredDemand || demandHouse.hasAdditionalDemand || @@ -211,7 +204,6 @@ final case class HpModel( turnHpOn, canOperate, canBeOutOfOperation, - demandIndicator, ) } @@ -223,22 +215,14 @@ final case class HpModel( * Current state of the heat pump * @param updatedGridState * The updated state of the [[ThermalGrid]] - * @param demandHouse - * heat demand of the thermal house - * @param demandThermalStorage - * heat demand of the thermal storage * @return - * First boolean is true, if house has heat demand. Second boolean is true, - * if thermalStorage has heat demand. Third boolean is true, if there is no - * thermalStorage, or it's empty. + * boolean which is true, if there is no thermalStorage, or it's empty. */ - private def determineDemandBooleans( + private def determineThermalStorageStatus( lastHpState: HpState, updatedGridState: ThermalGridState, - demandHouse: ThermalEnergyDemand, - demandThermalStorage: ThermalEnergyDemand, - ): (ThermalDemandIndicator, Boolean) = { + ): Boolean = { implicit val tolerance: Energy = KilowattHours(1e-3) val noThermalStorageOrThermalStorageIsEmpty: Boolean = updatedGridState.storageState.isEmpty || updatedGridState.storageState @@ -246,13 +230,7 @@ final case class HpModel( _.storedEnergy =~ zeroKWh ) - val houseDemand = - (demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) || (lastHpState.isRunning && demandHouse.hasAdditionalDemand) - val heatStorageDemand = - demandThermalStorage.hasRequiredDemand || (lastHpState.isRunning && demandThermalStorage.hasAdditionalDemand) - - val demandIndicator = ThermalDemandIndicator(houseDemand, heatStorageDemand) - (demandIndicator, noThermalStorageOrThermalStorageIsEmpty) + noThermalStorageOrThermalStorageIsEmpty } /** Calculate state depending on whether heat pump is needed or not. Also @@ -265,9 +243,8 @@ final case class HpModel( * data of heat pump including state of the heat pump * @param isRunning * determines whether the heat pump is running or not - * @param demandIndicator - * determines if the thermal units (house, storage) having some heat demand - * or not + * @param demandWrapper + * holds the thermal demands of the thermal units (house, storage) * @return * next [[HpState]] */ @@ -275,7 +252,7 @@ final case class HpModel( lastState: HpState, relevantData: HpRelevantData, isRunning: Boolean, - demandIndicator: ThermalDemandIndicator, + demandWrapper: ThermalDemandWrapper, ): HpState = { val lastStateStorageQDot = lastState.thermalGridState.storageState .map(_.qDot) @@ -297,7 +274,7 @@ final case class HpModel( relevantData.ambientTemperature, isRunning, newThermalPower, - demandIndicator, + demandWrapper, ) HpState( @@ -364,9 +341,8 @@ final case class HpModel( val turnOn = setPower > (sRated.toActivePower(cosPhiRated) * 0.5) val ( - thermalEnergyDemandHouse, - thermalEnergyDemandStorage, - updatedThermalGridState, + thermalDemandWrapper, + _, ) = thermalGrid.energyDemandAndUpdatedState( data.currentTick, @@ -375,21 +351,11 @@ final case class HpModel( lastState.thermalGridState, ) - val ( - demandIndicator, - _, - ) = determineDemandBooleans( - lastState, - updatedThermalGridState, - thermalEnergyDemandHouse, - thermalEnergyDemandStorage, - ) - val updatedHpState = calcState( lastState, data, turnOn, - demandIndicator, + thermalDemandWrapper, ) ( 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 033f84e532..4e7b99ddc1 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -15,7 +15,7 @@ import edu.ie3.datamodel.models.result.thermal.{ } import edu.ie3.simona.exceptions.agent.InconsistentStateException import edu.ie3.simona.model.thermal.ThermalGrid.{ - ThermalDemandIndicator, + ThermalDemandWrapper, ThermalEnergyDemand, ThermalGridState, } @@ -64,7 +64,7 @@ final case class ThermalGrid( lastAmbientTemperature: Temperature, ambientTemperature: Temperature, state: ThermalGridState, - ): (ThermalEnergyDemand, ThermalEnergyDemand, ThermalGridState) = { + ): (ThermalDemandWrapper, ThermalGridState) = { /* First get the energy demand of the houses but only if inner temperature is below target temperature */ val (houseDemand, updatedHouseState) = @@ -135,13 +135,15 @@ final case class ThermalGrid( } ( - ThermalEnergyDemand( - houseDemand.required, - houseDemand.possible, - ), - ThermalEnergyDemand( - storageDemand.required, - storageDemand.possible, + ThermalDemandWrapper( + ThermalEnergyDemand( + houseDemand.required, + houseDemand.possible, + ), + ThermalEnergyDemand( + storageDemand.required, + storageDemand.possible, + ), ), ThermalGridState(updatedHouseState, updatedStorageState), ) @@ -161,9 +163,8 @@ final case class ThermalGrid( * determines whether the heat pump is running or not * @param qDot * Thermal energy balance - * @param demandIndicator - * determines if the thermal units (house, storage) having some heat demand - * or not + * @param thermalDemands + * holds the thermal demands of the thermal units (house, storage) * @return * The updated state of the grid */ @@ -174,7 +175,7 @@ final case class ThermalGrid( ambientTemperature: Temperature, isRunning: Boolean, qDot: Power, - demandIndicator: ThermalDemandIndicator, + thermalDemands: ThermalDemandWrapper, ): (ThermalGridState, Option[ThermalThreshold]) = if (qDot > zeroKW) handleInfeed( tick, @@ -183,7 +184,7 @@ final case class ThermalGrid( state, isRunning, qDot, - demandIndicator, + thermalDemands, ) else handleConsumption( @@ -209,9 +210,8 @@ final case class ThermalGrid( * determines whether the heat pump is running or not * @param qDot * Infeed to the grid - * @param demandIndicator - * determines if the thermal units (house, storage) having some heat demand - * or not + * @param thermalDemands + * holds the thermal demands of the thermal units (house, storage) * @return * Updated thermal grid state */ @@ -222,7 +222,7 @@ final case class ThermalGrid( state: ThermalGridState, isRunning: Boolean, qDot: Power, - demandIndicator: ThermalDemandIndicator, + thermalDemands: ThermalDemandWrapper, ): (ThermalGridState, Option[ThermalThreshold]) = { // TODO: We would need to issue a storage result model here... @@ -240,7 +240,8 @@ final case class ThermalGrid( } if ( - (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW & demandIndicator.heatStorageDemand) + // todo: Check if it has to be hasRequiredDemand or hasAdditionalDemand + (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW & thermalDemands.heatStorageDemand.hasAdditionalDemand) ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( @@ -302,8 +303,11 @@ final case class ThermalGrid( ) } } else { - - (demandIndicator.houseDemand, demandIndicator.heatStorageDemand) match { + // todo: Check if it has to be hasRequiredDemand or hasAdditionalDemand + ( + thermalDemands.houseDemand.hasRequiredDemand, + thermalDemands.heatStorageDemand.hasRequiredDemand, + ) match { case (true, _) => // house first then heatStorage after heating House @@ -737,17 +741,16 @@ object ThermalGrid { thermalGrid.storage.map(_.startingState), ) - /** Wraps booleans indicating the demand of thermal units (thermal house, - * thermal storage). + /** Wraps the demand of thermal units (thermal house, thermal storage). * * @param houseDemand - * Boolean indicating the demand of the thermal house + * the demand of the thermal house * @param heatStorageDemand - * Boolean indicating the demand of the thermal heat storage + * the demand of the thermal heat storage */ - final case class ThermalDemandIndicator private ( - houseDemand: Boolean, - heatStorageDemand: Boolean, + final case class ThermalDemandWrapper private ( + houseDemand: ThermalEnergyDemand, + heatStorageDemand: ThermalEnergyDemand, ) /** Defines the thermal energy demand of a thermal grid. It comprises the @@ -776,8 +779,7 @@ object ThermalGrid { object ThermalEnergyDemand { /** Builds a new instance of [[ThermalEnergyDemand]]. If the possible energy - * is less than the required energy, this is considered to be a bad state - * and the required energy is curtailed to the possible energy. + * is less than the required energy, this is considered to be a bad state. * @param required * The absolutely required energy to reach target state * @param possible 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 81c62e549d..7080cac327 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala @@ -265,7 +265,7 @@ class HpModelSpec (95.0, 95.0, 95.0), ), // 2. Same as before but heat storage is NOT empty - // should be possible to keep hp off + // should be possible to turn hp on ( ThermalGridState( Some(ThermalHouseState(0L, Celsius(15), Kilowatts(0))), 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 21f27b1892..df410786c5 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridTestData.scala @@ -9,8 +9,12 @@ package edu.ie3.simona.model.thermal import edu.ie3.datamodel.models.OperationTime import edu.ie3.datamodel.models.input.OperatorInput import edu.ie3.datamodel.models.input.thermal.ThermalBusInput -import edu.ie3.simona.model.thermal.ThermalGrid.ThermalDemandIndicator -import squants.energy.{Kilowatts, Power} +import edu.ie3.simona.model.thermal.ThermalGrid.{ + ThermalDemandWrapper, + ThermalEnergyDemand, +} +import edu.ie3.util.scala.quantities.DefaultQuantities.zeroKWh +import squants.energy.{KilowattHours, Kilowatts, Power} import squants.thermal.{Celsius, Temperature} import java.util.UUID @@ -26,12 +30,21 @@ trait ThermalGridTestData { protected val testGridQDotInfeed: Power = Kilowatts(15d) protected val testGridQDotConsumption: Power = Kilowatts(-42d) protected val testGridQDotConsumptionHigh: Power = Kilowatts(-200d) - protected val noThermalDemand: ThermalDemandIndicator = - ThermalDemandIndicator(false, false) - protected val onlyThermalDemandOfHouse: ThermalDemandIndicator = - ThermalDemandIndicator(true, false) - protected val onlyThermalDemandOfHeatStorage: ThermalDemandIndicator = - ThermalDemandIndicator(false, true) + protected val noThermalDemand: ThermalDemandWrapper = + ThermalDemandWrapper( + ThermalEnergyDemand(zeroKWh, zeroKWh), + ThermalEnergyDemand(zeroKWh, zeroKWh), + ) + protected val onlyThermalDemandOfHouse: ThermalDemandWrapper = + ThermalDemandWrapper( + ThermalEnergyDemand(KilowattHours(1), KilowattHours(2)), + ThermalEnergyDemand(zeroKWh, zeroKWh), + ) + protected val onlyThermalDemandOfHeatStorage: ThermalDemandWrapper = + ThermalDemandWrapper( + ThermalEnergyDemand(zeroKWh, zeroKWh), + ThermalEnergyDemand(KilowattHours(1), KilowattHours(2)), + ) protected val isRunning: Boolean = true protected val isNotRunning: Boolean = false } 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 2351774f20..6cd7558e3d 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -13,13 +13,13 @@ import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseThreshold.{ HouseTemperatureLowerBoundaryReached, HouseTemperatureUpperBoundaryReached, } -import edu.ie3.util.scala.quantities.DefaultQuantities.{zeroKW, zeroKWh} import edu.ie3.simona.model.thermal.ThermalStorage.ThermalStorageState import edu.ie3.simona.model.thermal.ThermalStorage.ThermalStorageThreshold.{ StorageEmpty, StorageFull, } import edu.ie3.simona.test.common.UnitSpec +import edu.ie3.util.scala.quantities.DefaultQuantities.{zeroKW, zeroKWh} import squants.energy._ import squants.thermal.Celsius import squants.{Energy, Kelvin, Power, Temperature} @@ -97,13 +97,16 @@ class ThermalGridWithHouseAndStorageSpec "deliver the house demand (no demand) with added flexibility by storage" in { val tick = 10800 // after three hours - val (houseDemand, storageDemand, updatedThermalGridState) = + val (thermalDemands, updatedThermalGridState) = thermalGrid.energyDemandAndUpdatedState( tick, testGridAmbientTemperature, testGridAmbientTemperature, ThermalGrid.startingState(thermalGrid), ) + val houseDemand = thermalDemands.houseDemand + val storageDemand = thermalDemands.heatStorageDemand + houseDemand.required should approximate(zeroKWh) houseDemand.possible should approximate(KilowattHours(31.05009722d)) storageDemand.required should approximate(KilowattHours(1150d)) @@ -120,7 +123,7 @@ class ThermalGridWithHouseAndStorageSpec val tick = 10800 // after three hours val startingState = ThermalGrid.startingState(thermalGrid) - val (houseDemand, storageDemand, updatedThermalGridState) = + val (thermalDemands, updatedThermalGridState) = thermalGrid.energyDemandAndUpdatedState( tick, testGridAmbientTemperature, @@ -131,6 +134,8 @@ class ThermalGridWithHouseAndStorageSpec ) ), ) + val houseDemand = thermalDemands.houseDemand + val storageDemand = thermalDemands.heatStorageDemand houseDemand.required should approximate(KilowattHours(45.6000555)) houseDemand.possible should approximate(KilowattHours(75.600055555)) 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 0c61b79ba8..34b37c2e03 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala @@ -13,8 +13,8 @@ import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseThreshold.{ HouseTemperatureLowerBoundaryReached, HouseTemperatureUpperBoundaryReached, } -import edu.ie3.util.scala.quantities.DefaultQuantities.{zeroKW, zeroKWh} import edu.ie3.simona.test.common.UnitSpec +import edu.ie3.util.scala.quantities.DefaultQuantities.{zeroKW, zeroKWh} import squants.energy._ import squants.thermal.Celsius import squants.{Energy, Kelvin, Power, Temperature} @@ -81,7 +81,7 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { expectedHouseStartingState, ) - val (houseDemand, storageDemand, updatedThermalGridState) = + val (thermalDemands, updatedThermalGridState) = thermalGrid.energyDemandAndUpdatedState( tick, testGridAmbientTemperature, @@ -89,6 +89,9 @@ class ThermalGridWithHouseOnlySpec extends UnitSpec with ThermalHouseTestData { ThermalGrid.startingState(thermalGrid), ) + val houseDemand = thermalDemands.houseDemand + val storageDemand = thermalDemands.heatStorageDemand + houseDemand.required should approximate(expectedHouseDemand.required) houseDemand.possible should approximate(expectedHouseDemand.possible) storageDemand.required should approximate(zeroKWh) 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 d8b622e78c..c4e5339a54 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -81,13 +81,15 @@ class ThermalGridWithStorageOnlySpec "deliver the capabilities of the storage" in { val tick = 10800 // after three hours - val (houseDemand, storageDemand, updatedThermalGridState) = + val (thermalDemands, updatedThermalGridState) = thermalGrid.energyDemandAndUpdatedState( tick, testGridAmbientTemperature, testGridAmbientTemperature, ThermalGrid.startingState(thermalGrid), ) + val houseDemand = thermalDemands.houseDemand + val storageDemand = thermalDemands.heatStorageDemand houseDemand.required should approximate(zeroKWh) houseDemand.possible should approximate(zeroKWh) @@ -102,7 +104,7 @@ class ThermalGridWithStorageOnlySpec "deliver the capabilities of a half full storage" in { val tick = 10800 // after three hours - val (houseDemand, storageDemand, updatedThermalGridState) = + val (thermalDemands, updatedThermalGridState) = thermalGrid.energyDemandAndUpdatedState( tick, testGridAmbientTemperature, @@ -112,6 +114,8 @@ class ThermalGridWithStorageOnlySpec Some(ThermalStorageState(0L, KilowattHours(575d), zeroKW)), ), ) + val houseDemand = thermalDemands.houseDemand + val storageDemand = thermalDemands.heatStorageDemand houseDemand.required should approximate(zeroKWh) houseDemand.possible should approximate(zeroKWh) From 5c00a896c5ca9e086fa82e5384073e96a519482f Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 22 Nov 2024 17:02:32 +0100 Subject: [PATCH 15/63] fix thermalPower determination in calcState of HpModel --- .../edu/ie3/simona/model/participant/HpModel.scala | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) 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 76e9f24651..3e5c8f4cd1 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -258,12 +258,20 @@ final case class HpModel( .map(_.qDot) .getOrElse(zeroKW) - val (newActivePower, newThermalPower) = + val (newActivePower, newThermalPower) = { if (isRunning) (pRated, pThermal) else if (lastStateStorageQDot < zeroKW) (zeroKW, lastStateStorageQDot * -1) + else if ( + lastStateStorageQDot == zeroKW && (demandWrapper.houseDemand.hasRequiredDemand || demandWrapper.heatStorageDemand.hasRequiredDemand) + ) + ( + zeroKW, + thermalGrid.storage.map(_.getChargingPower: squants.Power).get * -1, + ) else (zeroKW, zeroKW) + } /* Push thermal energy to the thermal grid and get its updated state in return */ val (thermalGridState, maybeThreshold) = From cbd997ebc8ef6f86d87e5653b08c528710d29d56 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 22 Nov 2024 23:39:58 +0100 Subject: [PATCH 16/63] fix EmAgentIT --- .../scala/edu/ie3/simona/agent/em/EmAgentIT.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala index be1cee377f..b43b73f129 100644 --- a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala @@ -680,7 +680,7 @@ class EmAgentIT Celsius(0d), MetersPerSecond(0d), ), - Some(56000), + Some(28800), ) } @@ -692,26 +692,26 @@ class EmAgentIT emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) } - scheduler.expectMessage(Completion(emAgentActivation, Some(44398))) + scheduler.expectMessage(Completion(emAgentActivation, Some(26748))) - /* TICK 44398 + /* TICK 26748 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 */ - emAgentActivation ! Activation(44398) + emAgentActivation ! Activation(26748) resultListener.expectMessageType[ParticipantResultEvent] match { case ParticipantResultEvent(emResult: EmResult) => emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 44398.toDateTime + emResult.getTime shouldBe 26748.toDateTime emResult.getP should equalWithTolerance(0.005086768.asMegaWatt) emResult.getQ should equalWithTolerance(0.00107312004.asMegaVar) } - scheduler.expectMessage(Completion(emAgentActivation, Some(56000))) + scheduler.expectMessage(Completion(emAgentActivation, Some(28800))) } } From a07b6262cd8753532aebfcb6fdd9d0b5cd870e36 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Fri, 22 Nov 2024 23:51:58 +0100 Subject: [PATCH 17/63] also turn Hp on in case house has additional demand and the Hp was running in the last state --- src/main/scala/edu/ie3/simona/model/participant/HpModel.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 3e5c8f4cd1..74f80350d5 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -192,7 +192,9 @@ final case class HpModel( val turnHpOn = (demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) || - demandThermalStorage.hasRequiredDemand || (demandThermalStorage.hasAdditionalDemand && lastState.isRunning) + (demandHouse.hasAdditionalDemand && lastState.isRunning) || + demandThermalStorage.hasRequiredDemand || + (demandThermalStorage.hasAdditionalDemand && lastState.isRunning) val canOperate = demandHouse.hasRequiredDemand || demandHouse.hasAdditionalDemand || From 92e6c512f88c261af1e3216c4115f5512b7eeb7c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 09:56:34 +0100 Subject: [PATCH 18/63] fix EmAgentIT --- .../edu/ie3/simona/agent/em/EmAgentIT.scala | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala index b43b73f129..37155b6cba 100644 --- a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala @@ -692,25 +692,6 @@ class EmAgentIT emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) } - scheduler.expectMessage(Completion(emAgentActivation, Some(26748))) - - /* TICK 26748 - 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 - */ - - emAgentActivation ! Activation(26748) - - resultListener.expectMessageType[ParticipantResultEvent] match { - case ParticipantResultEvent(emResult: EmResult) => - emResult.getInputModel shouldBe emInput.getUuid - emResult.getTime shouldBe 26748.toDateTime - emResult.getP should equalWithTolerance(0.005086768.asMegaWatt) - emResult.getQ should equalWithTolerance(0.00107312004.asMegaVar) - } - scheduler.expectMessage(Completion(emAgentActivation, Some(28800))) } } From 481da32d59444f6eaf29b229db02a684f8996150 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 09:56:57 +0100 Subject: [PATCH 19/63] fmt --- src/main/scala/edu/ie3/simona/model/participant/HpModel.scala | 2 +- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 2 +- 2 files changed, 2 insertions(+), 2 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 74f80350d5..e32757d767 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -264,7 +264,7 @@ final case class HpModel( if (isRunning) (pRated, pThermal) else if (lastStateStorageQDot < zeroKW) - (zeroKW, lastStateStorageQDot * -1) + (zeroKW, lastStateStorageQDot * (-1)) else if ( lastStateStorageQDot == zeroKW && (demandWrapper.houseDemand.hasRequiredDemand || demandWrapper.heatStorageDemand.hasRequiredDemand) ) 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 4e7b99ddc1..08b48eda2b 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -51,7 +51,7 @@ final case class ThermalGrid( * @param lastAmbientTemperature * Ambient temperature until this tick * @param ambientTemperature - * Ambient temperature in the instance in question + * Current ambient temperature in the instance in question * @param state * Currently applicable state of the thermal grid * @return From b03b5760daacd16a9d15a9de0192565b0f0d853d Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 09:57:56 +0100 Subject: [PATCH 20/63] correct direction of thermal power of thermal heat storage --- src/main/scala/edu/ie3/simona/model/participant/HpModel.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e32757d767..92ad195af9 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -270,7 +270,7 @@ final case class HpModel( ) ( zeroKW, - thermalGrid.storage.map(_.getChargingPower: squants.Power).get * -1, + thermalGrid.storage.map(_.getChargingPower: squants.Power).get, ) else (zeroKW, zeroKW) } From 7b58297793ec0b70fc5e3ad41bde132d703064a0 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 09:59:05 +0100 Subject: [PATCH 21/63] fix handleInfeed of thermal energy --- .../simona/model/thermal/ThermalGrid.scala | 36 ++++++++++++++----- 1 file changed, 28 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 08b48eda2b..d94cf89d2c 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -240,8 +240,7 @@ final case class ThermalGrid( } if ( - // todo: Check if it has to be hasRequiredDemand or hasAdditionalDemand - (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW & thermalDemands.heatStorageDemand.hasAdditionalDemand) + (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW && thermalDemands.heatStorageDemand.hasAdditionalDemand) ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( @@ -280,7 +279,7 @@ final case class ThermalGrid( nextThreshold, ) } - // Handle edge case where house get heated from storage and HP will be activated in between + // Handle edge case where house was heated from storage and HP will be activated in between else if ((qDotHouseLastState > zeroKW && qDotStorageLastState < zeroKW)) { if (isRunning) { handleCases( @@ -302,14 +301,25 @@ final case class ThermalGrid( qDotStorageLastState, ) } + } + // Handle edge case where house should be heated from storage + else if ((!isRunning && qDot > zeroKW)) { + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDot, + -qDot, + ) } else { - // todo: Check if it has to be hasRequiredDemand or hasAdditionalDemand ( thermalDemands.houseDemand.hasRequiredDemand, - thermalDemands.heatStorageDemand.hasRequiredDemand, + thermalDemands.houseDemand.hasAdditionalDemand, + thermalDemands.heatStorageDemand.hasAdditionalDemand, ) match { - case (true, _) => + case (true, _, _) => // house first then heatStorage after heating House handleCases( tick, @@ -320,7 +330,7 @@ final case class ThermalGrid( zeroKW, ) - case (false, true) => + case (false, _, true) => handleCases( tick, lastAmbientTemperature, @@ -330,7 +340,17 @@ final case class ThermalGrid( qDot, ) - case (false, false) => + case (false, true, false) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDot, + zeroKW, + ) + + case (false, false, false) => handleCases( tick, lastAmbientTemperature, From 8d452ece6d9990b127edabfb254c355988168d4b Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 10:11:26 +0100 Subject: [PATCH 22/63] enhance ThermalGridSpec when checking for required and additional demand --- .../edu/ie3/simona/model/thermal/ThermalGridSpec.scala | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala index e4c1c14c70..1a59aede8b 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala @@ -51,6 +51,15 @@ class ThermalGridSpec extends UnitSpec { } "checking for required and additional demand" should { + "return proper information, if no required and no additional demand is apparent" in { + val required = MegawattHours(0d) + val possible = MegawattHours(0d) + + val energyDemand = ThermalEnergyDemand(required, possible) + energyDemand.hasRequiredDemand shouldBe false + energyDemand.hasAdditionalDemand shouldBe false + } + "return proper information, if no required but additional demand is apparent" in { val required = MegawattHours(0d) val possible = MegawattHours(45d) From 07746a48d067c7ab5ca49fabbfcf071e5386f65c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 10:12:29 +0100 Subject: [PATCH 23/63] fix inputs for thermalGridWith specs plus add another test case --- .../ThermalGridWithHouseAndStorageSpec.scala | 4 +- .../ThermalGridWithStorageOnlySpec.scala | 41 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 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 6cd7558e3d..39bc5e6c18 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala @@ -502,7 +502,7 @@ class ThermalGridWithHouseAndStorageSpec testGridAmbientTemperature, testGridAmbientTemperature, initialGridState, - isNotRunning, + isRunning, externalQDot, onlyThermalDemandOfHouse, ) @@ -550,7 +550,7 @@ class ThermalGridWithHouseAndStorageSpec testGridAmbientTemperature, testGridAmbientTemperature, gridState, - isNotRunning, + isRunning, externalQDot, onlyThermalDemandOfHeatStorage, ) 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 c4e5339a54..8f0ba6cdfe 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -187,7 +187,7 @@ class ThermalGridWithStorageOnlySpec testGridAmbientTemperature, testGridAmbientTemperature, gridState, - isNotRunning, + isRunning, testGridQDotInfeed, onlyThermalDemandOfHeatStorage, ) @@ -204,6 +204,45 @@ class ThermalGridWithStorageOnlySpec } reachedThreshold shouldBe Some(StorageFull(276000L)) } + + "properly take energy from storage" in { + val tick = 0L + val gridState = ThermalGrid + .startingState(thermalGrid) + .copy(storageState = + Some( + ThermalStorageState( + 0L, + KilowattHours(150d), + zeroKW, + ) + ) + ) + + val (updatedGridState, reachedThreshold) = + thermalGrid invokePrivate handleInfeed( + tick, + testGridAmbientTemperature, + testGridAmbientTemperature, + gridState, + isNotRunning, + testGridQDotInfeed, + onlyThermalDemandOfHeatStorage, + ) + + updatedGridState match { + case ThermalGridState( + None, + Some(ThermalStorageState(tick, storedEnergy, qDot)), + ) => + tick shouldBe 0L + storedEnergy should approximate(KilowattHours(150d)) + qDot should approximate(testGridQDotInfeed * (-1)) + case _ => fail("Thermal grid state has been calculated wrong.") + } + reachedThreshold shouldBe Some(StorageEmpty(36000L)) + } + } "updating the grid state dependent on the given thermal infeed" should { From aa9ffc97391a56ecdb8a200fa46a6323eee66ad8 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Sat, 23 Nov 2024 10:23:10 +0100 Subject: [PATCH 24/63] remove unused parameter --- .../scala/edu/ie3/simona/model/participant/HpModel.scala | 8 ++------ 1 file changed, 2 insertions(+), 6 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 92ad195af9..39b4eb4b75 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -186,8 +186,7 @@ final case class HpModel( val demandThermalStorage = thermalDemands.heatStorageDemand val noThermalStorageOrThermalStorageIsEmpty = determineThermalStorageStatus( - lastState, - currentThermalGridState, + currentThermalGridState ) val turnHpOn = @@ -213,8 +212,6 @@ final case class HpModel( * or thermal storage as well as a boolean indicating if there is no thermal * storage, or it is empty. * - * @param lastHpState - * Current state of the heat pump * @param updatedGridState * The updated state of the [[ThermalGrid]] * @return @@ -222,8 +219,7 @@ final case class HpModel( */ private def determineThermalStorageStatus( - lastHpState: HpState, - updatedGridState: ThermalGridState, + updatedGridState: ThermalGridState ): Boolean = { implicit val tolerance: Energy = KilowattHours(1e-3) val noThermalStorageOrThermalStorageIsEmpty: Boolean = From 0d157db2654ab4e97aa15983e10f14722b2987b1 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 15:47:44 +0100 Subject: [PATCH 25/63] fix after merging --- .../edu/ie3/simona/model/participant/HpModel.scala | 12 +++++------- 1 file changed, 5 insertions(+), 7 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 6c2bc6a540..c6bb721d01 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -302,7 +302,7 @@ final case class HpModel( * operating state and give back the next tick in which something will * change. * - * @param data + * @param relevantData * Relevant data for model calculation * @param lastState * The last known model state @@ -313,7 +313,7 @@ final case class HpModel( * options will change next */ override def handleControlledPowerChange( - data: HpRelevantData, + relevantData: HpRelevantData, lastState: HpState, setPower: Power, ): (HpState, FlexChangeIndicator) = { @@ -325,15 +325,13 @@ final case class HpModel( _, ) = thermalGrid.energyDemandAndUpdatedState( - data.currentTick, - lastState.ambientTemperature.getOrElse(data.ambientTemperature), - data.ambientTemperature, - lastState.thermalGridState, + relevantData, + lastState, ) val updatedHpState = calcState( lastState, - data, + relevantData, turnOn, thermalDemandWrapper, ) From 9a9096d8ad38dea4c64d4e67eb9e47195d26163f Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 17:26:07 +0100 Subject: [PATCH 26/63] fmt --- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 1 - 1 file changed, 1 deletion(-) 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 227701f729..a379510533 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -507,7 +507,6 @@ final case class ThermalGrid( * @return * The next threshold */ - private def determineMostRecentThreshold( maybeHouseThreshold: Option[ThermalThreshold], maybeStorageThreshold: Option[ThermalThreshold], From 81694cc6156c2494070fe0a213a4797cf947a63c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 22:19:56 +0100 Subject: [PATCH 27/63] hard fix for zero values as minimum storage volume level to prevent non-plausible behaviour till psdm release --- .../simona/model/thermal/CylindricalThermalStorage.scala | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala b/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala index e49dde2633..101e9b056b 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala @@ -187,8 +187,10 @@ object CylindricalThermalStorage { input: CylindricalStorageInput, initialStoredEnergy: Energy = DefaultQuantities.zeroKWh, ): CylindricalThermalStorage = { - val minEnergyThreshold: Energy = - CylindricalThermalStorage.volumeToEnergy( + val minEnergyThreshold: Energy = { + //Temporary fix until changes in PSDM are released, Some minimumEnergyThreshold would lead to non-plausible behaviour + zeroKWh + /*CylindricalThermalStorage.volumeToEnergy( CubicMeters( input.getStorageVolumeLvlMin .to(Units.CUBIC_METRE) @@ -204,6 +206,8 @@ object CylindricalThermalStorage { Celsius(input.getInletTemp.to(Units.CELSIUS).getValue.doubleValue()), Celsius(input.getReturnTemp.to(Units.CELSIUS).getValue.doubleValue()), ) + */ + } val maxEnergyThreshold: Energy = CylindricalThermalStorage.volumeToEnergy( From d9f859c3f14bc90dc81426421dea6f244be55f16 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 22:18:57 +0100 Subject: [PATCH 28/63] adapt ChpModelSpec and CylindricalThermalStorageSpec to zero for minimum storage volume level --- .../model/participant/ChpModelSpec.scala | 14 ++++++------- .../CylindricalThermalStorageSpec.scala | 20 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala index 91a72ddd63..57c0dd6725 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala @@ -62,7 +62,7 @@ class ChpModelSpec "ThermalStorage", thermalBus, 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), @@ -149,7 +149,7 @@ class ChpModelSpec ( chpStateNotRunning, 90, - 8 * 115, + 8 * 115 + 230, 95, ), // tests case (false, true, false) (chpStateNotRunning, 90, 10, 0), // tests case (false, true, true) @@ -194,7 +194,7 @@ class ChpModelSpec ( chpStateNotRunning, 90, - 8 * 115, + 8 * 115 + 230, 100, ), // tests case (false, true, false) (chpStateNotRunning, 90, 10, 0), // tests case (false, true, true) @@ -241,11 +241,11 @@ class ChpModelSpec chpStateNotRunning, 90, 8 * 115, - 230, + 115, ), // tests case (false, true, false) (chpStateNotRunning, 90, 10, 1025), // tests case (false, true, true) (chpStateRunning, 90, 0, 1135), // tests case (true, false, true) - (chpStateRunning, 90, 8 * 115, 230), // tests case (true, true, false) + (chpStateRunning, 90, 8 * 115, 215), // tests case (true, true, false) (chpStateRunning, 90, 10, 1125), // tests case (true, true, true) ( chpStateRunning, @@ -257,7 +257,7 @@ class ChpModelSpec chpStateRunning, 90, 9 * 115, - 230, + 100, ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, @@ -293,7 +293,7 @@ class ChpModelSpec ( chpStateNotRunning, 90, - 8 * 115, + 8 * 115 + 230, 7200, true, ), // Test case (false, true, false) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorageSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorageSpec.scala index 52cbb30f79..d2c2a15ee7 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorageSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorageSpec.scala @@ -34,7 +34,7 @@ class CylindricalThermalStorageSpec "ThermalStorage", null, 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), @@ -92,7 +92,7 @@ class CylindricalThermalStorageSpec storage.tryToStoreAndReturnRemainder(vol2Energy(CubicMeters(55))) val newLevel2 = storage._storedEnergy val isCovering = storage.isDemandCoveredByStorage(KilowattHours(5)) - val lack = storage.tryToTakeAndReturnLack(vol2Energy(CubicMeters(95))) + val lack = storage.tryToTakeAndReturnLack(vol2Energy(CubicMeters(115))) val newLevel3 = storage._storedEnergy val notCovering = storage.isDemandCoveredByStorage(KilowattHours(1)) @@ -101,7 +101,7 @@ class CylindricalThermalStorageSpec surplus.value shouldBe vol2Energy(CubicMeters(5)) newLevel2 should approximate(vol2Energy(CubicMeters(100))) lack.value shouldBe vol2Energy(CubicMeters(15)) - newLevel3 should approximate(vol2Energy(CubicMeters(20))) + newLevel3 should approximate(vol2Energy(CubicMeters(0))) isCovering shouldBe true notCovering shouldBe false } @@ -110,7 +110,7 @@ class CylindricalThermalStorageSpec val storage = buildThermalStorage(storageInput, CubicMeters(70)) val usableThermalEnergy = storage.usableThermalEnergy - usableThermalEnergy should approximate(KilowattHours(5 * 115)) + usableThermalEnergy should approximate(KilowattHours(5 * 115 + 230)) } "Apply, validation, and build method work correctly" in { @@ -145,11 +145,11 @@ class CylindricalThermalStorageSpec ), ( 0L, - 250.0, + 20.0, 10.0, 3600L, -42.0, - 260.0, + 30.0, ThermalStorage.ThermalStorageThreshold.StorageEmpty(6171L), ), ( @@ -163,11 +163,11 @@ class CylindricalThermalStorageSpec ), ( 0L, - 250.0, + 20.0, -10.0, 3600L, -42.0, - 240.0, + 10.0, ThermalStorage.ThermalStorageThreshold.StorageEmpty(4457L), ), ( @@ -181,11 +181,11 @@ class CylindricalThermalStorageSpec ), ( 0L, - 240.0, + 10.0, -9.0, 3600L, -5000.0, - 231.0, + 1.0, ThermalStorage.ThermalStorageThreshold.StorageEmpty(3601L), ), ) From bed4f7b926d6bdd8316b6ce1a05b21904895e2c2 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 22:29:51 +0100 Subject: [PATCH 29/63] adapt cases for handling thermal infeed into ThermalGrid --- .../simona/model/thermal/ThermalGrid.scala | 19 +++++++++++++++---- 1 file changed, 15 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 f9d353fe40..ae843cb306 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -312,10 +312,11 @@ final case class ThermalGrid( ( thermalDemands.houseDemand.hasRequiredDemand, thermalDemands.houseDemand.hasAdditionalDemand, + thermalDemands.heatStorageDemand.hasRequiredDemand, thermalDemands.heatStorageDemand.hasAdditionalDemand, ) match { - case (true, _, _) => + case (true,_, _, _) => // house first then heatStorage after heating House handleCases( tick, @@ -326,7 +327,7 @@ final case class ThermalGrid( zeroKW, ) - case (false, _, true) => + case (_,_, true, _) => handleCases( tick, lastAmbientTemperature, @@ -336,7 +337,17 @@ final case class ThermalGrid( qDot, ) - case (false, true, false) => + case (_, false, false, true) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + zeroKW, + qDot, + ) + + case (_, true, false, false) => handleCases( tick, lastAmbientTemperature, @@ -346,7 +357,7 @@ final case class ThermalGrid( zeroKW, ) - case (false, false, false) => + case (false, false, false, false) => handleCases( tick, lastAmbientTemperature, From badd6d9160315db83b40fa0aa6778b7445aff8d1 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 23:07:19 +0100 Subject: [PATCH 30/63] fix consider qDot as heat result of hp only when hp is running --- .../scala/edu/ie3/simona/model/participant/HpModel.scala | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 947076e17c..93a788d5e9 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -112,7 +112,12 @@ final case class HpModel( tick: Long, currentState: HpState, data: HpRelevantData, - ): Power = currentState.qDot + ): Power = + // only if Hp is running qDot will be from Hp, else qDot results from other source, e.g. some storage + if (currentState.isRunning) + currentState.qDot + else + zeroKW /** Given a [[HpRelevantData]] object and the last [[HpState]], this function * calculates the heat pump's next state to get the actual active power of From ae84f160aba579322b99c10bf77e0dfef67e2217 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 25 Nov 2024 23:07:39 +0100 Subject: [PATCH 31/63] fmt --- .../ie3/simona/model/thermal/CylindricalThermalStorage.scala | 2 +- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala b/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala index 101e9b056b..13145f2c7a 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala @@ -188,7 +188,7 @@ object CylindricalThermalStorage { initialStoredEnergy: Energy = DefaultQuantities.zeroKWh, ): CylindricalThermalStorage = { val minEnergyThreshold: Energy = { - //Temporary fix until changes in PSDM are released, Some minimumEnergyThreshold would lead to non-plausible behaviour + // Temporary fix until changes in PSDM are released, Some minimumEnergyThreshold would lead to non-plausible behaviour zeroKWh /*CylindricalThermalStorage.volumeToEnergy( CubicMeters( 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 ae843cb306..7eac95583b 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -316,7 +316,7 @@ final case class ThermalGrid( thermalDemands.heatStorageDemand.hasAdditionalDemand, ) match { - case (true,_, _, _) => + case (true, _, _, _) => // house first then heatStorage after heating House handleCases( tick, @@ -327,7 +327,7 @@ final case class ThermalGrid( zeroKW, ) - case (_,_, true, _) => + case (_, _, true, _) => handleCases( tick, lastAmbientTemperature, From dab5a85eee66d15adf51c26211d1e23c384b4eb7 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 09:36:42 +0100 Subject: [PATCH 32/63] fix wrong case within thermalGrid --- .../ie3/simona/model/thermal/ThermalGrid.scala | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 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 7eac95583b..ee426a5e00 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -337,15 +337,15 @@ final case class ThermalGrid( qDot, ) - case (_, false, false, true) => - handleCases( - tick, - lastAmbientTemperature, - ambientTemperature, - state, - zeroKW, - qDot, - ) + case (false, _, false, true) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + zeroKW, + qDot, + ) case (_, true, false, false) => handleCases( From 0adc6c9921ef3c4c85ab0360c01d980467dc12e1 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 09:38:00 +0100 Subject: [PATCH 33/63] split handleInfeed method a tiny bit --- .../simona/model/thermal/ThermalGrid.scala | 140 +++++++++++------- 1 file changed, 90 insertions(+), 50 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 ee426a5e00..9326dec16c 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -308,34 +308,75 @@ final case class ThermalGrid( qDot, -qDot, ) - } else { - ( - thermalDemands.houseDemand.hasRequiredDemand, - thermalDemands.houseDemand.hasAdditionalDemand, - thermalDemands.heatStorageDemand.hasRequiredDemand, - thermalDemands.heatStorageDemand.hasAdditionalDemand, - ) match { - - case (true, _, _, _) => - // house first then heatStorage after heating House - handleCases( - tick, - lastAmbientTemperature, - ambientTemperature, - state, - qDot, - zeroKW, - ) + } else handleFinaleInfeedCases(thermalDemands, tick, lastAmbientTemperature, ambientTemperature, state, qDot) + } - case (_, _, true, _) => - handleCases( - tick, - lastAmbientTemperature, - ambientTemperature, - state, - zeroKW, - qDot, - ) + /** Handles the last cases of [[ThermalGrid.handleInfeed]], where the thermal + * infeed should be determined. + * + * | house req. demand | house add. demand | storage req. demand | storage add. demand | qDot to house | qDot to storage | + * |:------------------|:------------------|:--------------------|:--------------------|:--------------|:----------------| + * | true | true | true | true | true | false | + * | true | true | true | false | true | false | + * | true | true | false | true | true | false | + * | true | true | false | false | true | false | + * | true | false | true | true | true | false | + * | true | false | true | false | true | false | + * | true | false | false | true | true | false | + * | true | false | false | false | true | false | + * | false | true | true | true | false | true | + * | false | true | true | false | false | true | + * | false | true | false | true | false | true | + * | false | true | false | false | true | false | + * | false | false | true | true | false | true | + * | false | false | true | false | false | true | + * | false | false | false | true | false | true | + * | false | false | false | false | false | false | + * + * This can be simplified to five cases + * | No | Conditions | Result | + * |:---|:-------------------------------------------------------------------------|:----------| + * | 1 | if(house.reqD) => house | house | + * | 2 | if(!house.reqD && !storage.reqD) => storage | storage | + * | 3 | if(!house.reqD && !storage.reqD && storage.addD) => storage | storage | + * | 4 | if(!house.reqD && house.addD && !storage.reqD && !storage.addD) => house | house | + * | 5 | if(all == false) => no output | no output | + */ + def handleFinaleInfeedCases( + thermalDemands: ThermalDemandWrapper, + tick: Long, + lastAmbientTemperature: Temperature, + ambientTemperature: Temperature, + state: ThermalGridState, + qDot: Power, + ) = { + ( + thermalDemands.houseDemand.hasRequiredDemand, + thermalDemands.houseDemand.hasAdditionalDemand, + thermalDemands.heatStorageDemand.hasRequiredDemand, + thermalDemands.heatStorageDemand.hasAdditionalDemand, + ) match { + + case (true, _, _, _) => + // house first then heatStorage after heating House + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDot, + zeroKW, + ) + + case (_, _, true, _) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + zeroKW, + qDot, + ) case (false, _, false, true) => handleCases( @@ -347,30 +388,29 @@ final case class ThermalGrid( qDot, ) - case (_, true, false, false) => - handleCases( - tick, - lastAmbientTemperature, - ambientTemperature, - state, - qDot, - zeroKW, - ) + case (_, true, false, false) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDot, + zeroKW, + ) - case (false, false, false, false) => - handleCases( - tick, - lastAmbientTemperature, - ambientTemperature, - state, - zeroKW, - zeroKW, - ) - case _ => - throw new InconsistentStateException( - "There should be at least a house or a storage state." - ) - } + case (false, false, false, false) => + handleCases( + tick, + lastAmbientTemperature, + ambientTemperature, + state, + zeroKW, + zeroKW, + ) + case _ => + throw new InconsistentStateException( + "There should be at least a house or a storage state." + ) } } From 1586bd3ca3ba730c641d5c3ec2e0dd5c6bce8d39 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 09:41:24 +0100 Subject: [PATCH 34/63] fmt --- .../ie3/simona/model/thermal/ThermalGrid.scala | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 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 9326dec16c..0521c2531f 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -276,7 +276,7 @@ final case class ThermalGrid( ) } // Handle edge case where house was heated from storage and HP will be activated in between - else if ((qDotHouseLastState > zeroKW && qDotStorageLastState < zeroKW)) { + else if (qDotHouseLastState > zeroKW && qDotStorageLastState < zeroKW) { if (isRunning) { handleCases( tick, @@ -299,7 +299,7 @@ final case class ThermalGrid( } } // Handle edge case where house should be heated from storage - else if ((!isRunning && qDot > zeroKW)) { + else if (!isRunning && qDot > zeroKW) { handleCases( tick, lastAmbientTemperature, @@ -308,7 +308,15 @@ final case class ThermalGrid( qDot, -qDot, ) - } else handleFinaleInfeedCases(thermalDemands, tick, lastAmbientTemperature, ambientTemperature, state, qDot) + } else + handleFinaleInfeedCases( + thermalDemands, + tick, + lastAmbientTemperature, + ambientTemperature, + state, + qDot, + ) } /** Handles the last cases of [[ThermalGrid.handleInfeed]], where the thermal @@ -342,14 +350,14 @@ final case class ThermalGrid( * | 4 | if(!house.reqD && house.addD && !storage.reqD && !storage.addD) => house | house | * | 5 | if(all == false) => no output | no output | */ - def handleFinaleInfeedCases( + private def handleFinaleInfeedCases( thermalDemands: ThermalDemandWrapper, tick: Long, lastAmbientTemperature: Temperature, ambientTemperature: Temperature, state: ThermalGridState, qDot: Power, - ) = { + ): (ThermalGridState, Option[ThermalThreshold]) = { ( thermalDemands.houseDemand.hasRequiredDemand, thermalDemands.houseDemand.hasAdditionalDemand, From be3b094f652a35cc73ed7faf60df19df52f06d07 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 11:51:08 +0100 Subject: [PATCH 35/63] fix after merging dev --- .../simona/model/thermal/ThermalGrid.scala | 72 ++++++++----------- 1 file changed, 30 insertions(+), 42 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 235de1e084..1850ba27ec 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -168,7 +168,14 @@ final case class ThermalGrid( qDot: Power, thermalDemands: ThermalDemandWrapper, ): (ThermalGridState, Option[ThermalThreshold]) = if (qDot > zeroKW) - handleInfeed(relevantData, lastAmbientTemperature, state, isRunning, qDot, thermalDemands) + handleInfeed( + relevantData, + lastAmbientTemperature, + state, + isRunning, + qDot, + thermalDemands, + ) else handleConsumption( relevantData, @@ -223,9 +230,8 @@ final case class ThermalGrid( ) { val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDotHouseLastState, ) @@ -234,13 +240,13 @@ final case class ThermalGrid( qDotStorageLastState >= zeroKW && remainingQDotHouse > qDotStorageLastState ) { handleInfeedStorage( - tick, + relevantData.currentTick, state, remainingQDotHouse, ) } else { handleInfeedStorage( - tick, + relevantData.currentTick, state, qDotStorageLastState, ) @@ -262,9 +268,8 @@ final case class ThermalGrid( else if (qDotHouseLastState > zeroKW && qDotStorageLastState < zeroKW) { if (isRunning) { handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDot, zeroKW, @@ -272,9 +277,8 @@ final case class ThermalGrid( } else { handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDotHouseLastState, qDotStorageLastState, @@ -284,9 +288,8 @@ final case class ThermalGrid( // Handle edge case where house should be heated from storage else if (!isRunning && qDot > zeroKW) { handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDot, -qDot, @@ -294,9 +297,8 @@ final case class ThermalGrid( } else handleFinaleInfeedCases( thermalDemands, - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDot, ) @@ -335,9 +337,8 @@ final case class ThermalGrid( */ private def handleFinaleInfeedCases( thermalDemands: ThermalDemandWrapper, - tick: Long, + relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - ambientTemperature: Temperature, state: ThermalGridState, qDot: Power, ): (ThermalGridState, Option[ThermalThreshold]) = { @@ -351,9 +352,8 @@ final case class ThermalGrid( case (true, _, _, _) => // house first then heatStorage after heating House handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDot, zeroKW, @@ -361,9 +361,8 @@ final case class ThermalGrid( case (_, _, true, _) => handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, zeroKW, qDot, @@ -371,9 +370,8 @@ final case class ThermalGrid( case (false, _, false, true) => handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, zeroKW, qDot, @@ -381,9 +379,8 @@ final case class ThermalGrid( case (_, true, false, false) => handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDot, zeroKW, @@ -391,9 +388,8 @@ final case class ThermalGrid( case (false, false, false, false) => handleCases( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, zeroKW, zeroKW, @@ -408,12 +404,10 @@ final case class ThermalGrid( /** Handles the different cases, of thermal flows from and into the thermal * grid. * - * @param tick - * Current tick + * @param relevantData + * data of heat pump including state of the heat pump * @param lastAmbientTemperature * Ambient temperature until this tick - * @param ambientTemperature - * actual ambient temperature * @param state * Current state of the thermal grid * @param qDotHouse @@ -424,24 +418,22 @@ final case class ThermalGrid( * Updated thermal grid state and the next threshold if there is one */ private def handleCases( - tick: Long, + relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - ambientTemperature: Temperature, state: ThermalGridState, qDotHouse: Power, qDotHeatStorage: Power, ): (ThermalGridState, Option[ThermalThreshold]) = { val (updatedHouseState, thermalHouseThreshold, _) = handleInfeedHouse( - tick, + relevantData, lastAmbientTemperature, - ambientTemperature, state, qDotHouse, ) val (updatedStorageState, thermalStorageThreshold) = - handleInfeedStorage(tick, state, qDotHeatStorage) + handleInfeedStorage(relevantData.currentTick, state, qDotHeatStorage) val nextThreshold = determineMostRecentThreshold( thermalHouseThreshold, @@ -460,12 +452,10 @@ final case class ThermalGrid( /** Handles the case, when the house has heat demand and will be heated up * here. * - * @param tick - * Current tick + * @param relevantData + * data of heat pump including state of the heat pump * @param lastAmbientTemperature * Ambient temperature until this tick - * @param ambientTemperature - * actual ambient temperature * @param state * Current state of the houses * @param qDot @@ -474,19 +464,17 @@ final case class ThermalGrid( * Updated thermal house state, a ThermalThreshold and the remaining qDot */ private def handleInfeedHouse( - tick: Long, + relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - ambientTemperature: Temperature, state: ThermalGridState, qDot: Power, ): (Option[ThermalHouseState], Option[ThermalThreshold], Power) = { (house, state.houseState) match { case (Some(thermalHouse), Some(lastHouseState)) => val (newState, threshold) = thermalHouse.determineState( - tick, + relevantData, lastHouseState, lastAmbientTemperature, - ambientTemperature, qDot, ) /* Check if house can handle the thermal feed in */ From 6163afd4ec2d827ba210670d52a623baa701d63a Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 11:53:41 +0100 Subject: [PATCH 36/63] fix tests after merging dev --- .../model/thermal/ThermalGridWithStorageOnlySpec.scala | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 c20fb8ce07..2c0b6b0771 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala @@ -231,7 +231,7 @@ class ThermalGridWithStorageOnlySpec } "properly take energy from storage" in { - val tick = 0L + val relevantData = HpRelevantData(0, testGridAmbientTemperature) val gridState = ThermalGrid .startingState(thermalGrid) .copy(storageState = @@ -246,8 +246,7 @@ class ThermalGridWithStorageOnlySpec val (updatedGridState, reachedThreshold) = thermalGrid invokePrivate handleInfeed( - tick, - testGridAmbientTemperature, + relevantData, testGridAmbientTemperature, gridState, isNotRunning, From 634fbf4bbf13e45e9fbe54c8139cc2c7cb04471b Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 13:36:19 +0100 Subject: [PATCH 37/63] fmt --- .../simona/model/thermal/ThermalGrid.scala | 57 ++++++++++++------- 1 file changed, 35 insertions(+), 22 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 1850ba27ec..773d862982 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -191,8 +191,8 @@ final case class ThermalGrid( * data of heat pump including state of the heat pump * @param lastAmbientTemperature * Ambient temperature valid up until (not including) the current tick - * @param state - * Current state of the houses + * @param thermalGridState + * Current state of the thermal Grid * @param isRunning * determines whether the heat pump is running or not * @param qDot @@ -200,12 +200,12 @@ final case class ThermalGrid( * @param thermalDemands * holds the thermal demands of the thermal units (house, storage) * @return - * Updated thermal grid state + * Updated thermal grid state and the thermalThreshold if there is one */ private def handleInfeed( relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - state: ThermalGridState, + thermalGridState: ThermalGridState, isRunning: Boolean, qDot: Power, thermalDemands: ThermalDemandWrapper, @@ -213,7 +213,7 @@ final case class ThermalGrid( // TODO: We would need to issue a storage result model here... /* Consider the action in the last state */ - val (qDotHouseLastState, qDotStorageLastState) = state match { + val (qDotHouseLastState, qDotStorageLastState) = thermalGridState match { case ThermalGridState(Some(houseState), Some(storageState)) => (houseState.qDot, storageState.qDot) case ThermalGridState(Some(houseState), None) => (houseState.qDot, zeroKW) @@ -232,7 +232,7 @@ final case class ThermalGrid( handleInfeedHouse( relevantData, lastAmbientTemperature, - state, + thermalGridState, qDotHouseLastState, ) val (updatedStorageState, thermalStorageThreshold) = @@ -241,13 +241,13 @@ final case class ThermalGrid( ) { handleInfeedStorage( relevantData.currentTick, - state, + thermalGridState, remainingQDotHouse, ) } else { handleInfeedStorage( relevantData.currentTick, - state, + thermalGridState, qDotStorageLastState, ) } @@ -257,7 +257,7 @@ final case class ThermalGrid( thermalStorageThreshold, ) ( - state.copy( + thermalGridState.copy( houseState = updatedHouseState, storageState = updatedStorageState, ), @@ -270,7 +270,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + thermalGridState, qDot, zeroKW, ) @@ -279,7 +279,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + thermalGridState, qDotHouseLastState, qDotStorageLastState, ) @@ -290,16 +290,16 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + thermalGridState, qDot, -qDot, ) } else - handleFinaleInfeedCases( + handleFinalInfeedCases( thermalDemands, relevantData, lastAmbientTemperature, - state, + thermalGridState, qDot, ) } @@ -334,12 +334,25 @@ final case class ThermalGrid( * | 3 | if(!house.reqD && !storage.reqD && storage.addD) => storage | storage | * | 4 | if(!house.reqD && house.addD && !storage.reqD && !storage.addD) => house | house | * | 5 | if(all == false) => no output | no output | + * + * @param thermalDemands + * holds the thermal demands of the thermal units (house, storage) + * @param relevantData + * data of heat pump including state of the heat pump + * @param lastAmbientTemperature + * Ambient temperature valid up until (not including) the current tick + * @param gridState + * Current state of the thermalGrid + * @param qDot + * Infeed to the grid + * @return + * Updated thermal grid state and the thermalThreshold if there is one */ - private def handleFinaleInfeedCases( + private def handleFinalInfeedCases( thermalDemands: ThermalDemandWrapper, relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - state: ThermalGridState, + gridState: ThermalGridState, qDot: Power, ): (ThermalGridState, Option[ThermalThreshold]) = { ( @@ -354,7 +367,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + gridState, qDot, zeroKW, ) @@ -363,7 +376,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + gridState, zeroKW, qDot, ) @@ -372,7 +385,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + gridState, zeroKW, qDot, ) @@ -381,7 +394,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + gridState, qDot, zeroKW, ) @@ -390,7 +403,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - state, + gridState, zeroKW, zeroKW, ) @@ -745,7 +758,7 @@ object ThermalGrid { ): ThermalGrid = { val houses = input.houses().asScala.map(ThermalHouse(_)).toSet val storages: Set[ThermalStorage] = input - .storages() + .heatStorages() .asScala .flatMap { case cylindricalInput: CylindricalStorageInput => From 6b97e8e37b8208d30b5d504b5fc896ea48bf5a6b Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 26 Nov 2024 13:38:01 +0100 Subject: [PATCH 38/63] fmt --- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 773d862982..0aa6a7c979 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -758,7 +758,7 @@ object ThermalGrid { ): ThermalGrid = { val houses = input.houses().asScala.map(ThermalHouse(_)).toSet val storages: Set[ThermalStorage] = input - .heatStorages() + .storages() .asScala .flatMap { case cylindricalInput: CylindricalStorageInput => From 0e484c41b12037e053c1feecbbd3bd06498180d0 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 27 Nov 2024 13:24:06 +0100 Subject: [PATCH 39/63] remove commented-out code --- .../thermal/CylindricalThermalStorage.scala | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala b/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala index 13145f2c7a..9694672907 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/CylindricalThermalStorage.scala @@ -190,23 +190,6 @@ object CylindricalThermalStorage { val minEnergyThreshold: Energy = { // Temporary fix until changes in PSDM are released, Some minimumEnergyThreshold would lead to non-plausible behaviour zeroKWh - /*CylindricalThermalStorage.volumeToEnergy( - CubicMeters( - input.getStorageVolumeLvlMin - .to(Units.CUBIC_METRE) - .getValue - .doubleValue - ), - KilowattHoursPerKelvinCubicMeters( - input.getC - .to(PowerSystemUnits.KILOWATTHOUR_PER_KELVIN_TIMES_CUBICMETRE) - .getValue - .doubleValue - ), - Celsius(input.getInletTemp.to(Units.CELSIUS).getValue.doubleValue()), - Celsius(input.getReturnTemp.to(Units.CELSIUS).getValue.doubleValue()), - ) - */ } val maxEnergyThreshold: Energy = From be33961708b59151d95bce69c16eef541a5b0726 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 27 Nov 2024 18:31:26 +0100 Subject: [PATCH 40/63] fix chp storage level check --- .../model/participant/ChpModelSpec.scala | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala index 57c0dd6725..26ea85895f 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala @@ -236,34 +236,34 @@ class ChpModelSpec "Check storage level after calculating next state with #chpState and heat demand #heatDemand kWh:" in { val testCases = Table( ("chpState", "storageLvl", "heatDemand", "expectedStoredEnergy"), - (chpStateNotRunning, 90, 0, 1035), // tests case (false, false, true) + (chpStateNotRunning, 70, 0, 805), // tests case (false, false, true) ( chpStateNotRunning, - 90, + 70, 8 * 115, - 115, + 0, ), // tests case (false, true, false) - (chpStateNotRunning, 90, 10, 1025), // tests case (false, true, true) - (chpStateRunning, 90, 0, 1135), // tests case (true, false, true) - (chpStateRunning, 90, 8 * 115, 215), // tests case (true, true, false) - (chpStateRunning, 90, 10, 1125), // tests case (true, true, true) + (chpStateNotRunning, 70, 10, 795), // tests case (false, true, true) + (chpStateRunning, 70, 0, 905), // tests case (true, false, true) + (chpStateRunning, 70, 8 * 115, 0), // tests case (true, true, false) + (chpStateRunning, 70, 10, 895), // tests case (true, true, true) ( chpStateRunning, - 90, + 70, 806, - 329, + 99, ), // test case (_, true, false) and demand covered together with chp ( chpStateRunning, - 90, + 70, 9 * 115, - 100, + 0, ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 92, + 72, 1, - 1150, + 927, ), // test case (true, true, true) and storage volume exceeds maximum ) From 88c4e24bf28e75ee37bbb059456a7ab2f0803fe4 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 27 Nov 2024 18:59:03 +0100 Subject: [PATCH 41/63] use table for testing purposes --- .../model/participant/ChpModelSpec.scala | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala index 26ea85895f..818d62d7a3 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala @@ -281,8 +281,14 @@ class ChpModelSpec } "Check time tick and running status after calculating next state with #chpState and heat demand #heatDemand kWh:" in { - val testCases = Seq( - // (ChpState, Storage Level, Heat Demand, Expected Time Tick, Expected Running Status) + val testCases = Table( + ( + "chpState", + "storageLvl", + "heatDemand", + "expectedTick", + "expectedRunningStatus", + ), ( chpStateNotRunning, 90, @@ -336,23 +342,22 @@ class ChpModelSpec ), // Test case (true, true, true) and storage volume exceeds maximum ) - for ( + forAll(testCases) { ( - chpState, - storageLvl, - heatDemand, - expectedTimeTick, - expectedRunningStatus, - ) <- testCases - ) { - val chpData = buildChpRelevantData(chpState, heatDemand) - val thermalStorage = buildThermalStorage(storageInput, storageLvl) - val chpModel = buildChpModel(thermalStorage) + chpState, + storageLvl, + heatDemand, + expectedTick, + expectedRunningStatus, + ) => + val chpData = buildChpRelevantData(chpState, heatDemand) + val thermalStorage = buildThermalStorage(storageInput, storageLvl) + val chpModel = buildChpModel(thermalStorage) - val nextState = chpModel.calculateNextState(chpData) + val nextState = chpModel.calculateNextState(chpData) - nextState.lastTimeTick shouldEqual expectedTimeTick - nextState.isRunning shouldEqual expectedRunningStatus + nextState.lastTimeTick shouldEqual expectedTick + nextState.isRunning shouldEqual expectedRunningStatus } } From 51fa462eb82489367b864f69444852239073a4c1 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 27 Nov 2024 18:59:28 +0100 Subject: [PATCH 42/63] fix ChpModelSpec --- .../model/participant/ChpModelSpec.scala | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala index 818d62d7a3..348be8b7a4 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala @@ -50,7 +50,7 @@ class ChpModelSpec val chpStateNotRunning: ChpState = ChpState(isRunning = false, 0, Kilowatts(0), KilowattHours(0)) val chpStateRunning: ChpState = - ChpState(isRunning = true, 0, Kilowatts(0), KilowattHours(0)) + ChpState(isRunning = true, 0, Kilowatts(42), KilowattHours(42)) val (storageInput, chpInput) = setupSpec() @@ -145,32 +145,32 @@ class ChpModelSpec "Check active power after calculating next state with #chpState and heat demand #heatDemand kWh:" in { val testCases = Table( ("chpState", "storageLvl", "heatDemand", "expectedActivePower"), - (chpStateNotRunning, 90, 0, 0), // tests case (false, false, true) + (chpStateNotRunning, 70, 0, 0), // tests case (false, false, true) ( chpStateNotRunning, - 90, - 8 * 115 + 230, + 70, + 8 * 115, 95, ), // tests case (false, true, false) - (chpStateNotRunning, 90, 10, 0), // tests case (false, true, true) - (chpStateRunning, 90, 0, 95), // tests case (true, false, true) - (chpStateRunning, 90, 8 * 115, 95), // tests case (true, true, false) - (chpStateRunning, 90, 10, 95), // tests case (true, true, true) + (chpStateNotRunning, 70, 10, 0), // tests case (false, true, true) + (chpStateRunning, 70, 0, 95), // tests case (true, false, true) + (chpStateRunning, 70, 8 * 115, 95), // tests case (true, true, false) + (chpStateRunning, 70, 10, 95), // tests case (true, true, true) ( chpStateRunning, - 90, + 70, 7 * 115 + 1, 95, ), // test case (_, true, false) and demand covered together with chp ( chpStateRunning, - 90, + 70, 9 * 115, 95, ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 92, + 72, 1, 95, ), // test case (true, true, true) and storage volume exceeds maximum @@ -190,34 +190,34 @@ class ChpModelSpec "Check total energy after calculating next state with #chpState and heat demand #heatDemand kWh:" in { val testCases = Table( ("chpState", "storageLvl", "heatDemand", "expectedTotalEnergy"), - (chpStateNotRunning, 90, 0, 0), // tests case (false, false, true) + (chpStateNotRunning, 70, 0, 0), // tests case (false, false, true) ( chpStateNotRunning, - 90, - 8 * 115 + 230, + 70, + 8 * 115, 100, ), // tests case (false, true, false) - (chpStateNotRunning, 90, 10, 0), // tests case (false, true, true) - (chpStateRunning, 90, 0, 100), // tests case (true, false, true) - (chpStateRunning, 90, 8 * 115, 100), // tests case (true, true, false) - (chpStateRunning, 90, 10, 100), // tests case (true, true, true) + (chpStateNotRunning, 70, 10, 0), // tests case (false, true, true) + (chpStateRunning, 70, 0, 100), // tests case (true, false, true) + (chpStateRunning, 70, 8 * 115, 100), // tests case (true, true, false) + (chpStateRunning, 70, 10, 100), // tests case (true, true, true) ( chpStateRunning, - 90, + 70, 7 * 115 + 1, 100, ), // test case (_, true, false) and demand covered together with chp ( chpStateRunning, - 90, + 70, 9 * 115, 100, ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 92, + 72, 1, - 93, + 100, ), // test case (true, true, true) and storage volume exceeds maximum ) @@ -291,51 +291,51 @@ class ChpModelSpec ), ( chpStateNotRunning, - 90, + 70, 0, 7200, false, ), // Test case (false, false, true) ( chpStateNotRunning, - 90, - 8 * 115 + 230, + 70, + 8 * 115, 7200, true, ), // Test case (false, true, false) ( chpStateNotRunning, - 90, + 70, 10, 7200, false, ), // Test case (false, true, true) - (chpStateRunning, 90, 0, 7200, true), // Test case (true, false, true) + (chpStateRunning, 70, 0, 7200, true), // Test case (true, false, true) ( chpStateRunning, - 90, + 70, 8 * 115, 7200, true, ), // Test case (true, true, false) - (chpStateRunning, 90, 10, 7200, true), // Test case (true, true, true) + (chpStateRunning, 70, 10, 7200, true), // Test case (true, true, true) ( chpStateRunning, - 90, + 70, 806, 7200, true, ), // Test case (_, true, false) and demand covered together with chp ( chpStateRunning, - 90, + 70, 9 * 115, 7200, true, ), // Test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 92, + 72, 1, 7200, false, From 42105bd106a9c76b36a15531a0bdd513619b8430 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 27 Nov 2024 19:11:32 +0100 Subject: [PATCH 43/63] hopefully final fix for ChpModelSpec --- .../simona/model/participant/ChpModelSpec.scala | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala index 348be8b7a4..c664788dae 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala @@ -170,7 +170,7 @@ class ChpModelSpec ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 72, + 92, 1, 95, ), // test case (true, true, true) and storage volume exceeds maximum @@ -215,9 +215,9 @@ class ChpModelSpec ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 72, + 92, 1, - 100, + 93, ), // test case (true, true, true) and storage volume exceeds maximum ) @@ -261,9 +261,9 @@ class ChpModelSpec ), // test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 72, + 92, 1, - 927, + 1150, ), // test case (true, true, true) and storage volume exceeds maximum ) @@ -289,7 +289,7 @@ class ChpModelSpec "expectedTick", "expectedRunningStatus", ), - ( + ( chpStateNotRunning, 70, 0, @@ -335,7 +335,7 @@ class ChpModelSpec ), // Test case (_, true, false) and demand not covered together with chp ( chpStateRunning, - 72, + 92, 1, 7200, false, From ef8556b96e954ef5b2d8626cac6a0e50326cae85 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 11 Dec 2024 15:57:25 +0100 Subject: [PATCH 44/63] fmt --- .../scala/edu/ie3/simona/model/participant/ChpModelSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala index 26eb66e314..8a43b3c6ff 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/ChpModelSpec.scala @@ -289,7 +289,7 @@ class ChpModelSpec "expectedTick", "expectedRunningStatus", ), - ( + ( chpStateNotRunning, 70, 0, From 9887c4768246ac60cdee6b88b8543f82814190c5 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 14 Jan 2025 15:28:37 +0100 Subject: [PATCH 45/63] fmt --- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 0aa6a7c979..eb381f055c 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -184,7 +184,7 @@ final case class ThermalGrid( qDot, ) - /** Handles the case, when a grid has infeed. Depending which entity has some + /** Handles the case, when a grid has infeed. Depending on which entity has some * heat demand the house or the storage will be heated up / filled up. * * @param relevantData From ee6e326ff9e3ad48176ada21688bbfc817668eec Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 14 Jan 2025 15:46:07 +0100 Subject: [PATCH 46/63] correctly name thermalGridState --- .../simona/model/thermal/ThermalGrid.scala | 88 ++++++++++--------- 1 file changed, 46 insertions(+), 42 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 eb381f055c..0cb8acf615 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -147,8 +147,8 @@ final case class ThermalGrid( * * @param relevantData * data of heat pump including state of the heat pump - * @param state - * Currently applicable state + * @param lastThermalGridState + * state of the thermalGrid until this tick * @param lastAmbientTemperature * Ambient temperature valid up until (not including) the current tick * @param isRunning @@ -162,7 +162,7 @@ final case class ThermalGrid( */ def updateState( relevantData: HpRelevantData, - state: ThermalGridState, + lastThermalGridState: ThermalGridState, lastAmbientTemperature: Temperature, isRunning: Boolean, qDot: Power, @@ -171,7 +171,7 @@ final case class ThermalGrid( handleInfeed( relevantData, lastAmbientTemperature, - state, + lastThermalGridState, isRunning, qDot, thermalDemands, @@ -180,7 +180,7 @@ final case class ThermalGrid( handleConsumption( relevantData, lastAmbientTemperature, - state, + lastThermalGridState, qDot, ) @@ -191,8 +191,8 @@ final case class ThermalGrid( * data of heat pump including state of the heat pump * @param lastAmbientTemperature * Ambient temperature valid up until (not including) the current tick - * @param thermalGridState - * Current state of the thermal Grid + * @param lastThermalGridState + * state of the thermalGrid until this tick * @param isRunning * determines whether the heat pump is running or not * @param qDot @@ -205,7 +205,7 @@ final case class ThermalGrid( private def handleInfeed( relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - thermalGridState: ThermalGridState, + lastThermalGridState: ThermalGridState, isRunning: Boolean, qDot: Power, thermalDemands: ThermalDemandWrapper, @@ -213,17 +213,19 @@ final case class ThermalGrid( // TODO: We would need to issue a storage result model here... /* Consider the action in the last state */ - val (qDotHouseLastState, qDotStorageLastState) = thermalGridState match { - case ThermalGridState(Some(houseState), Some(storageState)) => - (houseState.qDot, storageState.qDot) - case ThermalGridState(Some(houseState), None) => (houseState.qDot, zeroKW) - case ThermalGridState(None, Some(storageState)) => - (zeroKW, storageState.qDot) - case _ => - throw new InconsistentStateException( - "There should be at least a house or a storage state." - ) - } + val (qDotHouseLastState, qDotStorageLastState) = + lastThermalGridState match { + case ThermalGridState(Some(houseState), Some(storageState)) => + (houseState.qDot, storageState.qDot) + case ThermalGridState(Some(houseState), None) => + (houseState.qDot, zeroKW) + case ThermalGridState(None, Some(storageState)) => + (zeroKW, storageState.qDot) + case _ => + throw new InconsistentStateException( + "There should be at least a house or a storage state." + ) + } if ( (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW && thermalDemands.heatStorageDemand.hasAdditionalDemand) @@ -232,7 +234,7 @@ final case class ThermalGrid( handleInfeedHouse( relevantData, lastAmbientTemperature, - thermalGridState, + lastThermalGridState, qDotHouseLastState, ) val (updatedStorageState, thermalStorageThreshold) = @@ -241,13 +243,13 @@ final case class ThermalGrid( ) { handleInfeedStorage( relevantData.currentTick, - thermalGridState, + lastThermalGridState, remainingQDotHouse, ) } else { handleInfeedStorage( relevantData.currentTick, - thermalGridState, + lastThermalGridState, qDotStorageLastState, ) } @@ -257,7 +259,7 @@ final case class ThermalGrid( thermalStorageThreshold, ) ( - thermalGridState.copy( + lastThermalGridState.copy( houseState = updatedHouseState, storageState = updatedStorageState, ), @@ -270,7 +272,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - thermalGridState, + lastThermalGridState, qDot, zeroKW, ) @@ -279,7 +281,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - thermalGridState, + lastThermalGridState, qDotHouseLastState, qDotStorageLastState, ) @@ -290,7 +292,7 @@ final case class ThermalGrid( handleCases( relevantData, lastAmbientTemperature, - thermalGridState, + lastThermalGridState, qDot, -qDot, ) @@ -299,7 +301,7 @@ final case class ThermalGrid( thermalDemands, relevantData, lastAmbientTemperature, - thermalGridState, + lastThermalGridState, qDot, ) } @@ -570,8 +572,8 @@ final case class ThermalGrid( * data of heat pump including state of the heat pump * @param lastAmbientTemperature * Ambient temperature valid up until (not including) the current tick - * @param state - * Current state of the houses + * @param lastThermalGridState + * state of the thermalGrid until this tick * @param qDot * Infeed to the grid * @return @@ -580,24 +582,26 @@ final case class ThermalGrid( private def handleConsumption( relevantData: HpRelevantData, lastAmbientTemperature: Temperature, - state: ThermalGridState, + lastThermalGridState: ThermalGridState, qDot: Power, ): (ThermalGridState, Option[ThermalThreshold]) = { /* House will be left with no influx in all cases. Determine if and when a threshold is reached */ val maybeUpdatedHouseState = - house.zip(state.houseState).map { case (house, houseState) => - house.determineState( - relevantData, - houseState, - lastAmbientTemperature, - zeroMW, - ) + house.zip(lastThermalGridState.houseState).map { + case (house, houseState) => + house.determineState( + relevantData, + houseState, + lastAmbientTemperature, + zeroMW, + ) } /* Update the state of the storage */ val maybeUpdatedStorageState = - storage.zip(state.storageState).map { case (storage, storageState) => - storage.updateState(relevantData.currentTick, qDot, storageState) + storage.zip(lastThermalGridState.storageState).map { + case (storage, storageState) => + storage.updateState(relevantData.currentTick, qDot, storageState) } val (revisedHouseState, revisedStorageState) = @@ -605,8 +609,8 @@ final case class ThermalGrid( relevantData, maybeUpdatedHouseState, maybeUpdatedStorageState, - state.houseState, - state.storageState, + lastThermalGridState.houseState, + lastThermalGridState.storageState, lastAmbientTemperature, qDot, ) @@ -617,7 +621,7 @@ final case class ThermalGrid( ) ( - state.copy( + lastThermalGridState.copy( houseState = revisedHouseState.map(_._1), storageState = revisedStorageState.map(_._1), ), From 35f601f42c1b45dcbcaf8c7f250e8dcd7cecb24d Mon Sep 17 00:00:00 2001 From: Daniel Feismann <98817556+danielfeismann@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:48:46 +0100 Subject: [PATCH 47/63] Apply suggestions from code review Co-authored-by: Sebastian Peter --- .../ie3/simona/model/thermal/ThermalGrid.scala | 15 ++++----------- 1 file changed, 4 insertions(+), 11 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 0aa6a7c979..fb61c3ff1a 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -213,17 +213,10 @@ final case class ThermalGrid( // TODO: We would need to issue a storage result model here... /* Consider the action in the last state */ - val (qDotHouseLastState, qDotStorageLastState) = thermalGridState match { - case ThermalGridState(Some(houseState), Some(storageState)) => - (houseState.qDot, storageState.qDot) - case ThermalGridState(Some(houseState), None) => (houseState.qDot, zeroKW) - case ThermalGridState(None, Some(storageState)) => - (zeroKW, storageState.qDot) - case _ => - throw new InconsistentStateException( - "There should be at least a house or a storage state." - ) - } + val qDotHouseLastState = + thermalGridState.houseState.map(_.qDot).getOrElse(zeroKW) + val qDotStorageLastState = + thermalGridState.storageState.map(_.qDot).getOrElse(zeroKW) if ( (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW && thermalDemands.heatStorageDemand.hasAdditionalDemand) From 83866d33a5c9d176e8e4ada9ceadf27e076aabaa Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 14 Jan 2025 16:40:30 +0100 Subject: [PATCH 48/63] split cases and handle another edge case --- .../ie3/simona/model/thermal/ThermalGrid.scala | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 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 5fe427aba6..2f5c0db49c 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -218,9 +218,15 @@ final case class ThermalGrid( val qDotStorageLastState = lastThermalGridState.storageState.map(_.qDot).getOrElse(zeroKW) + // We can use the qDots from lastState to keep continuity. If... if ( - (qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW)) | (qDotStorageLastState > zeroKW && thermalDemands.heatStorageDemand.hasAdditionalDemand) + // ... house was heated in lastState but not from Storage and has still some demand. + ((qDotHouseLastState > zeroKW && (qDotStorageLastState >= zeroKW) && thermalDemands.houseDemand.hasAdditionalDemand) || + // ... storage was filled up in the lastState and has still additional demand + // But only if the house not reached some requiredDemand. + qDotStorageLastState > zeroKW && thermalDemands.heatStorageDemand.hasAdditionalDemand && !thermalDemands.houseDemand.hasRequiredDemand) ) { + // We can continue for the house val (updatedHouseState, thermalHouseThreshold, remainingQDotHouse) = handleInfeedHouse( relevantData, @@ -228,10 +234,11 @@ final case class ThermalGrid( lastThermalGridState, qDotHouseLastState, ) - val (updatedStorageState, thermalStorageThreshold) = - if ( - qDotStorageLastState >= zeroKW && remainingQDotHouse > qDotStorageLastState - ) { + + // ...and for the storage + val (updatedStorageState, thermalStorageThreshold) = { + // In case the ThermalHouse could not handle the infeed it will be used for the storage. + if (remainingQDotHouse > qDotStorageLastState) { handleInfeedStorage( relevantData.currentTick, lastThermalGridState, @@ -244,6 +251,7 @@ final case class ThermalGrid( qDotStorageLastState, ) } + } val nextThreshold = determineMostRecentThreshold( thermalHouseThreshold, From c34a83bae18555d9a7c0bc69e3e428f67042493c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 14 Jan 2025 16:40:55 +0100 Subject: [PATCH 49/63] some comments for the cases --- .../ie3/simona/model/thermal/ThermalGrid.scala | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 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 2f5c0db49c..24218b2aa8 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -184,8 +184,12 @@ final case class ThermalGrid( qDot, ) - /** Handles the case, when a grid has infeed. Depending on which entity has some - * heat demand the house or the storage will be heated up / filled up. + /** Handles the case, when a grid has infeed. Depending on which entity has + * some heat demand the house or the storage will be heated up / filled up. + * First the actions from lastState will be considered and checked if the + * behaviour should be continued. This might be the case, if we got activated + * by updated weather data. If this is not the case, all other cases will be + * handled by [[ThermalGrid.handleFinalInfeedCases]] * * @param relevantData * data of heat pump including state of the heat pump @@ -265,8 +269,9 @@ final case class ThermalGrid( nextThreshold, ) } - // Handle edge case where house was heated from storage and HP will be activated in between + // Handle edge case where house was heated from storage... else if (qDotHouseLastState > zeroKW && qDotStorageLastState < zeroKW) { + // ...and HP gets activated in current tick if (isRunning) { handleCases( relevantData, @@ -276,7 +281,7 @@ final case class ThermalGrid( zeroKW, ) } else { - + // ... or continue lastState's behaviour handleCases( relevantData, lastAmbientTemperature, @@ -295,7 +300,9 @@ final case class ThermalGrid( qDot, -qDot, ) - } else + } + // or finally check for all other cases. + else handleFinalInfeedCases( thermalDemands, relevantData, From 6229c18e666e9a5abce084dd0e1e686b6343684e Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Tue, 14 Jan 2025 17:12:58 +0100 Subject: [PATCH 50/63] some more comments and rename of variables for better understanding --- .../simona/model/participant/HpModel.scala | 4 +- .../simona/model/thermal/ThermalGrid.scala | 42 ++++++++++--------- .../simona/model/thermal/ThermalHouse.scala | 2 +- 3 files changed, 25 insertions(+), 23 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 17298208c6..817b883b92 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -406,9 +406,9 @@ object HpModel { * @param ambientTemperature * Optional ambient temperature, if available * @param activePower - * result active power + * result active power of heat pump * @param qDot - * result heat power + * result heat power of heat pump * @param thermalGridState * applicable state of the thermal grid * @param maybeThermalThreshold 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 24218b2aa8..1717c2858e 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -154,7 +154,7 @@ final case class ThermalGrid( * @param isRunning * determines whether the heat pump is running or not * @param qDot - * Thermal energy balance + * Infeed to the grid from thermal generation (e.g. heat pump) * @param thermalDemands * holds the thermal demands of the thermal units (house, storage) * @return @@ -200,7 +200,7 @@ final case class ThermalGrid( * @param isRunning * determines whether the heat pump is running or not * @param qDot - * Infeed to the grid + * Infeed to the grid from thermal generation (e.g. heat pump) * @param thermalDemands * holds the thermal demands of the thermal units (house, storage) * @return @@ -352,7 +352,7 @@ final case class ThermalGrid( * @param gridState * Current state of the thermalGrid * @param qDot - * Infeed to the grid + * Infeed to the grid from thermal generation (e.g. heat pump) * @return * Updated thermal grid state and the thermalThreshold if there is one */ @@ -371,7 +371,7 @@ final case class ThermalGrid( ) match { case (true, _, _, _) => - // house first then heatStorage after heating House + // house first handleCases( relevantData, lastAmbientTemperature, @@ -379,7 +379,7 @@ final case class ThermalGrid( qDot, zeroKW, ) - + // then heatStorage after heating House case (_, _, true, _) => handleCases( relevantData, @@ -388,7 +388,7 @@ final case class ThermalGrid( zeroKW, qDot, ) - + // charge storage if house has no requiredDemand case (false, _, false, true) => handleCases( relevantData, @@ -397,7 +397,7 @@ final case class ThermalGrid( zeroKW, qDot, ) - + // heat house if storage has no additionalDemand case (_, true, false, false) => handleCases( relevantData, @@ -406,7 +406,7 @@ final case class ThermalGrid( qDot, zeroKW, ) - + // if there is no demand, don't heat anything case (false, false, false, false) => handleCases( relevantData, @@ -434,7 +434,8 @@ final case class ThermalGrid( * @param qDotHouse * Infeed to the house * @param qDotHeatStorage - * Infeed to the heat storage + * Infeed to the heat storage (positive: Storage is charging, negative: + * Storage is discharging) * @return * Updated thermal grid state and the next threshold if there is one */ @@ -479,8 +480,8 @@ final case class ThermalGrid( * Ambient temperature until this tick * @param state * Current state of the houses - * @param qDot - * Infeed to the grid + * @param qDotHouse + * Infeed into the house * @return * Updated thermal house state, a ThermalThreshold and the remaining qDot */ @@ -488,7 +489,7 @@ final case class ThermalGrid( relevantData: HpRelevantData, lastAmbientTemperature: Temperature, state: ThermalGridState, - qDot: Power, + qDotHouse: Power, ): (Option[ThermalHouseState], Option[ThermalThreshold], Power) = { (house, state.houseState) match { case (Some(thermalHouse), Some(lastHouseState)) => @@ -496,7 +497,7 @@ final case class ThermalGrid( relevantData, lastHouseState, lastAmbientTemperature, - qDot, + qDotHouse, ) /* Check if house can handle the thermal feed in */ if ( @@ -511,7 +512,7 @@ final case class ThermalGrid( lastAmbientTemperature, zeroKW, ) - (Some(fullHouseState), maybeFullHouseThreshold, qDot) + (Some(fullHouseState), maybeFullHouseThreshold, qDotHouse) } else { (Some(newState), threshold, zeroKW) } @@ -526,21 +527,22 @@ final case class ThermalGrid( * Current tick * @param state * Current state of the houses - * @param qDot - * Infeed to the grid + * @param qDotStorage + * Infeed to the storage (positive: Storage is charging, negative: Storage + * is discharging) * @return * Updated thermal grid state */ private def handleInfeedStorage( tick: Long, state: ThermalGridState, - qDot: Power, + qDotStorage: Power, ): (Option[ThermalStorageState], Option[ThermalThreshold]) = { (storage, state.storageState) match { case (Some(thermalStorage), Some(lastStorageState)) => val (newState, threshold) = thermalStorage.updateState( tick, - qDot, + qDotStorage, lastStorageState, ) (Some(newState), threshold) @@ -581,7 +583,7 @@ final case class ThermalGrid( * @param lastThermalGridState * state of the thermalGrid until this tick * @param qDot - * Infeed to the grid + * Infeed to the grid from thermal generation (e.g. heat pump) * @return * Updated thermal grid state */ @@ -653,7 +655,7 @@ final case class ThermalGrid( * @param lastAmbientTemperature * Ambient temperature valid up until (not including) the current tick * @param qDot - * Thermal influx + * Infeed to the grid from thermal generation (e.g. heat pump) * @return * Options to revised thermal house and storage state */ diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalHouse.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalHouse.scala index 4296efa1ae..a8c2e347d1 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalHouse.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalHouse.scala @@ -374,7 +374,7 @@ object ThermalHouse { * @param innerTemperature * Inner temperature of the house * @param qDot - * Continuous infeed of thermal energy since the given tick + * Continuous external infeed of thermal energy since the given tick */ final case class ThermalHouseState( tick: Long, From b7bb639ece021c4ba9cff8e6c145ecae8d93fd60 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 16 Jan 2025 13:00:04 +0100 Subject: [PATCH 51/63] fix ThermalGridSpec --- .../ie3/simona/model/thermal/ThermalGridSpec.scala | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala index b259529471..375a0c09e9 100644 --- a/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/thermal/ThermalGridSpec.scala @@ -6,7 +6,6 @@ package edu.ie3.simona.model.thermal -import edu.ie3.simona.exceptions.InvalidParameterException import edu.ie3.datamodel.models.input.thermal.ThermalStorageInput import edu.ie3.simona.model.thermal.ThermalGrid.ThermalEnergyDemand import edu.ie3.simona.test.common.UnitSpec @@ -33,7 +32,7 @@ class ThermalGridSpec intercept[InvalidParameterException] { ThermalEnergyDemand(required, possible) - }.getMessage shouldBe s"The possible amount of energy {$possible} is smaller than the required amount of energy {$required}. This is not supported." + }.getMessage shouldBe s"The possible amount of energy $possible is smaller than the required amount of energy $required. This is not supported." } "set the correct values, if they are sensible" in { @@ -80,7 +79,7 @@ class ThermalGridSpec val possible = MegawattHours(0d) intercept[InvalidParameterException] { ThermalEnergyDemand(required, possible) - }.getMessage shouldBe s"The possible amount of energy {$possible} is smaller than the required amount of energy {$required}. This is not supported." + }.getMessage shouldBe s"The possible amount of energy $possible is smaller than the required amount of energy $required. This is not supported." } "throw exception, if required demand is smaller than zero" in { @@ -88,7 +87,7 @@ class ThermalGridSpec val possible = MegawattHours(5d) intercept[InvalidParameterException] { ThermalEnergyDemand(required, possible) - }.getMessage shouldBe s"The possible {$possible} or required {$required} amount of energy is smaller than zero. This is not supported." + }.getMessage shouldBe s"The possible $possible or required $required amount of energy cannot be negative. This is not supported." } "throw exception, if possible demand is smaller than zero" in { @@ -96,7 +95,7 @@ class ThermalGridSpec val possible = MegawattHours(-5d) intercept[InvalidParameterException] { ThermalEnergyDemand(required, possible) - }.getMessage shouldBe s"The possible {$possible} or required {$required} amount of energy is smaller than zero. This is not supported." + }.getMessage shouldBe s"The possible $possible or required $required amount of energy cannot be negative. This is not supported." } "throw exception, if possible and required demand are smaller than zero" in { @@ -104,7 +103,7 @@ class ThermalGridSpec val possible = MegawattHours(-5d) intercept[InvalidParameterException] { ThermalEnergyDemand(required, possible) - }.getMessage shouldBe s"The possible {$possible} or required {$required} amount of energy is smaller than zero. This is not supported." + }.getMessage shouldBe s"The possible $possible or required $required amount of energy cannot be negative. This is not supported." } "return proper information, if required and additional demand is apparent" in { From fb5ee23f95c64b0bd53f61f8d618c1a23b15bbd7 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Mon, 3 Feb 2025 18:13:34 +0100 Subject: [PATCH 52/63] fix tests after merging dev --- .../edu/ie3/simona/agent/em/EmAgentIT.scala | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala index 630f17575d..599fe4aa4b 100644 --- a/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala +++ b/src/test/scala/edu/ie3/simona/agent/em/EmAgentIT.scala @@ -695,26 +695,6 @@ class EmAgentIT emResult.getQ should equalWithTolerance(0.000088285537.asMegaVar) } - scheduler.expectMessage(Completion(emAgentActivation, Some(28665))) - - /* TICK 28666 - LOAD: 0.269 kW (unchanged) - PV: -0.026 kW (unchanged) - Heat pump: Is turned on again and cannot be turned off - -> flex signal is no control -> 0.00485 MW - -> remaining 5.092 kW - */ - - emAgentActivation ! 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.005092284024.asMegaWatt) - emResult.getQ should equalWithTolerance(0.001073120040.asMegaVar) - } - scheduler.expectMessage(Completion(emAgentActivation, Some(28800))) } } From 6a9c2c31cff293381be2954438344080b2786ff5 Mon Sep 17 00:00:00 2001 From: Sebastian Peter Date: Tue, 4 Feb 2025 15:53:00 +0100 Subject: [PATCH 53/63] Proposed simplification for infeed cases Signed-off-by: Sebastian Peter --- .../simona/model/thermal/ThermalGrid.scala | 108 +++++++----------- 1 file changed, 43 insertions(+), 65 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 9797e769fa..666ecfbda7 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -336,14 +336,13 @@ final case class ThermalGrid( * | false | false | false | true | false | true | * | false | false | false | false | false | false | * - * This can be simplified to five cases - * | No | Conditions | Result | - * |:---|:-------------------------------------------------------------------------|:----------| - * | 1 | if(house.reqD) => house | house | - * | 2 | if(!house.reqD && !storage.reqD) => storage | storage | - * | 3 | if(!house.reqD && !storage.reqD && storage.addD) => storage | storage | - * | 4 | if(!house.reqD && house.addD && !storage.reqD && !storage.addD) => house | house | - * | 5 | if(all == false) => no output | no output | + * This can be simplified to four cases + * | No | Conditions | Result | + * |:---|:-------------------------------------|:----------| + * | 1 | if house.reqD | house | + * | 2 | else if storage.reqD OR storage.addD | storage | + * | 3 | else if house.addD | house | + * | 4 | else | no output | * * @param thermalDemands * holds the thermal demands of the thermal units (house, storage) @@ -365,63 +364,42 @@ final case class ThermalGrid( gridState: ThermalGridState, qDot: Power, ): (ThermalGridState, Option[ThermalThreshold]) = { - ( - thermalDemands.houseDemand.hasRequiredDemand, - thermalDemands.houseDemand.hasAdditionalDemand, - thermalDemands.heatStorageDemand.hasRequiredDemand, - thermalDemands.heatStorageDemand.hasAdditionalDemand, - ) match { - - case (true, _, _, _) => - // house first - handleCases( - relevantData, - lastAmbientTemperature, - gridState, - qDot, - zeroKW, - ) - // then heatStorage after heating House - case (_, _, true, _) => - handleCases( - relevantData, - lastAmbientTemperature, - gridState, - zeroKW, - qDot, - ) - // charge storage if house has no requiredDemand - case (false, _, false, true) => - handleCases( - relevantData, - lastAmbientTemperature, - gridState, - zeroKW, - qDot, - ) - // heat house if storage has no additionalDemand - case (_, true, false, false) => - handleCases( - relevantData, - lastAmbientTemperature, - gridState, - qDot, - zeroKW, - ) - // if there is no demand, don't heat anything - case (false, false, false, false) => - handleCases( - relevantData, - lastAmbientTemperature, - gridState, - zeroKW, - zeroKW, - ) - case _ => - throw new InconsistentStateException( - "There should be at least a house or a storage state." - ) - } + + if (thermalDemands.houseDemand.hasRequiredDemand) + handleCases( + relevantData, + lastAmbientTemperature, + gridState, + qDot, + zeroKW, + ) + else if ( + thermalDemands.heatStorageDemand.hasRequiredDemand || thermalDemands.heatStorageDemand.hasAdditionalDemand + ) + handleCases( + relevantData, + lastAmbientTemperature, + gridState, + zeroKW, + qDot, + ) + else if (thermalDemands.houseDemand.hasAdditionalDemand) + handleCases( + relevantData, + lastAmbientTemperature, + gridState, + qDot, + zeroKW, + ) + else + handleCases( + relevantData, + lastAmbientTemperature, + gridState, + zeroKW, + zeroKW, + ) + } /** Handles the different cases, of thermal flows from and into the thermal From 17c492baf3ced1b10fc2dce8029b6c564ec09aab Mon Sep 17 00:00:00 2001 From: Sebastian Peter Date: Tue, 4 Feb 2025 16:00:59 +0100 Subject: [PATCH 54/63] ScalaDoc fix Signed-off-by: Sebastian Peter --- src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 666ecfbda7..21c6fe60c9 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -501,7 +501,7 @@ final case class ThermalGrid( } /** 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 + * here (positive qDot) or will return its stored energy into the thermal * grid (negative qDot). * @param tick * Current tick From 0b6599c0a4e4422d61bedc2ec92cc22cc4708090 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 5 Feb 2025 09:52:26 +0100 Subject: [PATCH 55/63] renaming handleInfeedStorage to handleStorageCases --- .../scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 8 ++++---- 1 file changed, 4 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 9797e769fa..6c7e572c87 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -245,13 +245,13 @@ final case class ThermalGrid( val (updatedStorageState, thermalStorageThreshold) = { // In case the ThermalHouse could not handle the infeed it will be used for the storage. if (remainingQDotHouse > qDotStorageLastState) { - handleInfeedStorage( + handleStorageCases( relevantData.currentTick, lastThermalGridState, remainingQDotHouse, ) } else { - handleInfeedStorage( + handleStorageCases( relevantData.currentTick, lastThermalGridState, qDotStorageLastState, @@ -457,7 +457,7 @@ final case class ThermalGrid( ) val (updatedStorageState, thermalStorageThreshold) = - handleInfeedStorage(relevantData.currentTick, state, qDotHeatStorage) + handleStorageCases(relevantData.currentTick, state, qDotHeatStorage) val nextThreshold = determineMostRecentThreshold( thermalHouseThreshold, @@ -535,7 +535,7 @@ final case class ThermalGrid( * @return * Updated thermal grid state */ - private def handleInfeedStorage( + private def handleStorageCases( tick: Long, state: ThermalGridState, qDotStorage: Power, From 4e2f49df86663bae244214a0225fd961cdf8fbd8 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 5 Feb 2025 10:48:17 +0100 Subject: [PATCH 56/63] update scalaDoc regarding qDot --- .../ie3/simona/model/thermal/ThermalGrid.scala | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 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 4daa15eefc..b237fb2004 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -156,7 +156,8 @@ final case class ThermalGrid( * @param isRunning * determines whether the heat pump is running or not * @param qDot - * Infeed to the grid from thermal generation (e.g. heat pump) + * Infeed to the grid from thermal generation (e.g. heat pump) or thermal + * storages * @param thermalDemands * holds the thermal demands of the thermal units (house, storage) * @return @@ -202,7 +203,8 @@ final case class ThermalGrid( * @param isRunning * determines whether the heat pump is running or not * @param qDot - * Infeed to the grid from thermal generation (e.g. heat pump) + * Infeed to the grid from thermal generation (e.g. heat pump) or thermal + * storages * @param thermalDemands * holds the thermal demands of the thermal units (house, storage) * @return @@ -353,7 +355,8 @@ final case class ThermalGrid( * @param gridState * Current state of the thermalGrid * @param qDot - * Infeed to the grid from thermal generation (e.g. heat pump) + * Infeed to the grid from thermal generation (e.g. heat pump) or thermal + * storages * @return * Updated thermal grid state and the thermalThreshold if there is one */ @@ -563,7 +566,8 @@ final case class ThermalGrid( * @param lastThermalGridState * state of the thermalGrid until this tick * @param qDot - * Infeed to the grid from thermal generation (e.g. heat pump) + * Infeed to the grid from thermal generation (e.g. heat pump) or thermal + * storages * @return * Updated thermal grid state */ @@ -635,7 +639,8 @@ final case class ThermalGrid( * @param lastAmbientTemperature * Ambient temperature valid up until (not including) the current tick * @param qDot - * Infeed to the grid from thermal generation (e.g. heat pump) + * Infeed to the grid from thermal generation (e.g. heat pump) or thermal + * storages * @return * Options to revised thermal house and storage state */ From 4ce951f6cf6ebe2c008739755bc9e7bdeb83c558 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 5 Feb 2025 12:34:40 +0100 Subject: [PATCH 57/63] distinguish between thermalPower of Hp and qDot into grid to avoid checking for conditions within HpModel.calculateHeat --- .../simona/model/participant/HpModel.scala | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 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 817b883b92..d070b007ab 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -113,11 +113,7 @@ final case class HpModel( currentState: HpState, data: HpRelevantData, ): Power = - // only if Hp is running qDot will be from Hp, else qDot results from other source, e.g. some storage - if (currentState.isRunning) - currentState.qDot - else - zeroKW + currentState.qDot /** Given a [[HpRelevantData]] object and the last [[HpState]], this function * calculates the heat pump's next state to get the actual active power of @@ -232,19 +228,20 @@ final case class HpModel( .map(_.qDot) .getOrElse(zeroKW) - val (newActivePower, newThermalPower) = { + val (newActivePowerHp, newThermalPowerHp, qDotIntoGrid) = { if (isRunning) - (pRated, pThermal) + (pRated, pThermal, pThermal) else if (lastStateStorageQDot < zeroKW) - (zeroKW, lastStateStorageQDot * (-1)) + (zeroKW, zeroKW, lastStateStorageQDot * (-1)) else if ( lastStateStorageQDot == zeroKW && (demandWrapper.houseDemand.hasRequiredDemand || demandWrapper.heatStorageDemand.hasRequiredDemand) ) ( + zeroKW, zeroKW, thermalGrid.storage.map(_.getChargingPower: squants.Power).get, ) - else (zeroKW, zeroKW) + else (zeroKW, zeroKW, zeroKW) } /* Push thermal energy to the thermal grid and get its updated state in return */ @@ -254,7 +251,7 @@ final case class HpModel( lastState.thermalGridState, lastState.ambientTemperature.getOrElse(relevantData.ambientTemperature), isRunning, - newThermalPower, + qDotIntoGrid, demandWrapper, ) @@ -262,8 +259,8 @@ final case class HpModel( isRunning, relevantData.currentTick, Some(relevantData.ambientTemperature), - newActivePower, - newThermalPower, + newActivePowerHp, + newThermalPowerHp, thermalGridState, maybeThreshold, ) From f48ad51f4f2b58d60ba3d35833f9632b0f7b00ba Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 5 Feb 2025 12:35:14 +0100 Subject: [PATCH 58/63] clearer naming of state --- src/main/scala/edu/ie3/simona/model/participant/HpModel.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 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 d070b007ab..a721241f25 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -149,9 +149,9 @@ final case class HpModel( ) // Updating the HpState - val updatedState = + val updatedHpState = calcState(lastHpState, relevantData, turnOn, thermalDemandWrapper) - (canOperate, canBeOutOfOperation, updatedState) + (canOperate, canBeOutOfOperation, updatedHpState) } /** Depending on the input, this function decides whether the heat pump will From b1a188f44e45027d89dbcd3b249e8c409e79b17c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 5 Feb 2025 12:44:05 +0100 Subject: [PATCH 59/63] Enhance ScalaDoc for clearer understanding of required thermalDemand for storages --- .../scala/edu/ie3/simona/model/thermal/ThermalGrid.scala | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 b237fb2004..c506e44cfd 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala @@ -820,7 +820,11 @@ object ThermalGrid { * than or equal to the absolutely required energy. Thus, this class can only * be instantiated via factory. * @param required - * The absolutely required energy to reach target state + * The absolutely required energy to reach target state. For + * [[ThermalHouse]] this would be the energy demand to reach the boundary + * or targetTemperature. For [[ThermalStorage]] this would be the amount of + * energy to get fully charged when empty. If the [[ThermalStorage]] is not + * empty, the required energy is zero. * @param possible * The maximum possible energy, that can be handled */ From 0af10b3a7769540e35121ce7448e804afacc5b85 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Wed, 5 Feb 2025 12:44:54 +0100 Subject: [PATCH 60/63] Add ScalaDoc ThermalStorageState --- .../ie3/simona/model/thermal/ThermalStorage.scala | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala index c7818351b6..de515346ce 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala @@ -73,6 +73,18 @@ abstract class ThermalStorage( } object ThermalStorage { + + /** State of a thermal storage + * + * @param tick + * Last tick of storage state change + * @param storedEnergy + * Energy stored in the storage at this tick + * @param qDot + * Infeed to the heat storage (positive: Storage is charging, negative: + * Storage is discharging) + */ + final case class ThermalStorageState( tick: Long, storedEnergy: Energy, From 37c934201288494100637b030c922f9bddf20431 Mon Sep 17 00:00:00 2001 From: Sebastian Peter Date: Thu, 6 Feb 2025 10:50:39 +0100 Subject: [PATCH 61/63] `OperationInterval` extends `RightOpenInterval` Signed-off-by: Sebastian Peter --- CHANGELOG.md | 1 + .../ie3/util/scala/OperationInterval.scala | 27 +++---------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb4710583..d0f4f89d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -123,6 +123,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rewrote PvModelIT from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - Fix negative required energy demand for thermalHouse [#1127](https://github.com/ie3-institute/simona/issues/1127) - Refactored EM messages [#1138](https://github.com/ie3-institute/simona/issues/1138) +- `OperationInterval` should extend `RightOpenInterval` [#1142](https://github.com/ie3-institute/simona/issues/1142) ### Fixed - Fix rendering of references in documentation [#505](https://github.com/ie3-institute/simona/issues/505) diff --git a/src/main/scala/edu/ie3/util/scala/OperationInterval.scala b/src/main/scala/edu/ie3/util/scala/OperationInterval.scala index 880f441460..fe80870ac0 100644 --- a/src/main/scala/edu/ie3/util/scala/OperationInterval.scala +++ b/src/main/scala/edu/ie3/util/scala/OperationInterval.scala @@ -6,34 +6,15 @@ package edu.ie3.util.scala -import edu.ie3.util.interval.ClosedInterval +import edu.ie3.util.interval.RightOpenInterval /** Wrapper class for an operation interval, as the superclass - * [[ClosedInterval]] only accepts [[java.lang.Long]] as type parameter + * [[RightOpenInterval]] only accepts [[java.lang.Long]] as type parameter * * @param start * Start of operation period (included) * @param end * End of operation period (included) */ -final case class OperationInterval(start: java.lang.Long, end: java.lang.Long) - extends ClosedInterval[java.lang.Long](start, end) { - - /** Get the first tick, in which the operation starts - * - * @return - * Tick, in which operation starts - */ - def getStart: Long = getLower - - /** Get the last tick, in which the operation end - * - * @return - * Tick, in which operation end - */ - def getEnd: Long = getUpper -} - -object OperationInterval { - def apply(start: Long, end: Long) = new OperationInterval(start, end) -} +final case class OperationInterval(start: Long, end: Long) + extends RightOpenInterval[java.lang.Long](start, end) From 0f71336be56010e08bed5383dd3aa1565817bf3c Mon Sep 17 00:00:00 2001 From: Sebastian Peter Date: Thu, 6 Feb 2025 12:24:26 +0100 Subject: [PATCH 62/63] Moving `ScheduleServiceActivation` to its right place Signed-off-by: Sebastian Peter --- CHANGELOG.md | 1 + src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala | 8 ++++---- .../ontology/messages/services/ServiceMessage.scala | 9 +++++---- .../scala/edu/ie3/simona/service/SimonaService.scala | 10 ++++++---- .../scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala | 2 +- 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb4710583..d8aac87b56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -168,6 +168,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed ignored EM strategy [#1091](https://github.com/ie3-institute/simona/issues/1091) - EM should output flex option results even if it has no parent [#1112](https://github.com/ie3-institute/simona/issues/1112) - Rename `PrimaryDataWithApparentPower` to `PrimaryDataWithComplexPower` [#1140](https://github.com/ie3-institute/simona/issues/1140) +- Move `ScheduleServiceActivation` out of `RegistrationResponseMessage` [#1143](https://github.com/ie3-institute/simona/issues/1143) ## [3.0.0] - 2023-08-07 diff --git a/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala b/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala index b71adf4a30..1dfb6a79c5 100644 --- a/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala +++ b/src/main/scala/edu/ie3/simona/api/ExtSimAdapter.scala @@ -6,8 +6,6 @@ package edu.ie3.simona.api -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import edu.ie3.simona.api.ExtSimAdapter.{Create, ExtSimAdapterStateData, Stop} import edu.ie3.simona.api.data.ontology.ScheduleDataServiceMessage import edu.ie3.simona.api.simulation.ExtSimAdapterData @@ -18,15 +16,17 @@ import edu.ie3.simona.api.simulation.ontology.{ CompletionMessage => ExtCompletionMessage, } import edu.ie3.simona.logging.SimonaActorLogging +import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation -import edu.ie3.simona.ontology.messages.Activation +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ScheduleServiceActivation import edu.ie3.simona.scheduler.ScheduleLock import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{Actor, ActorRef, PoisonPill, Props} import scala.jdk.OptionConverters._ diff --git a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala index d7444454fd..26d338ad61 100644 --- a/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala +++ b/src/main/scala/edu/ie3/simona/ontology/messages/services/ServiceMessage.scala @@ -60,12 +60,13 @@ object ServiceMessage { override val serviceRef: ActorRef ) extends RegistrationResponseMessage - final case class ScheduleServiceActivation( - tick: Long, - unlockKey: ScheduleKey, - ) } + final case class ScheduleServiceActivation( + tick: Long, + unlockKey: ScheduleKey, + ) + /** Actual provision of data * * @tparam D diff --git a/src/main/scala/edu/ie3/simona/service/SimonaService.scala b/src/main/scala/edu/ie3/simona/service/SimonaService.scala index 310c7f0b32..3b8099f5d1 100644 --- a/src/main/scala/edu/ie3/simona/service/SimonaService.scala +++ b/src/main/scala/edu/ie3/simona/service/SimonaService.scala @@ -6,16 +6,16 @@ package edu.ie3.simona.service -import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps -import org.apache.pekko.actor.{Actor, ActorContext, ActorRef, Stash} import edu.ie3.simona.logging.SimonaActorLogging import edu.ie3.simona.ontology.messages.Activation import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation -import edu.ie3.simona.ontology.messages.services.ServiceMessage.ServiceRegistrationMessage +import edu.ie3.simona.ontology.messages.services.ServiceMessage.{ + ScheduleServiceActivation, + ServiceRegistrationMessage, +} import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey import edu.ie3.simona.service.ServiceStateData.{ InitializeServiceStateData, @@ -23,6 +23,8 @@ import edu.ie3.simona.service.ServiceStateData.{ } import edu.ie3.simona.service.SimonaService.Create import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK +import org.apache.pekko.actor.typed.scaladsl.adapter.ClassicActorRefOps +import org.apache.pekko.actor.{Actor, ActorContext, ActorRef, Stash} import scala.util.{Failure, Success, Try} diff --git a/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala b/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala index 0a4dab2d51..b1d5d34028 100644 --- a/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala +++ b/src/test/scala/edu/ie3/simona/api/ExtSimAdapterSpec.scala @@ -21,7 +21,7 @@ import edu.ie3.simona.ontology.messages.SchedulerMessage.{ Completion, ScheduleActivation, } -import edu.ie3.simona.ontology.messages.services.ServiceMessage.RegistrationResponseMessage.ScheduleServiceActivation +import edu.ie3.simona.ontology.messages.services.ServiceMessage.ScheduleServiceActivation import edu.ie3.simona.scheduler.ScheduleLock.ScheduleKey import edu.ie3.simona.test.common.{TestKitWithShutdown, TestSpawnerClassic} import edu.ie3.simona.util.SimonaConstants.INIT_SIM_TICK From 3f67ba7b8368dbcec7f15aed7ab1008d53d66447 Mon Sep 17 00:00:00 2001 From: Sebastian Peter Date: Thu, 6 Feb 2025 12:57:48 +0100 Subject: [PATCH 63/63] Some nitpicky formatting things Signed-off-by: Sebastian Peter --- src/main/scala/edu/ie3/simona/model/participant/HpModel.scala | 3 +-- .../scala/edu/ie3/simona/model/thermal/ThermalStorage.scala | 1 - 2 files changed, 1 insertion(+), 3 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 a721241f25..e874e7c028 100644 --- a/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala +++ b/src/main/scala/edu/ie3/simona/model/participant/HpModel.scala @@ -112,8 +112,7 @@ final case class HpModel( tick: Long, currentState: HpState, data: HpRelevantData, - ): Power = - currentState.qDot + ): Power = currentState.qDot /** Given a [[HpRelevantData]] object and the last [[HpState]], this function * calculates the heat pump's next state to get the actual active power of diff --git a/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala b/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala index de515346ce..e5731823ae 100644 --- a/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala +++ b/src/main/scala/edu/ie3/simona/model/thermal/ThermalStorage.scala @@ -84,7 +84,6 @@ object ThermalStorage { * Infeed to the heat storage (positive: Storage is charging, negative: * Storage is discharging) */ - final case class ThermalStorageState( tick: Long, storedEnergy: Energy,