Skip to content

Commit 93ee7e8

Browse files
committed
Refactor battery aggregation so it can be re-used easier
Signed-off-by: Mathias L. Baumann <[email protected]>
1 parent 3c5e727 commit 93ee7e8

File tree

2 files changed

+69
-36
lines changed

2 files changed

+69
-36
lines changed

src/frequenz/sdk/actor/power_distributing/_distribution_algorithm/_distribution_algorithm.py

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import logging
77
import math
88
from dataclasses import dataclass
9-
from typing import NamedTuple
9+
from typing import NamedTuple, Sequence
1010

1111
from ...._internal._math import is_close_to_zero
1212
from ....microgrid.component import BatteryData, InverterData
13+
from ..result import PowerBounds
1314

1415
_logger = logging.getLogger(__name__)
1516

@@ -36,17 +37,8 @@ class AggregatedBatteryData:
3637
soc_lower_bound: float
3738
"""The aggregated lower SoC bound of the batteries."""
3839

39-
power_inclusion_upper_bound: float
40-
"""The aggregated upper power inclusion bound of the batteries."""
41-
42-
power_inclusion_lower_bound: float
43-
"""The aggregated lower power inclusion bound of the batteries."""
44-
45-
power_exclusion_upper_bound: float
46-
"""The aggregated upper power exclusion bound of the batteries."""
47-
48-
power_exclusion_lower_bound: float
49-
"""The aggregated lower power exclusion bound of the batteries."""
40+
power_bounds: PowerBounds
41+
"""The aggregated power bounds of the batteries."""
5042

5143
def __init__(self, batteries: list[BatteryData]) -> None:
5244
"""Create DistBatteryData from BatteryData.
@@ -84,21 +76,58 @@ def __init__(self, batteries: list[BatteryData]) -> None:
8476
self.soc_upper_bound = math.nan
8577
self.soc_lower_bound = math.nan
8678

87-
self.power_inclusion_upper_bound = sum(
88-
b.power_inclusion_upper_bound for b in batteries
89-
)
90-
self.power_inclusion_lower_bound = sum(
91-
b.power_inclusion_lower_bound for b in batteries
79+
self.power_bounds = _aggregate_battery_power_bounds(
80+
list(
81+
map(
82+
lambda metrics: PowerBounds(
83+
inclusion_upper=metrics.power_inclusion_upper_bound,
84+
inclusion_lower=metrics.power_inclusion_lower_bound,
85+
exclusion_upper=metrics.power_exclusion_upper_bound,
86+
exclusion_lower=metrics.power_exclusion_lower_bound,
87+
),
88+
batteries,
89+
)
90+
)
9291
)
93-
# To satisfy the largest exclusion bounds in the set we need to
94-
# provide the power defined by the largest bounds multiplied by the
95-
# number of batteries in the set.
96-
self.power_exclusion_upper_bound = max(
97-
b.power_exclusion_upper_bound for b in batteries
98-
) * len(batteries)
99-
self.power_exclusion_lower_bound = min(
100-
b.power_exclusion_lower_bound for b in batteries
101-
) * len(batteries)
92+
93+
94+
def _aggregate_battery_power_bounds(
95+
battery_metrics: Sequence[PowerBounds],
96+
) -> PowerBounds:
97+
"""Calculate bounds for a set of batteries located behind one set of inverters.
98+
99+
Args:
100+
battery_metrics: List of PowerBounds for each battery.
101+
102+
Returns:
103+
A PowerBounds object containing the aggregated bounds for all given batteries
104+
"""
105+
assert len(battery_metrics) > 0, "No batteries given."
106+
107+
# Calculate the aggregated bounds for the set of batteries
108+
power_inclusion_upper_bound = sum(
109+
bounds.inclusion_upper for bounds in battery_metrics
110+
)
111+
power_inclusion_lower_bound = sum(
112+
bounds.inclusion_lower for bounds in battery_metrics
113+
)
114+
115+
# To satisfy the largest exclusion bounds in the set we need to
116+
# provide the power defined by the largest bounds multiplied by the
117+
# number of batteries in the set.
118+
power_exclusion_upper_bound = max(
119+
bounds.exclusion_upper for bounds in battery_metrics
120+
) * len(battery_metrics)
121+
power_exclusion_lower_bound = min(
122+
bounds.exclusion_lower for bounds in battery_metrics
123+
) * len(battery_metrics)
124+
125+
return PowerBounds(
126+
inclusion_lower=power_inclusion_lower_bound,
127+
exclusion_lower=power_exclusion_lower_bound,
128+
exclusion_upper=power_exclusion_upper_bound,
129+
inclusion_upper=power_inclusion_upper_bound,
130+
)
102131

103132

104133
class InvBatPair(NamedTuple):
@@ -752,17 +781,21 @@ def _inclusion_exclusion_bounds(
752781
excl_bounds: dict[int, float] = {}
753782
for battery, inverters in components:
754783
if supply:
755-
excl_bounds[battery.component_id] = -battery.power_exclusion_lower_bound
756-
incl_bounds[battery.component_id] = -battery.power_inclusion_lower_bound
784+
excl_bounds[
785+
battery.component_id
786+
] = -battery.power_bounds.exclusion_lower
787+
incl_bounds[
788+
battery.component_id
789+
] = -battery.power_bounds.inclusion_lower
757790
else:
758-
excl_bounds[battery.component_id] = battery.power_exclusion_upper_bound
759-
incl_bounds[battery.component_id] = battery.power_inclusion_upper_bound
791+
excl_bounds[battery.component_id] = battery.power_bounds.exclusion_upper
792+
incl_bounds[battery.component_id] = battery.power_bounds.inclusion_upper
760793

761794
for inverter in inverters:
762795
if supply:
763796
incl_bounds[inverter.component_id] = -max(
764797
inverter.active_power_inclusion_lower_bound,
765-
battery.power_inclusion_lower_bound,
798+
battery.power_bounds.inclusion_lower,
766799
)
767800
excl_bounds[
768801
inverter.component_id
@@ -771,7 +804,7 @@ def _inclusion_exclusion_bounds(
771804
else:
772805
incl_bounds[inverter.component_id] = min(
773806
inverter.active_power_inclusion_upper_bound,
774-
battery.power_inclusion_upper_bound,
807+
battery.power_bounds.inclusion_upper,
775808
)
776809
excl_bounds[
777810
inverter.component_id

src/frequenz/sdk/actor/power_distributing/power_distributing.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ def _get_bounds(
159159
return PowerBounds(
160160
inclusion_lower=sum(
161161
max(
162-
battery.power_inclusion_lower_bound,
162+
battery.power_bounds.inclusion_lower,
163163
sum(
164164
inverter.active_power_inclusion_lower_bound
165165
for inverter in inverters
@@ -169,7 +169,7 @@ def _get_bounds(
169169
),
170170
inclusion_upper=sum(
171171
min(
172-
battery.power_inclusion_upper_bound,
172+
battery.power_bounds.inclusion_upper,
173173
sum(
174174
inverter.active_power_inclusion_upper_bound
175175
for inverter in inverters
@@ -178,15 +178,15 @@ def _get_bounds(
178178
for battery, inverters in pairs_data
179179
),
180180
exclusion_lower=min(
181-
sum(battery.power_exclusion_lower_bound for battery, _ in pairs_data),
181+
sum(battery.power_bounds.exclusion_lower for battery, _ in pairs_data),
182182
sum(
183183
inverter.active_power_exclusion_lower_bound
184184
for _, inverters in pairs_data
185185
for inverter in inverters
186186
),
187187
),
188188
exclusion_upper=max(
189-
sum(battery.power_exclusion_upper_bound for battery, _ in pairs_data),
189+
sum(battery.power_bounds.exclusion_upper for battery, _ in pairs_data),
190190
sum(
191191
inverter.active_power_exclusion_upper_bound
192192
for _, inverters in pairs_data

0 commit comments

Comments
 (0)