Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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: Issue #1562 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
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