"""Testing module holtrop.ship."""
from typing import NamedTuple
import pytest
from astropy import units as u # type: ignore
from astropy.units.quantity import Quantity # type: ignore
from berhoel.holtrop import hydro
from berhoel.holtrop.ship import (
Ship as Ship_,
C_WP_Schneekluth_U,
C_WP_Schneekluth_V,
BlockCoefficientMethod,
C_WP_Schneekluth_medium,
C_WP_Schneekluth_V_alt_1,
C_WP_Schneekluth_V_alt_2,
WaterlineCoefficientMethod,
WettedSurfaceEstimationMethod,
)
__date__ = "2024/08/01 21:31:56 hoel"
__author__ = "Berthold Höllmann"
__copyright__ = "Copyright © 2019 by Berthold Höllmann"
__credits__ = ["Berthold Höllmann"]
__maintainer__ = "Berthold Höllmann"
__email__ = "berhoel@gmail.com"
u.imperial.enable()
[docs]
class Ship(Ship_):
[docs]
def R(self, speed: Quantity) -> Quantity:
return 0 * u.m
[docs]
class TestPrau:
[docs]
@pytest.fixture(scope="function")
def probe(self):
return Ship(
L=30.564 * u.m,
B=12.65 * u.m,
T=4.50 * u.m,
h_b=0.0 * u.m,
Nab=741.0 * u.m**3,
S_app=[], # m^2
k_2=[], # 1 + k_2
# App = [(S_app, k_2)],
C_Stern=0.0,
A_BT=0.01 * u.m**2,
i_E=25.0 * u.deg,
C_M=0.744,
lcb=50.0 - 49.881, # %L aft of 1/2 L
A_T=0.01 * u.m**2,
A_WP=271.597 * u.m**2, #: Waterplane area
L_WP=30.564 * u.m, #: Waterline length
B_WP=12.430 * u.m, #: Waterlien beam
# Related coefficients
C_P=0.583,
C_B=0.434,
)
[docs]
def test_L(self, probe):
assert 30.564 * u.m == probe.L
[docs]
def test_T(self, probe):
assert Quantity(4.5, "m") == probe.T
[docs]
def test_B(self, probe):
assert Quantity(12.65, "m") == probe.B
[docs]
def test_C_B(self, probe):
assert probe.C_B == 0.434
[docs]
def test_C_M(self, probe):
assert probe.C_M == 0.744
[docs]
def test_C_WP(self, probe):
assert probe.C_WP == pytest.approx(0.7148972868663915)
[docs]
def test_A_BT(self, probe):
assert Quantity(0.01, "m2") == probe.A_BT
[docs]
def test_S(self, probe):
assert probe.S.value == pytest.approx(391.93508)
assert probe.S.unit == "m2"
[docs]
def test_S_calc_Schenzle(self, probe):
probe.set_S_Method(WettedSurfaceEstimationMethod.Schenzle)
assert probe.S.value == pytest.approx(416.80066)
assert probe.S.unit == "m2"
[docs]
def test_App(self, probe):
assert probe.App == []
[docs]
class TestGenerated:
[docs]
@pytest.fixture(scope="function")
def probe(self):
return Ship(
L=30.564 * u.m,
B=12.65 * u.m,
T=4.50 * u.m,
h_b=0.0 * u.m,
Nab=741.0 * u.m**3,
S_app=[], # m^2
k_2=[], # 1 + k_2
# App = [(S_app, k_2)],
C_Stern=0.0,
A_BT=0.01 * u.m**2,
i_E=25.0 * u.deg,
C_M=0.744,
lcb=50.0 - 49.881, # %L aft of 1/2 L
A_T=0.01 * u.m**2,
# A_WP=271.597 * u.m**2, #: Waterplane area
L_WP=30.564 * u.m, #: Waterline length
B_WP=12.430 * u.m, #: Waterlien beam
# Related coefficients
C_P=0.583,
C_B=0.434,
)
[docs]
def test_C_WP_calc_schneekluth_U(self, probe):
probe.set_C_WP_Method(WaterlineCoefficientMethod.Schneekluth_U)
assert probe.C_WP == pytest.approx(0.68086, 1e-5)
[docs]
def test_C_WP_calc_schneekluth_medium(self, probe):
probe.set_C_WP_Method(WaterlineCoefficientMethod.Schneekluth_medium)
assert probe.C_WP == pytest.approx(0.62267, 1e-5)
[docs]
def test_C_WP_calc_schneekluth_V(self, probe):
probe.set_C_WP_Method(WaterlineCoefficientMethod.Schneekluth_V)
assert probe.C_WP == pytest.approx(0.63379, 1e-5)
[docs]
def test_C_WP_calc_schneekluth_V_alt_1(self, probe):
probe.set_C_WP_Method(WaterlineCoefficientMethod.Schneekluth_V_alt_1)
assert probe.C_WP == pytest.approx(0.69788, 1e-5)
[docs]
def test_C_WP_calc_schneekluth_V_alt_2(self, probe):
probe.set_C_WP_Method(WaterlineCoefficientMethod.Schneekluth_V_alt_2)
assert probe.C_WP == pytest.approx(0.66877, 1e-5)
[docs]
class TestGenerated_C_B:
[docs]
@pytest.fixture(scope="function")
def probe(self):
return Ship(
L=60.0 * u.m,
B=10.0 * u.m,
T=4.50 * u.m,
h_b=0.0 * u.m,
Nab=741.0 * u.m**3,
S_app=[], # m^2
k_2=[], # 1 + k_2
# App = [(S_app, k_2)],
C_Stern=0.0,
A_BT=0.01 * u.m**2,
i_E=25.0 * u.deg,
C_M=0.744,
lcb=50.0 - 49.881, # %L aft of 1/2 L
A_T=0.01 * u.m**2,
# A_WP=271.597 * u.m**2, #: Waterplane area
L_WP=30.564 * u.m, #: Waterline length
B_WP=12.430 * u.m, #: Waterlien beam
# Related coefficients
C_P=0.583,
)
[docs]
class C_B_References(NamedTuple):
F_n: float
C_B_Ayre_1_06: float
C_B_Ayre_1_08: float
C_B_Ayre_1_09: float
C_B_Schneekluth_1: float
C_B_Schneekluth_2: float
[docs]
@pytest.fixture(
params=(
C_B_References(0.14, 0.82, 0.85, 0.85, 0.85, 0.85),
C_B_References(0.17, 0.77, 0.79, 0.80, 0.82, 0.75),
C_B_References(0.20, 0.72, 0.74, 0.75, 0.70, 0.67),
C_B_References(0.25, 0.64, 0.66, 0.67, 0.56, 0.58),
C_B_References(0.30, 0.55, 0.57, 0.58, 0.48, 0.51),
C_B_References(0.32, 0.52, 0.54, 0.55, 0.48, 0.51),
)
)
def C_B_reference(self, probe, request):
param = request.param
v = param.F_n * pow(probe.L * hydro.g, 0.5)
return param, v
[docs]
def test_C_B(self, probe, C_B_reference: tuple[C_B_References, Quantity]):
probe.set_default_speed(C_B_reference[1])
assert probe.C_B == pytest.approx(C_B_reference[0].C_B_Ayre_1_06, 1e-2)
[docs]
def test_C_B_calc_Ayre_1_06(
self, probe, C_B_reference: tuple[C_B_References, Quantity]
):
probe.set_default_speed(C_B_reference[1])
probe.set_C_B_method(BlockCoefficientMethod.Ayre_1_06)
assert probe.C_B == pytest.approx(C_B_reference[0].C_B_Ayre_1_06, 1e-2)
[docs]
def test_C_B_calc_Ayre_1_08(
self, probe, C_B_reference: tuple[C_B_References, Quantity]
):
probe.set_default_speed(C_B_reference[1])
probe.set_C_B_method(BlockCoefficientMethod.Ayre_1_08)
assert probe.C_B == pytest.approx(C_B_reference[0].C_B_Ayre_1_08, 1e-2)
[docs]
def test_C_B_calc_Ayre_1_09(
self, probe, C_B_reference: tuple[C_B_References, Quantity]
):
probe.set_default_speed(C_B_reference[1])
probe.set_C_B_method(BlockCoefficientMethod.Ayre_1_09)
assert probe.C_B == pytest.approx(C_B_reference[0].C_B_Ayre_1_09, 1e-2)
[docs]
def test_C_B_calc_Schneekluth_1(
self, probe, C_B_reference: tuple[C_B_References, Quantity]
):
probe.set_default_speed(C_B_reference[1])
probe.set_C_B_method(BlockCoefficientMethod.Schneekluth_1)
_C_B = probe.C_B
assert _C_B == pytest.approx(C_B_reference[0].C_B_Schneekluth_1, 1e-2)
[docs]
def test_C_B_calc_Schneekluth_2(
self, probe, C_B_reference: tuple[C_B_References, Quantity]
):
probe.set_default_speed(C_B_reference[1])
probe.set_C_B_method(BlockCoefficientMethod.Schneekluth_2)
_C_B = probe.C_B
assert _C_B == pytest.approx(C_B_reference[0].C_B_Schneekluth_2, 1e-2)
[docs]
class C_WP_References(NamedTuple):
C_B: float
C_M: float
C_WP_U: float
C_WP_medium: float
C_WP_V: float
C_WP_V_alt_1: float
C_WP_V_alt_2: float
# Schneekluth, Entwerfen, S. 145
[docs]
@pytest.fixture(
params=(
C_WP_References(0.50, 0.78, 0.667, 0.730, 0.743, 0.682, 0.711),
C_WP_References(0.50, 0.94, 0.667, 0.637, 0.656, 0.682, 0.677),
C_WP_References(0.60, 0.98, 0.733, 0.706, 0.721, 0.749, 0.737),
C_WP_References(0.70, 0.99, 0.800, 0.785, 0.793, 0.812, 0.802),
C_WP_References(0.80, 0.99, 0.866, 0.866, 0.868, 0.869, 0.870),
)
)
def C_WP_reference(request):
return request.param
[docs]
@pytest.mark.skip(
reason="reference values in literature do not match calculated values"
)
def test_calc_C_WP_Schneekluth_U(C_WP_reference):
C_P = C_WP_reference.C_B / C_WP_reference.C_M
assert C_WP_Schneekluth_U(C_P) == pytest.approx(C_WP_reference.C_WP_U, 1e-2)
[docs]
@pytest.mark.skip(
reason="reference values in literature do not match calculated values"
)
def test_calc_C_WP_Schneekluth_medium(C_WP_reference):
assert C_WP_Schneekluth_medium(C_WP_reference.C_B) == pytest.approx(
C_WP_reference.C_WP_medium, 1e-2
)
[docs]
@pytest.mark.skip(
reason="reference values in literature do not match calculated values"
)
def test_calc_C_WP_Schneekluth_V(C_WP_reference):
assert C_WP_Schneekluth_V(C_WP_reference.C_B) == pytest.approx(
C_WP_reference.C_WP_V, 1e-2
)
[docs]
@pytest.mark.skip(
reason="reference values in literature do not match calculated values"
)
def test_calc_C_WP_Schneekluth_V_alt_1(C_WP_reference):
C_P = C_WP_reference.C_B / C_WP_reference.C_M
assert C_WP_Schneekluth_V_alt_1(C_P) == pytest.approx(
C_WP_reference.C_WP_V_alt_1, 1e-3
)
[docs]
def test_calc_C_WP_Schneekluth_V_alt_2(C_WP_reference):
assert C_WP_Schneekluth_V_alt_2(
C_WP_reference.C_B, C_WP_reference.C_M
) == pytest.approx(C_WP_reference.C_WP_V_alt_2, 1e-3)