From 7dc2639a7fcdf51ef789f4af2e3afff11438be6e Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Fri, 14 Mar 2025 15:33:42 +0100 Subject: Added more battery policies (#312) * some updates * Updates * Added comments and renamed variables * Ran Spotless --- .../power/batteries/policy/BatteryPolicy.java | 12 ++- .../policy/DoubleThresholdBatteryPolicy.java | 79 ++++++++++++++++ .../batteries/policy/RunningMeanBatteryPolicy.java | 103 ++++++++++++++++++++ .../policy/RunningMeanPlusBatteryPolicy.java | 105 +++++++++++++++++++++ .../policy/SingleThresholdBatteryPolicy.java | 8 +- 5 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanBatteryPolicy.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanPlusBatteryPolicy.java (limited to 'opendc-simulator/opendc-simulator-compute') diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java index 5abbe861..a50f7e73 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java @@ -31,12 +31,16 @@ import org.opendc.simulator.compute.power.batteries.SimBattery; import org.opendc.simulator.engine.graph.FlowGraph; import org.opendc.simulator.engine.graph.FlowNode; +/** + * An abstract class representing a battery policy. + * A battery policy is used by a {@link SimBattery} to determine when to charge or discharge the battery. + */ public abstract class BatteryPolicy extends FlowNode implements CarbonReceiver { protected final SimBattery battery; protected final BatteryAggregator aggregator; - protected double carbonIntensity; + protected double carbonIntensity; // The current carbon Intensity of the grid protected BatteryState batteryState = BatteryState.IDLE; @@ -61,6 +65,12 @@ public abstract class BatteryPolicy extends FlowNode implements CarbonReceiver { @Override public abstract long onUpdate(long now); + /** + * Set the battery state. + * Both the battery and the aggregator are updated based on the new state. + * + * @param newBatteryState The new battery state. + */ public void setBatteryState(BatteryState newBatteryState) { if (newBatteryState == this.batteryState) { return; diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java new file mode 100644 index 00000000..3a9cb228 --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 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.compute.power.batteries.policy; + +import org.opendc.simulator.compute.power.batteries.BatteryAggregator; +import org.opendc.simulator.compute.power.batteries.BatteryState; +import org.opendc.simulator.compute.power.batteries.SimBattery; +import org.opendc.simulator.engine.graph.FlowGraph; + +/** + * A battery policy that uses two thresholds to determine if a better should be charging or discharging. + * - If the Carbon Intensity is below the lower threshold, + * the battery will start charging until full. + * - If the Carbon Intensity is above the upper threshold, + * the battery will start discharging until empty. + * - If the Carbon Intensity is between the two thresholds, + * The battery is idle. + */ +public class DoubleThresholdBatteryPolicy extends BatteryPolicy { + private final double lowerThreshold; + private final double upperThreshold; + + /** + * + * @param parentGraph The {@link FlowGraph} this stage belongs to. + * @param battery The {@link SimBattery} to control. + * @param aggregator The {@link BatteryAggregator} to use. + * @param lowerThreshold The lower carbon intensity threshold to trigger charging or discharging. + * @param upperThreshold The upper carbon intensity threshold to trigger charging or discharging. + */ + public DoubleThresholdBatteryPolicy( + FlowGraph parentGraph, + SimBattery battery, + BatteryAggregator aggregator, + double lowerThreshold, + double upperThreshold) { + super(parentGraph, battery, aggregator); + + this.lowerThreshold = lowerThreshold; + this.upperThreshold = upperThreshold; + } + + @Override + public long onUpdate(long now) { + + if (this.carbonIntensity > this.upperThreshold & !this.battery.isEmpty()) { + this.setBatteryState(BatteryState.DISCHARGING); + return Long.MAX_VALUE; + } + + if (this.carbonIntensity < this.lowerThreshold & !this.battery.isFull()) { + this.setBatteryState(BatteryState.CHARGING); + return Long.MAX_VALUE; + } + + this.setBatteryState(BatteryState.IDLE); + return Long.MAX_VALUE; + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanBatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanBatteryPolicy.java new file mode 100644 index 00000000..1c127abd --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanBatteryPolicy.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2025 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.compute.power.batteries.policy; + +import java.util.LinkedList; +import org.opendc.simulator.compute.power.batteries.BatteryAggregator; +import org.opendc.simulator.compute.power.batteries.BatteryState; +import org.opendc.simulator.compute.power.batteries.SimBattery; +import org.opendc.simulator.engine.graph.FlowGraph; + +/** + * A battery policy that uses a running mean to determine if a battery should be charging or discharging. + * This policy is similar to {@link SingleThresholdBatteryPolicy}, but instead of using a predifined threshold, + * the threshold is updated dynamically based on the running mean of the carbon intensity. + * - If the Carbon Intensity is below the running mean, + * the battery will start charging until full. + * - If the Carbon Intensity is above the running mean, + * the battery will start discharging until empty. + */ +public class RunningMeanBatteryPolicy extends BatteryPolicy { + private final int windowSize; + + private final LinkedList pastCarbonIntensities = new LinkedList<>(); + private double pastCarbonIntensitiesSum = 0.0; + private double pastCarbonIntensitiesMean = 0.0; + + /** + * + * @param parentGraph The {@link FlowGraph} this stage belongs to. + * @param battery The {@link SimBattery} to control. + * @param aggregator The {@link BatteryAggregator} to use. + */ + public RunningMeanBatteryPolicy( + FlowGraph parentGraph, + SimBattery battery, + BatteryAggregator aggregator, + double startingThreshold, + int windowSize) { + super(parentGraph, battery, aggregator); + + this.windowSize = windowSize; + + this.updatePastCarbonIntensities(startingThreshold); + } + + /** + * Update the past carbon intensities with the new carbon intensity. + * + * Update the current sum and mean. + * @param newCarbonIntensity + */ + private void updatePastCarbonIntensities(double newCarbonIntensity) { + if (this.pastCarbonIntensities.size() == this.windowSize) { + this.pastCarbonIntensitiesSum -= this.pastCarbonIntensities.removeFirst(); + } + this.pastCarbonIntensities.addLast(newCarbonIntensity); + this.pastCarbonIntensitiesSum += newCarbonIntensity; + this.pastCarbonIntensitiesMean = this.pastCarbonIntensitiesSum / this.pastCarbonIntensities.size(); + } + + @Override + public void updateCarbonIntensity(double newCarbonIntensity) { + this.updatePastCarbonIntensities(newCarbonIntensity); + + super.updateCarbonIntensity(newCarbonIntensity); + } + + @Override + public long onUpdate(long now) { + if (this.carbonIntensity >= this.pastCarbonIntensitiesMean & !this.battery.isEmpty()) { + this.setBatteryState(BatteryState.DISCHARGING); + return Long.MAX_VALUE; + } + + if (this.carbonIntensity < this.pastCarbonIntensitiesMean & !this.battery.isFull()) { + this.setBatteryState(BatteryState.CHARGING); + return Long.MAX_VALUE; + } + + this.setBatteryState(BatteryState.IDLE); + return Long.MAX_VALUE; + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanPlusBatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanPlusBatteryPolicy.java new file mode 100644 index 00000000..25b86dde --- /dev/null +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/RunningMeanPlusBatteryPolicy.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025 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.compute.power.batteries.policy; + +import java.util.LinkedList; +import org.opendc.simulator.compute.power.batteries.BatteryAggregator; +import org.opendc.simulator.compute.power.batteries.BatteryState; +import org.opendc.simulator.compute.power.batteries.SimBattery; +import org.opendc.simulator.engine.graph.FlowGraph; + +/** + * An improved version of {@link RunningMeanBatteryPolicy}. + * It uses the same logic, but only start charging if the carbon intensity is not decreasing anymore. + */ +public class RunningMeanPlusBatteryPolicy extends BatteryPolicy { + private final int windowSize; + + private final LinkedList pastCarbonIntensities = new LinkedList<>(); + private double previousCarbonIntensity = 0.0; + + private double pastCarbonIntensitiesSum = 0.0; + private double pastCarbonIntensitiesMean = 0.0; + + /** + * + * @param parentGraph The {@link FlowGraph} this stage belongs to. + * @param battery The {@link SimBattery} to control. + * @param aggregator The {@link BatteryAggregator} to use. + */ + public RunningMeanPlusBatteryPolicy( + FlowGraph parentGraph, + SimBattery battery, + BatteryAggregator aggregator, + double startingThreshold, + int windowSize) { + super(parentGraph, battery, aggregator); + + this.windowSize = windowSize; + + this.updatePastCarbonIntensities(startingThreshold); + } + + private void updatePastCarbonIntensities(double newCarbonIntensity) { + if (this.pastCarbonIntensities.size() == this.windowSize) { + this.pastCarbonIntensitiesSum -= this.pastCarbonIntensities.removeFirst(); + } + + if (this.pastCarbonIntensities.size() > 0) { + this.previousCarbonIntensity = this.pastCarbonIntensities.getLast(); + } + + this.pastCarbonIntensities.addLast(newCarbonIntensity); + this.pastCarbonIntensitiesSum += newCarbonIntensity; + this.pastCarbonIntensitiesMean = this.pastCarbonIntensitiesSum / this.pastCarbonIntensities.size(); + } + + @Override + public void updateCarbonIntensity(double newCarbonIntensity) { + this.updatePastCarbonIntensities(newCarbonIntensity); + + super.updateCarbonIntensity(newCarbonIntensity); + } + + private boolean isCharging = false; + + @Override + public long onUpdate(long now) { + if (this.carbonIntensity >= this.pastCarbonIntensitiesMean & !this.battery.isEmpty()) { + this.isCharging = false; + this.setBatteryState(BatteryState.DISCHARGING); + return Long.MAX_VALUE; + } + + if (this.carbonIntensity < this.pastCarbonIntensitiesMean & !this.battery.isFull()) { + if (this.carbonIntensity >= this.previousCarbonIntensity || this.isCharging) { + this.setBatteryState(BatteryState.CHARGING); + return Long.MAX_VALUE; + } + } + + this.isCharging = false; + this.setBatteryState(BatteryState.IDLE); + return Long.MAX_VALUE; + } +} diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java index e917a26f..26d85958 100644 --- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java +++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java @@ -27,11 +27,17 @@ import org.opendc.simulator.compute.power.batteries.BatteryState; import org.opendc.simulator.compute.power.batteries.SimBattery; import org.opendc.simulator.engine.graph.FlowGraph; +/** + * A battery policy that uses a single threshold to determine if a better should be charging or discharging. + * - If the Carbon Intensity is below the give thresholds, + * the battery will start charging until full. + * - If the Carbon Intensity is above the give thresholds, + * the battery will start discharging until empty. + */ public class SingleThresholdBatteryPolicy extends BatteryPolicy { private final double carbonThreshold; /** - * * @param parentGraph The {@link FlowGraph} this stage belongs to. * @param battery The {@link SimBattery} to control. * @param aggregator The {@link BatteryAggregator} to use. -- cgit v1.2.3