Esempio n. 1
0
def test_mixed_registry_operations():

    reg = UnitRegistry(unit_system="cgs")
    reg.add("fake_length", 0.001, length)
    a = unyt_quantity(1, units="fake_length", registry=reg)
    b = unyt_quantity(1, "cm")

    assert_almost_equal(a + b, b + a)
    assert_almost_equal(a - b, -(b - a))
    assert_almost_equal(a * b, b * a)
    assert_almost_equal(b / a, b / a.in_units("km"))
    assert_almost_equal(a / b, a / b.in_units("km"))
Esempio n. 2
0
def add_constants(namespace, registry):
    """Adds the quantities from :mod:`unyt.physical_constants` to a namespace

    Parameters
    ----------

    namespace : dict
       The dict to insert quantities into. The keys will be string names
       and values will be the corresponding quantities.
    registry : :class:`unyt.unit_registry.UnitRegistry`
       The registry to create units from. Note that if you would like to
       use a custom unit system, ensure your registry was created using
       that unit system.

    Example
    -------
    >>> from unyt.unit_registry import UnitRegistry
    >>> class MyClass():
    ...     def __init__(self):
    ...         self.reg = UnitRegistry(unit_system='cgs')
    ...         add_constants(vars(self), self.reg)
    >>> foo = MyClass()
    >>> foo.gravitational_constant
    unyt_quantity(6.67384e-08, 'cm**3/(g*s**2)')
    >>> foo.speed_of_light
    unyt_quantity(2.99792458e+10, 'cm/s')
    """
    from unyt.array import unyt_quantity

    for constant_name in physical_constants:
        value, unit_name, alternate_names = physical_constants[constant_name]
        for name in alternate_names + [constant_name]:
            quan = unyt_quantity(value, unit_name, registry=registry)
            try:
                namespace[name] = quan.in_base(
                    unit_system=registry.unit_system)
            except UnitsNotReducible:
                namespace[name] = quan
            namespace[name + "_mks"] = unyt_quantity(value,
                                                     unit_name,
                                                     registry=registry)
            try:
                namespace[name + "_cgs"] = quan.in_cgs()
            except UnitsNotReducible:
                pass
            if name == "h":
                # backward compatibility for unyt 1.0, which defined hmks
                namespace["hmks"] = namespace["h_mks"].copy()
                namespace["hcgs"] = namespace["h_cgs"].copy()
Esempio n. 3
0
    def __truediv__(self, u):
        """ Divide Unit by u (Unit object). """
        if not isinstance(u, Unit):
            if isinstance(u, (numeric_type, list, tuple, np.ndarray)):
                from unyt.array import unyt_quantity

                return unyt_quantity(1.0, self) / u
            else:
                raise InvalidUnitOperation(
                    "Tried to divide a Unit object by '%s' (type %s). This "
                    "behavior is undefined." % (u, type(u))
                )
        elif self.dimensions is logarithmic and not u.is_dimensionless:
            raise InvalidUnitOperation("Tried to divide '%s' and '%s'." % (self, u))
        elif u.dimensions is logarithmic and not self.is_dimensionless:
            raise InvalidUnitOperation("Tried to divide '%s' and '%s'." % (self, u))

        base_offset = 0.0
        if self.base_offset or u.base_offset:
            if self.dimensions in (temperature, angle) and u.is_dimensionless:
                base_offset = self.base_offset
            else:
                raise InvalidUnitOperation(
                    "Quantities with units of Farhenheit "
                    "and Celsius cannot be divided."
                )

        return Unit(
            self.expr / u.expr,
            base_value=(self.base_value / u.base_value),
            base_offset=base_offset,
            dimensions=(self.dimensions / u.dimensions),
            registry=self.registry,
        )
Esempio n. 4
0
def assert_allclose_units(actual, desired, rtol=1e-7, atol=0, **kwargs):
    """Raise an error if two objects are not equal up to desired tolerance

    This is a wrapper for :func:`numpy.testing.assert_allclose` that also
    verifies unit consistency

    Parameters
    ----------
    actual : array-like
        Array obtained (possibly with attached units)
    desired : array-like
        Array to compare with (possibly with attached units)
    rtol : float, optional
        Relative tolerance, defaults to 1e-7
    atol : float or quantity, optional
        Absolute tolerance. If units are attached, they must be consistent
        with the units of ``actual`` and ``desired``. If no units are attached,
        assumes the same units as ``desired``. Defaults to zero.

    Notes
    -----
    Also accepts additional keyword arguments accepted by
    :func:`numpy.testing.assert_allclose`, see the documentation of that
    function for details.

    """
    # Create a copy to ensure this function does not alter input arrays
    act = unyt_array(actual)
    des = unyt_array(desired)

    try:
        des = des.in_units(act.units)
    except (UnitOperationError, UnitConversionError):
        raise AssertionError(
            "Units of actual (%s) and desired (%s) do not have "
            "equivalent dimensions" % (act.units, des.units))

    rt = unyt_array(rtol)
    if not rt.units.is_dimensionless:
        raise AssertionError("Units of rtol (%s) are not "
                             "dimensionless" % rt.units)

    if not isinstance(atol, unyt_array):
        at = unyt_quantity(atol, des.units)

    try:
        at = at.in_units(act.units)
    except UnitOperationError:
        raise AssertionError("Units of atol (%s) and actual (%s) do not have "
                             "equivalent dimensions" % (at.units, act.units))

    # units have been validated, so we strip units before calling numpy
    # to avoid spurious errors
    act = act.value
    des = des.value
    rt = rt.value
    at = at.value

    return assert_allclose(act, des, rt, at, **kwargs)
Esempio n. 5
0
def define_unit(symbol, value, tex_repr=None, offset=None, prefixable=False,
                registry=None):
    """
    Define a new unit and add it to the default unit registry.

    Parameters
    ----------
    symbol : string
        The symbol for the new unit.
    value : tuple or ~unyt.array.unyt_quantity
        The definition of the new unit in terms of some other units. For
        example, one would define a new "mph" unit with ``(1.0, "mile/hr")``
        or with ``1.0*unyt.mile/unyt.hr``
    tex_repr : string, optional
        The LaTeX representation of the new unit. If one is not supplied, it
        will be generated automatically based on the symbol string.
    offset : float, optional
        The default offset for the unit. If not set, an offset of 0 is assumed.
    prefixable : boolean, optional
        Whether or not the new unit can use SI prefixes. Default: False
    registry : A ~unyt.unit_registry.UnitRegistry instance or None
        The unit registry to add the unit to. If None, then defaults to the
        global default unit registry. If registry is set to None then the
        unit object will be added as an attribute to the top-level :mod:`unyt`
        namespace to ease working with the newly defined unit. See the example
        below.

    Examples
    --------
    >>> from unyt import day
    >>> two_weeks = 14.0*day
    >>> one_day = 1.0*day
    >>> define_unit("fortnight", two_weeks)
    >>> from unyt import fortnight
    >>> print((3*fortnight)/one_day)
    42.0 dimensionless
    """
    from unyt.array import unyt_quantity, _iterable
    import unyt
    if registry is None:
        registry = default_unit_registry
    if symbol in registry:
        registry.pop(symbol)
    if not isinstance(value, unyt_quantity):
        if _iterable(value) and len(value) == 2:
            value = unyt_quantity(value[0], value[1])
        else:
            raise RuntimeError("\"value\" needs to be a quantity or "
                               "(value, unit) tuple!")
    base_value = float(value.in_base(unit_system='mks'))
    dimensions = value.units.dimensions
    registry.add(symbol, base_value, dimensions, tex_repr=tex_repr,
                 offset=offset)
    if prefixable:
        prefixable_units.append(symbol)
    if registry is default_unit_registry:
        u = Unit(symbol, registry=registry)
        setattr(unyt, symbol, u)
Esempio n. 6
0
 def __getattr__(self, item):
     if item in self._cache:
         return self._cache[item]
     if item in globals():
         const = globals()[item].copy()
         const.units.registry = self._registry
         const.convert_to_base(self._registry.unit_system)
         const_v, const_unit = const.v, const.units
         ret = unyt_quantity(const_v, const_unit, registry=self._registry)
         self._cache[item] = ret
         return ret
     raise AttributeError(item)
Esempio n. 7
0
def test_define_unit():
    define_unit("mph", (1.0, "mile/hr"))
    a = unyt_quantity(2.0, "mph")
    b = unyt_quantity(1.0, "mile")
    c = unyt_quantity(1.0, "hr")
    assert a == 2.0 * b / c
    d = unyt_quantity(1000.0, "cm**3")
    define_unit("L", d, prefixable=True)
    e = unyt_quantity(1.0, "mL")
    f = unyt_quantity(1.0, "cm**3")
    assert e == f
Esempio n. 8
0
def test_define_unit():
    define_unit("mph", (1.0, "mile/hr"))
    a = unyt_quantity(2.0, "mph")
    b = unyt_quantity(1.0, "mile")
    c = unyt_quantity(1.0, "hr")
    assert a == 2.0 * b / c
    d = unyt_quantity(1000.0, "cm**3")
    define_unit("Baz", d, prefixable=True)
    e = unyt_quantity(1.0, "mBaz")
    f = unyt_quantity(1.0, "cm**3")
    assert e == f

    define_unit("Foo", (1.0, "V/sqrt(s)"))
    g = unyt_quantity(1.0, "Foo")
    volt = unyt_quantity(1.0, "V")
    second = unyt_quantity(1.0, "s")
    assert g == volt / second**(0.5)

    # Test custom registry
    reg = UnitRegistry()
    define_unit("Foo", (1, "m"), registry=reg)
    define_unit("Baz", (1, "Foo**2"), registry=reg)
    h = unyt_quantity(1, "Baz", registry=reg)
    i = unyt_quantity(1, "m**2", registry=reg)
    assert h == i
Esempio n. 9
0
def test_atol_conversion_error():
    a1 = unyt_array([1.0, 2.0, 3.0], "cm")
    a2 = unyt_array([1.0, 2.0, 3.0], "cm")
    with pytest.raises(AssertionError):
        assert_allclose_units(a1, a2, atol=unyt_quantity(0.0, "kg"))
Esempio n. 10
0
def test_runtime_error():
    a1 = unyt_array([1.0, 2.0, 3.0], "cm")
    a2 = unyt_array([1.0, 2.0, 3.0], "cm")
    with pytest.raises(RuntimeError):
        assert_allclose_units(a1, a2, rtol=unyt_quantity(1e-7, "cm"))
Esempio n. 11
0
def Int(self):
    print(self.units)
    if isinstance(self, unyt_quantity):
        return unyt_quantity(int(self.value), self.units)
Esempio n. 12
0
def array_ufunc(self, ufunc, method, *inputs, **kwargs):
    func = getattr(ufunc, method)
    if "out" not in kwargs:
        out = None
        out_func = None
    else:
        # we need to get both the actual "out" object and a view onto it
        # in case we need to do in-place operations
        out = kwargs.pop("out")[0]
        if out.dtype.kind in ("u", "i"):
            new_dtype = "f" + str(out.dtype.itemsize)
            float_values = out.astype(new_dtype)
            out.dtype = new_dtype
            np.copyto(out, float_values)
        out_func = out.view(np.ndarray)
    if len(inputs) == 1:
        # Unary ufuncs
        inp = inputs[0]
        u = getattr(inp, "units", None)
        if u.dimensions is angle and ufunc in trigonometric_operators:
            # ensure np.sin(90*degrees) works as expected
            inp = inp.in_units("radian").v
        # evaluate the ufunc
        out_arr = func(np.asarray(inp), out=out_func, **kwargs)
        if ufunc in (multiply, divide) and method == "reduce":
            # a reduction of a multiply or divide corresponds to
            # a repeated product which we implement as an exponent
            mul = 1
            power_sign = POWER_SIGN_MAPPING[ufunc]
            if "axis" in kwargs and kwargs["axis"] is not None:
                unit = u**(power_sign * inp.shape[kwargs["axis"]])
            else:
                unit = u**(power_sign * inp.size)
        else:
            # get unit of result
            mul, unit = self._ufunc_registry[ufunc](u)
        # use type(self) here so we can support user-defined
        # subclasses of unyt_array
        ret_class = type(self)
    elif len(inputs) == 2:
        # binary ufuncs
        i0 = inputs[0]
        i1 = inputs[1]
        # coerce inputs to be ndarrays if they aren't already
        inp0 = _coerce_iterable_units(i0)
        inp1 = _coerce_iterable_units(i1)
        u0 = getattr(i0, "units", None) or getattr(inp0, "units", None)
        u1 = getattr(i1, "units", None) or getattr(inp1, "units", None)
        ret_class = _get_binary_op_return_class(type(i0), type(i1))
        if u0 is None:
            u0 = Unit(registry=getattr(u1, "registry", None))
        if u1 is None and ufunc is not power:
            u1 = Unit(registry=getattr(u0, "registry", None))
        elif ufunc is power:
            u1 = inp1
            if inp0.shape != () and inp1.shape != ():
                raise UnitOperationError(ufunc, u0, u1)
            if isinstance(u1, unyt_array):
                if u1.units.is_dimensionless:
                    pass
                else:
                    raise UnitOperationError(ufunc, u0, u1)
            if u1.shape == ():
                u1 = float(u1)
            else:
                u1 = 1.0
        unit_operator = self._ufunc_registry[ufunc]
        if unit_operator in (_preserve_units, _comparison_unit, _arctan2_unit):
            # check "is" equality first for speed
            if u0 is not u1 and u0 != u1:
                # we allow adding, multiplying, comparisons with
                # zero-filled arrays, lists, etc or scalar zero. We
                # do not allow zero-filled unyt_array instances for
                # performance reasons. If we did allow it, every
                # binary operation would need to scan over all the
                # elements of both arrays to check for arrays filled
                # with zeros
                if not isinstance(i0, unyt_array) or not isinstance(
                        i1, unyt_array):
                    any_nonzero = [np.count_nonzero(i0), np.count_nonzero(i1)]
                    if any_nonzero[0] == 0:
                        u0 = u1
                    elif any_nonzero[1] == 0:
                        u1 = u0
                if not u0.same_dimensions_as(u1):
                    if unit_operator is _comparison_unit:
                        # we allow comparisons between data with
                        # units and dimensionless data
                        if u0.is_dimensionless:
                            u0 = u1
                        elif u1.is_dimensionless:
                            u1 = u0
                        else:
                            raise UnitOperationError(ufunc, u0, u1)
                    else:
                        raise UnitOperationError(ufunc, u0, u1)
                conv, offset = u1.get_conversion_factor(u0, inp1.dtype)
                new_dtype = np.dtype("f" + str(inp1.dtype.itemsize))
                conv = new_dtype.type(conv)
                '''if offset is not None:
                    raise InvalidUnitOperation(
                        "Quantities with units of Fahrenheit or Celsius "
                        "cannot by multiplied, divided, subtracted or "
                        "added with data that has different units."
                    )'''
                inp1 = np.asarray(inp1) * conv
        # get the unit of the result
        mul, unit = unit_operator(u0, u1)
        # actually evaluate the ufunc
        out_arr = func(inp0.view(np.ndarray),
                       inp1.view(np.ndarray),
                       out=out_func,
                       **kwargs)
        if unit_operator in (_multiply_units, _divide_units):
            if unit.is_dimensionless and unit.base_value != 1.0:
                if not u0.is_dimensionless:
                    if u0.dimensions == u1.dimensions:
                        out_arr = np.multiply(out_arr.view(np.ndarray),
                                              unit.base_value,
                                              out=out_func)
                        unit = Unit(registry=unit.registry)
            '''if (
                u0.base_offset
                and u0.dimensions is temperature
                or u1.base_offset
                and u1.dimensions is temperature
            ):
                print(u0.base_offset,u0.dimensions,u1.base_offset,u1.dimensions)
                raise InvalidUnitOperation(
                    "Quantities with units of Fahrenheit or Celsius TODO "
                    "cannot by multiplied, divide, subtracted or added."
                )'''
    else:
        raise RuntimeError(
            "Support for the %s ufunc with %i inputs has not been"
            "added to unyt_array." % (str(ufunc), len(inputs)))
    if unit is None:
        out_arr = np.array(out_arr, copy=False)
    elif ufunc in (modf, divmod_):
        out_arr = tuple((ret_class(o, unit) for o in out_arr))
    elif out_arr.size == 1:
        out_arr = unyt_quantity(np.asarray(out_arr), unit)
    else:
        if ret_class is unyt_quantity:
            # This happens if you do ndarray * unyt_quantity.
            # Explicitly casting to unyt_array avoids creating a
            # unyt_quantity with size > 1
            out_arr = unyt_array(out_arr, unit)
        else:
            out_arr = ret_class(out_arr, unit, bypass_validation=True)
    if out is not None:
        if mul != 1:
            multiply(out, mul, out=out)
            if np.shares_memory(out_arr, out):
                mul = 1
        if isinstance(out, unyt_array):
            try:
                out.units = out_arr.units
            except AttributeError:
                # out_arr is an ndarray
                out.units = Unit("", registry=self.units.registry)
    if mul == 1:
        return out_arr
    return mul * out_arr
Esempio n. 13
0
    planck_length_m as _planck_length_m,
    planck_time_s as _planck_time_s,
    planck_energy_J as _planck_energy_J,
    planck_charge_C as _planck_charge_C,
    planck_temperature_K as _planck_temperature_K,
    standard_gravity_m_per_s2 as _standard_gravity_m_per_s2,
    newton_mks as _newton_mks,
    planck_mks as _planck_mks,
    eps_0 as _eps_0,
    mu_0 as _mu_0
)
from unyt.array import unyt_quantity

#: mass of the electron
mass_electron_mks = mass_electron = me = \
    unyt_quantity(_mass_electron_kg, 'kg')

#: atomic mass unit
amu_mks = amu = unyt_quantity(_amu_kg, 'kg')

#: Avogadro's number
Na = avogadros_number = unyt_quantity(6.02214085774*10**23, 'mol**-1')

#: Mass of hydrogen
mp = mh = mass_hydrogen = mass_hydrogen_mks = \
    unyt_quantity(_mass_hydrogen_kg, 'kg')

# Velocities
#: speed of light
c = clight = speed_of_light = speed_of_light_mks = \
    unyt_quantity(_speed_of_light_m_per_s, 'm/s')