Skip to content

Commit

Permalink
Merge pull request #798 from ie3-institute/df/#797_fix_config_fail_fast
Browse files Browse the repository at this point in the history
Fix ConfigFailFastSpec after Refsystem passing
  • Loading branch information
t-ober committed May 6, 2024
2 parents c5197b3 + 76af66f commit 741981d
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 272 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixing false negative in ref system voltage validation [#706](https://github.com/ie3-institute/simona/issues/706)
- Fixing randomly failing test in `RuntimeEventListenerSpec` etc. [#709](https://github.com/ie3-institute/simona/issues/709)
- Fixed config start and end datetime parsing hint [#767](https://github.com/ie3-institute/simona/issues/767)
- ConfigFailFast after making configuration of `RefSystem` via config optional [#797](https://github.com/ie3-institute/simona/issues/797)

## [3.0.0] - 2023-08-07

Expand Down
1 change: 1 addition & 0 deletions src/main/resources/config/config-template.conf
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ simona.powerflow.stopOnFailure = boolean | false
# Grid Configuration
##################################################################

#@optional
simona.gridConfig.refSystems = [RefSystemConfig]

##################################################################
Expand Down
113 changes: 59 additions & 54 deletions src/main/scala/edu/ie3/simona/config/ConfigFailFast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ case object ConfigFailFast extends LazyLogging {

// check if the provided combinations of refSystems provided are valid
val refSystems = simonaConfig.simona.gridConfig.refSystems
refSystems.foreach(checkRefSystem)
if (refSystems.isDefined)
refSystems.foreach(refsys => checkRefSystem(refsys))

/* Check all participant model configurations */
checkParticipantRuntimeConfiguration(
Expand Down Expand Up @@ -431,67 +432,71 @@ case object ConfigFailFast extends LazyLogging {
* @param refSystem
* the [[SimonaConfig.RefSystemConfig]] that should be checked
*/
private def checkRefSystem(refSystem: RefSystemConfig): Unit = {

val voltLvls =
refSystem.voltLvls.getOrElse(List.empty[SimonaConfig.VoltLvlConfig])
val gridIds = refSystem.gridIds.getOrElse(List.empty[String])
private def checkRefSystem(refSystems: List[RefSystemConfig]): Unit = {
refSystems.foreach { refSystem =>
{
val voltLvls =
refSystem.voltLvls.getOrElse(List.empty[SimonaConfig.VoltLvlConfig])
val gridIds = refSystem.gridIds.getOrElse(List.empty[String])

if (voltLvls.isEmpty && gridIds.isEmpty)
throw new InvalidConfigParameterException(
"The provided values for voltLvls and gridIds are empty! " +
s"At least one of these optional parameters has to be provided for a valid refSystem! " +
s"Provided refSystem is: $refSystem."
)

voltLvls.foreach { voltLvl =>
Try(Quantities.getQuantity(voltLvl.vNom)) match {
case Success(quantity) =>
if (!quantity.getUnit.isCompatible(Units.VOLT))
throw new InvalidConfigParameterException(
s"The given nominal voltage '${voltLvl.vNom}' cannot be parsed to electrical potential! Please provide the volt level with its unit, e.g. \"20 kV\""
)
case Failure(exception) =>
if (voltLvls.isEmpty && gridIds.isEmpty)
throw new InvalidConfigParameterException(
s"The given nominal voltage '${voltLvl.vNom}' cannot be parsed to a quantity. Did you provide the volt level with it's unit (e.g. \"20 kV\")?",
exception,
"The provided values for voltLvls and gridIds are empty! " +
s"At least one of these optional parameters has to be provided for a valid refSystem! " +
s"Provided refSystem is: $refSystem."
)
}
}

gridIds.foreach {
case gridIdRange @ ConfigConventions.gridIdDotRange(from, to) =>
rangeCheck(from.toInt, to.toInt, gridIdRange)
case gridIdRange @ ConfigConventions.gridIdMinusRange(from, to) =>
rangeCheck(from.toInt, to.toInt, gridIdRange)
case ConfigConventions.singleGridId(_) =>
case gridId =>
throw new InvalidConfigParameterException(
s"The provided gridId $gridId is malformed!"
)
}
voltLvls.foreach { voltLvl =>
Try(Quantities.getQuantity(voltLvl.vNom)) match {
case Success(quantity) =>
if (!quantity.getUnit.isCompatible(Units.VOLT))
throw new InvalidConfigParameterException(
s"The given nominal voltage '${voltLvl.vNom}' cannot be parsed to electrical potential! Please provide the volt level with its unit, e.g. \"20 kV\""
)
case Failure(exception) =>
throw new InvalidConfigParameterException(
s"The given nominal voltage '${voltLvl.vNom}' cannot be parsed to a quantity. Did you provide the volt level with it's unit (e.g. \"20 kV\")?",
exception,
)
}
}

refSystem.sNom match {
case ConfigConventions.refSystemQuantRegex(_) =>
case _ =>
throw new InvalidConfigParameterException(
s"Invalid value for sNom from provided refSystem $refSystem. Is a valid unit provided?"
)
}
gridIds.foreach {
case gridIdRange @ ConfigConventions.gridIdDotRange(from, to) =>
rangeCheck(from.toInt, to.toInt, gridIdRange)
case gridIdRange @ ConfigConventions.gridIdMinusRange(from, to) =>
rangeCheck(from.toInt, to.toInt, gridIdRange)
case ConfigConventions.singleGridId(_) =>
case gridId =>
throw new InvalidConfigParameterException(
s"The provided gridId $gridId is malformed!"
)
}

refSystem.vNom match {
case ConfigConventions.refSystemQuantRegex(_) =>
case _ =>
throw new InvalidConfigParameterException(
s"Invalid value for vNom from provided refSystem $refSystem. Is a valid unit provided?"
)
}
refSystem.sNom match {
case ConfigConventions.refSystemQuantRegex(_) =>
case _ =>
throw new InvalidConfigParameterException(
s"Invalid value for sNom from provided refSystem $refSystem. Is a valid unit provided?"
)
}

def rangeCheck(from: Int, to: Int, gridIdRange: String): Unit = {
if (from >= to)
throw new InvalidConfigParameterException(
s"Invalid gridId Range $gridIdRange. Start $from cannot be equals or bigger than end $to."
)
refSystem.vNom match {
case ConfigConventions.refSystemQuantRegex(_) =>
case _ =>
throw new InvalidConfigParameterException(
s"Invalid value for vNom from provided refSystem $refSystem. Is a valid unit provided?"
)
}
}

def rangeCheck(from: Int, to: Int, gridIdRange: String): Unit = {
if (from >= to)
throw new InvalidConfigParameterException(
s"Invalid gridId Range $gridIdRange. Start $from cannot be equals or bigger than end $to."
)
}
}
}

Expand Down
195 changes: 96 additions & 99 deletions src/main/scala/edu/ie3/simona/config/RefSystemParser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,109 +55,106 @@ object RefSystemParser {
* RefSystems
*/
def parse(
configRefSystems: List[SimonaConfig.RefSystemConfig]
configRefSystems: Option[List[SimonaConfig.RefSystemConfig]]
): ConfigRefSystems = {

if (configRefSystems.isEmpty) {
// if no config was provided, the default refSystems are used
ConfigRefSystems(
Map.empty,
Map(
GermanVoltageLevelUtils.LV -> RefSystem(Kilowatts(100), Volts(400)),
GermanVoltageLevelUtils.MV_10KV -> RefSystem(
Megawatts(40),
Kilovolts(10),
),
GermanVoltageLevelUtils.MV_20KV -> RefSystem(
Megawatts(60),
Kilovolts(20),
),
GermanVoltageLevelUtils.MV_30KV -> RefSystem(
Megawatts(150),
Kilovolts(30),
),
GermanVoltageLevelUtils.HV -> RefSystem(
Megawatts(600),
Kilovolts(110),
),
GermanVoltageLevelUtils.EHV_220KV -> RefSystem(
Megawatts(800),
Kilovolts(220),
),
GermanVoltageLevelUtils.EHV_380KV -> RefSystem(
Megawatts(1000),
Kilovolts(380),
),
val defaultRefSystems = ConfigRefSystems(
Map.empty,
Map(
GermanVoltageLevelUtils.LV -> RefSystem(Kilowatts(100), Volts(400)),
GermanVoltageLevelUtils.MV_10KV -> RefSystem(
Megawatts(40),
Kilovolts(10),
),
GermanVoltageLevelUtils.MV_20KV -> RefSystem(
Megawatts(60),
Kilovolts(20),
),
GermanVoltageLevelUtils.MV_30KV -> RefSystem(
Megawatts(150),
Kilovolts(30),
),
GermanVoltageLevelUtils.HV -> RefSystem(Megawatts(600), Kilovolts(110)),
GermanVoltageLevelUtils.EHV_220KV -> RefSystem(
Megawatts(800),
Kilovolts(220),
),
)
} else {
// units for parsing are not initialized by default
// hence we call them manually
new PowerSystemUnits

val refSystems = configRefSystems.map { configRefSystem =>
(configRefSystem, RefSystem(configRefSystem.sNom, configRefSystem.vNom))
}

val gridIdRefSystems = refSystems.flatMap {
case (configRefSystem, parsedRefSystem) =>
configRefSystem.gridIds
.map {
_.flatMap { gridId =>
{
val allGridIds = gridId match {
case ConfigConventions.gridIdDotRange(from, to) =>
from.toInt to to.toInt
case ConfigConventions.gridIdMinusRange(from, to) =>
from.toInt to to.toInt
case ConfigConventions.singleGridId(singleGridId) =>
Seq(singleGridId.toInt)
case unknownGridIdFormat =>
throw new InvalidConfigParameterException(
s"Unknown gridId format $unknownGridIdFormat provided for refSystem $configRefSystem"
)
}

allGridIds.map(gridId => (gridId, parsedRefSystem))
}
GermanVoltageLevelUtils.EHV_380KV -> RefSystem(
Megawatts(1000),
Kilovolts(380),
),
),
)

configRefSystems match {
case Some(refSystems) if refSystems.nonEmpty =>
// units for parsing are not initialized by default
// hence we call them manually
new PowerSystemUnits

val parsedRefSystems = refSystems.flatMap { configRefSystem =>
val refSystem = RefSystem(configRefSystem.sNom, configRefSystem.vNom)

configRefSystem.gridIds.getOrElse(Seq.empty).flatMap {
case ConfigConventions.gridIdDotRange(from, to) =>
(from.toInt to to.toInt)
.map(gridId => (gridId, refSystem))
case ConfigConventions.gridIdMinusRange(from, to) =>
(from.toInt to to.toInt)
.map(gridId => (gridId, refSystem))
case ConfigConventions.singleGridId(singleGridId) =>
Seq((singleGridId.toInt, refSystem))
case unknownGridIdFormat =>
throw new InvalidConfigParameterException(
s"Unknown gridId format $unknownGridIdFormat provided for refSystem $configRefSystem"
)
} ++ configRefSystem.voltLvls.getOrElse(Seq.empty).map { voltLvlDef =>
(VoltLvlParser.from(voltLvlDef), refSystem)
}
}

val gridIdRefSystemsList: List[(Int, RefSystem)] =
parsedRefSystems.flatMap {
case (gridId: Int, refSystems) =>
refSystems match {
case refSystem: RefSystem => Some(gridId -> refSystem)
case _ => None
}
}
.getOrElse(Seq.empty[(Int, RefSystem)])
}

val voltLvlRefSystems = refSystems.flatMap {
case (configRefSystem, parsedRefSystem) =>
configRefSystem.voltLvls
.map {
_.map { voltLvlDef =>
(VoltLvlParser.from(voltLvlDef), parsedRefSystem)
case _ => None
}

val gridIdRefSystems: Map[Int, RefSystem] =
gridIdRefSystemsList.toMap

if (CollectionUtils.listHasDuplicates(gridIdRefSystemsList)) {
throw new InvalidConfigParameterException(
"The provided gridIds in simona.gridConfig.refSystems contain duplicates. " +
"Please check if there are either duplicate entries or overlapping ranges!"
)
}

val voltLvLRefSystemsList: List[(VoltageLevel, RefSystem)] =
parsedRefSystems.flatMap {
case (voltLvl: VoltageLevel, refSystems) =>
refSystems match {
case refSystem: RefSystem => Some(voltLvl -> refSystem)
case _ => None
}
}
.getOrElse(Seq.empty[(VoltageLevel, RefSystem)])
}

// check for duplicates of gridIds and voltLevels which will be the key for the following map conversion
if (
CollectionUtils.listHasDuplicates(
gridIdRefSystems.map { case (gridId, _) => gridId }
)
)
throw new InvalidConfigParameterException(
s"The provided gridIds in simona.gridConfig.refSystems contains duplicates. " +
s"Please check if there are either duplicate entries or overlapping ranges!"
)
if (
CollectionUtils.listHasDuplicates(
voltLvlRefSystems.map { case (voltLvl, _) => voltLvl }
)
)
throw new InvalidConfigParameterException(
s"The provided voltLvls in simona.gridConfig.refSystems contains duplicates. " +
s"Please check your configuration for duplicates in voltLvl entries!"
)

ConfigRefSystems(gridIdRefSystems.toMap, voltLvlRefSystems.toMap)
case _ => None
}

if (CollectionUtils.listHasDuplicates(voltLvLRefSystemsList))
throw new InvalidConfigParameterException(
"The provided voltLvls in simona.gridConfig.refSystems contain duplicates. " +
"Please check your configuration for duplicates in voltLvl entries!"
)

val voltLvLRefSys: Map[VoltageLevel, RefSystem] =
parsedRefSystems.collect { case (voltLvl: VoltageLevel, values) =>
(voltLvl, values)
}.toMap

ConfigRefSystems(gridIdRefSystems, voltLvLRefSys)
case _ => defaultRefSystems
}
}

}
17 changes: 11 additions & 6 deletions src/main/scala/edu/ie3/simona/config/SimonaConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@ object SimonaConfig {
}

final case class GridConfig(
refSystems: scala.List[SimonaConfig.RefSystemConfig]
refSystems: scala.Option[scala.List[SimonaConfig.RefSystemConfig]]
)
object GridConfig {
def apply(
Expand All @@ -1145,11 +1145,16 @@ object SimonaConfig {
$tsCfgValidator: $TsCfgValidator,
): SimonaConfig.Simona.GridConfig = {
SimonaConfig.Simona.GridConfig(
refSystems = $_LSimonaConfig_RefSystemConfig(
c.getList("refSystems"),
parentPath,
$tsCfgValidator,
)
refSystems =
if (c.hasPathOrNull("refSystems"))
scala.Some(
$_LSimonaConfig_RefSystemConfig(
c.getList("refSystems"),
parentPath,
$tsCfgValidator,
)
)
else None
)
}
private def $_LSimonaConfig_RefSystemConfig(
Expand Down

0 comments on commit 741981d

Please sign in to comment.