Skip to content

Refactoring uuids in default runtime configs. #1337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: dev
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed determining FlexOptions of `Evcs` [#1322](https://github.com/ie3-institute/simona/issues/1322)
- Refactor handleFeedIn and handleConsumption of `ThermalGrid` due to qDotIntoGrid [#1343](https://github.com/ie3-institute/simona/issues/1343)
- Adapted to typed actor in simonaAPI [#1311](https://github.com/ie3-institute/simona/issues/1311)
- Refactoring uuids in default runtime configs [#1336](https://github.com/ie3-institute/simona/issues/1336)

### Fixed
- Fix rendering of references in documentation [#505](https://github.com/ie3-institute/simona/issues/505)
Expand Down
7 changes: 4 additions & 3 deletions docs/readthedocs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ The participant runtime can be either based on default configuration or individu
simona.runtime.participant.load = {
defaultConfig = {
calculateMissingReactivePowerWithModel = false
uuids = ["default"]
uuids = []
scaling = 1.0
modelBehaviour = "fix"
reference = "power"
Expand All @@ -208,9 +208,10 @@ The reactive power is determined based on the chosen Q-control of the participan

calculateMissingReactivePowerWithModel = true

Using the default configuration the universally unique identifier can be set to "default".
Using the default configuration the universally unique identifier should be empty. Alternatively, the parameter can dropped
to use the default empty list.

uuids = ["default"]
uuids = []

Choosing the scaling factor of relevant participant parameters such as rated power or annual power consumption:

Expand Down
90 changes: 23 additions & 67 deletions src/main/scala/edu/ie3/simona/config/ConfigFailFast.scala
Original file line number Diff line number Diff line change
Expand Up @@ -337,17 +337,12 @@ object ConfigFailFast extends LazyLogging {
private def checkBaseRuntimeConfigs(
defaultConfig: BaseRuntimeConfig,
individualConfigs: List[BaseRuntimeConfig],
defaultString: String = "default",
): Unit = {
// special default config check
val uuidString = defaultConfig.uuids.mkString(",")
if (
StringUtils
.cleanString(uuidString)
.toLowerCase != StringUtils.cleanString(defaultString).toLowerCase
)
val defaultUuids = defaultConfig.uuids
if (defaultUuids.nonEmpty)
logger.warn(
s"You provided '$uuidString' as uuid reference for the default model config. Those references will not be considered!"
s"You provided '${defaultUuids.mkString(",")}' as uuid reference for the default model config. Those references will not be considered!"
)

// special individual configs check
Expand All @@ -358,75 +353,36 @@ object ConfigFailFast extends LazyLogging {
)

// check that is valid for all model configs
val allConfigs = Map(defaultConfig -> Some(defaultString)) ++
individualConfigs.map(config => (config, None)).toMap

allConfigs.foreach { case (config, singleEntryStringOpt) =>
/* Checking the uuids */
if (config.uuids.isEmpty)
throw new InvalidConfigParameterException(
"There has to be at least one identifier for each participant."
)
/* If there is an option to a String that is also valid as a single entry, then check for this */
singleEntryStringOpt match {
case Some(singleString) =>
checkSingleString(singleString, config.uuids)
case None =>
config.uuids.foreach(uuid =>
try {
UUID.fromString(uuid)
} catch {
case e: IllegalArgumentException =>
throw new InvalidConfigParameterException(
s"The UUID '$uuid' cannot be parsed as it is invalid.",
e,
)
}
val allConfigs = Map(defaultConfig -> true) ++
individualConfigs.map(config => (config, false)).toMap

allConfigs.foreach { case (config, default) =>
// we only check the uuids for individual configs
if (!default) {
/* Checking the uuids */
if (config.uuids.isEmpty)
throw new InvalidConfigParameterException(
"There has to be at least one identifier for each participant."
)
}

// check for scaling
if (config.scaling < 0)
throw new InvalidConfigParameterException(
s"The scaling factor for system participants with UUID '${config.uuids.mkString(",")}' may not be negative."
)
}
}

/** Check method for a single string, normally the default string
*
* @param singleString
* the single string that is expected
* @param uuids
* the corresponding list of uuids
*/
private def checkSingleString(
singleString: String,
uuids: List[String],
): Unit = {
if (uuids.toVector.size != 1)
throw new InvalidConfigParameterException(
"The list of UUIDs is supposed to only have one entry!"
)
uuids.headOption match {
case Some(singleEntry) =>
if (
StringUtils
.cleanString(singleEntry)
.toLowerCase() != singleString
)
/* Checking if all uuids are valid */
config.uuids.foreach(uuid =>
try {
UUID.fromString(singleEntry)
UUID.fromString(uuid)
} catch {
case e: IllegalArgumentException =>
throw new InvalidConfigParameterException(
s"Found invalid UUID '$singleEntry' it was meant to be the string '$singleString' or a valid UUID.",
s"The UUID '$uuid' cannot be parsed as it is invalid.",
e,
)
}
case None =>
)
}

// check for scaling
if (config.scaling < 0)
throw new InvalidConfigParameterException(
"There is no valid uuid entry in the list."
s"The scaling factor for system participants with UUID '${config.uuids.mkString(",")}' may not be negative."
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/edu/ie3/simona/config/SimonaConfig.scala
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ object SimonaConfig {
input: InputConfig,
output: OutputConfig,
powerflow: Simona.Powerflow,
runtime: RuntimeConfig,
runtime: RuntimeConfig = RuntimeConfig(),
simulationName: String,
time: Simona.Time = Simona.Time(),
)
Expand Down
78 changes: 11 additions & 67 deletions src/test/scala/edu/ie3/simona/config/ConfigFailFastSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -596,71 +596,18 @@ class ConfigFailFastSpec extends UnitSpec with ConfigTestData {
val checkBaseRuntimeConfigs =
PrivateMethod[Unit](Symbol("checkBaseRuntimeConfigs"))

val defaultString: String = "default"

"throw an InvalidConfigParameterException if the list of UUIDs of the base model config is empty" in {
val baseRuntimeConfig = ConfigFactory.parseString(
"""simona.runtime.participant.load = {
| defaultConfig = {
| calculateMissingReactivePowerWithModel = false
| uuids = []
| scaling = 1.3
| modelBehaviour = "profile"
| reference = "power"
| }
| individualConfigs = []
|}""".stripMargin
)
val config =
baseRuntimeConfig.withFallback(typesafeConfig).resolve()
val simonaConfig = SimonaConfig(config)

intercept[InvalidConfigParameterException] {
ConfigFailFast invokePrivate checkBaseRuntimeConfigs(
simonaConfig.simona.runtime.participant.load.defaultConfig,
simonaConfig.simona.runtime.participant.load.individualConfigs,
defaultString,
)
}.getMessage shouldBe "There has to be at least one identifier for each participant."
}

"throw an InvalidConfigParameterException if a valid single key is given and the UUID of the base model config is not valid" in {
val baseRuntimeConfig = ConfigFactory.parseString(
"""simona.runtime.participant.load = {
| defaultConfig = {
| calculateMissingReactivePowerWithModel = false
| uuids = ["blabla"]
| scaling = 1.3
| modelBehaviour = "profile"
| reference = "power"
| }
| individualConfigs = []
|}""".stripMargin
)
val config =
baseRuntimeConfig.withFallback(typesafeConfig).resolve()
val simonaConfig = SimonaConfig(config)

intercept[InvalidConfigParameterException] {
ConfigFailFast invokePrivate checkBaseRuntimeConfigs(
simonaConfig.simona.runtime.participant.load.defaultConfig,
simonaConfig.simona.runtime.participant.load.individualConfigs,
defaultString,
)
}.getMessage shouldBe "Found invalid UUID 'blabla' it was meant to be the string 'default' or a valid UUID."
}

"throw an InvalidConfigParameterException if the UUID of the base model config is not valid" in {
"throw an InvalidConfigParameterException if the UUID of an individual config is not valid" in {
val baseRuntimeConfig = ConfigFactory.parseString(
"""simona.runtime.participant.load = {
| defaultConfig = {
| calculateMissingReactivePowerWithModel = false
| uuids = ["blabla"]
| scaling = 1.3
| modelBehaviour = "profile"
| reference = "power"
| }
| individualConfigs = []
| individualConfigs = [
| {
| calculateMissingReactivePowerWithModel = false
| uuids = ["blabla"]
| scaling = 1.3
| modelBehaviour = "profile"
| reference = "power"
| }
| ]
|}""".stripMargin
)
val config =
Expand All @@ -671,9 +618,8 @@ class ConfigFailFastSpec extends UnitSpec with ConfigTestData {
ConfigFailFast invokePrivate checkBaseRuntimeConfigs(
simonaConfig.simona.runtime.participant.load.defaultConfig,
simonaConfig.simona.runtime.participant.load.individualConfigs,
defaultString,
)
}.getMessage shouldBe s"Found invalid UUID 'blabla' it was meant to be the string 'default' or a valid UUID."
}.getMessage shouldBe s"The UUID 'blabla' cannot be parsed as it is invalid."
}

"throw an InvalidConfigParameterException if the scaling factor of the load model config is negative" in {
Expand All @@ -697,7 +643,6 @@ class ConfigFailFastSpec extends UnitSpec with ConfigTestData {
ConfigFailFast invokePrivate checkBaseRuntimeConfigs(
simonaConfig.simona.runtime.participant.load.defaultConfig,
simonaConfig.simona.runtime.participant.load.individualConfigs,
defaultString,
)
}.getMessage shouldBe "The scaling factor for system participants with UUID '49f250fa-41ff-4434-a083-79c98d260a76' may not be negative."
}
Expand Down Expand Up @@ -738,7 +683,6 @@ class ConfigFailFastSpec extends UnitSpec with ConfigTestData {
ConfigFailFast invokePrivate checkBaseRuntimeConfigs(
simonaConfig.simona.runtime.participant.load.defaultConfig,
simonaConfig.simona.runtime.participant.load.individualConfigs,
defaultString,
)
}.getMessage shouldBe "The basic model configurations contain ambiguous definitions."
}
Expand Down