From f0c0c6d45165ad0ce398ec7300b11bf77c7ae5a6 Mon Sep 17 00:00:00 2001 From: Hongyu He Date: Thu, 10 Jun 2021 13:27:56 +0200 Subject: simulator: Add power loss to SimPdu This change adds a model for power loss to the Power Distribution Unit (PDU) model in OpenDC. --- .../kotlin/org/opendc/simulator/power/SimPdu.kt | 40 ++++++++++++++++++++-- .../org/opendc/simulator/power/SimPduTest.kt | 12 +++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/opendc-simulator/opendc-simulator-power/src/main/kotlin/org/opendc/simulator/power/SimPdu.kt b/opendc-simulator/opendc-simulator-power/src/main/kotlin/org/opendc/simulator/power/SimPdu.kt index 365f3435..ed3175c7 100644 --- a/opendc-simulator/opendc-simulator-power/src/main/kotlin/org/opendc/simulator/power/SimPdu.kt +++ b/opendc-simulator/opendc-simulator-power/src/main/kotlin/org/opendc/simulator/power/SimPdu.kt @@ -28,8 +28,14 @@ import org.opendc.simulator.resources.* * A model of a Power Distribution Unit (PDU). * * @param interpreter The underlying [SimResourceInterpreter] to drive the simulation under the hood. + * @param idlePower The idle power consumption of the PDU independent of the load on the PDU. + * @param lossCoefficient The coefficient for the power loss of the PDU proportional to the square load. */ -public class SimPdu(interpreter: SimResourceInterpreter) : SimPowerInlet() { +public class SimPdu( + interpreter: SimResourceInterpreter, + public val idlePower: Double = 0.0, + public val lossCoefficient: Double = 0.0, +) : SimPowerInlet() { /** * The [SimResourceDistributor] that distributes the electricity over the PDU outlets. */ @@ -40,10 +46,40 @@ public class SimPdu(interpreter: SimResourceInterpreter) : SimPowerInlet() { */ public fun newOutlet(): Outlet = Outlet(distributor.newOutput()) - override fun createConsumer(): SimResourceConsumer = distributor + override fun createConsumer(): SimResourceConsumer = object : SimResourceConsumer by distributor { + override fun onNext(ctx: SimResourceContext): SimResourceCommand { + return when (val cmd = distributor.onNext(ctx)) { + is SimResourceCommand.Consume -> { + val duration = cmd.work / cmd.limit + val loss = computePowerLoss(cmd.limit) + val newLimit = cmd.limit + loss + + SimResourceCommand.Consume(duration * newLimit, newLimit, cmd.deadline) + } + is SimResourceCommand.Idle -> { + val loss = computePowerLoss(0.0) + if (loss > 0.0) + SimResourceCommand.Consume(Double.POSITIVE_INFINITY, loss, cmd.deadline) + else + cmd + } + else -> cmd + } + } + + override fun toString(): String = "SimPdu.Consumer" + } override fun toString(): String = "SimPdu" + /** + * Compute the power loss that occurs in the PDU. + */ + private fun computePowerLoss(load: Double): Double { + // See https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN + return idlePower + lossCoefficient * (load * load) + } + /** * A PDU outlet. */ diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt index cef9a97a..b7f51ad3 100644 --- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt +++ b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt @@ -54,6 +54,7 @@ internal class SimPduTest { val pdu = SimPdu(interpreter) source.connect(pdu) pdu.newOutlet().connect(SimpleInlet()) + assertEquals(50.0, source.powerDraw) } @@ -88,6 +89,17 @@ internal class SimPduTest { verify { consumer.onEvent(any(), SimResourceEvent.Exit) } } + @Test + fun testLoss() = runBlockingSimulation { + val interpreter = SimResourceInterpreter(coroutineContext, clock) + val source = SimPowerSource(interpreter, capacity = 100.0) + // https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN + val pdu = SimPdu(interpreter, idlePower = 0.015, lossCoefficient = 0.015) + source.connect(pdu) + pdu.newOutlet().connect(SimpleInlet()) + assertEquals(87.515, source.powerDraw, 0.01) + } + @Test fun testOutletClose() = runBlockingSimulation { val interpreter = SimResourceInterpreter(coroutineContext, clock) -- cgit v1.2.3