Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Unify coordinate class [#1516](https://github.com/ie3-institute/simona/issues/1516)
- Remove type parameters from data and message classes [#1524](https://github.com/ie3-institute/simona/issues/1524)
- Adapt ThermalHouse and HP flexibility behaviour [#1391](https://github.com/ie3-institute/simona/issues/1391)
- Use ThermalStorageTypes for type safety [#1556](https://github.com/ie3-institute/simona/issues/1556)

### Fixed
- Fixes in Documentation, ScalaDocs, Code Style and more [#1397](https://github.com/ie3-institute/simona/issues/1397)
Expand Down
80 changes: 57 additions & 23 deletions src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import edu.ie3.datamodel.models.result.ResultEntity
import edu.ie3.datamodel.models.result.thermal.{
CylindricalStorageResult,
DomesticHotWaterStorageResult,
ThermalHouseResult,
}
import edu.ie3.simona.exceptions.InvalidParameterException
Expand All @@ -27,10 +28,10 @@
import edu.ie3.simona.model.thermal.ThermalHouse.ThermalHouseState
import edu.ie3.simona.model.thermal.ThermalStorage.ThermalStorageState
import edu.ie3.util.quantities.QuantityUtils.{
asMegaWattHour,
asKelvin,
asPu,
asMegaWatt,
asMegaWattHour,
asPu,
}
import edu.ie3.util.scala.quantities.DefaultQuantities.*
import squants.energy.KilowattHours
Expand All @@ -50,7 +51,7 @@
*/
final case class ThermalGrid(
house: Option[ThermalHouse],
heatStorage: Option[ThermalStorage],
heatStorage: Option[CylindricalThermalStorage],
) extends LazyLogging {

/** Determines the state of the ThermalGrid by using the HpOperatingPoint.
Expand Down Expand Up @@ -255,7 +256,7 @@
handleFeedInHouse(state, qDotHouse)

val heatStorageThreshold =
handleFeedInStorage(state, qDotHeatStorage)
handleFeedInStorages(state, qDotHeatStorage)

val nextThreshold = determineNextThreshold(
Seq(
Expand Down Expand Up @@ -314,35 +315,42 @@

/** Handles the case, when the storage has heat demand and will be filled up
* here (positive qDot).
*
* @param state
* State of the heat pump.
* @param qDotStorage
* Feed in to the storage (positive: Storage is charging, negative: Storage
* is discharging).
* @param qDotHeatStorage
* Feed in to the heat storage (positive: Storage is charging, negative:
* Storage is discharging).
* @return
* The ThermalThreshold if there is one.
*/
private def handleFeedInStorage(
private def handleFeedInStorages(
state: HpState,
qDotStorage: Power,
qDotHeatStorage: Power,
): Option[ThermalThreshold] = {
heatStorage.zip(state.thermalGridState.heatStorageState) match {
case Some((thermalStorage, storageState)) =>
thermalStorage.determineNextThreshold(
storageState,
qDotStorage,
)
case _ => None
}
// TODO: We should somewhere check that pThermalMax of Storage is always capable for qDot pThermalMax >= pThermal of Hp

Check notice on line 331 in src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala

View check run for this annotation

SonarQubeGithubPRChecks / SonarQube Code Analysis

src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala#L331

Complete the task associated to this TODO comment.
if qDotHeatStorage != zeroKW then
handleFeedInHeatStorage(state, qDotHeatStorage)
else None
}

private def handleFeedInHeatStorage(
state: HpState,
qDotStorage: Power,
): Option[ThermalThreshold] = {
for {
storage <- heatStorage.collect { case s: CylindricalThermalStorage => s }
storageState <- state.thermalGridState.heatStorageState
} yield storage.determineNextThreshold(storageState, qDotStorage)
}.flatten

/** Determines the next threshold of a given input sequence of thresholds.
*
* @param thresholds
* Sequence of Options of possible next thresholds from the thermal house
* or storage.
* @return
* The next threshold.
* The next [[ThermalThreshold]] or [[None]].
*/
private def determineNextThreshold(
thresholds: Seq[Option[ThermalThreshold]]
Expand Down Expand Up @@ -501,7 +509,27 @@
)
}

// We always want the results if there are changes or it's the first tick
def createDomesticHotWaterStorageResult(
storage: DomesticHotWaterStorage
): Option[DomesticHotWaterStorageResult] = {
state.thermalGridState.heatStorageState // TODO Dummy

Check notice on line 515 in src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala

View check run for this annotation

SonarQubeGithubPRChecks / SonarQube Code Analysis

src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala#L515

Complete the task associated to this TODO comment.
.collectFirst { case ThermalStorageState(_, storedEnergy) =>
new DomesticHotWaterStorageResult(
dateTime,
storage.uuid,
storedEnergy.toMegawattHours.asMegaWattHour,
currentOpThermals.qDotHeatStorage.toMegawatts.asMegaWatt, // TODO Dummy

Check notice on line 521 in src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala

View check run for this annotation

SonarQubeGithubPRChecks / SonarQube Code Analysis

src/main/scala/edu/ie3/simona/model/thermal/ThermalGrid.scala#L521

Complete the task associated to this TODO comment.
(storedEnergy / storage.maxEnergyThreshold).asPu,
)
}
.orElse(
throw new NotImplementedError(
s"Result handling for storage type '${storage.getClass.getSimpleName}' not supported."
)
)
}

// We always want the results if there are changes, or it's the first tick
val maybeHouseResult = {
(
house,
Expand All @@ -515,7 +543,7 @@
}
}

// We always want the results if there are changes or it's the first tick
// We always want the results if there are changes, or it's the first tick
val maybeHeatStorageResult = {
(
heatStorage,
Expand All @@ -529,7 +557,10 @@
}
}

Seq(maybeHouseResult, maybeHeatStorageResult).flatten
Seq(
maybeHouseResult,
maybeHeatStorageResult,
).flatten
}
}

Expand All @@ -554,6 +585,7 @@
}

/** Current state of a grid.
*
* @param houseState
* State of the thermal house.
* @param heatStorageState
Expand Down Expand Up @@ -608,6 +640,7 @@
* energy, that can be handled. The possible energy always has to be greater
* 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. For
* [[ThermalHouse]] this would be the energy demand to reach the boundary
Expand All @@ -626,10 +659,11 @@
possible + rhs.possible,
)

def hasRequiredDemand: Boolean = required > zeroMWh
def hasRequiredDemand: Boolean = required > zeroKWh

def hasPossibleDemand: Boolean = possible > zeroMWh
def hasPossibleDemand: Boolean = possible > zeroKWh
}

object ThermalEnergyDemand {

/** Builds a new instance of [[ThermalEnergyDemand]]. If the possible energy
Expand Down
32 changes: 32 additions & 0 deletions src/main/scala/edu/ie3/simona/model/thermal/ThermalResult.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* © 2025. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/

package edu.ie3.simona.model.thermal

import edu.ie3.datamodel.models.result.ResultEntity
import edu.ie3.datamodel.models.result.thermal.{
CylindricalStorageResult,
DomesticHotWaterStorageResult,
ThermalHouseResult,
}

sealed trait ThermalResult {
def getResultEntity: ResultEntity
}

case class HouseResult(result: ThermalHouseResult) extends ThermalResult {
override def getResultEntity: ResultEntity = result
}

case class HeatStorageResult(result: CylindricalStorageResult)
extends ThermalResult {
override def getResultEntity: ResultEntity = result
}

case class HotWaterStorageResult(result: DomesticHotWaterStorageResult)
extends ThermalResult {
override def getResultEntity: ResultEntity = result
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* © 2025. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/

package edu.ie3.simona.model.thermal

import edu.ie3.simona.model.thermal.ThermalStorage.ThermalStorageState

sealed trait ThermalStorageType
case class HeatStorageType(storage: CylindricalThermalStorage)
extends ThermalStorageType
case class HotWaterStorageType(storage: DomesticHotWaterStorage)
extends ThermalStorageType

sealed trait StorageWithState
case class HeatStorageWithState(
storage: CylindricalThermalStorage,
state: ThermalStorageState,
) extends StorageWithState
case class HotWaterStorageWithState(
storage: DomesticHotWaterStorage,
state: ThermalStorageState,
) extends StorageWithState
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ trait HpInputTestData extends NodeInputTestData with ThermalGridTestData {

protected def thermalGrid(
thermalHouse: ThermalHouse,
thermalStorage: Option[ThermalStorage] = None,
thermalStorage: Option[CylindricalThermalStorage] = None,
): ThermalGrid =
ThermalGrid(
Some(thermalHouse),
Expand Down
Loading