1"""Fitting adapters against the ``fluids`` functions they adapt.
3The module docstring of :mod:`feedtwin.comps.correlations` says every fitting is
4an adapter onto ``fluids`` and computes nothing of its own. These hold it to
5that: the K a fitting component prices must be the K ``fluids`` gives for the
6same geometry, in the units ``fluids`` documents.
9from __future__
import annotations
13import fluids.fittings
as ft
20M = Provenance.MANUFACTURER
25 return conditions_from_fluid(
Fluid(
"ethanol"), 4.0e6, 293.0)
28def _K(component: object, mdot: float, flow: object) -> float:
30 v = mdot / (rho * math.pi * BORE**2 / 4.0)
31 return component.pressure_drop(mdot, flow) / (0.5 * rho * v * v)
34def _fitting(kind: str, **extra: Param) -> object:
35 params = {
"bore":
Param(BORE * 1e3,
"mm", M,
"test")}
37 return build_component(
38 ComponentInstance.build(
"F",
"fitting", params, options={
"kind": kind})
42@pytest.mark.parametrize("degrees", [45.0, 90.0, 180.0])
44 """``fluids.bend_rounded`` takes its angle in degrees.
46 The fitting's ``angle`` parameter is an *angle* dimension, so the model
47 layer hands it over in radians; passed straight through, a 90-degree bend
48 priced as a 1.57-degree one (K 0.018 against 0.229).
54 angle=
Param(degrees,
"deg", M,
"test"),
55 bend_diameters=
Param(1.5,
"-", M,
"test"),
57 Re = 4.0 * mdot / (math.pi * BORE * flow.mu)
58 expected = ft.bend_rounded(
59 Di=BORE, angle=degrees, bend_diameters=1.5, Re=Re, roughness=1.5e-6
61 assert _K(bend, mdot, flow) == pytest.approx(expected, rel=1e-9)
64@pytest.mark.parametrize("mdot", [0.05, 0.3, 1.0])
65@pytest.mark.parametrize("kind,n", [("elbow_90_crane", 30.0), (
"elbow_45_crane", 16.0)])
67 kind: str, n: float, mdot: float
69 """Crane TP-410 gives these as ``K = n . f_T``, f_T the fully turbulent
70 friction factor of the pipe size (fluids' ``ft_Crane``) -- not the line's
71 friction factor at its own Reynolds number, which put a 30 f_T elbow
72 anywhere from 0.55 to 1.09 against Crane's 0.885 in 9.5 mm."""
74 assert _K(
_fitting(kind), mdot, flow) == pytest.approx(
75 n * ft.ft_Crane(BORE), rel=1e-12
79@pytest.mark.parametrize("kind,n", [("tee_run", 20.0), (
"tee_branch", 60.0)])
81 """A segment's tee carries one flow and does not know the other leg's, so
82 it is Crane's unsplit tee: through the run 20 f_T, turning through the
83 branch 60 f_T. It used to read fluids' converging-tee correlations at a
84 split of 0.5/0.5 -- which is *all* the flow from the branch -- giving
85 0.41 for the branch (Crane 1.77) and 0.525 for a run carrying nothing."""
87 assert _K(
_fitting(kind), 0.3, flow) == pytest.approx(
88 n * ft.ft_Crane(BORE), rel=1e-12
93 """Same geometry, two components, one correlation: one K."""
97 angle=
Param(90.0,
"deg", M,
"test"),
98 bend_diameters=
Param(1.5,
"-", M,
"test"),
100 bend = build_component(
101 ComponentInstance.build(
105 "bore":
Param(BORE * 1e3,
"mm", M,
"test"),
106 "bend_radius":
Param(1.5 * BORE * 1e3,
"mm", M,
"test"),
107 "angle":
Param(90.0,
"deg", M,
"test"),
108 "roughness":
Param(1.5e-6,
"m", M,
"test"),
113 assert _K(fitting, 1.0, flow) == pytest.approx(
_K(bend, 1.0, flow), rel=1e-9)
None test_a_bend_fitting_reads_its_angle_in_degrees(float degrees)
None test_an_unsplit_tee_is_cranes_f_T_multiple(str kind, float n)
None test_a_bend_fitting_equals_the_bend_component()
object _fitting(str kind, **Param extra)
float _K(object component, float mdot, object flow)
None test_a_crane_multiple_is_of_the_fully_turbulent_f_T(str kind, float n, float mdot)