Skip to content

Commit f37db52

Browse files
Fix bug where max_raynolds_number was not set with Cigre601WithSolarRadiation model (#94)
1 parent 74d35b7 commit f37db52

24 files changed

+466
-319
lines changed

linerate/models/cigre207.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ def compute_joule_heating(
3535
)
3636

3737
@_copy_method_docstring(ThermalModel)
38-
def compute_solar_heating(
39-
self, conductor_temperature: Celsius, current: Ampere
40-
) -> WattPerMeter:
38+
def compute_solar_heating(self) -> WattPerMeter:
4139
alpha_s = self.span.conductor.solar_absorptivity
4240
phi = self.span.latitude
4341
gamma_c = self.span.conductor_azimuth
@@ -74,9 +72,7 @@ def compute_solar_heating(
7472
)
7573

7674
@_copy_method_docstring(ThermalModel)
77-
def compute_convective_cooling(
78-
self, conductor_temperature: Celsius, current: Ampere
79-
) -> WattPerMeter:
75+
def compute_convective_cooling(self, conductor_temperature: Celsius) -> WattPerMeter:
8076
D = self.span.conductor.conductor_diameter
8177
d = self.span.conductor.outer_layer_strand_diameter
8278
V = self.weather.wind_speed
@@ -126,10 +122,11 @@ def compute_convective_cooling(
126122

127123
@_copy_method_docstring(ThermalModel)
128124
def compute_radiative_cooling(
129-
self, conductor_temperature: Celsius, current: Ampere
125+
self,
126+
conductor_temperature: Celsius,
130127
) -> WattPerMeter:
131128
return super().compute_radiative_cooling(
132-
conductor_temperature=conductor_temperature, current=current
129+
conductor_temperature=conductor_temperature,
133130
)
134131

135132
@_copy_method_docstring(ThermalModel)

linerate/models/cigre601.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222

2323

2424
class BaseCigre601(ThermalModel):
25+
DEFAULT_MAX_REYNOLDS_NUMBER = 4000.0 # Max value of the angle correction in CIGRE601
26+
2527
def __init__(
2628
self,
2729
span: Span,
2830
weather: BaseWeather,
2931
time: Date,
30-
max_reynolds_number: Unitless = 4000.0, # Max value of the angle correction in CIGRE601
32+
max_reynolds_number: Unitless = DEFAULT_MAX_REYNOLDS_NUMBER,
3133
):
3234
super().__init__(span, weather)
3335
self.time = time
@@ -49,7 +51,8 @@ def compute_joule_heating(
4951

5052
@_copy_method_docstring(ThermalModel)
5153
def compute_convective_cooling(
52-
self, conductor_temperature: Celsius, current: Ampere
54+
self,
55+
conductor_temperature: Celsius,
5356
) -> WattPerMeter:
5457
D = self.span.conductor.conductor_diameter
5558
d = self.span.conductor.outer_layer_strand_diameter
@@ -105,10 +108,11 @@ def compute_convective_cooling(
105108

106109
@_copy_method_docstring(ThermalModel)
107110
def compute_radiative_cooling(
108-
self, conductor_temperature: Celsius, current: Ampere
111+
self,
112+
conductor_temperature: Celsius,
109113
) -> WattPerMeter:
110114
return super().compute_radiative_cooling(
111-
conductor_temperature=conductor_temperature, current=current
115+
conductor_temperature=conductor_temperature,
112116
)
113117

114118
def compute_temperature_gradient(
@@ -142,22 +146,22 @@ def compute_temperature_gradient(
142146

143147

144148
class Cigre601(BaseCigre601):
149+
"""Extension of the BaseCigre601 model that uses the solar radiation parametrisation in CIGRE601."""
150+
145151
def __init__(
146152
self,
147153
span: Span,
148154
weather: Weather,
149155
time: Date,
150-
max_reynolds_number: Unitless = 4000.0, # Max value of the angle correction in CIGRE601
156+
max_reynolds_number: Unitless = BaseCigre601.DEFAULT_MAX_REYNOLDS_NUMBER,
151157
):
152158
self.span = span
153159
self.weather = weather
154160
self.time = time
155161
self.max_reynolds_number = max_reynolds_number
156162

157163
@_copy_method_docstring(ThermalModel)
158-
def compute_solar_heating(
159-
self, conductor_temperature: Celsius, current: Ampere
160-
) -> WattPerMeter:
164+
def compute_solar_heating(self) -> WattPerMeter:
161165
alpha_s = self.span.conductor.solar_absorptivity
162166
F = self.weather.ground_albedo
163167
y = self.span.conductor_altitude
@@ -183,18 +187,22 @@ def compute_solar_heating(
183187

184188

185189
class Cigre601WithSolarRadiation(BaseCigre601):
186-
"""Extension of the Cigre601 model that accepts external solar radiation data for direct and diffuse solar
190+
"""Extension of the BaseCigre601 model that accepts external solar radiation data for direct and diffuse solar
187191
radiation."""
188192

189-
def __init__(self, span: Span, weather: WeatherWithSolarRadiation, time: Date):
193+
def __init__(
194+
self,
195+
span: Span,
196+
weather: WeatherWithSolarRadiation,
197+
time: Date,
198+
max_reynolds_number: Unitless = BaseCigre601.DEFAULT_MAX_REYNOLDS_NUMBER,
199+
):
190200
self.span = span
191201
self.weather = weather
192202
self.time = time
193-
self.weather = weather
203+
self.max_reynolds_number = max_reynolds_number
194204

195-
def compute_solar_heating(
196-
self, conductor_temperature: Celsius, current: Ampere
197-
) -> WattPerMeter:
205+
def compute_solar_heating(self) -> WattPerMeter:
198206
alpha_s = self.span.conductor.solar_absorptivity
199207
F = self.weather.ground_albedo
200208
D = self.span.conductor.conductor_diameter

linerate/models/ieee738.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def compute_joule_heating(
3434

3535
@_copy_method_docstring(ThermalModel)
3636
def compute_solar_heating(
37-
self, conductor_temperature: Celsius, current: Ampere
37+
self,
3838
) -> WattPerMeter:
3939
alpha_s = self.span.conductor.solar_absorptivity # alpha in IEEE
4040
phi = self.span.latitude # Lat in IEEE
@@ -56,9 +56,7 @@ def compute_solar_heating(
5656
return ieee738.solar_heating.compute_solar_heating(alpha_s, Q_se, cos_theta, D)
5757

5858
@_copy_method_docstring(ThermalModel)
59-
def compute_convective_cooling(
60-
self, conductor_temperature: Celsius, current: Ampere
61-
) -> WattPerMeter:
59+
def compute_convective_cooling(self, conductor_temperature: Celsius) -> WattPerMeter:
6260
D = self.span.conductor.conductor_diameter # D_0 in IEEE
6361
y = self.span.conductor_altitude # H_e in IEEE
6462
V = self.weather.wind_speed # V_w in IEEE
@@ -83,9 +81,7 @@ def compute_convective_cooling(
8381
return ieee738.convective_cooling.compute_convective_cooling(q_cf, q_cn)
8482

8583
@_copy_method_docstring(ThermalModel)
86-
def compute_radiative_cooling(
87-
self, conductor_temperature: Celsius, current: Ampere
88-
) -> WattPerMeter:
84+
def compute_radiative_cooling(self, conductor_temperature: Celsius) -> WattPerMeter:
8985
return super().compute_radiative_cooling(
90-
conductor_temperature=conductor_temperature, current=current
86+
conductor_temperature=conductor_temperature,
9187
)

linerate/models/thermal_model.py

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,10 @@ def compute_joule_heating(
8484

8585
@abstractmethod
8686
def compute_solar_heating(
87-
self, conductor_temperature: Celsius, current: Ampere
87+
self,
8888
) -> WattPerMeter:
8989
r"""Compute the solar heating, :math:`P_S~\left[\text{W}~\text{m}^{-1}\right]`.
9090
91-
Parameters
92-
----------
93-
conductor_temperature:
94-
:math:`T_\text{av}~\left[^\circ\text{C}\right]`. The average conductor temperature.
95-
current:
96-
:math:`I~\left[\text{A}\right]`. The current.
97-
9891
Returns
9992
-------
10093
Union[float, float64, ndarray[Any, dtype[float64]]]
@@ -104,16 +97,15 @@ def compute_solar_heating(
10497

10598
@abstractmethod
10699
def compute_convective_cooling(
107-
self, conductor_temperature: Celsius, current: Ampere
100+
self,
101+
conductor_temperature: Celsius,
108102
) -> WattPerMeter:
109103
r"""Compute the convective cooling, :math:`P_c~\left[\text{W}~\text{m}^{-1}\right]`.
110104
111105
Parameters
112106
----------
113107
conductor_temperature:
114108
:math:`T_\text{av}~\left[^\circ\text{C}\right]`. The average conductor temperature.
115-
current:
116-
:math:`I~\left[\text{A}\right]`. The current.
117109
118110
Returns
119111
-------
@@ -124,16 +116,15 @@ def compute_convective_cooling(
124116

125117
@abstractmethod
126118
def compute_radiative_cooling(
127-
self, conductor_temperature: Celsius, current: Ampere
119+
self,
120+
conductor_temperature: Celsius,
128121
) -> WattPerMeter:
129122
r"""Compute the radiative cooling, :math:`P_r~\left[\text{W}~\text{m}^{-1}\right]`.
130123
131124
Parameters
132125
----------
133126
conductor_temperature:
134127
:math:`T_\text{av}~\left[^\circ\text{C}\right]`. The average conductor temperature.
135-
current:
136-
:math:`I~\left[\text{A}\right]`. The current.
137128
138129
Returns
139130
-------
@@ -163,9 +154,9 @@ def compute_heat_balance(self, conductor_temperature: Celsius, current: Ampere)
163154
:math:`P_J + P_s - P_c - P_r~\left[\text{W}~\text{m}^{-1}\right]`. The heat balance.
164155
"""
165156
P_j = self.compute_joule_heating(conductor_temperature, current)
166-
P_s = self.compute_solar_heating(conductor_temperature, current)
167-
P_c = self.compute_convective_cooling(conductor_temperature, current)
168-
P_r = self.compute_radiative_cooling(conductor_temperature, current)
157+
P_s = self.compute_solar_heating()
158+
P_c = self.compute_convective_cooling(conductor_temperature)
159+
P_r = self.compute_radiative_cooling(conductor_temperature)
169160
return P_j + P_s - P_c - P_r
170161

171162
def compute_info(
@@ -186,10 +177,10 @@ def compute_info(
186177
A dictionary with the magnitude of the different heating and cooling effects.
187178
"""
188179
return {
189-
"convective_cooling": self.compute_convective_cooling(conductor_temperature, current),
190-
"radiative_cooling": self.compute_radiative_cooling(conductor_temperature, current),
180+
"convective_cooling": self.compute_convective_cooling(conductor_temperature),
181+
"radiative_cooling": self.compute_radiative_cooling(conductor_temperature),
191182
"joule_heating": self.compute_joule_heating(conductor_temperature, current),
192-
"solar_heating": self.compute_solar_heating(conductor_temperature, current),
183+
"solar_heating": self.compute_solar_heating(),
193184
}
194185

195186
def compute_steady_state_ampacity(

linerate/units.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
BoolOrBoolArray = Union[bool, np.bool_, npt.NDArray[np.bool_]]
1313

1414
OhmPerMeter = Annotated[FloatOrFloatArray, "Ω/m"]
15+
OhmPerMeterPerCelsius = Annotated[FloatOrFloatArray, "Ω/(m °C)"]
1516
Ampere = Annotated[FloatOrFloatArray, "A"]
1617
Radian = Annotated[FloatOrFloatArray, "rad"]
1718
Degrees = Annotated[FloatOrFloatArray, "°"]

tests/acceptance_tests/test_cigre_ampacity_cases.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,39 @@
44
import pytest
55
from pytest import approx
66

7-
import linerate
7+
from linerate.models.cigre601 import Cigre601
8+
from linerate.models.thermal_model import ThermalModel
9+
from linerate.types import Conductor, Span, Tower, Weather
810

911

10-
def test_example_a_convective_cooling(example_model_1_conductors):
11-
assert example_model_1_conductors.compute_convective_cooling(100, None) == approx(77.6, abs=0.5)
12+
def test_example_a_convective_cooling(example_model_1_conductors: ThermalModel):
13+
assert example_model_1_conductors.compute_convective_cooling(100) == approx(77.6, abs=0.5)
1214

1315

14-
def test_example_a_radiative_cooling(example_model_1_conductors):
15-
assert example_model_1_conductors.compute_radiative_cooling(100, None) == approx(39.1, abs=0.5)
16+
def test_example_a_radiative_cooling(example_model_1_conductors: ThermalModel):
17+
assert example_model_1_conductors.compute_radiative_cooling(100) == approx(39.1, abs=0.5)
1618

1719

18-
def test_example_a_solar_heating(example_model_1_conductors):
19-
assert example_model_1_conductors.compute_solar_heating(100, None) == approx(27.2, abs=0.5)
20+
def test_example_a_solar_heating(example_model_1_conductors: ThermalModel):
21+
assert example_model_1_conductors.compute_solar_heating() == approx(27.2, abs=0.5)
2022

2123

22-
def test_example_a_resistance(example_model_1_conductors):
23-
assert example_model_1_conductors.compute_resistance(100, None) == approx(
24+
def test_example_a_resistance(example_model_1_conductors: ThermalModel):
25+
assert example_model_1_conductors.compute_resistance(100, np.nan) == approx(
2426
9.3905e-5, abs=0.0001e-5
2527
)
2628

2729

28-
def test_example_a_ampacity(example_model_1_conductors):
30+
def test_example_a_ampacity(example_model_1_conductors: ThermalModel):
2931
# There are noticable roundoff errors in the report
3032
assert example_model_1_conductors.compute_steady_state_ampacity(100, tolerance=1e-8) == approx(
3133
976, abs=1.5
3234
)
3335

3436

3537
@pytest.fixture
36-
def drake_conductor_b():
37-
return linerate.Conductor(
38+
def drake_conductor_b() -> Conductor:
39+
return Conductor(
3840
core_diameter=10.4e-3,
3941
conductor_diameter=28.1e-3,
4042
outer_layer_strand_diameter=2.2e-3,
@@ -52,8 +54,8 @@ def drake_conductor_b():
5254

5355

5456
@pytest.fixture
55-
def example_weather_b():
56-
return linerate.Weather(
57+
def example_weather_b() -> Weather:
58+
return Weather(
5759
air_temperature=20,
5860
wind_direction=np.radians(80), # Conductor azimuth is 0, so angle of attack is 80
5961
wind_speed=1.66,
@@ -63,51 +65,51 @@ def example_weather_b():
6365

6466

6567
@pytest.fixture()
66-
def example_span_b(drake_conductor_b):
67-
start_tower = linerate.Tower(latitude=50 - 0.0045, longitude=0, altitude=500 - 88)
68-
end_tower = linerate.Tower(latitude=50 + 0.0045, longitude=0, altitude=500 + 88)
69-
return linerate.Span(
68+
def example_span_b(drake_conductor_b: Conductor) -> Span:
69+
start_tower = Tower(latitude=50 - 0.0045, longitude=0, altitude=500 - 88)
70+
end_tower = Tower(latitude=50 + 0.0045, longitude=0, altitude=500 + 88)
71+
return Span(
7072
conductor=drake_conductor_b,
7173
start_tower=start_tower,
7274
end_tower=end_tower,
7375
num_conductors=1,
7476
)
7577

7678

77-
def test_example_span_b_has_correct_altitude(example_span_b):
79+
def test_example_span_b_has_correct_altitude(example_span_b: Span):
7880
assert example_span_b.conductor_altitude == approx(500, abs=0.5)
7981

8082

81-
def test_example_span_b_has_correct_inclination(example_span_b):
83+
def test_example_span_b_has_correct_inclination(example_span_b: Span):
8284
assert np.degrees(example_span_b.inclination) == approx(10, abs=0.5)
8385

8486

85-
def test_example_span_b_has_correct_latitude(example_span_b):
87+
def test_example_span_b_has_correct_latitude(example_span_b: Span):
8688
assert example_span_b.latitude == approx(50)
8789

8890

8991
@pytest.fixture()
90-
def example_model_b(example_span_b, example_weather_b):
91-
return linerate.Cigre601(example_span_b, example_weather_b, np.datetime64("2016-10-03 14:00"))
92+
def example_model_b(example_span_b: Span, example_weather_b: Weather) -> Cigre601:
93+
return Cigre601(example_span_b, example_weather_b, np.datetime64("2016-10-03 14:00"))
9294

9395

94-
def test_example_b_convective_cooling(example_model_b):
95-
assert example_model_b.compute_convective_cooling(100, None) == approx(172.1, abs=0.5)
96+
def test_example_b_convective_cooling(example_model_b: ThermalModel):
97+
assert example_model_b.compute_convective_cooling(100) == approx(172.1, abs=0.5)
9698

9799

98-
def test_example_b_radiative_cooling(example_model_b):
99-
assert example_model_b.compute_radiative_cooling(100, None) == approx(54, abs=0.5)
100+
def test_example_b_radiative_cooling(example_model_b: ThermalModel):
101+
assert example_model_b.compute_radiative_cooling(100) == approx(54, abs=0.5)
100102

101103

102-
def test_example_b_solar_heating(example_model_b):
103-
assert example_model_b.compute_solar_heating(100, None) == approx(13.7, abs=0.5)
104+
def test_example_b_solar_heating(example_model_b: ThermalModel):
105+
assert example_model_b.compute_solar_heating() == approx(13.7, abs=0.5)
104106

105107

106-
def test_example_b_resistance(example_model_b):
107-
assert example_model_b.compute_resistance(100, None) == approx(9.3905e-5, abs=0.0001e-5)
108+
def test_example_b_resistance(example_model_b: ThermalModel):
109+
assert example_model_b.compute_resistance(100, np.nan) == approx(9.3905e-5, abs=0.0001e-5)
108110

109111

110-
def test_example_b_ampacity(example_model_b):
112+
def test_example_b_ampacity(example_model_b: ThermalModel):
111113
# There are noticable roundoff errors in the report
112114
# There is a typo in the report, where it says that the ampacity is 1054, but it is 1504.
113115
assert example_model_b.compute_steady_state_ampacity(100, tolerance=1e-8) == approx(

0 commit comments

Comments
 (0)