Exemple #1
0
def test_properties_Fluid():

    props = Fluid.ALL_PROPERTIES

    fluid_names = ['water', 'methane', 'R134a']

    Ts = [
        25, 0, -1, -100, np.nan, [25, 30], [np.nan, 25], [np.nan, np.nan],
        [np.inf, np.nan],
        np.linspace(0, 10, 10),
        np.linspace(-10, 10, 10)
    ]

    Ps = [
        1, 0, -1, -100, np.nan, [3, 4], [np.nan, 3], [np.nan, np.nan],
        [np.inf, np.nan],
        np.linspace(0, 10, 10),
        np.linspace(-10, 10, 10)
    ]

    for fluid_name in fluid_names:
        for T, P in zip(Ts, Ps):

            fluid = Fluid(fluid_name, T=Q(T, 'C'), P=Q(P, 'bar'))
            repr(fluid)

            for p in props:
                getattr(fluid, p)
Exemple #2
0
def test_properties_HumidAir():

    props = HumidAir.ALL_PROPERTIES

    Ts = [
        25, 0, -1, -100, np.nan, [25, 30], [np.nan, 25], [np.nan, np.nan],
        [np.inf, np.nan],
        np.linspace(0, 10, 10),
        np.linspace(-10, 10, 10)
    ]

    Ps = [
        1, 0, -1, -100, np.nan, [3, 4], [np.nan, 3], [np.nan, np.nan],
        [np.inf, np.nan],
        np.linspace(0, 10, 10),
        np.linspace(-10, 10, 10)
    ]

    Rs = [
        0.5, 0.1, -1, -100, np.nan, -0.5, 0.00001, -0.0001, 0.99999, 1,
        1.00001, [0.3, 0.4], [np.nan, 0.3], [np.nan, np.nan], [np.inf, np.nan],
        np.linspace(0, 1, 10),
        np.linspace(-0.5, 0.5, 10)
    ]

    for T, P, R in zip(Ts, Ps, Rs):

        ha = HumidAir(T=Q(T, 'C'), P=Q(P, 'bar'), R=Q(R))
        repr(ha)

        for p in props:
            getattr(ha, p)
Exemple #3
0
def test_Quantity_integration():
    x, y, z = sp.symbols('x, y, z')

    expr = x * y / z

    result = expr.subs({
        x: Q(235, 'yard'),
        y: Q(98, 'K/m²'),
        z: Q(0.4, 'minutes')
    })

    Q.from_expr(result).dimensionality
Exemple #4
0
def test_check():

    assert not Q(1, 'kg').check('[energy]')
    assert Q(1, 'kg').check(Mass)
    assert not Q(1, 'kg').check(Energy)

    @check('[length]', '[mass]')
    def func(a, b):

        return a * b

    func(Q(1, 'yd'), Q(20, 'lbs'))
Exemple #5
0
def test_context():

    with silence_stdout():
        print('silenced')

    with quantity_format('~Lx'):

        s = str(Q(1, 'kPa'))
        assert s == '\\SI[]{1}{\\kilo\\pascal}'

    s = str(Q(1, 'kPa'))
    assert s == '1 kPa'
Exemple #6
0
def test_get_function():

    x, y, z = sp.symbols('x, y, z')

    expr = 25 * x * y / z

    fcn = get_function(expr, units=True)

    result_arr = fcn({
        x: Q(np.array([235, 335]), 'yard'),
        y: Q(np.array([2, 5]), 'm²'),
        z: Q(0.4, 'm³/kg')
    })
Exemple #7
0
def test_wraps():

    # @wraps(ret, args, strict=True|False) is a convenience
    # decorator for making the input/output of a function into Quantity
    # however, it does not enforce the return value

    @wraps('kg', ('m', 'kg'), strict=True)
    def func(a, b):

        # this is incorrect, cannot add 1 to a dimensional Quantity
        return a * b**2 + 1

    assert isinstance(func(Q(1, 'yd'), Q(20, 'lbs')), Q['Mass'])
    assert Q(1, 'bar').check(Pressure)
Exemple #8
0
def test_heat_balance():

    assert isinstance(heat_balance(Q(2, 'kg/s'), Q(2, 'kJ/s')),
                      Q['Temperature'])

    assert isinstance(heat_balance(Q(2, 'K'), Q(2, 'kJ/s')), Q['MassFlow'])

    assert isinstance(heat_balance(Q(2, 'kg'), Q(2, 'delta_degF')),
                      Q['Energy'])

    assert isinstance(heat_balance(Q(2, 'kg/s'), Q(2, 'delta_degF')),
                      Q['Power'])
Exemple #9
0
def test_typechecked():

    @typechecked
    def func_a(a: Quantity['Temperature']) -> Quantity['Pressure']:
        return Q(2, 'bar')

    assert func_a(Q(2, 'degC')) == Q(2, 'bar')

    with pytest.raises(TypeError):
        func_a(Q(2, 'meter'))

    @typechecked
    def func_b(a: Quantity) -> Quantity['Pressure']:
        return a

    assert func_b(Q(2, 'bar')) == Q(2, 'bar')
    assert func_b(Q(2, 'psi')) == Q(2, 'psi')
    assert func_b(Q(2, 'mmHg')) == Q(2, 'mmHg')

    with pytest.raises(TypeError):
        func_a(Q(2, 'meter'))
Exemple #10
0
def test_shapes():

    N = 16

    T = Q(np.linspace(50, 60, N).reshape(4, 4), 'C')
    P = Q(np.linspace(2, 4, N).reshape(4, 4), 'bar')

    water = Fluid('water', T=T, P=P)

    assert water.D.m.shape == P.m.shape
    assert water.D.m.shape == T.m.shape

    N = 27

    T = Q(np.linspace(50, 60, N).reshape(3, 3, 3), 'C')
    P = Q(np.linspace(2, 4, N).reshape(3, 3, 3), 'bar')

    water = Fluid('water', T=T, P=P)

    assert water.D.m.shape == P.m.shape
    assert water.D.m.shape == T.m.shape
Exemple #11
0
def test_invalid_areas():

    N = 10
    T = Q(np.linspace(-100, -50, N), 'K')
    P = Q(np.linspace(-1, -2, N), 'bar')

    water = Fluid('water', T=T, P=P)

    assert water.D.check(Density)
    assert isinstance(water.D.m, np.ndarray)

    T = Q(np.linspace(-100, 300, N), 'K')
    P = Q(np.linspace(-1, 2, N), 'bar')

    water = Fluid('water', T=T, P=P)

    assert water.D.check(Density)
    assert isinstance(water.D.m, np.ndarray)
    assert np.isnan(water.D.m[0])
    assert not np.isnan(water.D.m[-1])

    arr1 = np.linspace(-100, 400, N)
    arr2 = np.linspace(-1, 2, N)

    arr1[-2] = np.nan
    arr2[-1] = np.nan
    arr2[-3] = np.nan

    T = Q(arr1, 'K')
    P = Q(arr2, 'bar')

    water = Fluid('water', T=T, P=P)

    assert water.D.m.size == N
Exemple #12
0
def test_intermediate_temperatures():

    T1, T2 = intermediate_temperatures(Q(25, 'degC'), Q(10, 'degC'),
                                       Q(0.05, 'W/m/K'), Q(10, 'cm'),
                                       Q(1, 'W/m²/K'), Q(2, 'W/m²/K'), 0.7)

    assert isinstance(T1, Q['Temperature'])
    assert isinstance(T2, Q[Temperature])

    assert T2.check(Temperature)
    assert T2.check('K')
Exemple #13
0
class Constants:
    """
    Collection of constants.
    Use a single instance of this class to refer to these constants.
    """

    R = Q(8.3144598, 'kg*m²/K/mol/s²')
    SIGMA = Q(5.670374419e-8, 'W/m**2/K**4')

    default_density: Quantity[Density] = Q(997, 'kg/m³')

    normal_conditions_pressure: Quantity[Pressure] = Q(1, 'atm')
    normal_conditions_temperature: Quantity[Temperature] = Q(0, '°C').to('K')

    standard_conditions_pressure: Quantity[Pressure] = Q(1, 'atm')
    standard_conditions_temperature: Quantity[Temperature] = Q(15,
                                                               'degC').to('K')
Exemple #14
0
def test_Water():

    water_single = Water(T=Q(25, '°C'), P=Q(5, 'bar'))

    repr(water_single)

    water_multi = Water(T=Q(np.linspace(25, 50), '°C'), P=Q(5, 'bar'))

    repr(water_multi)

    water_mixed_phase = Water(T=Q(np.linspace(25, 500, 10), '°C'),
                              P=Q(np.linspace(0.5, 10, 10), 'bar'))

    repr(water_mixed_phase)

    with pytest.raises(Exception):

        # mismatching sizes
        # must access an attribute before it's actually evaluated
        Water(T=Q(np.linspace(25, 500, 10), '°C'),
              P=Q(np.linspace(0.5, 10, 50), 'bar')).P
Exemple #15
0
def test_custom_units():

    # "ton" should always default to metric ton
    assert (Q(1, 'ton') == Q(1, 'Ton') == Q(1, 'TON') == Q(
        1, 'tonne') == Q(1, 'metric_ton') == Q(1000, 'kg'))

    assert Q(1, 'US_ton') == Q(907.1847400000001, 'kg')

    assert (Q(1, 'ton/hour') == Q(1, 'Ton/hour') == Q(1, 'TON/hour') ==
            Q(1, 'tonne/hour') == Q(1, 'metric_ton/hour') == Q(1000, 'kg/hour'))

    v1 = (Q(1000, 'liter') * Q(1, 'normal')).to_base_units().m
    v2 = Q(1000, 'normal liter').to_base_units().m
    v3 = Q(1, 'nm3').m
    v4 = Q(1, 'Nm3').m

    # floating point accuracy
    assert round(v1, 10) == round(v2, 10) == round(v3, 10) == round(v4, 10)

    factor = Q(12, 'Nm3 water/ (normal liter air)')
    (Q(1, 'kg water') / factor).to('pound air')

    Q['NormalVolume'](2, 'nm**3')

    with pytest.raises(DimensionalityError):
        Q['NormalVolumeFlow'](2, 'm**3/hour')

    Q['NormalVolumeFlow'](2, 'Nm**3/hour').to('normal liter/sec')

    Q[Normal * VolumeFlow](2, 'Nm**3/hour').to('normal liter/sec')

    Q(2, 'normal liter air / day')
    Q(2, '1/Nm3').to('1 / (liter normal)')
Exemple #16
0
def test_HumidAir():
    T = Q(20, 'C')
    P = Q(20, 'bar')
    R = Q(20, '%')

    ha = HumidAir(T=T, P=P, R=R)
    ha.V

    T = Q([25, 34], 'C')
    P = Q(20, 'bar')
    R = Q(20, '%')

    ha = HumidAir(T=T, P=P, R=R)
    ha.V

    T = Q([25, 34], 'C')
    P = Q([20, 30], 'bar')
    R = Q([20, 40], '%')

    ha = HumidAir(T=T, P=P, R=R)
    ha.V

    T = Q([25, 34], 'C')
    P = Q([20, 30], 'bar')
    R = Q([20, np.nan], '%')

    ha = HumidAir(T=T, P=P, R=R)
    ha.V

    T = Q([np.nan, 34], 'C')
    P = Q([np.nan, 30], 'bar')
    R = Q([20, np.nan], '%')

    ha = HumidAir(T=T, P=P, R=R)
    ha.V

    T = Q([20, 40], 'C')
    P = Q([20, 1], 'bar')
    R = Q([20, 101], '%')

    ha = HumidAir(T=T, P=P, R=R)
    val = ha.V.m
    assert not np.isnan(val[0])
    assert np.isnan(val[1])
Exemple #17
0
def test_Fluid():

    fld = Fluid('R123', P=Q(2, 'bar'), T=Q(25, '°C'))

    assert fld.get('S') == Q(1087.7758824621442, 'J/(K kg)')
    assert fld.D == fld.get('D')

    water = Fluid('water', P=Q(2, 'bar'), T=Q(25, '°C'))
    assert water.T.u == Q.get_unit('degC')
    assert water.T.m == 25

    HumidAir(T=Q(25, 'degC'), P=Q(125, 'kPa'), R=Q(0.2, 'dimensionless'))

    Water(P=Q(1, 'bar'), Q=Q(0.9, ''))
    Water(P=Q(1, 'bar'), T=Q(0.9, 'degC'))
    Water(T=Q(1, 'bar'), Q=Q(0.9, ''))

    with pytest.raises(Exception):

        # cannot fix all of P, T, Q
        Water(P=Q(1, 'bar'), T=Q(150, 'degC'), Q=(0.4, ''))

        # incorrect argument name
        Water(T=Q(1, 'bar'), P=Q(9, 'degC'))

    Fluid('water', T=Q([25, 95], 'C'), P=Q([1, 2], 'bar')).H
    Fluid('water', T=Q([25, np.nan], 'C'), P=Q([1, 2], 'bar')).H
    Fluid('water', T=Q([np.nan, np.nan], 'C'), P=Q([1, 2], 'bar')).H
    Fluid('water', T=Q([np.nan, np.nan], 'C'), P=Q([np.nan, np.nan], 'bar')).H
    Fluid('water', T=Q(23, 'C'), P=Q([1, 2], 'bar')).H
    Fluid('water', T=Q(23, 'C'), P=Q([1], 'bar')).H
    Fluid('water', T=Q([23, 25], 'C'), P=Q([1], 'bar')).H
    Fluid('water', T=Q([23, 25], 'C'), P=Q(np.nan, 'bar')).H
    Fluid('water', T=Q([23, 25], 'C'), P=Q([1, np.nan], 'bar')).H

    Water(T=Q([25, 25, 63], 'C'), Q=Q([np.nan, np.nan, 0.4], '')).H
    Water(T=Q([25, np.nan, 63], 'C'), Q=Q([np.nan, 0.2, 0.5], '')).H
    Water(T=Q([25, np.nan, np.nan], 'C'), Q=Q([np.nan, 0.2, np.nan], '')).H

    # returns empty array (not nan)
    ret = Fluid('water', T=Q([], 'C'), P=Q([], 'bar')).H.m
    assert isinstance(ret, np.ndarray) and ret.size == 0
    ret = Fluid('water', T=Q([], 'C'), P=Q((), 'bar')).H.m
    assert isinstance(ret, np.ndarray) and ret.size == 0
    ret = Fluid('water', T=Q([], 'C'), P=Q(np.array([]), 'bar')).H.m
    assert isinstance(ret, np.ndarray) and ret.size == 0

    # 1-element list or array works in the same way as scalar,
    # except that the output is also a 1-element list or array
    ret = Water(P=Q([2, 3], 'bar'), Q=Q([0.5])).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 2

    ret = Water(P=Q([2, 3], 'bar'), Q=Q(0.5)).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 2

    ret = Water(P=Q([2], 'bar'), Q=Q([0.5])).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 1

    ret = Water(P=Q([2], 'bar'), Q=Q(0.5)).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 1

    ret = Water(P=Q(2, 'bar'), Q=Q([0.5])).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 1

    ret = Water(P=Q(2, 'bar'), Q=Q(0.5)).D.m

    assert isinstance(ret, float)

    ret = Water(P=Q([], 'bar'), Q=Q([0.5])).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 0

    ret = Water(P=Q([], 'bar'), Q=Q([])).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 0

    ret = Water(P=Q(np.array([]), 'bar'), Q=Q(np.array([]))).D.m

    assert isinstance(ret, np.ndarray) and ret.size == 0

    # returns 1-element list
    assert isinstance(
        Fluid('water', T=Q([23], 'C'), P=Q([1], 'bar')).H.m, np.ndarray)

    assert isinstance(
        Fluid('water', T=Q(23, 'C'), P=Q([1], 'bar')).H.m, np.ndarray)

    assert isinstance(
        Fluid('water', T=Q([23], 'C'), P=Q(1, 'bar')).H.m, np.ndarray)

    # returns float
    assert isinstance(Fluid('water', T=Q(23, 'C'), P=Q(1, 'bar')).H.m, float)

    with pytest.raises(ValueError):

        Fluid('water',
              T=Q([np.nan, np.nan], 'C'),
              P=Q([np.nan, np.nan, np.nan], 'bar')).H
        Fluid('water', T=Q([np.nan, np.nan], 'C'), P=Q([], 'bar')).H
Exemple #18
0
def test_convert_gas_volume():

    ret = convert_gas_volume(Q(1, 'm3'), 'N', (Q(2, 'bar'), Q(25, 'degC')))

    assert ret.check(Q(0, 'liter'))
Exemple #19
0
def test_Q():

    # test that Quantity objects can be constructed
    Q(1, 'dimensionless')
    Q(1, 'kg')
    Q(1, 'bar')
    Q(1, 'h')
    Q(1, 'newton')
    Q(1, 'cSt')

    # make sure that the alias Q behaves identically to Quantity
    assert Q(1) == Quantity(1)
    assert type(Q(1)) is type(Quantity(1))
    assert type(Q) is type(Quantity)

    # ensure that the inputs can be nested
    Q(Q(1, 'kg'))
    mass = Q(12, 'kg')
    Q(Q(Q(Q(mass))))
    Q(Q(Q(Q(mass), 'lbs')))
    Q(Q(Q(Q(mass), 'lbs')), 'stone')

    # no unit input defaults to dimensionless
    assert Q(12).check('')
    assert Q(1) == Q(100, '%')
    Q['Dimensionless'](21)
    assert isinstance(Q(21), Q['Dimensionless'])

    assert Q(1) == Q('1')
    assert Q(1) == Q('\n1\n')
    assert Q(1) == Q('1 dimensionless')

    # check type of "m"
    assert isinstance(Q(1, 'meter').m, int)
    assert isinstance(Q(2.3, 'meter').m, float)
    assert isinstance(Q([2, 3.4], 'meter').m, np.ndarray)
    assert isinstance(Q(np.array([2, 3.4]), 'meter').m, np.ndarray)

    # input Quantity as unit
    Q(1, Q(2, 'bar'))

    # input Quantity as val
    Q(Q(2, 'bar'), 'kPa')

    # input Quantity as both val and unit
    Q(Q(2, 'bar'), Q(3, 'kPa'))
    Q(Q(2, 'bar'), Q(3, 'mmHg'))

    # check that the dimensionality constraints work
    Q[Length](1, 'm')
    Q[Pressure](1, 'kPa')
    Q[Temperature](1, '°C')

    # the dimensionalities can also be specified as strings
    Q['Temperature'](1, '°C')

    P = Q(1, 'bar')
    # this Quantity must have the same dimensionality as P
    Q[P](2, 'kPa')

    with pytest.raises(DimensionalityError):
        Q[Temperature](1, 'kg')
        Q[Pressure](1, 'meter')
        Q[Mass](1, P)

    # in-place conversion
    # NOTE: don't use this for objects that are passed in by the user
    P3 = Q(1, 'bar')
    P3.ito('kPa')
    P3.ito(Q(123123, 'kPa'))

    assert P3.m == approx(100, rel=1e-12)

    # test conversions to np.ndarray with int/float dtypes
    a = Q([1, 2, 3], 'bar')
    a.ito('kPa')

    a = Q(np.array([1, 2, 3.0]), 'bar')
    a.ito('kPa')

    a = Q(np.array([1.0, 2.0, 3.0]), 'bar')
    a.ito('kPa')

    # conversion to new object
    P4 = Q(1, 'bar')
    P4_b = P4.to('kPa')
    P4_b = P4.to(Q(123123, 'kPa'))

    assert P4_b.m == approx(100, rel=1e-12)

    assert Q(1, 'bar') == Q(100, 'kPa') == Q('0.1 MPa') == Q('1e5', 'Pa')

    # check that nested Quantity objects can be used as input
    # only the first value is used as magnitude, the other Quantity
    # objects are only used to determine unit
    P2 = Q(Q(2, 'feet_water'), Q(321321, 'kPa')).to(Q(123123, 'feet_water'))

    # floating point math might make this off at the N:th decimal
    assert P2.m == approx(2, rel=1e-12)
    assert isinstance(P2, Q['Pressure'])

    with pytest.raises(Exception):

        # incorrect dimensionalities should raise Exception
        Q(Q(2, 'feet_water'), Q(321321, 'kg')).to(Q(123123, 'feet_water'))

    # the UnitsContainer objects can be used to construct new dimensionalities
    Q[Length * Length * Length / Temperature](1, 'm³/K')

    with pytest.raises(Exception):
        Q[Pressure / Area](1, 'bar/m')

    # percent or %
    Q(1.124124e-3, '').to('%').to('percent')
    Q(1.124124e-3).to('%').to('percent')

    # pd.Series is converted to np.ndarray
    vals = [2, 3, 4]
    s = pd.Series(vals, name='Pressure')
    arr = Q(s, 'bar').to('kPa').m
    assert isinstance(arr, np.ndarray)
    assert arr[0] == 200

    # np.ndarray magnitudes equality check
    assert (Q(s, 'bar') == Q(vals, 'bar').to('kPa')).all()

    # support a single string as input if the
    # magnitude and units are separated by one or more spaces
    assert Q('1 meter').check(Length)
    assert Q('1 meter per second').check(Velocity)
    assert (Q('1 m') ** 3).check(Volume)
Exemple #20
0
def test_dataframe_assign():

    df_multiple_rows = pd.DataFrame(
        {
            'A': [1, 2, 3],
            'B': [1, 2, 3],
        }
    )

    df_single_row = pd.DataFrame(
        {
            'A': [1],
            'B': [1],
        }
    )

    df_empty = pd.DataFrame(
        {
            'A': [],
            'B': [],
        }
    )

    for df in [df_multiple_rows, df_single_row, df_empty]:

        df['C'] = Q(df.A, 'bar') * Q(25, 'meter')

        df['Temp'] = Q(df.A, 'degC')

        with pytest.raises(AttributeError):

            density = Water(

                # this is pd.Series[float]
                T=df.Temp,
                Q=Q(0.5)

            ).D

        density = Water(

            # wrap in Quantity() to use the Water class
            T=Q(df.Temp, 'degC'),
            Q=Q(0.5)

        ).D

        # implicitly strips magnitude in whatever unit the Quantity happens to have
        df['density'] = density

        # assigns a column with specific unit
        df['density_with_unit'] = density.to('kg/m3')

        # the .m accessor is not necessary for vectors
        df['density_with_unit_magnitude'] = density.to('kg/m3').m

        # this does not work -- pandas function is_list_like(Q(4, 'bar')) -> True
        # which means that this fails internally in pandas
        # ValueError: Length of values (1) does not match length of index (3)
        # df['D'] = Q(4, 'bar')

        # i.e. the .m accessor must be used for scalar Quantity assignment

        df['E'] = Q(df.A, 'bar').m
        df['F'] = Q(4, 'bar').m
Exemple #21
0
 def func_a(a: Quantity['Temperature']) -> Quantity['Pressure']:
     return Q(2, 'bar')