From fe42a313e7646cf72ac239f76ea11a1f22cb9581 Mon Sep 17 00:00:00 2001 From: Halvor Lund Date: Wed, 29 May 2024 14:20:09 +0200 Subject: [PATCH] Fix tests, compute Reynolds number as in Cigre207 report --- linerate/equations/cigre207/ac_resistance.py | 34 +-- .../equations/cigre207/convective_cooling.py | 38 ++- linerate/models/Cigre207.md | 2 +- linerate/models/cigre207.py | 49 +++- .../cigre601/test_convective_cooling.py | 241 +----------------- ...ing.py => test_ieee_convective_cooling.py} | 36 --- tests/equations/test_convective_cooling.py | 97 +++++++ tests/equations/test_dimensionless.py | 157 ++++++++++++ 8 files changed, 346 insertions(+), 308 deletions(-) rename tests/equations/ieee738/{test_convective_cooling.py => test_ieee_convective_cooling.py} (89%) create mode 100644 tests/equations/test_convective_cooling.py create mode 100644 tests/equations/test_dimensionless.py diff --git a/linerate/equations/cigre207/ac_resistance.py b/linerate/equations/cigre207/ac_resistance.py index 86fa2ff..748baef 100644 --- a/linerate/equations/cigre207/ac_resistance.py +++ b/linerate/equations/cigre207/ac_resistance.py @@ -1,45 +1,27 @@ from typing import Union -from linerate.units import OhmPerMeter, Ampere, SquareMeter, Unitless, SquareMeterPerAmpere +from linerate.units import OhmPerMeter -def correct_resistance_acsr_magnetic_core_loss_simple( - ac_resistance: OhmPerMeter, - current: Ampere, - aluminium_cross_section_area: SquareMeter, - constant_magnetic_effect: Union[Unitless, None], - current_density_proportional_magnetic_effect: Union[SquareMeterPerAmpere, None], - max_relative_increase: Unitless, +def correct_resistance_for_skin_effect( + dc_resistance: OhmPerMeter, ) -> OhmPerMeter: r""" - Return resistance with constant correction for magnetic effects, using simple method from + Return resistance with constant correction for skin effect, using simple method from Cigre 207, see section 2.1.1. Parameters ---------- - ac_resistance: - :math:`R~\left[\Omega\right]`. The AC resistance of the conductor. - current: - :math:`I~\left[\text{A}\right]`. The current going through the conductor. - aluminium_cross_section_area: - :math:`A_{\text{Al}}~\left[\text{m}^2\right]`. The cross sectional area of the aluminium - strands in the conductor. - constant_magnetic_effect: - :math:`b`. The constant magnetic effect, most likely equal to 1. If ``None``, then no - correction is used (useful for non-ACSR cables). - current_density_proportional_magnetic_effect: - :math:`m`. The current density proportional magnetic effect. If ``None``, then it is - assumed equal to 0. - max_relative_increase: - :math:`c_\text{max}`. Saturation point of the relative increase in conductor resistance. + dc_resistance: + :math:`R~\left[\Omega\right]`. The DC resistance of the conductor. Returns ------- Union[float, float64, ndarray[Any, dtype[float64]]] :math:`R_\text{corrected}~\left[\Omega\right]`. The resistance of the conductor after - taking steel core magnetization effects into account. + taking skin effect into account. """ - return 1.0123 * ac_resistance + return 1.0123 * dc_resistance # TODO: Implement section 2.1.2? \ No newline at end of file diff --git a/linerate/equations/cigre207/convective_cooling.py b/linerate/equations/cigre207/convective_cooling.py index e3b12f7..78e7215 100644 --- a/linerate/equations/cigre207/convective_cooling.py +++ b/linerate/equations/cigre207/convective_cooling.py @@ -10,7 +10,7 @@ MeterPerSecond, Radian, Unitless, - WattPerMeterPerKelvin, + WattPerMeterPerKelvin, SquareMeterPerSecond, ) @@ -107,6 +107,42 @@ def compute_prandtl_number( return 0.715 - 2.5e-4*film_temperature +def compute_reynolds_number( + wind_speed: MeterPerSecond, + conductor_diameter: Meter, + kinematic_viscosity_of_air: SquareMeterPerSecond, + relative_air_density: Unitless +) -> Unitless: + r"""Compute the Reynolds number using the conductor diameter as characteristic length scale. + + Defined on page 5 of :cite:p:`cigre207`. + This is a non-standard definition which seems to indicate that the kinematic viscosity has to + be corrected for the density. + + Parameters + ---------- + wind_speed: + :math:`v~\left[\text{m}~\text{s}^{-1}\right]`. The wind speed. + conductor_diameter: + :math:`D~\left[\text{m}\right]`. Outer diameter of the conductor. + kinematic_viscosity_of_air: + :math:`\nu_f~\left[\text{m}^2~\text{s}^{-1}\right]`. The kinematic viscosity of air. + relative_air_density: + :math:`\rho_r~1`. The air density relative to density at sea level. + + Returns + ------- + Union[float, float64, ndarray[Any, dtype[float64]]] + :math:`\text{Re}`. The Reynolds number. + """ + v = wind_speed + D = conductor_diameter + nu_f = kinematic_viscosity_of_air + rho_r = relative_air_density + return rho_r * v * D / nu_f + + + ## Nusselt number calculation ############################# diff --git a/linerate/models/Cigre207.md b/linerate/models/Cigre207.md index b3702ed..3912193 100644 --- a/linerate/models/Cigre207.md +++ b/linerate/models/Cigre207.md @@ -3,7 +3,7 @@ ## Cigre 207 vs 601 The Cigre 601 report states that 601 takes into account improvements in the calculation of AC resistance of stranded -conductors, includes a more realistic estimation of the axial and radial temeprature distributions, more coherent +conductors, includes a more realistic estimation of the axial and radial temperature distributions, more coherent convection model for low wind speeds, and has a more flexible solar radiation model. ## Skin effect diff --git a/linerate/models/cigre207.py b/linerate/models/cigre207.py index c15c0e3..9f2ae92 100644 --- a/linerate/models/cigre207.py +++ b/linerate/models/cigre207.py @@ -1,8 +1,10 @@ +from abc import abstractmethod + from linerate import ThermalModel, Span, Weather -from linerate.equations import solar_angles, cigre601, math, cigre207, dimensionless, convective_cooling +from linerate.equations import solar_angles, cigre601, math, cigre207, dimensionless, convective_cooling, joule_heating from linerate.equations.math import switch_cos_sin from linerate.model import _copy_method_docstring -from linerate.units import Date, Celsius, Ampere, WattPerMeter +from linerate.units import Date, Celsius, Ampere, WattPerMeter, OhmPerMeter class Cigre207(ThermalModel): @@ -63,8 +65,8 @@ def compute_convective_cooling( ) -> WattPerMeter: D = self.span.conductor.conductor_diameter d = self.span.conductor.outer_layer_strand_diameter - y = self.span.conductor_altitude V = self.weather.wind_speed + y = self.span.conductor_altitude T_a = self.weather.air_temperature T_c = conductor_temperature T_f = 0.5 * (T_c + T_a) @@ -80,7 +82,8 @@ def compute_convective_cooling( # Reynolds number is defined in the text on page 5 of :cite:p:`cigre207`. # The definition includes a relative air density, which does not make sense, so we omit it here and use the # standard definition of Reynolds number instead. - Re = dimensionless.compute_reynolds_number(V, D, nu_f) + rho_r = cigre207.convective_cooling.compute_relative_air_density(y) + Re = cigre207.convective_cooling.compute_reynolds_number(V, D, nu_f, rho_r) Gr = dimensionless.compute_grashof_number(D, T_c, T_a, nu_f) Pr = cigre207.convective_cooling.compute_prandtl_number(T_f) Rs = dimensionless.compute_conductor_roughness(D, d) @@ -115,3 +118,41 @@ def compute_radiative_cooling( return super().compute_radiative_cooling( conductor_temperature=conductor_temperature, current=current ) + + @abstractmethod + def compute_resistance(self, conductor_temperature: Celsius, current: Ampere) -> OhmPerMeter: + r"""Compute the conductor resistance, :math:`R~\left[\Omega~\text{m}^{-1}\right]`. + + Parameters + ---------- + conductor_temperature: + :math:`T_\text{av}~\left[^\circ\text{C}\right]`. The average conductor temperature. + current: + :math:`I~\left[\text{A}\right]`. The current. + + Returns + ------- + Union[float, float64, ndarray[Any, dtype[float64]]] + :math:`R~\left[\Omega\right]`. The resistance at the given temperature and current. + """ + resistance = joule_heating.compute_resistance( + conductor_temperature, + temperature1=self.span.conductor.temperature1, + temperature2=self.span.conductor.temperature2, + resistance_at_temperature1=self.span.conductor.resistance_at_temperature1, + resistance_at_temperature2=self.span.conductor.resistance_at_temperature2, + ) + + A = self.span.conductor.aluminium_cross_section_area + b = self.span.conductor.constant_magnetic_effect + m = self.span.conductor.current_density_proportional_magnetic_effect + max_increase = self.span.conductor.max_magnetic_core_relative_resistance_increase + + return joule_heating.correct_resistance_acsr_magnetic_core_loss( + ac_resistance=resistance, + current=current, + aluminium_cross_section_area=A, + constant_magnetic_effect=b, + current_density_proportional_magnetic_effect=m, + max_relative_increase=max_increase, + ) diff --git a/tests/equations/cigre601/test_convective_cooling.py b/tests/equations/cigre601/test_convective_cooling.py index 13a74c4..6e690c4 100644 --- a/tests/equations/cigre601/test_convective_cooling.py +++ b/tests/equations/cigre601/test_convective_cooling.py @@ -7,6 +7,7 @@ import linerate.equations.cigre601.convective_cooling as convective_cooling + # Tests for physical quantities ############################### @@ -259,155 +260,6 @@ def test_kinematic_viscosity_of_air_with_example(): assert convective_cooling.compute_kinematic_viscosity_of_air(mu_f, gamma) == approx(1) -# Tests for unitless quantities -############################### - - -@hypothesis.given(wind_speed=st.floats(min_value=0, max_value=1000, allow_nan=False)) -def test_reynolds_number_scales_linearly_with_wind_speed(wind_speed): - V = wind_speed - D = 1 - Nu_f = 1 - - assert convective_cooling.compute_reynolds_number(V, D, Nu_f) == pytest.approx(V) - - -@hypothesis.given(conductor_diameter=st.floats(min_value=0, max_value=1000, allow_nan=False)) -def test_reynolds_number_scales_linearly_with_diameter(conductor_diameter): - V = 1 - D = conductor_diameter - Nu_f = 1 - - assert convective_cooling.compute_reynolds_number(V, D, Nu_f) == pytest.approx(D) - - -@hypothesis.given(kinematic_viscosity=st.floats(min_value=1e-10, allow_nan=False)) -def test_reynolds_number_scales_inversly_with_kinematic_viscosity(kinematic_viscosity): - V = 1 - D = 1 - Nu_f = kinematic_viscosity - - assert convective_cooling.compute_reynolds_number(V, D, Nu_f) == approx(1 / Nu_f) - - -def test_reynolds_number_with_example(): - V = 0.1 - D = 1.2 - Nu_f = 10 - - assert convective_cooling.compute_reynolds_number(V, D, Nu_f) == approx(0.012) - - -@hypothesis.given(conductor_diameter=st.floats(min_value=1e-5, max_value=1e5, allow_nan=False)) -def test_grashof_number_scales_cubic_with_conductor_diameter(conductor_diameter): - D = conductor_diameter - T_s = 1 - T_a = 0 - Nu_f = 1 - g = 273.65 # 0.5*T_s in Kelvin - - Gr = convective_cooling.compute_grashof_number(D, T_s, T_a, Nu_f, g) - assert Gr == approx(D**3) - - -@hypothesis.given(surface_temperature=st.floats(min_value=273, max_value=1000, allow_nan=False)) -def test_grashof_number_scales_correctly_with_surface_temperature(surface_temperature): - D = 1 - T_s = surface_temperature - T_a = 0 - Nu_f = 1 - g = 0.5 * T_s + 273.15 - - Gr = convective_cooling.compute_grashof_number(D, T_s, T_a, Nu_f, g) - assert Gr == approx(abs(T_s)) - - -@hypothesis.given(air_temperature=st.floats(min_value=273, max_value=1000, allow_nan=False)) -def test_grashof_number_scales_correctly_with_air_temperature(air_temperature): - D = 1 - T_s = 0 - T_a = air_temperature - Nu_f = 1 - g = 0.5 * T_a + 273.15 - - Gr = convective_cooling.compute_grashof_number(D, T_s, T_a, Nu_f, g) - assert Gr == approx(abs(T_a)) - - -@hypothesis.given( - kinematic_viscosity_of_air=st.floats(min_value=1e-5, max_value=1e10, allow_nan=False) -) -def test_grashof_number_scales_inversely_squared_with_kinematic_viscosity( - kinematic_viscosity_of_air, -): - D = 1 - T_s = 1 - T_a = 0 - Nu_f = kinematic_viscosity_of_air - g = 273.65 # 0.5*T_s in Kelvin - - Gr = convective_cooling.compute_grashof_number(D, T_s, T_a, Nu_f, g) - assert Gr == approx(1 / (Nu_f**2)) - - -@hypothesis.given(coefficient_of_gravity=st.floats(min_value=1e-3, max_value=1e3, allow_nan=False)) -def test_grashof_number_scales_linearly_with_gravity(coefficient_of_gravity): - D = 1 - T_s = 1 - T_a = 0 - Nu_f = np.sqrt(1 / 273.65) - g = coefficient_of_gravity - - Gr = convective_cooling.compute_grashof_number(D, T_s, T_a, Nu_f, g) - assert Gr == approx(g) - - -def test_grashof_number_with_example(): - D = 4 - T_s = 4 - T_a = 2 - Nu_f = 2 - g = 276.15 - - Gr = convective_cooling.compute_grashof_number(D, T_s, T_a, Nu_f, g) - assert Gr == approx(32) - - -@hypothesis.given(thermal_conductivity=st.floats(min_value=1e-10, max_value=1e10, allow_nan=False)) -def test_prandtl_number_scales_inversely_with_thermal_conductivity(thermal_conductivity): - c_f = 1 - mu_f = 1 - lambda_f = thermal_conductivity - - assert convective_cooling.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(1 / lambda_f) - - -@hypothesis.given(dynamic_viscosity=st.floats(min_value=1e-10, max_value=1e10, allow_nan=False)) -def test_prandtl_number_scales_linearly_with_dynamic_viscosity(dynamic_viscosity): - c_f = 1 - mu_f = dynamic_viscosity - lambda_f = 1 - - assert convective_cooling.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(mu_f) - - -@hypothesis.given( - specific_heat_capacity=st.floats(min_value=1e-10, max_value=1e10, allow_nan=False) -) -def test_prandtl_number_scales_linearly_with_specific_heat_capacity(specific_heat_capacity): - c_f = specific_heat_capacity - mu_f = 1 - lambda_f = 1 - - assert convective_cooling.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(c_f) - - -def test_compute_prandtl_number_with_example(): - c_f = 0.5 - mu_f = 3 - lambda_f = 0.5 - - assert convective_cooling.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(3) ## Nusselt number calculation @@ -646,94 +498,3 @@ def test_compute_nusselt_number(forced_convection_nusselt_number, natural_nussel Nu_est = convective_cooling.compute_nusselt_number(Nu_delta, Nu_beta) assert Nu == Nu_est - - -@hypothesis.given( - nusselt_number=st.floats( - min_value=0, - max_value=1e10, - allow_nan=False, - ) -) -def test_convective_cooling_scales_linearly_with_nusselt_number(nusselt_number): - Nu = nusselt_number - T_s = 1 - T_a = 0 - lambda_f = 1 / np.pi - - assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx(Nu) - - -@hypothesis.given( - thermal_conductivity_of_air=st.floats( - min_value=0, - max_value=1e10, - allow_nan=False, - ) -) -def test_convective_cooling_scales_linearly_with_thermal_conductivity_of_air( - thermal_conductivity_of_air, -): - Nu = 1 / np.pi - T_s = 1 - T_a = 0 - lambda_f = thermal_conductivity_of_air - - assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx(lambda_f) - - -@hypothesis.given( - surface_temperature=st.floats( - min_value=-1e10, - max_value=1e10, - allow_nan=False, - ), - air_temperature=st.floats( - min_value=-1e10, - max_value=1e10, - allow_nan=False, - ), -) -def test_convective_cooling_scales_linearly_with_temperature_difference( - surface_temperature, air_temperature -): - Nu = 1 - T_s = surface_temperature - T_a = air_temperature - lambda_f = 1 / np.pi - - assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx( - T_s - T_a - ) - - -@hypothesis.given( - air_temperature=st.floats( - min_value=-1e10, - max_value=1e10, - allow_nan=False, - ) -) -def test_convective_cooling_scales_affinely_with_air_temperature(air_temperature): - Nu = 1 - T_s = 1 - T_a = air_temperature - lambda_f = 1 / np.pi - - assert 1 - convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx(T_a) - - -@hypothesis.given( - surface_temperature=st.floats( - min_value=-1e10, - max_value=1e10, - allow_nan=False, - ), -) -def test_convective_cooling_scales_affinely_with_surface_temperature(surface_temperature): - Nu = 1 - T_s = surface_temperature - T_a = 1 - lambda_f = 1 / np.pi - - assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) + 1 == approx(T_s) diff --git a/tests/equations/ieee738/test_convective_cooling.py b/tests/equations/ieee738/test_ieee_convective_cooling.py similarity index 89% rename from tests/equations/ieee738/test_convective_cooling.py rename to tests/equations/ieee738/test_ieee_convective_cooling.py index 2d9a887..2d7c97e 100644 --- a/tests/equations/ieee738/test_convective_cooling.py +++ b/tests/equations/ieee738/test_ieee_convective_cooling.py @@ -1,7 +1,6 @@ import hypothesis import hypothesis.strategies as st import numpy as np -import pytest from pytest import approx from scipy.interpolate import lagrange @@ -102,41 +101,6 @@ def test_kinematic_viscosity_of_air_with_example(): assert convective_cooling.compute_kinematic_viscosity_of_air(mu_f, rho_f) == approx(1) -@hypothesis.given(wind_speed=st.floats(min_value=0, max_value=1000, allow_nan=False)) -def test_reynolds_number_scales_linearly_with_wind_speed(wind_speed): - v = wind_speed - D = 1 - nu_f = 1 - - assert convective_cooling.compute_reynolds_number(v, D, nu_f) == pytest.approx(v) - - -@hypothesis.given(conductor_diameter=st.floats(min_value=0, max_value=1000, allow_nan=False)) -def test_reynolds_number_scales_linearly_with_diameter(conductor_diameter): - v = 1 - D = conductor_diameter - nu_f = 1 - - assert convective_cooling.compute_reynolds_number(v, D, nu_f) == pytest.approx(D) - - -@hypothesis.given(kinematic_viscosity=st.floats(min_value=1e-10, allow_nan=False)) -def test_reynolds_number_scales_inversly_with_kinematic_viscosity(kinematic_viscosity): - v = 1 - D = 1 - nu_f = kinematic_viscosity - - assert convective_cooling.compute_reynolds_number(v, D, nu_f) == approx(1 / nu_f) - - -def test_reynolds_number_with_example(): - v = 0.1 - D = 1.2 - nu_f = 10 - - assert convective_cooling.compute_reynolds_number(v, D, nu_f) == approx(0.012) - - def test_wind_direction_factor_with_example(): Phi = 0 assert convective_cooling.compute_wind_direction_factor(Phi) == approx(0.388) diff --git a/tests/equations/test_convective_cooling.py b/tests/equations/test_convective_cooling.py new file mode 100644 index 0000000..876f749 --- /dev/null +++ b/tests/equations/test_convective_cooling.py @@ -0,0 +1,97 @@ +import hypothesis +import hypothesis.strategies as st +import numpy as np + +from pytest import approx +from linerate.equations import convective_cooling + + +@hypothesis.given( + nusselt_number=st.floats( + min_value=0, + max_value=1e10, + allow_nan=False, + ) +) +def test_convective_cooling_scales_linearly_with_nusselt_number(nusselt_number): + Nu = nusselt_number + T_s = 1 + T_a = 0 + lambda_f = 1 / np.pi + + assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx(Nu) + + +@hypothesis.given( + thermal_conductivity_of_air=st.floats( + min_value=0, + max_value=1e10, + allow_nan=False, + ) +) +def test_convective_cooling_scales_linearly_with_thermal_conductivity_of_air( + thermal_conductivity_of_air, +): + Nu = 1 / np.pi + T_s = 1 + T_a = 0 + lambda_f = thermal_conductivity_of_air + + assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx(lambda_f) + + +@hypothesis.given( + surface_temperature=st.floats( + min_value=-1e10, + max_value=1e10, + allow_nan=False, + ), + air_temperature=st.floats( + min_value=-1e10, + max_value=1e10, + allow_nan=False, + ), +) +def test_convective_cooling_scales_linearly_with_temperature_difference( + surface_temperature, air_temperature +): + Nu = 1 + T_s = surface_temperature + T_a = air_temperature + lambda_f = 1 / np.pi + + assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx( + T_s - T_a + ) + + +@hypothesis.given( + air_temperature=st.floats( + min_value=-1e10, + max_value=1e10, + allow_nan=False, + ) +) +def test_convective_cooling_scales_affinely_with_air_temperature(air_temperature): + Nu = 1 + T_s = 1 + T_a = air_temperature + lambda_f = 1 / np.pi + + assert 1 - convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) == approx(T_a) + + +@hypothesis.given( + surface_temperature=st.floats( + min_value=-1e10, + max_value=1e10, + allow_nan=False, + ), +) +def test_convective_cooling_scales_affinely_with_surface_temperature(surface_temperature): + Nu = 1 + T_s = surface_temperature + T_a = 1 + lambda_f = 1 / np.pi + + assert convective_cooling.compute_convective_cooling(T_s, T_a, Nu, lambda_f) + 1 == approx(T_s) diff --git a/tests/equations/test_dimensionless.py b/tests/equations/test_dimensionless.py new file mode 100644 index 0000000..efbf4ba --- /dev/null +++ b/tests/equations/test_dimensionless.py @@ -0,0 +1,157 @@ +# Tests for unitless quantities +############################### + +import hypothesis +import hypothesis.strategies as st +import numpy as np +import pytest +from pytest import approx + +from linerate.equations import dimensionless + + +@hypothesis.given(wind_speed=st.floats(min_value=0, max_value=1000, allow_nan=False)) +def test_reynolds_number_scales_linearly_with_wind_speed(wind_speed): + V = wind_speed + D = 1 + Nu_f = 1 + + assert dimensionless.compute_reynolds_number(V, D, Nu_f) == pytest.approx(V) + + +@hypothesis.given(conductor_diameter=st.floats(min_value=0, max_value=1000, allow_nan=False)) +def test_reynolds_number_scales_linearly_with_diameter(conductor_diameter): + V = 1 + D = conductor_diameter + Nu_f = 1 + + assert dimensionless.compute_reynolds_number(V, D, Nu_f) == pytest.approx(D) + + +@hypothesis.given(kinematic_viscosity=st.floats(min_value=1e-10, allow_nan=False)) +def test_reynolds_number_scales_inversly_with_kinematic_viscosity(kinematic_viscosity): + V = 1 + D = 1 + Nu_f = kinematic_viscosity + + assert dimensionless.compute_reynolds_number(V, D, Nu_f) == approx(1 / Nu_f) + + +def test_reynolds_number_with_example(): + V = 0.1 + D = 1.2 + Nu_f = 10 + + assert dimensionless.compute_reynolds_number(V, D, Nu_f) == approx(0.012) + + +@hypothesis.given(conductor_diameter=st.floats(min_value=1e-5, max_value=1e5, allow_nan=False)) +def test_grashof_number_scales_cubic_with_conductor_diameter(conductor_diameter): + D = conductor_diameter + T_s = 1 + T_a = 0 + Nu_f = 1 + g = 273.65 # 0.5*T_s in Kelvin + + Gr = dimensionless.compute_grashof_number(D, T_s, T_a, Nu_f, g) + assert Gr == approx(D**3) + + +@hypothesis.given(surface_temperature=st.floats(min_value=273, max_value=1000, allow_nan=False)) +def test_grashof_number_scales_correctly_with_surface_temperature(surface_temperature): + D = 1 + T_s = surface_temperature + T_a = 0 + Nu_f = 1 + g = 0.5 * T_s + 273.15 + + Gr = dimensionless.compute_grashof_number(D, T_s, T_a, Nu_f, g) + assert Gr == approx(abs(T_s)) + + +@hypothesis.given(air_temperature=st.floats(min_value=273, max_value=1000, allow_nan=False)) +def test_grashof_number_scales_correctly_with_air_temperature(air_temperature): + D = 1 + T_s = 0 + T_a = air_temperature + Nu_f = 1 + g = 0.5 * T_a + 273.15 + + Gr = dimensionless.compute_grashof_number(D, T_s, T_a, Nu_f, g) + assert Gr == approx(abs(T_a)) + + +@hypothesis.given( + kinematic_viscosity_of_air=st.floats(min_value=1e-5, max_value=1e10, allow_nan=False) +) +def test_grashof_number_scales_inversely_squared_with_kinematic_viscosity( + kinematic_viscosity_of_air, +): + D = 1 + T_s = 1 + T_a = 0 + Nu_f = kinematic_viscosity_of_air + g = 273.65 # 0.5*T_s in Kelvin + + Gr = dimensionless.compute_grashof_number(D, T_s, T_a, Nu_f, g) + assert Gr == approx(1 / (Nu_f**2)) + + +@hypothesis.given(coefficient_of_gravity=st.floats(min_value=1e-3, max_value=1e3, allow_nan=False)) +def test_grashof_number_scales_linearly_with_gravity(coefficient_of_gravity): + D = 1 + T_s = 1 + T_a = 0 + Nu_f = np.sqrt(1 / 273.65) + g = coefficient_of_gravity + + Gr = dimensionless.compute_grashof_number(D, T_s, T_a, Nu_f, g) + assert Gr == approx(g) + + +def test_grashof_number_with_example(): + D = 4 + T_s = 4 + T_a = 2 + Nu_f = 2 + g = 276.15 + + Gr = dimensionless.compute_grashof_number(D, T_s, T_a, Nu_f, g) + assert Gr == approx(32) + + +@hypothesis.given(thermal_conductivity=st.floats(min_value=1e-10, max_value=1e10, allow_nan=False)) +def test_prandtl_number_scales_inversely_with_thermal_conductivity(thermal_conductivity): + c_f = 1 + mu_f = 1 + lambda_f = thermal_conductivity + + assert dimensionless.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(1 / lambda_f) + + +@hypothesis.given(dynamic_viscosity=st.floats(min_value=1e-10, max_value=1e10, allow_nan=False)) +def test_prandtl_number_scales_linearly_with_dynamic_viscosity(dynamic_viscosity): + c_f = 1 + mu_f = dynamic_viscosity + lambda_f = 1 + + assert dimensionless.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(mu_f) + + +@hypothesis.given( + specific_heat_capacity=st.floats(min_value=1e-10, max_value=1e10, allow_nan=False) +) +def test_prandtl_number_scales_linearly_with_specific_heat_capacity(specific_heat_capacity): + c_f = specific_heat_capacity + mu_f = 1 + lambda_f = 1 + + assert dimensionless.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(c_f) + + +def test_compute_prandtl_number_with_example(): + c_f = 0.5 + mu_f = 3 + lambda_f = 0.5 + + assert dimensionless.compute_prandtl_number(lambda_f, mu_f, c_f) == approx(3)