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 (