From 32d34651b39c5b6c1ddd71281c93b55a1531a569 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Thu, 17 Oct 2024 12:24:45 +0200 Subject: [PATCH 01/14] test --- .../model/participant/StorageModelSpec.scala | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala new file mode 100644 index 0000000000..beda5cecab --- /dev/null +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -0,0 +1,121 @@ +/* + * © 2022. TU Dortmund University, + * Institute of Energy Systems, Energy Efficiency and Energy Economics, + * Research group Distribution grid planning and operation + */ + +package edu.ie3.simona.model.participant + +import edu.ie3.datamodel.models.OperationTime +import edu.ie3.datamodel.models.input.{NodeInput, OperatorInput} +import edu.ie3.datamodel.models.input.system.StorageInput +import edu.ie3.datamodel.models.input.system.`type`.StorageTypeInput +import edu.ie3.datamodel.models.input.system.characteristic.CosPhiFixed +import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils +import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions +import edu.ie3.simona.test.common.UnitSpec +import edu.ie3.util.TimeUtil +import edu.ie3.util.quantities.PowerSystemUnits +import org.scalatest.matchers.should.Matchers +import squants.energy.{KilowattHours, Kilowatts} +import squants.market.EUR +import tech.units.indriya.quantity.Quantities +import tech.units.indriya.quantity.Quantities.getQuantity + +import java.util.UUID + +class StorageModelSpec extends UnitSpec with Matchers { + + var inputModel: StorageInput = _ + final val TOLERANCE = 1e-10 + + "Setup for StorageModel" should { + "initialize the input model" in { + val nodeInput = new NodeInput( + UUID.fromString("ad39d0b9-5ad6-4588-8d92-74c7d7de9ace"), + "NodeInput", + OperatorInput.NO_OPERATOR_ASSIGNED, + OperationTime.notLimited(), + Quantities.getQuantity(1, PowerSystemUnits.PU), + false, + NodeInput.DEFAULT_GEO_POSITION, + GermanVoltageLevelUtils.LV, + -1 + ) + + val typeInput = new StorageTypeInput( + UUID.fromString("fbee4995-24dd-45e4-9c85-7d986fe99ff3"), + "Test_StorageTypeInput", + Quantities.getQuantity(10000d, EUR0), + getQuantity(0.05d, EURO_PER_MEGAWATTHOUR), + Quantities.getQuantity(100d, KILOWATTHOUR), + getQuantity(13d, KILOVOLTAMPERE), + 0.997, + getQuantity(10d, KILOWATT), + getQuantity(0.03, PU_PER_HOUR), + getQuantity(0.9, PU), + ) + + inputModel = new StorageInput( + UUID.randomUUID(), + "Test_StorageInput", + new OperatorInput(UUID.randomUUID(), "NO_OPERATOR"), + OperationTime.notLimited(), + nodeInput, + CosPhiFixed.CONSTANT_CHARACTERISTIC, + null, + typeInput + ) + } + } + + def buildStorageModel(targetSoc: Option[Double] = Option.empty): StorageModel = { + StorageModel.apply( + inputModel, + 1, + TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"), + TimeUtil.withDefaults.toZonedDateTime("2020-01-01T01:00:00Z"), + 0d, + targetSoc + ) + } + + "Calculate flex options" should { + "correctly compute the flexibility options" in { + val storageModel = buildStorageModel() + val startTick = 3600L + + val testCases = Table( + ("lastStored", "lastPower", "timeDelta", "pRef", "pMin", "pMax"), + // UNCHANGED STATE + (0.0, 0.0, 1, 0.0, 0.0, 10.0), + (0.011, 0.0, 1, 0.0, -10.0, 10.0), + (60.0, 0.0, 1, 0.0, -10.0, 10.0), + (99.989, 0.0, 1, 0.0, -10.0, 10.0), + (100.0, 0.0, 1, 0.0, -10.0, 0.0), + // CHANGED STATE + (10.0, -9.0, 3600, 0.0, 0.0, 10.0), + (10.0, -9.0, 3590, 0.0, -10.0, 10.0), + (41.0, 10.0, 3600, 0.0, -10.0, 10.0), + (60.0, -9.0, 3600, 0.0, -10.0, 10.0), + (95.5, 4.98, 3600, 0.0, -10.0, 10.0), + (95.5, 5.0, 3600, 0.0, -10.0, 0.0) + ) + + forAll(testCases) { (lastStored: Double, lastPower: Double, timeDelta: Int, pRef: Double, pMin: Double, pMax: Double) => + val data = StorageModel.StorageRelevantData(startTick + timeDelta) + val oldState = StorageModel.StorageState( + KilowattHours(lastStored), + Kilowatts(lastPower), + startTick + ) + + val result = storageModel.determineFlexOptions(data, oldState).asInstanceOf[ProvideMinMaxFlexOptions] + + result.ref.toKilowatts shouldBe pRef +- TOLERANCE + result.min.toKilowatts shouldBe pMin +- TOLERANCE + result.max.toKilowatts shouldBe pMax +- TOLERANCE + } + } + } +} From f9b228ef25c597d4178f3018c436c0c173db7b17 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Thu, 17 Oct 2024 13:26:55 +0200 Subject: [PATCH 02/14] test --- .../model/participant/StorageModelSpec.scala | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index beda5cecab..bbf5fbf0eb 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -7,18 +7,19 @@ package edu.ie3.simona.model.participant import edu.ie3.datamodel.models.OperationTime -import edu.ie3.datamodel.models.input.{NodeInput, OperatorInput} import edu.ie3.datamodel.models.input.system.StorageInput import edu.ie3.datamodel.models.input.system.`type`.StorageTypeInput import edu.ie3.datamodel.models.input.system.characteristic.CosPhiFixed +import edu.ie3.datamodel.models.input.{NodeInput, OperatorInput} import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions import edu.ie3.simona.test.common.UnitSpec import edu.ie3.util.TimeUtil import edu.ie3.util.quantities.PowerSystemUnits +import edu.ie3.util.quantities.PowerSystemUnits._ import org.scalatest.matchers.should.Matchers +import squants.Power import squants.energy.{KilowattHours, Kilowatts} -import squants.market.EUR import tech.units.indriya.quantity.Quantities import tech.units.indriya.quantity.Quantities.getQuantity @@ -28,9 +29,9 @@ class StorageModelSpec extends UnitSpec with Matchers { var inputModel: StorageInput = _ final val TOLERANCE = 1e-10 + final implicit val TOLERANCE2: Power = Kilowatts(1e-10) - "Setup for StorageModel" should { - "initialize the input model" in { + "StorageModel" should { val nodeInput = new NodeInput( UUID.fromString("ad39d0b9-5ad6-4588-8d92-74c7d7de9ace"), "NodeInput", @@ -46,7 +47,7 @@ class StorageModelSpec extends UnitSpec with Matchers { val typeInput = new StorageTypeInput( UUID.fromString("fbee4995-24dd-45e4-9c85-7d986fe99ff3"), "Test_StorageTypeInput", - Quantities.getQuantity(10000d, EUR0), + Quantities.getQuantity(10000d, EURO), getQuantity(0.05d, EURO_PER_MEGAWATTHOUR), Quantities.getQuantity(100d, KILOWATTHOUR), getQuantity(13d, KILOVOLTAMPERE), @@ -112,9 +113,9 @@ class StorageModelSpec extends UnitSpec with Matchers { val result = storageModel.determineFlexOptions(data, oldState).asInstanceOf[ProvideMinMaxFlexOptions] - result.ref.toKilowatts shouldBe pRef +- TOLERANCE - result.min.toKilowatts shouldBe pMin +- TOLERANCE - result.max.toKilowatts shouldBe pMax +- TOLERANCE + result.ref should approximate(Kilowatts(pRef)) + result.min should approximate(Kilowatts(pMin)) + result.max should approximate(Kilowatts(pMax)) } } } From c8a6519c6852e699807dd7f51c59a9a3e57ace86 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Thu, 17 Oct 2024 13:41:36 +0200 Subject: [PATCH 03/14] test --- .../edu/ie3/simona/model/participant/StorageModelSpec.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index bbf5fbf0eb..c1d31c16dd 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -68,7 +68,7 @@ class StorageModelSpec extends UnitSpec with Matchers { typeInput ) } - } + def buildStorageModel(targetSoc: Option[Double] = Option.empty): StorageModel = { StorageModel.apply( @@ -81,8 +81,7 @@ class StorageModelSpec extends UnitSpec with Matchers { ) } - "Calculate flex options" should { - "correctly compute the flexibility options" in { + "Calculate flex options correctly compute the flexibility options" in { val storageModel = buildStorageModel() val startTick = 3600L @@ -118,5 +117,4 @@ class StorageModelSpec extends UnitSpec with Matchers { result.max should approximate(Kilowatts(pMax)) } } - } } From fdb8756faf2950b02aa550d278ebda10f163a046 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Tue, 22 Oct 2024 11:37:09 +0200 Subject: [PATCH 04/14] Rewrote StorageModelTest from groovy to scala --- CHANGELOG.md | 1 + .../model/participant/StorageModelTest.groovy | 374 ---------------- .../model/participant/StorageModelSpec.scala | 408 +++++++++++++++--- 3 files changed, 354 insertions(+), 429 deletions(-) delete mode 100644 src/test/groovy/edu/ie3/simona/model/participant/StorageModelTest.groovy diff --git a/CHANGELOG.md b/CHANGELOG.md index b5c786457f..120d71724b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,6 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Renamed `ActivityStartTrigger`, `ScheduleTriggerMessage`, `CompletionMessage` in UML Diagrams[#675](https://github.com/ie3-institute/simona/issues/675) - Simplifying quantity integration in QuantityUtil [#973](https://github.com/ie3-institute/simona/issues/973) - Reorganized Jenkins pipeline to separate build and test stages for better efficiency [#938](https://github.com/ie3-institute/simona/issues/938) +- Rewrote StorageModelTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) ### Fixed - Removed a repeated line in the documentation of vn_simona config [#658](https://github.com/ie3-institute/simona/issues/658) diff --git a/src/test/groovy/edu/ie3/simona/model/participant/StorageModelTest.groovy b/src/test/groovy/edu/ie3/simona/model/participant/StorageModelTest.groovy deleted file mode 100644 index a28a405901..0000000000 --- a/src/test/groovy/edu/ie3/simona/model/participant/StorageModelTest.groovy +++ /dev/null @@ -1,374 +0,0 @@ -/* - * © 2022. TU Dortmund University, - * Institute of Energy Systems, Energy Efficiency and Energy Economics, - * Research group Distribution grid planning and operation - */ - -package edu.ie3.simona.model.participant - -import edu.ie3.datamodel.models.OperationTime -import edu.ie3.datamodel.models.input.NodeInput -import edu.ie3.datamodel.models.input.OperatorInput -import edu.ie3.datamodel.models.input.system.StorageInput -import edu.ie3.datamodel.models.input.system.characteristic.CosPhiFixed -import edu.ie3.datamodel.models.input.system.type.StorageTypeInput -import edu.ie3.datamodel.models.voltagelevels.GermanVoltageLevelUtils -import edu.ie3.simona.ontology.messages.flex.MinMaxFlexibilityMessage.ProvideMinMaxFlexOptions -import edu.ie3.util.TimeUtil -import edu.ie3.util.scala.quantities.Sq -import scala.Option -import spock.lang.Shared -import spock.lang.Specification -import squants.energy.* - -import static edu.ie3.util.quantities.PowerSystemUnits.* -import static tech.units.indriya.quantity.Quantities.getQuantity - -class StorageModelTest extends Specification { - - @Shared - StorageInput inputModel - @Shared - static final Double TOLERANCE = 1e-10 - - def setupSpec() { - def nodeInput = new NodeInput( - UUID.fromString("ad39d0b9-5ad6-4588-8d92-74c7d7de9ace"), - "NodeInput", - OperatorInput.NO_OPERATOR_ASSIGNED, - OperationTime.notLimited(), - getQuantity(1d, PU), - false, - NodeInput.DEFAULT_GEO_POSITION, - GermanVoltageLevelUtils.LV, - -1) - - def typeInput = new StorageTypeInput( - UUID.fromString("fbee4995-24dd-45e4-9c85-7d986fe99ff3"), - "Test_StorageTypeInput", - getQuantity(10000d, EURO), - getQuantity(0.05d, EURO_PER_MEGAWATTHOUR), - getQuantity(100d, KILOWATTHOUR), - getQuantity(13d, KILOVOLTAMPERE), - 0.997, - getQuantity(10d, KILOWATT), - getQuantity(0.03, PU_PER_HOUR), - getQuantity(0.9, PU), - ) - - inputModel = new StorageInput( - UUID.randomUUID(), - "Test_StorageInput", - new OperatorInput(UUID.randomUUID(), "NO_OPERATOR"), - OperationTime.notLimited(), - nodeInput, - CosPhiFixed.CONSTANT_CHARACTERISTIC, - null, - typeInput - ) - } - - def buildStorageModel(Option targetSoc = Option.empty()) { - return StorageModel.apply(inputModel, 1, - TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"), - TimeUtil.withDefaults.toZonedDateTime("2020-01-01T01:00:00Z"), - 0d, - targetSoc) - } - - def "Calculate flex options"() { - given: - def storageModel = buildStorageModel() - def startTick = 3600L - def data = new StorageModel.StorageRelevantData(startTick + timeDelta) - def oldState = new StorageModel.StorageState( - Sq.create(lastStored.doubleValue(), KilowattHours$.MODULE$), - Sq.create(lastPower.doubleValue(), Kilowatts$.MODULE$), - startTick - ) - - when: - def result = (ProvideMinMaxFlexOptions) storageModel.determineFlexOptions(data, oldState) - - then: - Math.abs(result.ref().toKilowatts() - pRef) < TOLERANCE - Math.abs(result.min().toKilowatts() - pMin) < TOLERANCE - Math.abs(result.max().toKilowatts() - pMax) < TOLERANCE - - where: - lastStored | lastPower | timeDelta || pRef | pMin | pMax - // UNCHANGED STATE - // completely empty - 0 | 0 | 1 || 0 | 0 | 10 - // at a tiny bit above empty - 0.011d | 0 | 1 || 0 | -10 | 10 - // at mid-level charge - 60 | 0 | 1 || 0 | -10 | 10 - // almost fully charged - 99.989d | 0 | 1 || 0 | -10 | 10 - // fully charged - 100 | 0 | 1 || 0 | -10 | 0 - // CHANGED STATE - // discharged to empty - 10 | -9 | 3600 || 0 | 0 | 10 - // almost discharged to lowest allowed charge - 10 | -9 | 3590 || 0 | -10 | 10 - // charged to mid-level charge - 41 | 10 | 3600 || 0 | -10 | 10 - // discharged to mid-level charge - 60 | -9 | 3600 || 0 | -10 | 10 - // almost fully charged - 95.5 | 4.98 | 3600 || 0 | -10 | 10 - // fully charged - 95.5 | 5 | 3600 || 0 | -10 | 0 - } - - def "Calculate flex options with target SOC"() { - given: - def storageModel = buildStorageModel(Option.apply(0.5d)) - def startTick = 3600L - def data = new StorageModel.StorageRelevantData(startTick + 1) - def oldState = new StorageModel.StorageState( - Sq.create(lastStored.doubleValue(), KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = (ProvideMinMaxFlexOptions) storageModel.determineFlexOptions(data, oldState) - - then: - Math.abs(result.ref().toKilowatts() - pRef) < TOLERANCE - Math.abs(result.min().toKilowatts() - pMin) < TOLERANCE - Math.abs(result.max().toKilowatts() - pMax) < TOLERANCE - - where: - lastStored || pRef | pMin | pMax - // completely empty - 0 || 10 | 0 | 10 - // below margin of ref power target - 49.9974 || 10 | -10 | 10 - // within margin below ref power target - 49.9976 || 0 | -10 | 10 - // exactly at ref power target - 50 || 0 | -10 | 10 - // within margin above ref power target - 50.0030 || 0 | -10 | 10 - // above margin of ref power target - 50.0031 || -10 | -10 | 10 - // at mid-level charge - 60 || -10 | -10 | 10 - // fully charged - 100 || -10 | -10 | 0 - } - - def "Handle controlled power change"() { - given: - def storageModel = buildStorageModel() - def startTick = 3600L - def data = new StorageModel.StorageRelevantData(startTick + 1) - def oldState = new StorageModel.StorageState( - Sq.create(lastStored.doubleValue(), KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = storageModel.handleControlledPowerChange( - data, - oldState, - Sq.create(setPower.doubleValue(), Kilowatts$.MODULE$) - ) - - then: - Math.abs(result._1.chargingPower().toKilowatts() - expPower.doubleValue()) < TOLERANCE - result._1.tick() == startTick + 1 - Math.abs(result._1.storedEnergy().toKilowattHours() - lastStored.doubleValue()) < TOLERANCE - def flexChangeIndication = result._2 - flexChangeIndication.changesAtTick().defined == expScheduled - flexChangeIndication.changesAtTick().map(x -> x == startTick + 1 + expDelta).getOrElse(_ -> true) - flexChangeIndication.changesAtNextActivation() == expActiveNext - - where: - lastStored | setPower || expPower | expActiveNext | expScheduled | expDelta - // no power - 0 | 0 || 0 | false | false | 0 - 50 | 0 || 0 | false | false | 0 - 100 | 0 || 0 | false | false | 0 - // charging on empty - 0 | 1 || 1 | true | true | 100 * 3600 / 0.9 - 0 | 2.5 || 2.5 | true | true | 40 * 3600 / 0.9 - 0 | 5 || 5 | true | true | 20 * 3600 / 0.9 - 0 | 10 || 10 | true | true | 10 * 3600 / 0.9 - // charging on half full - 50 | 5 || 5 | false | true | 10 * 3600 / 0.9 - 50 | 10 || 10 | false | true | 5 * 3600 / 0.9 - // discharging on half full - 50 | -4.5 || -4.5 | false | true | 10 * 3600 - 50 | -9 || -9 | false | true | 5 * 3600 - // discharging on full - 100 | -4.5 || -4.5 | true | true | 20 * 3600 - 100 | -9 || -9 | true | true | 10 * 3600 - } - - def "Handle controlled power change with ref target SOC"() { - given: - def storageModel = buildStorageModel(Option.apply(0.5d)) - def startTick = 3600L - def data = new StorageModel.StorageRelevantData(startTick + 1) - def oldState = new StorageModel.StorageState( - Sq.create(lastStored.doubleValue(), KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = storageModel.handleControlledPowerChange( - data, - oldState, - Sq.create(setPower.doubleValue(), Kilowatts$.MODULE$) - ) - - then: - Math.abs(result._1.chargingPower().toKilowatts() - expPower.doubleValue()) < TOLERANCE - result._1.tick() == startTick + 1 - Math.abs(result._1.storedEnergy().toKilowattHours() - lastStored.doubleValue()) < TOLERANCE - def flexChangeIndication = result._2 - flexChangeIndication.changesAtTick().defined == expScheduled - flexChangeIndication.changesAtTick().map(x -> x == startTick + 1 + expDelta).getOrElse(_ -> true) - flexChangeIndication.changesAtNextActivation() == expActiveNext - - where: - lastStored | setPower || expPower | expActiveNext | expScheduled | expDelta - // no power - 0 | 0 || 0 | false | false | 0 - 50 | 0 || 0 | false | false | 0 - 100 | 0 || 0 | false | false | 0 - // charging on empty - 0 | 1 || 1 | true | true | 50 * 3600 / 0.9 - 0 | 2.5 || 2.5 | true | true | 20 * 3600 / 0.9 - 0 | 5 || 5 | true | true | 10 * 3600 / 0.9 - 0 | 10 || 10 | true | true | 5 * 3600 / 0.9 - // charging on target ref - 50 | 5 || 5 | true | true | 10 * 3600 / 0.9 - 50 | 10 || 10 | true | true | 5 * 3600 / 0.9 - // discharging on target ref - 50 | -4.5 || -4.5 | true | true | 10 * 3600 - 50 | -9 || -9 | true | true | 5 * 3600 - // discharging on full - 100 | -4.5 || -4.5 | true | true | 10 * 3600 - 100 | -9 || -9 | true | true | 5 * 3600 - } - - def "Handle the edge case of discharging in tolerance margins"() { - given: - def storageModel = buildStorageModel() - def startTick = 1800L - def data = new StorageModel.StorageRelevantData(startTick + 1) - // margin is at ~ 0.0030864 kWh - def oldState = new StorageModel.StorageState( - Sq.create(0.002d, KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = storageModel.handleControlledPowerChange( - data, - oldState, - Sq.create(-5d, Kilowatts$.MODULE$) - ) - - then: - Math.abs(result._1.chargingPower().toKilowatts()) < TOLERANCE - result._1.tick() == startTick + 1 - Math.abs(result._1.storedEnergy().toKilowattHours() - oldState.storedEnergy().toKilowattHours()) < TOLERANCE - def flexChangeIndication = result._2 - !flexChangeIndication.changesAtTick().defined - flexChangeIndication.changesAtNextActivation() - } - - def "Handle the edge case of charging in tolerance margins"() { - given: - def storageModel = buildStorageModel() - def startTick = 1800L - def data = new StorageModel.StorageRelevantData(startTick + 1) - // margin is at ~ 99.9975 kWh - def oldState = new StorageModel.StorageState( - Sq.create(99.999d, KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = storageModel.handleControlledPowerChange( - data, - oldState, - Sq.create(9d, Kilowatts$.MODULE$) - ) - - then: - Math.abs(result._1.chargingPower().toKilowatts()) < TOLERANCE - result._1.tick() == startTick + 1 - Math.abs(result._1.storedEnergy().toKilowattHours() - oldState.storedEnergy().toKilowattHours()) < TOLERANCE - def flexChangeIndication = result._2 - !flexChangeIndication.changesAtTick().defined - flexChangeIndication.changesAtNextActivation() - } - - def "Handle the edge case of discharging in positive target margin"() { - given: - def storageModel = buildStorageModel(Option.apply(0.3d)) - def startTick = 1800L - def data = new StorageModel.StorageRelevantData(startTick + 1) - // margin is at ~ 30.0025 kWh - def oldState = new StorageModel.StorageState( - Sq.create(30.0024d, KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = storageModel.handleControlledPowerChange( - data, - oldState, - Sq.create(-9d, Kilowatts$.MODULE$) - ) - - then: - Math.abs(result._1.chargingPower().toKilowatts() - (-9d)) < TOLERANCE - result._1.tick() == startTick + 1 - Math.abs(result._1.storedEnergy().toKilowattHours() - oldState.storedEnergy().toKilowattHours()) < TOLERANCE - def flexChangeIndication = result._2 - flexChangeIndication.changesAtTick() == Option.apply(startTick + 1L + 10801L) - flexChangeIndication.changesAtNextActivation() - } - - def "Handle the edge case of charging in negative target margin"() { - given: - def storageModel = buildStorageModel(Option.apply(0.4d)) - def startTick = 1800L - def data = new StorageModel.StorageRelevantData(startTick + 1) - // margin is at ~ 39.9975 kWh - def oldState = new StorageModel.StorageState( - Sq.create(39.998d, KilowattHours$.MODULE$), - Sq.create(0d, Kilowatts$.MODULE$), - startTick - ) - - when: - def result = storageModel.handleControlledPowerChange( - data, - oldState, - Sq.create(5d, Kilowatts$.MODULE$) - ) - - then: - Math.abs(result._1.chargingPower().toKilowatts() - (5d)) < TOLERANCE - result._1.tick() == startTick + 1 - Math.abs(result._1.storedEnergy().toKilowattHours() - oldState.storedEnergy().toKilowattHours()) < TOLERANCE - def flexChangeIndication = result._2 - flexChangeIndication.changesAtTick() == Option.apply(startTick + 1L + 48002L) - flexChangeIndication.changesAtNextActivation() - } -} diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index c1d31c16dd..e235a1d233 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -18,8 +18,8 @@ import edu.ie3.util.TimeUtil import edu.ie3.util.quantities.PowerSystemUnits import edu.ie3.util.quantities.PowerSystemUnits._ import org.scalatest.matchers.should.Matchers -import squants.Power import squants.energy.{KilowattHours, Kilowatts} +import squants.{Energy, Power} import tech.units.indriya.quantity.Quantities import tech.units.indriya.quantity.Quantities.getQuantity @@ -27,61 +27,63 @@ import java.util.UUID class StorageModelSpec extends UnitSpec with Matchers { - var inputModel: StorageInput = _ - final val TOLERANCE = 1e-10 - final implicit val TOLERANCE2: Power = Kilowatts(1e-10) + final val inputModel: StorageInput = createStorageInput() + final implicit val powerTolerance: Power = Kilowatts(1e-10) + final implicit val energyTolerance: Energy = KilowattHours(1e-10) - "StorageModel" should { - val nodeInput = new NodeInput( - UUID.fromString("ad39d0b9-5ad6-4588-8d92-74c7d7de9ace"), - "NodeInput", - OperatorInput.NO_OPERATOR_ASSIGNED, - OperationTime.notLimited(), - Quantities.getQuantity(1, PowerSystemUnits.PU), - false, - NodeInput.DEFAULT_GEO_POSITION, - GermanVoltageLevelUtils.LV, - -1 - ) - - val typeInput = new StorageTypeInput( - UUID.fromString("fbee4995-24dd-45e4-9c85-7d986fe99ff3"), - "Test_StorageTypeInput", - Quantities.getQuantity(10000d, EURO), - getQuantity(0.05d, EURO_PER_MEGAWATTHOUR), - Quantities.getQuantity(100d, KILOWATTHOUR), - getQuantity(13d, KILOVOLTAMPERE), - 0.997, - getQuantity(10d, KILOWATT), - getQuantity(0.03, PU_PER_HOUR), - getQuantity(0.9, PU), - ) + def createStorageInput(): StorageInput = { + val nodeInput = new NodeInput( + UUID.fromString("ad39d0b9-5ad6-4588-8d92-74c7d7de9ace"), + "NodeInput", + OperatorInput.NO_OPERATOR_ASSIGNED, + OperationTime.notLimited(), + Quantities.getQuantity(1, PowerSystemUnits.PU), + false, + NodeInput.DEFAULT_GEO_POSITION, + GermanVoltageLevelUtils.LV, + -1, + ) - inputModel = new StorageInput( - UUID.randomUUID(), - "Test_StorageInput", - new OperatorInput(UUID.randomUUID(), "NO_OPERATOR"), - OperationTime.notLimited(), - nodeInput, - CosPhiFixed.CONSTANT_CHARACTERISTIC, - null, - typeInput - ) - } + val typeInput = new StorageTypeInput( + UUID.fromString("fbee4995-24dd-45e4-9c85-7d986fe99ff3"), + "Test_StorageTypeInput", + Quantities.getQuantity(10000d, EURO), + getQuantity(0.05d, EURO_PER_MEGAWATTHOUR), + Quantities.getQuantity(100d, KILOWATTHOUR), + getQuantity(13d, KILOVOLTAMPERE), + 0.997, + getQuantity(10d, KILOWATT), + getQuantity(0.03, PU_PER_HOUR), + getQuantity(0.9, PU), + ) + new StorageInput( + UUID.randomUUID(), + "Test_StorageInput", + new OperatorInput(UUID.randomUUID(), "NO_OPERATOR"), + OperationTime.notLimited(), + nodeInput, + CosPhiFixed.CONSTANT_CHARACTERISTIC, + null, + typeInput, + ) + } - def buildStorageModel(targetSoc: Option[Double] = Option.empty): StorageModel = { + def buildStorageModel( + targetSoc: Option[Double] = Option.empty + ): StorageModel = { StorageModel.apply( inputModel, 1, TimeUtil.withDefaults.toZonedDateTime("2020-01-01T00:00:00Z"), TimeUtil.withDefaults.toZonedDateTime("2020-01-01T01:00:00Z"), 0d, - targetSoc + targetSoc, ) } - "Calculate flex options correctly compute the flexibility options" in { + "StorageModel" should { + "Calculate flex options" in { val storageModel = buildStorageModel() val startTick = 3600L @@ -99,22 +101,318 @@ class StorageModelSpec extends UnitSpec with Matchers { (41.0, 10.0, 3600, 0.0, -10.0, 10.0), (60.0, -9.0, 3600, 0.0, -10.0, 10.0), (95.5, 4.98, 3600, 0.0, -10.0, 10.0), - (95.5, 5.0, 3600, 0.0, -10.0, 0.0) + (95.5, 5.0, 3600, 0.0, -10.0, 0.0), ) - forAll(testCases) { (lastStored: Double, lastPower: Double, timeDelta: Int, pRef: Double, pMin: Double, pMax: Double) => - val data = StorageModel.StorageRelevantData(startTick + timeDelta) - val oldState = StorageModel.StorageState( - KilowattHours(lastStored), - Kilowatts(lastPower), - startTick - ) + forAll(testCases) { + ( + lastStored: Double, + lastPower: Double, + timeDelta: Int, + pRef: Double, + pMin: Double, + pMax: Double, + ) => + val data = StorageModel.StorageRelevantData(startTick + timeDelta) + val oldState = StorageModel.StorageState( + KilowattHours(lastStored), + Kilowatts(lastPower), + startTick, + ) - val result = storageModel.determineFlexOptions(data, oldState).asInstanceOf[ProvideMinMaxFlexOptions] + val result = storageModel + .determineFlexOptions(data, oldState) + .asInstanceOf[ProvideMinMaxFlexOptions] - result.ref should approximate(Kilowatts(pRef)) - result.min should approximate(Kilowatts(pMin)) - result.max should approximate(Kilowatts(pMax)) + result.ref should approximate(Kilowatts(pRef)) + result.min should approximate(Kilowatts(pMin)) + result.max should approximate(Kilowatts(pMax)) } } + "Calculate flex options with target SOC" in { + val storageModel = buildStorageModel(Some(0.5d)) + val startTick = 3600L + val data = StorageModel.StorageRelevantData(startTick + 1) + + val testCases = Table( + ("lastStored", "pRef", "pMin", "pMax"), + // completely empty + (0.0, 10.0, 0.0, 10.0), + // below margin of ref power target + (49.9974, 10.0, -10.0, 10.0), + // within margin below ref power target + (49.9976, 0.0, -10.0, 10.0), + // exactly at ref power target + (50.0, 0.0, -10.0, 10.0), + // within margin above ref power target + (50.0030, 0.0, -10.0, 10.0), + // above margin of ref power target + (50.0031, -10.0, -10.0, 10.0), + // at mid-level charge + (60.0, -10.0, -10.0, 10.0), + // fully charged + (100.0, -10.0, -10.0, 0.0), + ) + + forAll(testCases) { + (lastStored: Double, pRef: Double, pMin: Double, pMax: Double) => + val oldState = StorageModel.StorageState( + KilowattHours(lastStored), + Kilowatts(0d), + startTick, + ) + + val result = storageModel + .determineFlexOptions(data, oldState) + .asInstanceOf[ProvideMinMaxFlexOptions] + + result.ref should approximate(Kilowatts(pRef)) + result.min should approximate(Kilowatts(pMin)) + result.max should approximate(Kilowatts(pMax)) + } + } + + "Handle controlled power change" in { + val storageModel = buildStorageModel() + val startTick = 3600L + val data = StorageModel.StorageRelevantData(startTick + 1) + val testCases = Table( + ( + "lastStored", + "setPower", + "expPower", + "expActiveNext", + "expScheduled", + "expDelta", + ), + // no power + (0.0, 0.0, 0.0, false, false, 0), + (50.0, 0.0, 0.0, false, false, 0), + (100.0, 0.0, 0.0, false, false, 0), + // charging on empty + (0.0, 1.0, 1.0, true, true, (100 * 3600 / 0.9).toInt), + (0.0, 2.5, 2.5, true, true, (40 * 3600 / 0.9).toInt), + (0.0, 5.0, 5.0, true, true, (20 * 3600 / 0.9).toInt), + (0.0, 10.0, 10.0, true, true, (10 * 3600 / 0.9).toInt), + // charging on half full + (50.0, 5.0, 5.0, false, true, (10 * 3600 / 0.9).toInt), + (50.0, 10.0, 10.0, false, true, (5 * 3600 / 0.9).toInt), + // discharging on half full + (50.0, -4.5, -4.5, false, true, 10 * 3600), + (50.0, -9.0, -9.0, false, true, 5 * 3600), + // discharging on full + (100.0, -4.5, -4.5, true, true, 20 * 3600), + (100.0, -9.0, -9.0, true, true, 10 * 3600), + ) + + forAll(testCases) { + ( + lastStored: Double, + setPower: Double, + expPower: Double, + expActiveNext: Boolean, + expScheduled: Boolean, + expDelta: Int, + ) => + val oldState = StorageModel.StorageState( + KilowattHours(lastStored), + Kilowatts(0d), + startTick, + ) + + val result = storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(setPower), + ) + + val (newState, flexChangeIndication) = result + + newState.chargingPower should approximate(Kilowatts(expPower)) + newState.tick shouldBe (startTick + 1) + newState.storedEnergy should approximate(KilowattHours(lastStored)) + + flexChangeIndication.changesAtTick.isDefined shouldBe expScheduled + flexChangeIndication.changesAtTick.forall( + _ == (startTick + 1 + expDelta) + ) shouldBe true + flexChangeIndication.changesAtNextActivation shouldBe expActiveNext + } + } + + "Handle controlled power change with ref target SOC" in { + val storageModel = buildStorageModel(Some(0.5d)) + val startTick = 3600L + val data = StorageModel.StorageRelevantData(startTick + 1) + + val testCases = Table( + ( + "lastStored", + "setPower", + "expPower", + "expActiveNext", + "expScheduled", + "expDelta", + ), + // no power + (0.0, 0.0, 0.0, false, false, 0), + (50.0, 0.0, 0.0, false, false, 0), + (100.0, 0.0, 0.0, false, false, 0), + // charging on empty + (0.0, 1.0, 1.0, true, true, (50 * 3600 / 0.9).toInt), + (0.0, 2.5, 2.5, true, true, (20 * 3600 / 0.9).toInt), + (0.0, 5.0, 5.0, true, true, (10 * 3600 / 0.9).toInt), + (0.0, 10.0, 10.0, true, true, (5 * 3600 / 0.9).toInt), + // charging on target ref + (50.0, 5.0, 5.0, true, true, (10 * 3600 / 0.9).toInt), + (50.0, 10.0, 10.0, true, true, (5 * 3600 / 0.9).toInt), + // discharging on target ref + (50.0, -4.5, -4.5, true, true, 10 * 3600), + (50.0, -9.0, -9.0, true, true, 5 * 3600), + // discharging on full + (100.0, -4.5, -4.5, true, true, 10 * 3600), + (100.0, -9.0, -9.0, true, true, 5 * 3600), + ) + + forAll(testCases) { + ( + lastStored: Double, + setPower: Double, + expPower: Double, + expActiveNext: Boolean, + expScheduled: Boolean, + expDelta: Int, + ) => + val oldState = StorageModel.StorageState( + KilowattHours(lastStored), + Kilowatts(0d), + startTick, + ) + + val result = storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(setPower), + ) + + val (newState, flexChangeIndication) = result + + newState.chargingPower should approximate(Kilowatts(expPower)) + newState.tick shouldBe (startTick + 1) + newState.storedEnergy should approximate(KilowattHours(lastStored)) + + flexChangeIndication.changesAtTick.isDefined shouldBe expScheduled + flexChangeIndication.changesAtTick.forall( + _ == (startTick + 1 + expDelta) + ) shouldBe true + flexChangeIndication.changesAtNextActivation shouldBe expActiveNext + } + } + + "Handle the edge case of discharging in tolerance margins" in { + val storageModel = buildStorageModel() + val startTick = 1800L + val data = StorageModel.StorageRelevantData(startTick + 1) + // margin is at ~ 0.0030864 kWh + val oldState = StorageModel.StorageState( + KilowattHours(0.002d), + Kilowatts(0d), + startTick, + ) + + val result = storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(-5d), + ) + + result._1.chargingPower should approximate(Kilowatts(0)) + result._1.tick shouldBe (startTick + 1) + result._1.storedEnergy should approximate(oldState.storedEnergy) + + val flexChangeIndication = result._2 + flexChangeIndication.changesAtTick.isDefined shouldBe false + flexChangeIndication.changesAtNextActivation shouldBe true + } + + "Handle the edge case of charging in tolerance margins" in { + val storageModel = buildStorageModel() + val startTick = 1800L + val data = StorageModel.StorageRelevantData(startTick + 1) + // margin is at ~ 99.9975 kWh + val oldState = StorageModel.StorageState( + KilowattHours(99.999d), + Kilowatts(0d), + startTick, + ) + + val result = storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(9d), + ) + + result._1.chargingPower should approximate(Kilowatts(0)) + result._1.tick shouldBe (startTick + 1) + result._1.storedEnergy should approximate(oldState.storedEnergy) + + val flexChangeIndication = result._2 + flexChangeIndication.changesAtTick.isDefined shouldBe false + flexChangeIndication.changesAtNextActivation shouldBe true + } + "Handle the edge case of discharging in positive target margin" in { + val storageModel = buildStorageModel(Some(0.3d)) + val startTick = 1800L + val data = new StorageModel.StorageRelevantData(startTick + 1) + // margin is at ~ 30.0025 kWh + val oldState = new StorageModel.StorageState( + KilowattHours(30.0024d), + Kilowatts(0d), + startTick, + ) + + val result = storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(-9d), + ) + + // Verifications + result._1.chargingPower should approximate(Kilowatts(-9d)) + result._1.tick shouldBe (startTick + 1) + result._1.storedEnergy should approximate(oldState.storedEnergy) + val flexChangeIndication = result._2 + flexChangeIndication.changesAtTick should be( + Some(startTick + 1L + 10801L) + ) + flexChangeIndication.changesAtNextActivation should be(true) + } + "Handle the edge case of charging in negative target margin" in { + val storageModel = buildStorageModel(Some(0.4d)) + val startTick = 1800L + val data = new StorageModel.StorageRelevantData(startTick + 1) + // margin is at ~ 39.9975 kWh + val oldState = new StorageModel.StorageState( + KilowattHours(39.998d), + Kilowatts(0d), + startTick, + ) + + val result = storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(5d), + ) + + // Verifications + result._1.chargingPower should approximate(Kilowatts(5d)) + result._1.tick shouldBe (startTick + 1) + result._1.storedEnergy should approximate(oldState.storedEnergy) + val flexChangeIndication = result._2 + flexChangeIndication.changesAtTick should be( + Some(startTick + 1L + 48002L) + ) + flexChangeIndication.changesAtNextActivation should be(true) + } + } } From 5506f9ee2ec017d19b87dfe329521e57a9603f82 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Tue, 22 Oct 2024 11:38:37 +0200 Subject: [PATCH 05/14] Remove unnecessary use of new. --- .../ie3/simona/model/participant/StorageModelSpec.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index e235a1d233..0c85da85e9 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -363,9 +363,9 @@ class StorageModelSpec extends UnitSpec with Matchers { "Handle the edge case of discharging in positive target margin" in { val storageModel = buildStorageModel(Some(0.3d)) val startTick = 1800L - val data = new StorageModel.StorageRelevantData(startTick + 1) + val data = StorageModel.StorageRelevantData(startTick + 1) // margin is at ~ 30.0025 kWh - val oldState = new StorageModel.StorageState( + val oldState = StorageModel.StorageState( KilowattHours(30.0024d), Kilowatts(0d), startTick, @@ -390,9 +390,9 @@ class StorageModelSpec extends UnitSpec with Matchers { "Handle the edge case of charging in negative target margin" in { val storageModel = buildStorageModel(Some(0.4d)) val startTick = 1800L - val data = new StorageModel.StorageRelevantData(startTick + 1) + val data = StorageModel.StorageRelevantData(startTick + 1) // margin is at ~ 39.9975 kWh - val oldState = new StorageModel.StorageState( + val oldState = StorageModel.StorageState( KilowattHours(39.998d), Kilowatts(0d), startTick, From 7ada36fd5b6b57fb62a2833613afc3fd414a0ae2 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Mon, 28 Oct 2024 12:48:14 +0100 Subject: [PATCH 06/14] Use zeroKW and remove comments --- .../model/participant/StorageModelSpec.scala | 53 +++++++++++-------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index 0c85da85e9..c93c411b85 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -17,6 +17,7 @@ import edu.ie3.simona.test.common.UnitSpec import edu.ie3.util.TimeUtil import edu.ie3.util.quantities.PowerSystemUnits import edu.ie3.util.quantities.PowerSystemUnits._ +import edu.ie3.util.scala.quantities.DefaultQuantities.zeroKW import org.scalatest.matchers.should.Matchers import squants.energy.{KilowattHours, Kilowatts} import squants.{Energy, Power} @@ -28,8 +29,8 @@ import java.util.UUID class StorageModelSpec extends UnitSpec with Matchers { final val inputModel: StorageInput = createStorageInput() - final implicit val powerTolerance: Power = Kilowatts(1e-10) - final implicit val energyTolerance: Energy = KilowattHours(1e-10) + implicit val powerTolerance: Power = Kilowatts(1e-10) + implicit val energyTolerance: Energy = KilowattHours(1e-10) def createStorageInput(): StorageInput = { val nodeInput = new NodeInput( @@ -90,17 +91,28 @@ class StorageModelSpec extends UnitSpec with Matchers { val testCases = Table( ("lastStored", "lastPower", "timeDelta", "pRef", "pMin", "pMax"), // UNCHANGED STATE + // completely empty (0.0, 0.0, 1, 0.0, 0.0, 10.0), + // at a tiny bit above empty (0.011, 0.0, 1, 0.0, -10.0, 10.0), + // at mid-level charge (60.0, 0.0, 1, 0.0, -10.0, 10.0), + // almost fully charged (99.989, 0.0, 1, 0.0, -10.0, 10.0), + // fully charged (100.0, 0.0, 1, 0.0, -10.0, 0.0), // CHANGED STATE + // discharged to empty (10.0, -9.0, 3600, 0.0, 0.0, 10.0), + // almost discharged to lowest allowed charge (10.0, -9.0, 3590, 0.0, -10.0, 10.0), + // charged to mid-level charge (41.0, 10.0, 3600, 0.0, -10.0, 10.0), + // discharged to mid-level charge (60.0, -9.0, 3600, 0.0, -10.0, 10.0), + // almost fully charged (95.5, 4.98, 3600, 0.0, -10.0, 10.0), + // fully charged (95.5, 5.0, 3600, 0.0, -10.0, 0.0), ) @@ -158,7 +170,7 @@ class StorageModelSpec extends UnitSpec with Matchers { (lastStored: Double, pRef: Double, pMin: Double, pMax: Double) => val oldState = StorageModel.StorageState( KilowattHours(lastStored), - Kilowatts(0d), + zeroKW, startTick, ) @@ -220,14 +232,12 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel.handleControlledPowerChange( + val (newState, flexChangeIndication) = storageModel.handleControlledPowerChange( data, oldState, Kilowatts(setPower), ) - val (newState, flexChangeIndication) = result - newState.chargingPower should approximate(Kilowatts(expPower)) newState.tick shouldBe (startTick + 1) newState.storedEnergy should approximate(KilowattHours(lastStored)) @@ -259,13 +269,14 @@ class StorageModelSpec extends UnitSpec with Matchers { (50.0, 0.0, 0.0, false, false, 0), (100.0, 0.0, 0.0, false, false, 0), // charging on empty - (0.0, 1.0, 1.0, true, true, (50 * 3600 / 0.9).toInt), - (0.0, 2.5, 2.5, true, true, (20 * 3600 / 0.9).toInt), - (0.0, 5.0, 5.0, true, true, (10 * 3600 / 0.9).toInt), - (0.0, 10.0, 10.0, true, true, (5 * 3600 / 0.9).toInt), + (0.0, 1.0, 1.0, true, true, 50 * 3600 / 0.9), + //), + // (0.0, 2.5, 2.5, true, true, (20 * 3600 / 0.9)), + // (0.0, 5.0, 5.0, true, true, (10 * 3600 / 0.9)), + //(0.0, 10.0, 10.0, true, true, 5 * 3600 / 0.9), // charging on target ref - (50.0, 5.0, 5.0, true, true, (10 * 3600 / 0.9).toInt), - (50.0, 10.0, 10.0, true, true, (5 * 3600 / 0.9).toInt), + // (50.0, 5.0, 5.0, true, true, 10 * 3600 / 0.9), + // (50.0, 10.0, 10.0, true, true, 5 * 3600 / 0.9), // discharging on target ref (50.0, -4.5, -4.5, true, true, 10 * 3600), (50.0, -9.0, -9.0, true, true, 5 * 3600), @@ -276,16 +287,17 @@ class StorageModelSpec extends UnitSpec with Matchers { forAll(testCases) { ( + lastStored: Double, setPower: Double, expPower: Double, expActiveNext: Boolean, expScheduled: Boolean, - expDelta: Int, + expDelta: Double, ) => val oldState = StorageModel.StorageState( KilowattHours(lastStored), - Kilowatts(0d), + zeroKW, startTick, ) @@ -302,6 +314,7 @@ class StorageModelSpec extends UnitSpec with Matchers { newState.storedEnergy should approximate(KilowattHours(lastStored)) flexChangeIndication.changesAtTick.isDefined shouldBe expScheduled + // flexChangeIndication.changesAtTick().map(x -> x == startTick + 1 + expDelta).getOrElse(_ -> true) flexChangeIndication.changesAtTick.forall( _ == (startTick + 1 + expDelta) ) shouldBe true @@ -326,7 +339,7 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(-5d), ) - result._1.chargingPower should approximate(Kilowatts(0)) + result._1.chargingPower should approximate(zeroKW) result._1.tick shouldBe (startTick + 1) result._1.storedEnergy should approximate(oldState.storedEnergy) @@ -342,7 +355,7 @@ class StorageModelSpec extends UnitSpec with Matchers { // margin is at ~ 99.9975 kWh val oldState = StorageModel.StorageState( KilowattHours(99.999d), - Kilowatts(0d), + zeroKW, startTick, ) @@ -352,7 +365,7 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(9d), ) - result._1.chargingPower should approximate(Kilowatts(0)) + result._1.chargingPower should approximate(zeroKW) result._1.tick shouldBe (startTick + 1) result._1.storedEnergy should approximate(oldState.storedEnergy) @@ -367,7 +380,7 @@ class StorageModelSpec extends UnitSpec with Matchers { // margin is at ~ 30.0025 kWh val oldState = StorageModel.StorageState( KilowattHours(30.0024d), - Kilowatts(0d), + zeroKW, startTick, ) @@ -377,7 +390,6 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(-9d), ) - // Verifications result._1.chargingPower should approximate(Kilowatts(-9d)) result._1.tick shouldBe (startTick + 1) result._1.storedEnergy should approximate(oldState.storedEnergy) @@ -394,7 +406,7 @@ class StorageModelSpec extends UnitSpec with Matchers { // margin is at ~ 39.9975 kWh val oldState = StorageModel.StorageState( KilowattHours(39.998d), - Kilowatts(0d), + zeroKW, startTick, ) @@ -404,7 +416,6 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(5d), ) - // Verifications result._1.chargingPower should approximate(Kilowatts(5d)) result._1.tick shouldBe (startTick + 1) result._1.storedEnergy should approximate(oldState.storedEnergy) From bcef5a84fc4db9ba5242b5f07fff64a856cd996c Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 31 Oct 2024 07:20:53 +0100 Subject: [PATCH 07/14] fix test to handle controlled power change and controlled power chang with ref target SOC --- .../model/participant/StorageModelSpec.scala | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index c93c411b85..e66a3ee408 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -198,23 +198,23 @@ class StorageModelSpec extends UnitSpec with Matchers { "expDelta", ), // no power - (0.0, 0.0, 0.0, false, false, 0), - (50.0, 0.0, 0.0, false, false, 0), - (100.0, 0.0, 0.0, false, false, 0), + (0.0, 0.0, 0.0, false, false, 0.0), + (50.0, 0.0, 0.0, false, false, 0.0), + (100.0, 0.0, 0.0, false, false, 0.0), // charging on empty - (0.0, 1.0, 1.0, true, true, (100 * 3600 / 0.9).toInt), - (0.0, 2.5, 2.5, true, true, (40 * 3600 / 0.9).toInt), - (0.0, 5.0, 5.0, true, true, (20 * 3600 / 0.9).toInt), - (0.0, 10.0, 10.0, true, true, (10 * 3600 / 0.9).toInt), + (0.0, 1.0, 1.0, true, true, 100 * 3600 / 0.9), + (0.0, 2.5, 2.5, true, true, 40 * 3600 / 0.9), + (0.0, 5.0, 5.0, true, true, 20 * 3600 / 0.9), + (0.0, 10.0, 10.0, true, true, 10 * 3600 / 0.9), // charging on half full - (50.0, 5.0, 5.0, false, true, (10 * 3600 / 0.9).toInt), - (50.0, 10.0, 10.0, false, true, (5 * 3600 / 0.9).toInt), + (50.0, 5.0, 5.0, false, true, 10 * 3600 / 0.9), + (50.0, 10.0, 10.0, false, true, 5 * 3600 / 0.9), // discharging on half full - (50.0, -4.5, -4.5, false, true, 10 * 3600), - (50.0, -9.0, -9.0, false, true, 5 * 3600), + (50.0, -4.5, -4.5, false, true, 10 * 3600.0), + (50.0, -9.0, -9.0, false, true, 5 * 3600.0), // discharging on full - (100.0, -4.5, -4.5, true, true, 20 * 3600), - (100.0, -9.0, -9.0, true, true, 10 * 3600), + (100.0, -4.5, -4.5, true, true, 20 * 3600.0), + (100.0, -9.0, -9.0, true, true, 10 * 3600.0), ) forAll(testCases) { @@ -224,7 +224,7 @@ class StorageModelSpec extends UnitSpec with Matchers { expPower: Double, expActiveNext: Boolean, expScheduled: Boolean, - expDelta: Int, + expDelta: Double, ) => val oldState = StorageModel.StorageState( KilowattHours(lastStored), @@ -232,11 +232,12 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val (newState, flexChangeIndication) = storageModel.handleControlledPowerChange( - data, - oldState, - Kilowatts(setPower), - ) + val (newState, flexChangeIndication) = + storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(setPower), + ) newState.chargingPower should approximate(Kilowatts(expPower)) newState.tick shouldBe (startTick + 1) @@ -265,29 +266,27 @@ class StorageModelSpec extends UnitSpec with Matchers { "expDelta", ), // no power - (0.0, 0.0, 0.0, false, false, 0), - (50.0, 0.0, 0.0, false, false, 0), - (100.0, 0.0, 0.0, false, false, 0), + (0.0, 0.0, 0.0, false, false, 0.0), + (50.0, 0.0, 0.0, false, false, 0.0), + (100.0, 0.0, 0.0, false, false, 0.0), // charging on empty (0.0, 1.0, 1.0, true, true, 50 * 3600 / 0.9), - //), - // (0.0, 2.5, 2.5, true, true, (20 * 3600 / 0.9)), - // (0.0, 5.0, 5.0, true, true, (10 * 3600 / 0.9)), - //(0.0, 10.0, 10.0, true, true, 5 * 3600 / 0.9), + (0.0, 2.5, 2.5, true, true, 20 * 3600 / 0.9), + (0.0, 5.0, 5.0, true, true, 10 * 3600 / 0.9), + (0.0, 10.0, 10.0, true, true, 5 * 3600 / 0.9), // charging on target ref - // (50.0, 5.0, 5.0, true, true, 10 * 3600 / 0.9), - // (50.0, 10.0, 10.0, true, true, 5 * 3600 / 0.9), + (50.0, 5.0, 5.0, true, true, 10 * 3600 / 0.9), + (50.0, 10.0, 10.0, true, true, 5 * 3600 / 0.9), // discharging on target ref - (50.0, -4.5, -4.5, true, true, 10 * 3600), - (50.0, -9.0, -9.0, true, true, 5 * 3600), + (50.0, -4.5, -4.5, true, true, 10 * 3600.0), + (50.0, -9.0, -9.0, true, true, 5 * 3600.0), // discharging on full - (100.0, -4.5, -4.5, true, true, 10 * 3600), - (100.0, -9.0, -9.0, true, true, 5 * 3600), + (100.0, -4.5, -4.5, true, true, 10 * 3600.0), + (100.0, -9.0, -9.0, true, true, 5 * 3600.0), ) forAll(testCases) { ( - lastStored: Double, setPower: Double, expPower: Double, @@ -314,7 +313,6 @@ class StorageModelSpec extends UnitSpec with Matchers { newState.storedEnergy should approximate(KilowattHours(lastStored)) flexChangeIndication.changesAtTick.isDefined shouldBe expScheduled - // flexChangeIndication.changesAtTick().map(x -> x == startTick + 1 + expDelta).getOrElse(_ -> true) flexChangeIndication.changesAtTick.forall( _ == (startTick + 1 + expDelta) ) shouldBe true From ce17f46f49d56908b9f8c5377b4f9f1ef40da236 Mon Sep 17 00:00:00 2001 From: Pierre <155652256+pierrepetersmeier@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:21:49 +0100 Subject: [PATCH 08/14] Update src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala Co-authored-by: Daniel Feismann <98817556+danielfeismann@users.noreply.github.com> --- .../edu/ie3/simona/model/participant/StorageModelSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index e66a3ee408..53cfb416bf 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -327,7 +327,7 @@ class StorageModelSpec extends UnitSpec with Matchers { // margin is at ~ 0.0030864 kWh val oldState = StorageModel.StorageState( KilowattHours(0.002d), - Kilowatts(0d), + zeroKW, startTick, ) From 5b3dacb8e0037f7b4a188c87132654ba04285a42 Mon Sep 17 00:00:00 2001 From: Pierre <155652256+pierrepetersmeier@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:23:13 +0100 Subject: [PATCH 09/14] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 636344e4d1..ac4517ba8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -92,8 +92,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rewrote ChpModelTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - Rewrote CylindricalThermalStorageTest Test from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - Replace mutable var in ChpModelSpec [#1002](https://github.com/ie3-institute/simona/issues/1002) -- Rewrote StorageModelTest from groovy to scala [#646](https://github.com/ie3-institute/simona/issues/646) - 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) ### Fixed - Removed a repeated line in the documentation of vn_simona config [#658](https://github.com/ie3-institute/simona/issues/658) From 235ff63783a20decb10c2832e3e840025bce7e8a Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Tue, 5 Nov 2024 14:23:01 +0100 Subject: [PATCH 10/14] fmt --- .../edu/ie3/simona/model/participant/StorageModelSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index 53cfb416bf..8f2ca46def 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -327,7 +327,7 @@ class StorageModelSpec extends UnitSpec with Matchers { // margin is at ~ 0.0030864 kWh val oldState = StorageModel.StorageState( KilowattHours(0.002d), - zeroKW, + zeroKW, startTick, ) From 0977febd97f99494db8cff16eab29b64c02b8221 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Tue, 5 Nov 2024 15:15:30 +0100 Subject: [PATCH 11/14] remove unnecessary use of val result. --- .../model/participant/StorageModelSpec.scala | 123 ++++++++++-------- 1 file changed, 71 insertions(+), 52 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index 8f2ca46def..7e4d85ce8c 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -228,7 +228,7 @@ class StorageModelSpec extends UnitSpec with Matchers { ) => val oldState = StorageModel.StorageState( KilowattHours(lastStored), - Kilowatts(0d), + zeroKW, startTick, ) @@ -300,13 +300,12 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel.handleControlledPowerChange( - data, - oldState, - Kilowatts(setPower), - ) - - val (newState, flexChangeIndication) = result + val (newState, flexChangeIndication) = + storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(setPower), + ) newState.chargingPower should approximate(Kilowatts(expPower)) newState.tick shouldBe (startTick + 1) @@ -331,19 +330,23 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel.handleControlledPowerChange( - data, - oldState, - Kilowatts(-5d), - ) + val (newState, flexChangeIndication) = + storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(-5d), + ) - result._1.chargingPower should approximate(zeroKW) - result._1.tick shouldBe (startTick + 1) - result._1.storedEnergy should approximate(oldState.storedEnergy) + (newState, flexChangeIndication)._1.chargingPower should approximate( + zeroKW + ) + (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) + (newState, flexChangeIndication)._1.storedEnergy should approximate( + oldState.storedEnergy + ) - val flexChangeIndication = result._2 - flexChangeIndication.changesAtTick.isDefined shouldBe false - flexChangeIndication.changesAtNextActivation shouldBe true + (newState, flexChangeIndication)._2.changesAtTick.isDefined shouldBe false + (newState, flexChangeIndication)._2.changesAtNextActivation shouldBe true } "Handle the edge case of charging in tolerance margins" in { @@ -357,19 +360,23 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel.handleControlledPowerChange( - data, - oldState, - Kilowatts(9d), - ) + val (newState, flexChangeIndication) = + storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(9d), + ) - result._1.chargingPower should approximate(zeroKW) - result._1.tick shouldBe (startTick + 1) - result._1.storedEnergy should approximate(oldState.storedEnergy) + (newState, flexChangeIndication)._1.chargingPower should approximate( + zeroKW + ) + (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) + (newState, flexChangeIndication)._1.storedEnergy should approximate( + oldState.storedEnergy + ) - val flexChangeIndication = result._2 - flexChangeIndication.changesAtTick.isDefined shouldBe false - flexChangeIndication.changesAtNextActivation shouldBe true + (newState, flexChangeIndication)._2.changesAtTick.isDefined shouldBe false + (newState, flexChangeIndication)._2.changesAtNextActivation shouldBe true } "Handle the edge case of discharging in positive target margin" in { val storageModel = buildStorageModel(Some(0.3d)) @@ -382,20 +389,26 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel.handleControlledPowerChange( - data, - oldState, - Kilowatts(-9d), - ) + val (newState, flexChangeIndication) = + storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(-9d), + ) - result._1.chargingPower should approximate(Kilowatts(-9d)) - result._1.tick shouldBe (startTick + 1) - result._1.storedEnergy should approximate(oldState.storedEnergy) - val flexChangeIndication = result._2 - flexChangeIndication.changesAtTick should be( + (newState, flexChangeIndication)._1.chargingPower should approximate( + Kilowatts(-9d) + ) + (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) + (newState, flexChangeIndication)._1.storedEnergy should approximate( + oldState.storedEnergy + ) + (newState, flexChangeIndication)._2.changesAtTick should be( Some(startTick + 1L + 10801L) ) - flexChangeIndication.changesAtNextActivation should be(true) + (newState, flexChangeIndication)._2.changesAtNextActivation should be( + true + ) } "Handle the edge case of charging in negative target margin" in { val storageModel = buildStorageModel(Some(0.4d)) @@ -408,20 +421,26 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel.handleControlledPowerChange( - data, - oldState, - Kilowatts(5d), - ) + val (newState, flexChangeIndication) = + storageModel.handleControlledPowerChange( + data, + oldState, + Kilowatts(5d), + ) - result._1.chargingPower should approximate(Kilowatts(5d)) - result._1.tick shouldBe (startTick + 1) - result._1.storedEnergy should approximate(oldState.storedEnergy) - val flexChangeIndication = result._2 - flexChangeIndication.changesAtTick should be( + (newState, flexChangeIndication)._1.chargingPower should approximate( + Kilowatts(5d) + ) + (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) + (newState, flexChangeIndication)._1.storedEnergy should approximate( + oldState.storedEnergy + ) + (newState, flexChangeIndication)._2.changesAtTick should be( Some(startTick + 1L + 48002L) ) - flexChangeIndication.changesAtNextActivation should be(true) + (newState, flexChangeIndication)._2.changesAtNextActivation should be( + true + ) } } } From afc673b017ca61a1a5d941a2132341fa73ce01c5 Mon Sep 17 00:00:00 2001 From: Pierre <155652256+pierrepetersmeier@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:27:31 +0100 Subject: [PATCH 12/14] Update src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala Co-authored-by: Daniel Feismann <98817556+danielfeismann@users.noreply.github.com> --- .../edu/ie3/simona/model/participant/StorageModelSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index 7e4d85ce8c..4326925a05 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -428,7 +428,7 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(5d), ) - (newState, flexChangeIndication)._1.chargingPower should approximate( + newState.chargingPower should approximate( Kilowatts(5d) ) (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) From 98f390010fb3ec13ea9feed2e487e7fbcac75d76 Mon Sep 17 00:00:00 2001 From: pierrepetersmeier Date: Wed, 6 Nov 2024 11:00:54 +0100 Subject: [PATCH 13/14] Simplified code by accessing tuple directly. --- .../model/participant/StorageModelSpec.scala | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index 4326925a05..2375639729 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -337,16 +337,16 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(-5d), ) - (newState, flexChangeIndication)._1.chargingPower should approximate( + newState.chargingPower should approximate( zeroKW ) - (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) - (newState, flexChangeIndication)._1.storedEnergy should approximate( + newState.tick shouldBe (startTick + 1) + newState.storedEnergy should approximate( oldState.storedEnergy ) - (newState, flexChangeIndication)._2.changesAtTick.isDefined shouldBe false - (newState, flexChangeIndication)._2.changesAtNextActivation shouldBe true + flexChangeIndication.changesAtTick.isDefined shouldBe false + flexChangeIndication.changesAtNextActivation shouldBe true } "Handle the edge case of charging in tolerance margins" in { @@ -367,16 +367,16 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(9d), ) - (newState, flexChangeIndication)._1.chargingPower should approximate( + newState.chargingPower should approximate( zeroKW ) - (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) - (newState, flexChangeIndication)._1.storedEnergy should approximate( + newState.tick shouldBe (startTick + 1) + newState.storedEnergy should approximate( oldState.storedEnergy ) - (newState, flexChangeIndication)._2.changesAtTick.isDefined shouldBe false - (newState, flexChangeIndication)._2.changesAtNextActivation shouldBe true + flexChangeIndication.changesAtTick.isDefined shouldBe false + flexChangeIndication.changesAtNextActivation shouldBe true } "Handle the edge case of discharging in positive target margin" in { val storageModel = buildStorageModel(Some(0.3d)) @@ -396,17 +396,17 @@ class StorageModelSpec extends UnitSpec with Matchers { Kilowatts(-9d), ) - (newState, flexChangeIndication)._1.chargingPower should approximate( + newState.chargingPower should approximate( Kilowatts(-9d) ) - (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) - (newState, flexChangeIndication)._1.storedEnergy should approximate( + newState.tick shouldBe (startTick + 1) + newState.storedEnergy should approximate( oldState.storedEnergy ) - (newState, flexChangeIndication)._2.changesAtTick should be( + flexChangeIndication.changesAtTick should be( Some(startTick + 1L + 10801L) ) - (newState, flexChangeIndication)._2.changesAtNextActivation should be( + flexChangeIndication.changesAtNextActivation should be( true ) } @@ -431,14 +431,14 @@ class StorageModelSpec extends UnitSpec with Matchers { newState.chargingPower should approximate( Kilowatts(5d) ) - (newState, flexChangeIndication)._1.tick shouldBe (startTick + 1) - (newState, flexChangeIndication)._1.storedEnergy should approximate( + newState.tick shouldBe (startTick + 1) + newState.storedEnergy should approximate( oldState.storedEnergy ) - (newState, flexChangeIndication)._2.changesAtTick should be( + flexChangeIndication.changesAtTick should be( Some(startTick + 1L + 48002L) ) - (newState, flexChangeIndication)._2.changesAtNextActivation should be( + flexChangeIndication.changesAtNextActivation should be( true ) } From 2c1252e282643c47ff1f4dfee9c823c8bbc309c6 Mon Sep 17 00:00:00 2001 From: danielfeismann Date: Thu, 7 Nov 2024 10:47:54 +0100 Subject: [PATCH 14/14] handle sonar code smell when using asInstanceOf --- .../model/participant/StorageModelSpec.scala | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala index 2375639729..4d6fff7060 100644 --- a/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala +++ b/src/test/scala/edu/ie3/simona/model/participant/StorageModelSpec.scala @@ -132,13 +132,15 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel - .determineFlexOptions(data, oldState) - .asInstanceOf[ProvideMinMaxFlexOptions] - - result.ref should approximate(Kilowatts(pRef)) - result.min should approximate(Kilowatts(pMin)) - result.max should approximate(Kilowatts(pMax)) + storageModel + .determineFlexOptions(data, oldState) match { + case result: ProvideMinMaxFlexOptions => + result.ref should approximate(Kilowatts(pRef)) + result.min should approximate(Kilowatts(pMin)) + result.max should approximate(Kilowatts(pMax)) + case _ => + fail("Expected result of type ProvideMinMaxFlexOptions") + } } } "Calculate flex options with target SOC" in { @@ -174,13 +176,15 @@ class StorageModelSpec extends UnitSpec with Matchers { startTick, ) - val result = storageModel - .determineFlexOptions(data, oldState) - .asInstanceOf[ProvideMinMaxFlexOptions] - - result.ref should approximate(Kilowatts(pRef)) - result.min should approximate(Kilowatts(pMin)) - result.max should approximate(Kilowatts(pMax)) + storageModel + .determineFlexOptions(data, oldState) match { + case result: ProvideMinMaxFlexOptions => + result.ref should approximate(Kilowatts(pRef)) + result.min should approximate(Kilowatts(pMin)) + result.max should approximate(Kilowatts(pMax)) + case _ => + fail("Expected result of type ProvideMinMaxFlexOptions") + } } }