1
1
from functools import partial
2
- from typing import Callable
2
+ from typing import Callable , Optional
3
3
4
4
import numpy as np
5
5
@@ -13,6 +13,7 @@ def bisect(
13
13
xmin : FloatOrFloatArray ,
14
14
xmax : FloatOrFloatArray ,
15
15
tolerance : float ,
16
+ invalid_value : Optional [float ] = None ,
16
17
) -> FloatOrFloatArray :
17
18
r"""Compute the roots of a function using a vectorized bisection method.
18
19
@@ -31,6 +32,9 @@ def bisect(
31
32
bounded within an interval of size :math:`\Delta x` or less. The bisection method will
32
33
run for :math:`\left\lceil\frac{x_\max - x_\min}{\Delta x}\right\rceil`
33
34
iterations.
35
+ invalid_value:
36
+ If provided, then this value is used whenever
37
+ :math:`\text{sign}(f(\mathbf{x}_\min)) = \text{sign}(f(\mathbf{x}_\max))`.
34
38
35
39
Returns
36
40
-------
@@ -47,10 +51,12 @@ def bisect(
47
51
f_right = f (xmax )
48
52
49
53
invalid_mask = np .sign (f_left ) == np .sign (f_right )
50
- if np .any (invalid_mask ):
54
+ if np .any (invalid_mask ) and invalid_value is None :
51
55
raise ValueError (
52
56
"f(xmin) and f(xmax) have the same sign. Consider increasing the search interval."
53
57
)
58
+ elif isinstance (invalid_mask , bool ) and invalid_mask :
59
+ return invalid_value # type: ignore
54
60
55
61
while interval > tolerance :
56
62
xmid = 0.5 * (xmax + xmin )
@@ -63,7 +69,7 @@ def bisect(
63
69
f_left = np .where (mask , f_mid , f_left )
64
70
f_right = np .where (mask , f_right , f_mid )
65
71
66
- out = 0.5 * (xmax + xmin )
72
+ out = np . where ( invalid_mask , invalid_value , 0.5 * (xmax + xmin )) # type: ignore
67
73
return out
68
74
69
75
@@ -112,6 +118,7 @@ def compute_conductor_ampacity(
112
118
min_ampacity : Ampere = 0 ,
113
119
max_ampacity : Ampere = 5_000 ,
114
120
tolerance : float = 1 , # Ampere
121
+ invalid_value = None ,
115
122
) -> Ampere :
116
123
r"""Use the bisection method to compute the steady-state thermal rating (ampacity).
117
124
@@ -134,6 +141,10 @@ def compute_conductor_ampacity(
134
141
bisection iterations will stop once the numerical ampacity uncertainty is below
135
142
:math:`\Delta I`. The bisection method will run for
136
143
:math:`\left\lceil\frac{I_\text{max} - I_\text{min}}{\Delta I}\right\rceil` iterations.
144
+ invalid_value:
145
+ if the optimization problem is invalid, this value is returned instead of an error.
146
+ Suggested value: 0 for 0-ampacity when max_conductor_temperature is exceeded for all
147
+ ampacities.
137
148
138
149
Returns
139
150
-------
@@ -142,4 +153,4 @@ def compute_conductor_ampacity(
142
153
"""
143
154
f = partial (heat_balance , max_conductor_temperature )
144
155
145
- return bisect (f , min_ampacity , max_ampacity , tolerance )
156
+ return bisect (f , min_ampacity , max_ampacity , tolerance , invalid_value = invalid_value )
0 commit comments