summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-power/src/main/java
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2022-08-25 15:14:57 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2022-10-21 22:13:04 +0200
commitc1f67a872e2d7ce63ac96f8ca80cbe8b25c62e3b (patch)
tree3518a6552c0f47c4218abcd06162743d6dc000fc /opendc-simulator/opendc-simulator-power/src/main/java
parent7f7b6226e6f50da698080177f6298bf8baac32b9 (diff)
refactor(sim/power): Re-implement power sim using flow2
This change updates the `opendc-simulator-power` module to use the new flow simulation framework in OpenDC (named flow2 for now).
Diffstat (limited to 'opendc-simulator/opendc-simulator-power/src/main/java')
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java141
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java53
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java91
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java71
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java137
5 files changed, 493 insertions, 0 deletions
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java
new file mode 100644
index 00000000..8790a2d7
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.power;
+
+import org.jetbrains.annotations.NotNull;
+import org.opendc.simulator.flow2.FlowGraph;
+import org.opendc.simulator.flow2.Inlet;
+import org.opendc.simulator.flow2.Outlet;
+import org.opendc.simulator.flow2.mux.FlowMultiplexer;
+import org.opendc.simulator.flow2.mux.MaxMinFlowMultiplexer;
+import org.opendc.simulator.flow2.util.FlowTransform;
+import org.opendc.simulator.flow2.util.FlowTransformer;
+
+/**
+ * A model of a Power Distribution Unit (PDU).
+ */
+public final class SimPdu extends SimPowerInlet {
+ /**
+ * The {@link FlowMultiplexer} that distributes the electricity over the PDU outlets.
+ */
+ private final MaxMinFlowMultiplexer mux;
+
+ /**
+ * A {@link FlowTransformer} that applies the power loss to the PDU's power inlet.
+ */
+ private final FlowTransformer transformer;
+
+ /**
+ * Construct a {@link SimPdu} instance.
+ *
+ * @param graph The underlying {@link FlowGraph} to which the PDU belongs.
+ * @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 SimPdu(FlowGraph graph, float idlePower, float lossCoefficient) {
+ this.mux = new MaxMinFlowMultiplexer(graph);
+ this.transformer = new FlowTransformer(graph, new FlowTransform() {
+ @Override
+ public float apply(float value) {
+ // See https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
+ return value * (lossCoefficient * value + 1) + idlePower;
+ }
+
+ @Override
+ public float applyInverse(float value) {
+ float c = lossCoefficient;
+ if (c != 0.f) {
+ return (float) (1 + Math.sqrt(4 * value * c - 4 * idlePower * c + 1)) / (2 * c);
+ } else {
+ return value - idlePower;
+ }
+ }
+ });
+
+ graph.connect(mux.newOutput(), transformer.getInput());
+ }
+
+ /**
+ * Construct a {@link SimPdu} instance without any loss.
+ *
+ * @param graph The underlying {@link FlowGraph} to which the PDU belongs.
+ */
+ public SimPdu(FlowGraph graph) {
+ this(graph, 0.f, 0.f);
+ }
+
+ /**
+ * Create a new PDU outlet.
+ */
+ public PowerOutlet newOutlet() {
+ return new PowerOutlet(mux);
+ }
+
+ @NotNull
+ @Override
+ public Outlet getFlowOutlet() {
+ return transformer.getOutput();
+ }
+
+ @Override
+ public String toString() {
+ return "SimPdu";
+ }
+
+ /**
+ * A PDU outlet.
+ */
+ public static final class PowerOutlet extends SimPowerOutlet implements AutoCloseable {
+ private final FlowMultiplexer mux;
+ private final Inlet inlet;
+ private boolean isClosed;
+
+ private PowerOutlet(FlowMultiplexer mux) {
+ this.mux = mux;
+ this.inlet = mux.newInput();
+ }
+
+ /**
+ * Remove the outlet from the PDU.
+ */
+ @Override
+ public void close() {
+ isClosed = true;
+ mux.releaseInput(inlet);
+ }
+
+ @Override
+ public String toString() {
+ return "SimPdu.Outlet";
+ }
+
+ @NotNull
+ @Override
+ protected Inlet getFlowInlet() {
+ if (isClosed) {
+ throw new IllegalStateException("Outlet is closed");
+ }
+ return inlet;
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java
new file mode 100644
index 00000000..a6e167c2
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.power;
+
+import org.opendc.simulator.flow2.Outlet;
+
+/**
+ * An abstract inlet that consumes electricity from a power outlet.
+ */
+public abstract class SimPowerInlet {
+ SimPowerOutlet outlet;
+
+ /**
+ * Determine whether the inlet is connected to a {@link SimPowerOutlet}.
+ *
+ * @return <code>true</code> if the inlet is connected to an outlet, <code>false</code> otherwise.
+ */
+ public boolean isConnected() {
+ return outlet != null;
+ }
+
+ /**
+ * Return the {@link SimPowerOutlet} to which the inlet is connected.
+ */
+ public SimPowerOutlet getOutlet() {
+ return outlet;
+ }
+
+ /**
+ * Return the flow {@link Outlet} that models the consumption of a power inlet as flow output.
+ */
+ protected abstract Outlet getFlowOutlet();
+}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java
new file mode 100644
index 00000000..e33d35d0
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.power;
+
+import org.opendc.simulator.flow2.Inlet;
+import org.opendc.simulator.flow2.Outlet;
+
+/**
+ * An abstract outlet that provides a source of electricity for datacenter components.
+ */
+public abstract class SimPowerOutlet {
+ private SimPowerInlet inlet;
+
+ /**
+ * Determine whether the outlet is connected to a {@link SimPowerInlet}.
+ *
+ * @return <code>true</code> if the outlet is connected to an inlet, <code>false</code> otherwise.
+ */
+ public boolean isConnected() {
+ return inlet != null;
+ }
+
+ /**
+ * Return the {@link SimPowerInlet} to which the outlet is connected.
+ */
+ public SimPowerInlet getInlet() {
+ return inlet;
+ }
+
+ /**
+ * Connect the specified power [inlet] to this outlet.
+ *
+ * @param inlet The inlet to connect to the outlet.
+ */
+ public void connect(SimPowerInlet inlet) {
+ if (isConnected()) {
+ throw new IllegalStateException("Outlet already connected");
+ }
+ if (inlet.isConnected()) {
+ throw new IllegalStateException("Inlet already connected");
+ }
+
+ this.inlet = inlet;
+ this.inlet.outlet = this;
+
+ final Inlet flowInlet = getFlowInlet();
+ final Outlet flowOutlet = inlet.getFlowOutlet();
+
+ flowInlet.getGraph().connect(flowOutlet, flowInlet);
+ }
+
+ /**
+ * Disconnect the connected power outlet from this inlet
+ */
+ public void disconnect() {
+ SimPowerInlet inlet = this.inlet;
+ if (inlet != null) {
+ this.inlet = null;
+ assert inlet.outlet == this : "Inlet state incorrect";
+ inlet.outlet = null;
+
+ final Inlet flowInlet = getFlowInlet();
+ flowInlet.getGraph().disconnect(flowInlet);
+ }
+ }
+
+ /**
+ * Return the flow {@link Inlet} that models the consumption of a power outlet as flow input.
+ */
+ protected abstract Inlet getFlowInlet();
+}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java
new file mode 100644
index 00000000..a2d62c48
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.power;
+
+import org.opendc.simulator.flow2.FlowGraph;
+import org.opendc.simulator.flow2.Inlet;
+import org.opendc.simulator.flow2.sink.SimpleFlowSink;
+
+/**
+ * A {@link SimPowerOutlet} that represents a source of electricity with a maximum capacity.
+ */
+public final class SimPowerSource extends SimPowerOutlet {
+ /**
+ * The resource source that drives this power source.
+ */
+ private final SimpleFlowSink sink;
+
+ /**
+ * Construct a {@link SimPowerSource} instance.
+ *
+ * @param graph The underlying {@link FlowGraph} to which the power source belongs.
+ * @param capacity The maximum amount of power provided by the source.
+ */
+ public SimPowerSource(FlowGraph graph, float capacity) {
+ this.sink = new SimpleFlowSink(graph, capacity);
+ }
+
+ /**
+ * Return the capacity of the power source.
+ */
+ public float getCapacity() {
+ return sink.getCapacity();
+ }
+
+ /**
+ * Return the power draw at this instant.
+ */
+ public float getPowerDraw() {
+ return sink.getRate();
+ }
+
+ @Override
+ protected Inlet getFlowInlet() {
+ return sink.getInput();
+ }
+
+ @Override
+ public String toString() {
+ return "SimPowerSource";
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java
new file mode 100644
index 00000000..df7508d9
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2022 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.power;
+
+import org.jetbrains.annotations.NotNull;
+import org.opendc.simulator.flow2.FlowGraph;
+import org.opendc.simulator.flow2.Inlet;
+import org.opendc.simulator.flow2.Outlet;
+import org.opendc.simulator.flow2.mux.FlowMultiplexer;
+import org.opendc.simulator.flow2.mux.MaxMinFlowMultiplexer;
+import org.opendc.simulator.flow2.util.FlowTransform;
+import org.opendc.simulator.flow2.util.FlowTransformer;
+
+/**
+ * A model of an Uninterruptible Power Supply (UPS).
+ * <p>
+ * This model aggregates multiple power sources into a single source in order to ensure that power is always available.
+ */
+public final class SimUps extends SimPowerOutlet {
+ /**
+ * The {@link FlowMultiplexer} that distributes the electricity over the PDU outlets.
+ */
+ private final MaxMinFlowMultiplexer mux;
+
+ /**
+ * A {@link FlowTransformer} that applies the power loss to the PDU's power inlet.
+ */
+ private final FlowTransformer transformer;
+
+ /**
+ * Construct a {@link SimUps} instance.
+ *
+ * @param graph The underlying {@link FlowGraph} to which the UPS belongs.
+ * @param idlePower The idle power consumption of the UPS independent of the load.
+ * @param lossCoefficient The coefficient for the power loss of the UPS proportional to the load.
+ */
+ public SimUps(FlowGraph graph, float idlePower, float lossCoefficient) {
+ this.mux = new MaxMinFlowMultiplexer(graph);
+ this.transformer = new FlowTransformer(graph, new FlowTransform() {
+ @Override
+ public float apply(float value) {
+ // See https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
+ return value * (lossCoefficient + 1) + idlePower;
+ }
+
+ @Override
+ public float applyInverse(float value) {
+ return (value - idlePower) / (lossCoefficient + 1);
+ }
+ });
+
+ graph.connect(transformer.getOutput(), mux.newInput());
+ }
+
+ /**
+ * Construct a {@link SimUps} instance without any loss.
+ *
+ * @param graph The underlying {@link FlowGraph} to which the UPS belongs.
+ */
+ public SimUps(FlowGraph graph) {
+ this(graph, 0.f, 0.f);
+ }
+
+ /**
+ * Create a new UPS inlet.
+ */
+ public PowerInlet newInlet() {
+ return new PowerInlet(mux);
+ }
+
+ @Override
+ protected Inlet getFlowInlet() {
+ return transformer.getInput();
+ }
+
+ @Override
+ public String toString() {
+ return "SimUps";
+ }
+
+ /**
+ * A UPS inlet.
+ */
+ public static final class PowerInlet extends SimPowerInlet implements AutoCloseable {
+ private final FlowMultiplexer mux;
+ private final Outlet outlet;
+ private boolean isClosed;
+
+ private PowerInlet(FlowMultiplexer mux) {
+ this.mux = mux;
+ this.outlet = mux.newOutput();
+ }
+
+ /**
+ * Remove the inlet from the PDU.
+ */
+ @Override
+ public void close() {
+ isClosed = true;
+ mux.releaseOutput(outlet);
+ }
+
+ @Override
+ public String toString() {
+ return "SimPdu.Inlet";
+ }
+
+ @NotNull
+ @Override
+ protected Outlet getFlowOutlet() {
+ if (isClosed) {
+ throw new IllegalStateException("Inlet is closed");
+ }
+ return outlet;
+ }
+ }
+}