Skip to content

Commit

Permalink
Merge branch 'df/#1023-zeroKW-and-kWh-in-test' into df/#856-tap-water
Browse files Browse the repository at this point in the history
# Conflicts:
#	CHANGELOG.md
#	src/main/scala/edu/ie3/simona/agent/participant/ParticipantAgentFundamentals.scala
#	src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgentFundamentals.scala
#	src/main/scala/edu/ie3/simona/event/ResultEvent.scala
#	src/main/scala/edu/ie3/simona/model/participant/HpModel.scala
#	src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala
#	src/test/scala/edu/ie3/simona/model/participant/HpModelSpec.scala
#	src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseAndStorageSpec.scala
#	src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithHouseOnlySpec.scala
#	src/test/scala/edu/ie3/simona/model/thermal/ThermalGridWithStorageOnlySpec.scala
  • Loading branch information
danielfeismann committed Nov 15, 2024
2 parents d3357f6 + 932794b commit 378f2f6
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 87 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added option to directly zip the output files [#793](https://github.com/ie3-institute/simona/issues/793)
- Added weatherData HowTo for Copernicus ERA5 data [#967](https://github.com/ie3-institute/simona/issues/967)
- Add some quote to 'printGoodbye' [#997](https://github.com/ie3-institute/simona/issues/997)
- Add unapply method for ThermalHouseResults [#934](https://github.com/ie3-institute/simona/issues/934)
- Integration test for thermal grids [#878](https://github.com/ie3-institute/simona/issues/878)

### Changed
Expand Down Expand Up @@ -97,6 +98,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Move compression of output files into `ResultEventListener`[#965](https://github.com/ie3-institute/simona/issues/965)
- Rewrote StorageModelTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646)
- Updated `ExtEvSimulationClasses` [#898](https://github.com/ie3-institute/simona/issues/898)
- Refactoring of `ThermalGrid.energyGrid` to distinguish between demand of house and storage [#928](https://github.com/ie3-institute/simona/issues/928)
- Refactoring to use zeroKW and zeroKWH in thermal grid unit tests [#1023](https://github.com/ie3-institute/simona/issues/1023)

### Fixed
- Fix rendering of references in documentation [#505](https://github.com/ie3-institute/simona/issues/505)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1913,7 +1913,6 @@ protected trait ParticipantAgentFundamentals[
): Option[ResultEvent] = result match {
case thermalUnitResult: ThermalUnitResult =>
Some(ResultEvent.ThermalResultEvent(thermalUnitResult))

case unsupported =>
log.debug(
s"Results of class '${unsupported.getClass.getSimpleName}' are currently not supported."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,7 @@ trait HpAgentFundamentals
nodalVoltage: squants.Dimensionless,
model: HpModel,
): HpState = {
val (_, _, state) =
model.determineState(modelState, calcRelevantData)
state
model.determineState(modelState, calcRelevantData)._3
}

/** Abstract definition, individual implementations found in individual agent
Expand Down
55 changes: 21 additions & 34 deletions src/main/scala/edu/ie3/simona/event/ResultEvent.scala
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,15 @@ object ResultEvent {
ComparableQuantity[Power],
ComparableQuantity[Temperature],
)
] = {
if (result != null) {
Some(
(
result.getTime,
result.getInputModel,
result.getqDot,
result.getIndoorTemperature,
)
] =
Option(result).map { result =>
(
result.getTime,
result.getInputModel,
result.getqDot,
result.getIndoorTemperature,
)
} else {
None
}
}
}

object CylindricalThermalStorageResult {
Expand All @@ -87,41 +82,33 @@ object ResultEvent {
ComparableQuantity[Energy],
)
] = {
if (result != null) {
Some(
(
result.getTime,
result.getInputModel,
result.getqDot,
result.getEnergy,
)
Option(result).map { result =>
(
result.getTime,
result.getInputModel,
result.getqDot,
result.getEnergy,
)
} else {
None
}
}
}

object DomesticHotWaterStorageResult {
def unapply(result: DomesticHotWaterStorageResult): Option[
(
ZonedDateTime,
ZonedDateTime,
UUID,
ComparableQuantity[Power],
ComparableQuantity[Energy],
)
)
] = {
if (result != null) {
Some(
(
result.getTime,
result.getInputModel,
result.getqDot,
result.getEnergy,
)
Option(result).map { result =>
(
result.getTime,
result.getInputModel,
result.getqDot,
result.getEnergy,
)
} else {
None
}
}
}
Expand Down
99 changes: 56 additions & 43 deletions src/main/scala/edu/ie3/simona/model/participant/HpModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,17 @@ final case class HpModel(
* [[HpModel.determineState]]. This state then is fed into the power
* calculation logic by [[HpState]].
*
* @param modelState
* @param currentState
* Current state of the heat pump
* @param relevantData
* data of heat pump including state of the heat pump
* @return
* active power
*/
override protected def calculateActivePower(
modelState: HpState,
currentState: HpState,
relevantData: HpRelevantData,
): Power = modelState.activePower
): Power = currentState.activePower

/** "Calculate" the heat output of the heat pump. The hp's state is already
* updated, because the calculation of apparent power in
Expand All @@ -101,7 +101,7 @@ final case class HpModel(
*
* @param tick
* Current simulation time for the calculation
* @param modelState
* @param currentState
* Current state of the heat pump
* @param data
* Relevant (external) data for calculation
Expand All @@ -110,45 +110,51 @@ final case class HpModel(
*/
override def calculateHeat(
tick: Long,
modelState: HpState,
currentState: HpState,
data: HpRelevantData,
): Power = modelState.qDot
): Power = currentState.qDot

/** Given a [[HpRelevantData]] object and the current [[HpState]], this
* function calculates the heat pump's next state to get the actual active
* power of this state use [[calculateActivePower]] with the generated state
/** Given a [[HpRelevantData]] object and the last [[HpState]], this function
* calculates the heat pump's next state to get the actual active power of
* this state use [[calculateActivePower]] with the generated state
*
* @param lastState
* @param lastHpState
* Last state of the heat pump
* @param relevantData
* data of heat pump including
* @return
* Booleans if Hp can operate and can be out of operation plus next
* Booleans if Hp can operate and can be out of operation plus the updated
* [[HpState]]
*/
def determineState(
lastState: HpState,
lastHpState: HpState,
relevantData: HpRelevantData,
): (Boolean, Boolean, HpState) = {
val (
turnOn,
canOperate,
canBeOutOfOperation,
houseDemand,
thermalStorageDemand,
domesticHotWaterStorageDemand,
) =
operatesInNextState(lastState, relevantData)
val updatedState = calcState(
lastState,
relevantData,
turnOn,
houseDemand,
thermalStorageDemand,
domesticHotWaterStorageDemand,
relevantData.simulationStart,
relevantData.houseInhabitants,
)

// Use lastHpState and relevantData to update state of thermalGrid to the current tick
val (demandHouse, demandThermalStorage, currentThermalGridState) =
thermalGrid.energyDemandAndUpdatedState(
relevantData.currentTick,
lastHpState.ambientTemperature.getOrElse(
relevantData.ambientTemperature
),
relevantData.ambientTemperature,
lastHpState.thermalGridState,
)

// Determining the operation point and limitations at this tick
val (turnOn, canOperate, canBeOutOfOperation) =
operatesInNextState(
lastHpState,
currentThermalGridState,
relevantData,
demandHouse,
demandThermalStorage,
)

// Updating the HpState
val updatedState =
calcState(lastHpState, relevantData, turnOn)
(canOperate, canBeOutOfOperation, updatedState)
}

Expand All @@ -158,17 +164,24 @@ final case class HpModel(
* met or the heat pump currently is in operation and the grid is able to
* handle additional energy
*
* @param state
* Current state of the heat pump
* @param lastState
* last state of the heat pump
* @param currentThermalGridState
* 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
* @return
* boolean defining if heat pump runs in next time step, if it can be in
* operation and out of operation plus the [[ThermalEnergyDemand]] of
* house, heat storage, domestic hot water storage
*/
private def operatesInNextState(
state: HpState,
lastState: HpState,
currentThermalGridState: ThermalGridState,
relevantData: HpRelevantData,
): (
Boolean,
Expand Down Expand Up @@ -269,8 +282,8 @@ final case class HpModel(
* calculate inner temperature change of thermal house and update its inner
* temperature.
*
* @param state
* Current state of the heat pump
* @param lastState
* state of the heat pump until this tick
* @param relevantData
* data of heat pump including state of the heat pump
* @param isRunning
Expand All @@ -289,7 +302,7 @@ final case class HpModel(
* next [[HpState]]
*/
private def calcState(
state: HpState,
lastState: HpState,
relevantData: HpRelevantData,
isRunning: Boolean,
houseDemand: ThermalEnergyDemand,
Expand All @@ -298,23 +311,23 @@ final case class HpModel(
simulationStartTime: ZonedDateTime,
houseInhabitants: Double,
): HpState = {
val lastStateStorageqDot = state.thermalGridState.storageState
val lastStateStorageQDot = lastState.thermalGridState.storageState
.map(_.qDot)
.getOrElse(zeroKW)

val (newActivePower, newThermalPower) =
if (isRunning)
(pRated, pThermal)
else if (lastStateStorageqDot < zeroKW)
(zeroKW, lastStateStorageqDot * (-1))
else if (lastStateStorageQDot < zeroKW)
(zeroKW, lastStateStorageQDot * (-1))
else (zeroKW, zeroKW)

/* Push thermal energy to the thermal grid and get its updated state in return */
val (thermalGridState, maybeThreshold) =
thermalGrid.updateState(
relevantData.currentTick,
state.thermalGridState,
state.ambientTemperature.getOrElse(relevantData.ambientTemperature),
lastState.thermalGridState,
lastState.ambientTemperature.getOrElse(relevantData.ambientTemperature),
relevantData.ambientTemperature,
isRunning,
newThermalPower,
Expand Down Expand Up @@ -488,7 +501,7 @@ object HpModel {
* @param qDot
* result heat power
* @param thermalGridState
* Currently applicable state of the thermal grid
* applicable state of the thermal grid
* @param maybeThermalThreshold
* An optional threshold of the thermal grid, indicating the next state
* change
Expand Down
10 changes: 5 additions & 5 deletions src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ final case class ThermalGrid(
* @param tick
* Questioned instance in time
* @param lastAmbientTemperature
* Ambient temperature valid up until (not including) the current tick
* Ambient temperature until this tick
* @param ambientTemperature
* Current ambient temperature
* @param state
Expand Down Expand Up @@ -132,8 +132,8 @@ final case class ThermalGrid(
heatStorage
.zip(state.storageState)
.map { case (storage, state) =>
val updatedStorageState =
storage.updateState(tick, state.qDot, state)._1
val (updatedStorageState,_) =
storage.updateState(tick, state.qDot, state)
val storedEnergy = updatedStorageState.storedEnergy
val soc = storedEnergy / storage.getMaxEnergyThreshold
val storageRequired = {
Expand Down Expand Up @@ -173,8 +173,8 @@ final case class ThermalGrid(
)
)
.getOrElse(ThermalEnergyDemand(zeroKWH, zeroKWH))
val applicableqDotDomesticStorage =
identifyApplicableQDot(tick, domesticHotWaterDemand)._1
val (applicableqDotDomesticStorage,_) =
identifyApplicableQDot(tick, domesticHotWaterDemand)

domesticHotWaterStorage
.zip(state.domesticHotWaterStorageState)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import edu.ie3.simona.model.thermal.ThermalStorage.ThermalStorageThreshold.{
StorageEmpty,
StorageFull,
}
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._
Expand Down Expand Up @@ -190,7 +191,7 @@ class ThermalGridWithHouseOnlySpec
"deliver the house state by just letting it cool down, if just no infeed is given" in {
val tick = 0L
val gridState = ThermalGrid.startingState(thermalGrid)
val externalQDot = Megawatts(0d)
val externalQDot = zeroKW

val (updatedGridState, reachedThreshold) =
thermalGrid invokePrivate handleConsumption(
Expand Down

0 comments on commit 378f2f6

Please sign in to comment.