Skip to content

Commit c3076b6

Browse files
committed
Allow _clamp_to_bounds to clamp power values to both sides
In cases where there's an exclusion zone within the usable bounds, the given power can be clamped to both ends of the exclusion zone. This function now returns both sides, rather than just the one that's closest to the given power. This can also be used in the bounds interface, exposed through the `Report` class. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 11f325c commit c3076b6

File tree

1 file changed

+27
-12
lines changed

1 file changed

+27
-12
lines changed

src/frequenz/sdk/actor/_power_managing/_matryoshka.py

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,15 @@ def _clamp_to_bounds( # pylint: disable=too-many-return-statements
4343
lower_bound: Power,
4444
upper_bound: Power,
4545
exclusion_bounds: timeseries.Bounds[Power] | None,
46-
) -> Power:
46+
) -> tuple[Power | None, Power | None]:
4747
"""Clamp the given value to the given bounds.
4848
49+
When the given value can falls within the exclusion zone, and can be clamped to
50+
both sides, both options will be returned.
51+
52+
When the given value falls outside the usable bounds and can be clamped only to
53+
one side, only that option will be returned.
54+
4955
Args:
5056
value: The value to clamp.
5157
lower_bound: The lower bound to clamp to.
@@ -65,29 +71,27 @@ def _clamp_to_bounds( # pylint: disable=too-many-return-statements
6571
lower_bound, upper_bound, exclusion_bounds
6672
):
6773
case (True, True):
68-
return Power.zero()
74+
return None, None
6975
case (True, False):
7076
if value < exclusion_bounds.upper:
71-
return exclusion_bounds.upper
77+
return None, exclusion_bounds.upper
7278
case (False, True):
7379
if value > exclusion_bounds.lower:
74-
return exclusion_bounds.lower
80+
return exclusion_bounds.lower, None
7581

7682
# If the given value is outside the given bounds, clamp it to the closest bound.
7783
if value < lower_bound:
78-
return lower_bound
84+
return lower_bound, None
7985
if value > upper_bound:
80-
return upper_bound
86+
return None, upper_bound
8187

8288
# If the given value is within the exclusion bounds and the exclusion bounds are
8389
# within the given bounds, clamp the given value to the closest exclusion bound.
8490
if exclusion_bounds is not None:
8591
if exclusion_bounds.lower < value < exclusion_bounds.upper:
86-
if value - exclusion_bounds.lower < exclusion_bounds.upper - value:
87-
return exclusion_bounds.lower
88-
return exclusion_bounds.upper
92+
return exclusion_bounds.lower, exclusion_bounds.upper
8993

90-
return value
94+
return value, value
9195

9296

9397
def _check_exclusion_bounds_overlap(
@@ -217,12 +221,23 @@ def _calc_target_power(
217221
if upper_bound < lower_bound:
218222
break
219223
if next_proposal.preferred_power:
220-
target_power = _clamp_to_bounds(
224+
match _clamp_to_bounds(
221225
next_proposal.preferred_power,
222226
lower_bound,
223227
upper_bound,
224228
exclusion_bounds,
225-
)
229+
):
230+
case (None, power) | (power, None) if power:
231+
target_power = power
232+
case (power_low, power_high) if power_low and power_high:
233+
if (
234+
power_high - next_proposal.preferred_power
235+
< next_proposal.preferred_power - power_low
236+
):
237+
target_power = power_high
238+
else:
239+
target_power = power_low
240+
226241
proposal_lower = next_proposal.bounds.lower or lower_bound
227242
proposal_upper = next_proposal.bounds.upper or upper_bound
228243
# If the bounds from the current proposal are fully within the exclusion

0 commit comments

Comments
 (0)