1"""Unit conversion, and the dimension check that catches the expensive mistake.
3Unit confusion is the most costly recurring error in this field and the easiest
4to prevent, provided the prevention sits at a boundary rather than in everyone's
5memory. These tests hold that boundary.
7Conversion factors are checked against exact definitions where one exists --
8an inch is 0.0254 m by definition, not by measurement -- so a typo in a factor
9fails rather than shifting every result by a fraction of a percent.
12from __future__
import annotations
34 (1.0,
"psi", 6894.757293168361),
36 (1.0,
"atm", 101325.0),
37 (1.0,
"lbm", 0.45359237),
38 (1.0,
"gal", 3.785411784e-3),
45@pytest.mark.parametrize("value,unit,expected", CONVERSIONS)
47 assert to_si(value, unit) == pytest.approx(expected, rel=1e-12)
50@pytest.mark.parametrize("value,unit,_expected", CONVERSIONS)
52 assert from_si(to_si(value, unit), unit) == pytest.approx(value, rel=1e-12)
56 """The one dimension where a scale factor alone is wrong."""
57 assert to_si(0.0,
"degC") == pytest.approx(273.15)
58 assert to_si(20.0,
"degC") == pytest.approx(293.15)
59 assert from_si(293.15,
"degC") == pytest.approx(20.0)
60 assert to_si(491.67,
"degR") == pytest.approx(273.15, rel=1e-6)
64 """A 20 K rise and a 20 K absolute temperature are not the same quantity.
66 Sharing a dimension would let a temperature *difference* be written where an
67 absolute temperature belongs and convert with a 273.15 offset applied -- a
68 silent 273 K error in a heat balance.
70 assert dimension_of(
"K") ==
"temperature"
71 assert dimension_of(
"K_diff") ==
"temperature_difference"
72 assert to_si(20.0,
"degC_diff") == pytest.approx(20.0)
73 assert to_si(20.0,
"degC") == pytest.approx(293.15)
77 """Cv/Kv comes from IEC 60534 via ``fluids``, not from a literal here.
79 The same constant the Phase 03 valve correlations will use, so a valve
80 authored in Kv and one authored in Cv cannot disagree.
82 from fluids.fittings
import Kv_to_Cv
84 assert to_si(1.0,
"Kv") == pytest.approx(Kv_to_Cv(1.0), rel=1e-12)
85 assert to_si(1.0,
"Cv") == 1.0
86 assert dimension_of(
"Cv") == dimension_of(
"Kv") ==
"flow_coefficient"
90 """The whole point: the message says what was expected and what was given."""
91 with pytest.raises(DimensionMismatch)
as excinfo:
92 check_dimension(
"psi",
"length",
"pipe.bore")
94 message = str(excinfo.value)
95 assert "pipe.bore" in message
96 assert "length" in message
and "pressure" in message
100 """No close match for this one, so it should still say where to look."""
101 with pytest.raises(UnknownUnit, match=
"registered_units"):
106 """``psig`` is one standard atmosphere above ``psia``; bare ``psi`` carries
107 no offset, so it converts a *difference* exactly. Which a drawing's bare
108 pressure means is decided per parameter (feedtwin.model.pressure), never by
110 assert to_si(500.0,
"psig") == pytest.approx(500.0 * 6894.757293168361 + 101325.0)
111 assert to_si(500.0,
"psia") == pytest.approx(500.0 * 6894.757293168361)
112 assert to_si(500.0,
"psi") == to_si(500.0,
"psia")
113 assert to_si(5.0,
"barg") == pytest.approx(5e5 + 101325.0)
115 assert si_unit_of(
"pressure") ==
"Pa"
119 """Guards the reverse lookup used to label output.
121 ``si_unit_of`` scans for the unit with factor 1.0; a dimension whose units
122 all have factors would make it raise, and only at report time.
124 for unit
in registered_units():
125 assert si_unit_of(dimension_of(unit))
129 register_unit(
"furlong",
"length", 201.168)
130 assert to_si(1.0,
"furlong") == pytest.approx(201.168)
131 assert dimension_of(
"furlong") ==
"length"
None test_conversion_round_trips(float value, str unit, float _expected)
None test_temperature_difference_is_a_separate_dimension()
None test_a_unit_can_be_added_from_outside()
None test_cv_and_kv_convert_through_the_standard_factor()
None test_every_dimension_has_a_canonical_unit()
None test_conversion_to_si(float value, str unit, float expected)
None test_temperature_carries_an_offset()
None test_an_unknown_unit_points_at_the_registry()
None test_a_wrong_dimension_is_rejected_by_name()
None test_gauge_and_absolute_are_spelled_out_and_bare_is_a_difference()