linerate 2.1.2__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. {linerate-2.1.2 → linerate-2.2.0}/PKG-INFO +1 -1
  2. {linerate-2.1.2 → linerate-2.2.0}/linerate/models/thermal_model.py +5 -0
  3. {linerate-2.1.2 → linerate-2.2.0}/linerate/solver.py +20 -15
  4. {linerate-2.1.2 → linerate-2.2.0}/linerate.egg-info/PKG-INFO +1 -1
  5. {linerate-2.1.2 → linerate-2.2.0}/tests/test_solver.py +32 -0
  6. {linerate-2.1.2 → linerate-2.2.0}/.github/workflows/deploy.yml +0 -0
  7. {linerate-2.1.2 → linerate-2.2.0}/.github/workflows/tests.yml +0 -0
  8. {linerate-2.1.2 → linerate-2.2.0}/.gitignore +0 -0
  9. {linerate-2.1.2 → linerate-2.2.0}/.pre-commit-config.yaml +0 -0
  10. {linerate-2.1.2 → linerate-2.2.0}/LICENSE +0 -0
  11. {linerate-2.1.2 → linerate-2.2.0}/README.md +0 -0
  12. {linerate-2.1.2 → linerate-2.2.0}/docs/Makefile +0 -0
  13. {linerate-2.1.2 → linerate-2.2.0}/docs/_static/css/custom.css +0 -0
  14. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/cigre207/convective_cooling.rst +0 -0
  15. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/cigre207/solar_heating.rst +0 -0
  16. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/cigre601/convective_cooling.rst +0 -0
  17. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/cigre601/solar_heating.rst +0 -0
  18. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/convective_cooling.rst +0 -0
  19. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/dimensionless.rst +0 -0
  20. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/ieee738/convective_cooling.rst +0 -0
  21. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/ieee738/solar_heating.rst +0 -0
  22. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/index.rst +0 -0
  23. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/joule_heating.rst +0 -0
  24. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/math.rst +0 -0
  25. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/radiative_cooling.rst +0 -0
  26. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/solar_angles.rst +0 -0
  27. {linerate-2.1.2 → linerate-2.2.0}/docs/api/equations/solar_heating.rst +0 -0
  28. {linerate-2.1.2 → linerate-2.2.0}/docs/api/model.rst +0 -0
  29. {linerate-2.1.2 → linerate-2.2.0}/docs/api/solver.rst +0 -0
  30. {linerate-2.1.2 → linerate-2.2.0}/docs/api/types.rst +0 -0
  31. {linerate-2.1.2 → linerate-2.2.0}/docs/api.rst +0 -0
  32. {linerate-2.1.2 → linerate-2.2.0}/docs/bibliography.rst +0 -0
  33. {linerate-2.1.2 → linerate-2.2.0}/docs/conf.py +0 -0
  34. {linerate-2.1.2 → linerate-2.2.0}/docs/figs/frontpage.png +0 -0
  35. {linerate-2.1.2 → linerate-2.2.0}/docs/index.rst +0 -0
  36. {linerate-2.1.2 → linerate-2.2.0}/docs/make.bat +0 -0
  37. {linerate-2.1.2 → linerate-2.2.0}/docs/refs.bib +0 -0
  38. {linerate-2.1.2 → linerate-2.2.0}/examples/README.rst +0 -0
  39. {linerate-2.1.2 → linerate-2.2.0}/examples/__init__.py +0 -0
  40. {linerate-2.1.2 → linerate-2.2.0}/examples/plot_cigre.py +0 -0
  41. {linerate-2.1.2 → linerate-2.2.0}/examples/plot_solar_heating_comparison.py +0 -0
  42. {linerate-2.1.2 → linerate-2.2.0}/examples/plot_solar_radiation.py +0 -0
  43. {linerate-2.1.2 → linerate-2.2.0}/linerate/__init__.py +0 -0
  44. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/__init__.py +0 -0
  45. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre207/__init__.py +0 -0
  46. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre207/ac_resistance.py +0 -0
  47. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre207/convective_cooling.py +0 -0
  48. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre207/solar_heating.py +0 -0
  49. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre601/__init__.py +0 -0
  50. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre601/convective_cooling.py +0 -0
  51. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre601/py.typed +0 -0
  52. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/cigre601/solar_heating.py +0 -0
  53. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/convective_cooling.py +0 -0
  54. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/dimensionless.py +0 -0
  55. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/ieee738/__init__.py +0 -0
  56. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/ieee738/convective_cooling.py +0 -0
  57. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/ieee738/py.typed +0 -0
  58. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/ieee738/solar_heating.py +0 -0
  59. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/joule_heating.py +0 -0
  60. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/math.py +0 -0
  61. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/py.typed +0 -0
  62. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/radiative_cooling.py +0 -0
  63. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/solar_angles.py +0 -0
  64. {linerate-2.1.2 → linerate-2.2.0}/linerate/equations/solar_heating.py +0 -0
  65. {linerate-2.1.2 → linerate-2.2.0}/linerate/model.py +0 -0
  66. {linerate-2.1.2 → linerate-2.2.0}/linerate/models/Cigre207.md +0 -0
  67. {linerate-2.1.2 → linerate-2.2.0}/linerate/models/cigre207.py +0 -0
  68. {linerate-2.1.2 → linerate-2.2.0}/linerate/models/cigre601.py +0 -0
  69. {linerate-2.1.2 → linerate-2.2.0}/linerate/models/ieee738.py +0 -0
  70. {linerate-2.1.2 → linerate-2.2.0}/linerate/py.typed +0 -0
  71. {linerate-2.1.2 → linerate-2.2.0}/linerate/types.py +0 -0
  72. {linerate-2.1.2 → linerate-2.2.0}/linerate/units.py +0 -0
  73. {linerate-2.1.2 → linerate-2.2.0}/linerate.egg-info/SOURCES.txt +0 -0
  74. {linerate-2.1.2 → linerate-2.2.0}/linerate.egg-info/dependency_links.txt +0 -0
  75. {linerate-2.1.2 → linerate-2.2.0}/linerate.egg-info/requires.txt +0 -0
  76. {linerate-2.1.2 → linerate-2.2.0}/linerate.egg-info/top_level.txt +0 -0
  77. {linerate-2.1.2 → linerate-2.2.0}/pyproject.toml +0 -0
  78. {linerate-2.1.2 → linerate-2.2.0}/renovate.json +0 -0
  79. {linerate-2.1.2 → linerate-2.2.0}/setup.cfg +0 -0
  80. {linerate-2.1.2 → linerate-2.2.0}/tests/__init__.py +0 -0
  81. {linerate-2.1.2 → linerate-2.2.0}/tests/acceptance_tests/__init__.py +0 -0
  82. {linerate-2.1.2 → linerate-2.2.0}/tests/acceptance_tests/test_cigre_ampacity_cases.py +0 -0
  83. {linerate-2.1.2 → linerate-2.2.0}/tests/acceptance_tests/test_ieee_ampacity_cases.py +0 -0
  84. {linerate-2.1.2 → linerate-2.2.0}/tests/acceptance_tests/test_ratekit_ampacity_cases.py +0 -0
  85. {linerate-2.1.2 → linerate-2.2.0}/tests/acceptance_tests/test_thermal_model.py +0 -0
  86. {linerate-2.1.2 → linerate-2.2.0}/tests/conftest.py +0 -0
  87. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/__init__.py +0 -0
  88. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/cigre207/test_convective_cooling.py +0 -0
  89. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/cigre601/__init__.py +0 -0
  90. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/cigre601/test_convective_cooling.py +0 -0
  91. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/cigre601/test_solar_heating.py +0 -0
  92. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/ieee738/test_ieee_convective_cooling.py +0 -0
  93. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/ieee738/test_solar_heating.py +0 -0
  94. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_convective_cooling.py +0 -0
  95. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_dimensionless.py +0 -0
  96. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_joule_heating.py +0 -0
  97. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_math.py +0 -0
  98. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_radiative_cooling.py +0 -0
  99. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_solar_angles.py +0 -0
  100. {linerate-2.1.2 → linerate-2.2.0}/tests/equations/test_solar_heating.py +0 -0
  101. {linerate-2.1.2 → linerate-2.2.0}/tests/integration_tests/test_vectorization.py +0 -0
  102. {linerate-2.1.2 → linerate-2.2.0}/tests/models/test_thermal_model.py +0 -0
  103. {linerate-2.1.2 → linerate-2.2.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: linerate
3
- Version: 2.1.2
3
+ Version: 2.2.0
4
4
  Summary: Library for computing line ampacity ratings for overhead lines
5
5
  Author-email: Statnett Datascience <Datascience.Drift@Statnett.no>, Yngve Mardal Moe <yngve.m.moe@gmail.com>
6
6
  Requires-Python: >=3.9
@@ -198,6 +198,7 @@ class ThermalModel(ABC):
198
198
  min_ampacity: Ampere = 0,
199
199
  max_ampacity: Ampere = 5000,
200
200
  tolerance: float = 1.0,
201
+ accept_invalid_values: bool = False,
201
202
  ) -> Ampere:
202
203
  r"""Use the bisection method to compute the steady-state thermal rating (ampacity).
203
204
 
@@ -216,6 +217,9 @@ class ThermalModel(ABC):
216
217
  bisection iterations will stop once the numerical ampacity uncertainty is below
217
218
  :math:`\Delta I`. The bisection method will run for
218
219
  :math:`\left\lceil\frac{I_\text{min} - I_\text{min}}{\Delta I}\right\rceil` iterations.
220
+ accept_invalid_values:
221
+ If True, np.nan is returned whenever the current cannot be found within the provided
222
+ search interval. If False, a ValueError will be raised instead.
219
223
 
220
224
  Returns
221
225
  -------
@@ -228,6 +232,7 @@ class ThermalModel(ABC):
228
232
  min_ampacity=min_ampacity,
229
233
  max_ampacity=max_ampacity,
230
234
  tolerance=tolerance,
235
+ accept_invalid_values=accept_invalid_values,
231
236
  )
232
237
  n = self.span.num_conductors
233
238
  return I * n
@@ -1,5 +1,5 @@
1
1
  from functools import partial
2
- from typing import Callable, Optional
2
+ from typing import Callable
3
3
 
4
4
  import numpy as np
5
5
 
@@ -13,7 +13,7 @@ def bisect(
13
13
  xmin: FloatOrFloatArray,
14
14
  xmax: FloatOrFloatArray,
15
15
  tolerance: float,
16
- invalid_value: Optional[float] = None,
16
+ accept_invalid_values: bool = False,
17
17
  ) -> FloatOrFloatArray:
18
18
  r"""Compute the roots of a function using a vectorized bisection method.
19
19
 
@@ -32,10 +32,10 @@ def bisect(
32
32
  bounded within an interval of size :math:`\Delta x` or less. The bisection method will
33
33
  run for :math:`\left\lceil\frac{x_\max - x_\min}{\Delta x}\right\rceil`
34
34
  iterations.
35
- invalid_value:
36
- This value is used whenever
37
- :math:`\text{sign}(f(\mathbf{x}_\min)) = \text{sign}(f(\mathbf{x}_\max))`. If not provided
38
- np.nan is used.
35
+ accept_invalid_values:
36
+ If True, np.nan is returned whenever
37
+ :math:`\text{sign}(f(\mathbf{x}_\min)) = \text{sign}(f(\mathbf{x}_\max))`
38
+ If False, a ValueError will be raised.
39
39
 
40
40
  Returns
41
41
  -------
@@ -44,7 +44,7 @@ def bisect(
44
44
  there is a root :math:`x_i \in [\tilde{x}_i - 0.5 \Delta x, \tilde{x}_i + 0.5 \Delta x]`
45
45
  so :math:`f_i(x_i) = 0`.
46
46
  """
47
- _invalid_value = np.nan if invalid_value is None else invalid_value
47
+ _invalid_value = np.nan
48
48
 
49
49
  if not np.all(np.isfinite(xmin)) or not np.all(np.isfinite(xmax)):
50
50
  raise ValueError("xmin and xmax must be finite.")
@@ -54,14 +54,15 @@ def bisect(
54
54
  f_right = f(xmax)
55
55
 
56
56
  invalid_mask = np.sign(f_left) == np.sign(f_right)
57
- if np.any(invalid_mask) and invalid_value is None:
57
+ if np.any(invalid_mask) and not accept_invalid_values:
58
58
  raise ValueError(
59
59
  "f(xmin) and f(xmax) have the same sign. Consider increasing the search interval."
60
60
  )
61
61
  elif isinstance(invalid_mask, bool) and invalid_mask:
62
62
  return _invalid_value
63
63
 
64
- while interval > tolerance:
64
+ nan_mask = np.isnan(f_left) | np.isnan(f_right)
65
+ while interval > tolerance and not np.all(nan_mask):
65
66
  xmid = 0.5 * (xmax + xmin)
66
67
  interval *= 0.5
67
68
  f_mid = f(xmid)
@@ -72,7 +73,10 @@ def bisect(
72
73
  f_left = np.where(mask, f_mid, f_left)
73
74
  f_right = np.where(mask, f_right, f_mid)
74
75
 
76
+ nan_mask = np.isnan(f_left) | np.isnan(f_right)
77
+
75
78
  out = np.where(invalid_mask, _invalid_value, 0.5 * (xmax + xmin))
79
+ out = np.where(nan_mask, np.nan, out)
76
80
  return out
77
81
 
78
82
 
@@ -121,7 +125,7 @@ def compute_conductor_ampacity(
121
125
  min_ampacity: Ampere = 0,
122
126
  max_ampacity: Ampere = 5_000,
123
127
  tolerance: float = 1, # Ampere
124
- invalid_value=None,
128
+ accept_invalid_values: bool = False,
125
129
  ) -> Ampere:
126
130
  r"""Use the bisection method to compute the steady-state thermal rating (ampacity).
127
131
 
@@ -144,10 +148,9 @@ def compute_conductor_ampacity(
144
148
  bisection iterations will stop once the numerical ampacity uncertainty is below
145
149
  :math:`\Delta I`. The bisection method will run for
146
150
  :math:`\left\lceil\frac{I_\text{max} - I_\text{min}}{\Delta I}\right\rceil` iterations.
147
- invalid_value:
148
- if the optimization problem is invalid, this value is returned instead of an error.
149
- Suggested value: 0 for 0-ampacity when max_conductor_temperature is exceeded for all
150
- ampacities.
151
+ accept_invalid_values:
152
+ If True, np.nan is returned whenever the current cannot be found within the provided
153
+ search interval. If False, a ValueError will be raised instead.
151
154
 
152
155
  Returns
153
156
  -------
@@ -156,4 +159,6 @@ def compute_conductor_ampacity(
156
159
  """
157
160
  f = partial(heat_balance, max_conductor_temperature)
158
161
 
159
- return bisect(f, min_ampacity, max_ampacity, tolerance, invalid_value=invalid_value)
162
+ return bisect(
163
+ f, min_ampacity, max_ampacity, tolerance, accept_invalid_values=accept_invalid_values
164
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: linerate
3
- Version: 2.1.2
3
+ Version: 2.2.0
4
4
  Summary: Library for computing line ampacity ratings for overhead lines
5
5
  Author-email: Statnett Datascience <Datascience.Drift@Statnett.no>, Yngve Mardal Moe <yngve.m.moe@gmail.com>
6
6
  Requires-Python: >=3.9
@@ -87,3 +87,35 @@ def test_bisect_raises_valueerror_when_infinite_in_array_input():
87
87
  xmax=np.array([10_000, 10_000]),
88
88
  tolerance=1e-8,
89
89
  )
90
+
91
+
92
+ def test_bisect_returns_dtype_float_if_not_accept_invalid_values():
93
+ def heat_balance(currents: np.array):
94
+ A = currents
95
+ T = 90
96
+ res = (A - 100 * T) * (currents + 100 * T)
97
+ return res
98
+
99
+ solution = solver.bisect(
100
+ heat_balance,
101
+ xmin=np.array([0, 0]),
102
+ xmax=np.array([10_000, 10_000]),
103
+ tolerance=1e-8,
104
+ accept_invalid_values=False,
105
+ )
106
+
107
+ assert solution.dtype == np.float64
108
+
109
+
110
+ def test_bisect_return_nan_if_heat_balance_returns_nan():
111
+ def heat_balance(currents: np.array):
112
+ return np.ones_like(currents) * np.nan
113
+
114
+ solution = solver.bisect(
115
+ heat_balance,
116
+ xmin=np.array([0, 0]),
117
+ xmax=np.array([10_000, 10_000]),
118
+ tolerance=1e-8,
119
+ )
120
+
121
+ np.testing.assert_array_equal(np.isnan(solution), np.full_like(solution, True, dtype=bool))
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes