Skip to content

Commit

Permalink
Merge branch 'dev' into df/#878-thermalGridIT
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/main/scala/edu/ie3/simona/agent/participant/hp/HpAgentFundamentals.scala
#	src/main/scala/edu/ie3/simona/model/participant/HpModel.scala
#	src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala
  • Loading branch information
danielfeismann committed Nov 15, 2024
2 parents b40cfe0 + 3306aea commit f33fc1a
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ 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)

### 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 @@ -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
162 changes: 128 additions & 34 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,31 +110,59 @@ 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, storageDemand) =

/* FIXME
val (turnOn, canOperate, canBeOutOfOperation, houseDemand, storageDemand) =
operatesInNextState(lastState, relevantData)
val updatedState =
calcState(lastState, relevantData, turnOn, houseDemand, storageDemand)
(canOperate, canBeOutOfOperation, updatedState)
*/
// 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)
}

/** Depending on the input, this function decides whether the heat pump will
Expand All @@ -143,19 +171,31 @@ 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 demand of house and storage
*/
private def operatesInNextState(
state: HpState,
lastState: HpState,
currentThermalGridState: ThermalGridState,
relevantData: HpRelevantData,
demandHouse: ThermalEnergyDemand,
demandThermalStorage: ThermalEnergyDemand,
): (Boolean, Boolean, Boolean, Boolean, Boolean) = {
val (demandHouse, demandThermalStorage, updatedState) =

//FIXME
/*
val (demandHouse, demandThermalStorage, updatedState) =
thermalGrid.energyDemandAndUpdatedState(
relevantData.currentTick,
state.ambientTemperature.getOrElse(relevantData.ambientTemperature),
Expand Down Expand Up @@ -185,13 +225,59 @@ final case class HpModel(
(turnHpOn, canOperate, canBeOutOfOperation, houseDemand, heatStorageDemand)
}
*/

def determineDemandBooleans(
hpState: HpState,
updatedGridState: ThermalGridState,
demandHouse: ThermalEnergyDemand,
demandThermalStorage: ThermalEnergyDemand,
): (Boolean, Boolean, Boolean) = {
/*
val (
houseHasDemand,
heatStorageHasDemand,
noThermalStorageOrThermalStorageIsEmpty,
) = determineDemandBooleans(
lastState,
currentThermalGridState,
demandHouse,
demandThermalStorage,
)
val turnHpOn: Boolean =
houseHasDemand || heatStorageHasDemand
val canOperate =
demandHouse.hasRequiredDemand || demandHouse.hasAdditionalDemand ||
demandThermalStorage.hasRequiredDemand || demandThermalStorage.hasAdditionalDemand
val canBeOutOfOperation =
!(demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty)
(turnHpOn, canOperate, canBeOutOfOperation)
*/

}

/** This method will return booleans whether there is a heat demand of house
* 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]]
* @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.
*/

private def determineDemandBooleans(
lastHpState: HpState,
updatedGridState: ThermalGridState,
demandHouse: ThermalEnergyDemand,
demandThermalStorage: ThermalEnergyDemand,
): (Boolean, Boolean, Boolean) = {
implicit val tolerance: Energy = KilowattHours(1e-3)
val noThermalStorageOrThermalStorageIsEmpty: Boolean =
updatedGridState.storageState.isEmpty || updatedGridState.storageState
Expand All @@ -200,19 +286,18 @@ final case class HpModel(
)

val houseDemand =
(demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) || (hpState.isRunning && demandHouse.hasAdditionalDemand)
val heatStorageDemand = {
(demandThermalStorage.hasRequiredDemand) || (hpState.isRunning && demandThermalStorage.hasAdditionalDemand)
}
(demandHouse.hasRequiredDemand && noThermalStorageOrThermalStorageIsEmpty) || (lastHpState.isRunning && demandHouse.hasAdditionalDemand)
val heatStorageDemand =
demandThermalStorage.hasRequiredDemand || (lastHpState.isRunning && demandThermalStorage.hasAdditionalDemand)
(houseDemand, heatStorageDemand, noThermalStorageOrThermalStorageIsEmpty)
}

/** Calculate state depending on whether heat pump is needed or not. Also
* 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 @@ -225,13 +310,13 @@ final case class HpModel(
* next [[HpState]]
*/
private def calcState(
state: HpState,
lastState: HpState,
relevantData: HpRelevantData,
isRunning: Boolean,
houseDemand: Boolean,
storageDemand: Boolean,
): HpState = {
val lastStateStorageqDot = state.thermalGridState.storageState
val lastStateStorageQDot = lastState.thermalGridState.storageState
.map(_.qDot)
.getOrElse(zeroKW)

Expand All @@ -246,8 +331,8 @@ final case class HpModel(
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 @@ -318,6 +403,15 @@ final case class HpModel(
/* If the setpoint value is above 50 % of the electrical power, turn on the heat pump otherwise turn it off */
val turnOn = setPower > (sRated * cosPhiRated * 0.5)

// FIXME
/* val updatedHpState = calcState(
lastState,
data,
turnOn,
)
*/

val (
thermalEnergyDemandHouse,
thermalEnergyDemandStorage,
Expand Down Expand Up @@ -423,7 +517,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
9 changes: 5 additions & 4 deletions src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,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 in the instance in question
* @param state
Expand All @@ -68,9 +68,9 @@ final case class ThermalGrid(
/* First get the energy demand of the houses but only if inner temperature is below target temperature */

val (houseDemand, updatedHouseState) =
house.zip(state.houseState).headOption match {
house.zip(state.houseState) match {
case Some((thermalHouse, lastHouseState)) =>
val (updatedHouseState, updatedStorageState) =
val (updatedHouseState, _) =
thermalHouse.determineState(
tick,
lastHouseState,
Expand All @@ -79,7 +79,8 @@ final case class ThermalGrid(
lastHouseState.qDot,
)
if (
updatedHouseState.innerTemperature < thermalHouse.targetTemperature | (lastHouseState.qDot > zeroKW && updatedHouseState.innerTemperature < thermalHouse.upperBoundaryTemperature)
updatedHouseState.innerTemperature < thermalHouse.targetTemperature |
(lastHouseState.qDot > zeroKW && updatedHouseState.innerTemperature < thermalHouse.upperBoundaryTemperature)
) {
(
thermalHouse.energyDemand(
Expand Down

0 comments on commit f33fc1a

Please sign in to comment.