Ejemplo n.º 1
0
 def test_dimensionality_error(self):
     ex = DimensionalityError("a", "b")
     self.assertEqual(str(ex), "Cannot convert from 'a' to 'b'")
     ex = DimensionalityError("a", "b", "c")
     self.assertEqual(str(ex), "Cannot convert from 'a' (c) to 'b' ()")
     ex = DimensionalityError("a", "b", "c", "d", extra_msg=": msg")
     self.assertEqual(str(ex), "Cannot convert from 'a' (c) to 'b' (d): msg")
Ejemplo n.º 2
0
 def test_dimensionality_error(self):
     ex = DimensionalityError("a", "b")
     assert str(ex) == "Cannot convert from 'a' to 'b'"
     ex = DimensionalityError("a", "b", "c")
     assert str(ex) == "Cannot convert from 'a' (c) to 'b' ()"
     ex = DimensionalityError("a", "b", "c", "d", extra_msg=": msg")
     assert str(ex) == "Cannot convert from 'a' (c) to 'b' (d): msg"
Ejemplo n.º 3
0
 def test_str_errors(self):
     self.assertEqual(str(UndefinedUnitError('rabbits')), "'{0!s}' is not defined in the unit registry".format('rabbits'))
     self.assertEqual(str(UndefinedUnitError(('rabbits', 'horses'))), "'{0!s}' are not defined in the unit registry".format(('rabbits', 'horses')))
     self.assertEqual(u(str(DimensionalityError('meter', 'second'))),
                      "Cannot convert from 'meter' to 'second'")
     self.assertEqual(str(DimensionalityError('meter', 'second', 'length', 'time')),
                      "Cannot convert from 'meter' (length) to 'second' (time)")
Ejemplo n.º 4
0
    def __init__(self, name="", **kwargs):
        c1 = set(kwargs.keys()) == {'magnitude', 'units'}
        c2 = set(kwargs.keys()) == {'quantity'}
        self.name = name

        # why bitwise exclusive or opposed to bitwise | or?
        assert c1 ^ c2
        if c1:
            magnitude = kwargs['magnitude']
            units = kwargs['units']
            if isinstance(magnitude, numbers.Number):
                self.magnitude = ufloat(magnitude, 0)
            else:
                self.magnitude = magnitude
                self.units = units
            self.value = Q_(self.magnitude, self.units)
        if c2:
            quantity = kwargs['quantity']
            self.value = quantity

        if c1 ^ c2:
            try:
                assert self.class_units.dimensionality == Q_(
                    1, self.units).dimensionality
            except AssertionError:
                raise DimensionalityError(self.class_units.units,
                                          self.value.units)
Ejemplo n.º 5
0
def xr_check_dimensionality(da: xr.DataArray, units_ref: Union[str,
                                                               pint.Unit]):
    """Check if the dimensionality of a ``DataArray`` is compatible with reference unit.

    Parameters
    ----------
    da:
        The data array that should be checked.
    units_ref:
        The reference unit

    Raises
    ------
    pint.DimensionalityError
        The error is raised if the check fails

    """
    if units_ref is None:
        return

    units_ref = U_(units_ref)
    units = da.weldx.units

    if units is None or not units.is_compatible_with(units_ref):
        raise DimensionalityError(
            units,
            units_ref,
            extra_msg=
            f"\nDataArray units are '{units}'.  This is incompatible with "
            f"the expected dimensionality '{units_ref.dimensionality}'",
        )
Ejemplo n.º 6
0
    def test_pickle_definition_syntax_error(self):
        # OffsetUnitCalculusError raised from a custom ureg must be pickleable even if
        # the ureg is not registered as the application ureg
        ureg = UnitRegistry(filename=None)
        ureg.define("foo = [bar]")
        ureg.define("bar = 2 foo")
        q1 = ureg.Quantity("1 foo")
        q2 = ureg.Quantity("1 bar")

        for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
            for ex in [
                    DefinitionSyntaxError("foo", filename="a.txt", lineno=123),
                    RedefinitionError("foo", "bar"),
                    UndefinedUnitError("meter"),
                    DimensionalityError("a", "b", "c", "d", extra_msg=": msg"),
                    OffsetUnitCalculusError(
                        Quantity("1 kg")._units,
                        Quantity("1 s")._units),
                    OffsetUnitCalculusError(q1._units, q2._units),
            ]:
                with self.subTest(protocol=protocol, etype=type(ex)):
                    pik = pickle.dumps(ureg.Quantity("1 foo"), protocol)
                    with self.assertRaises(UndefinedUnitError):
                        pickle.loads(pik)

                    # assert False, ex.__reduce__()
                    ex2 = pickle.loads(pickle.dumps(ex, protocol))
                    assert type(ex) is type(ex2)
                    self.assertEqual(ex.args, ex2.args)
                    self.assertEqual(ex.__dict__, ex2.__dict__)
                    self.assertEqual(str(ex), str(ex2))
Ejemplo n.º 7
0
def convert_universal(
    I,
    from_unit,
    to_unit,
    spec=None,
    per_nm_is_like="mW/sr/cm2/nm",
    per_cm_is_like="mW/sr/cm2/cm_1",
):
    """ Return variable var in whatever unit, and converts to to_unit
    Also deal with cases where var is in ~1/nm (per_nm_is_like) or ~1/cm-1
    (per_cm_is_like)


    Parameters    
    ----------

    var: str
        variable to get. Usually 'radiance' or 'radiance_noslit'

    to_unit: str
        unit to convert variable to

    Other Parameters
    ----------------

    spec: :class:`~radis.spectrum.spectrum.Spectrum` object
        needed to get wavenumber in case we need to do a change of variable 
        within the integral

    Notes
    -----

    wavenumber is needed in case we convert from ~1/nm to ~1/cm-1 (requires 
    a change of variable in the integral)

    """
    Iunit0 = from_unit
    Iunit = to_unit
    try:
        if is_homogeneous(Iunit0, per_nm_is_like) and is_homogeneous(
            Iunit, per_cm_is_like
        ):
            w_cm = spec.get_wavenumber()
            I = convert_rad2cm(I, w_cm, Iunit0, Iunit)
            # note that there may still be a new DimensionalityError
            # raise here if the input was non-sense.
        elif is_homogeneous(Iunit0, per_cm_is_like) and is_homogeneous(
            Iunit, per_nm_is_like
        ):
            w_cm = spec.get_wavenumber()
            I = convert_rad2nm(I, w_cm, Iunit0, Iunit)
            # note that there may still be a new DimensionalityError
            # raise here if the input was non-sense.
        else:  # general case: just convert
            I = conv2(I, Iunit0, Iunit)
    except DimensionalityError:
        raise DimensionalityError(Iunit0, Iunit)

    return I
Ejemplo n.º 8
0
 def convert_user_input(self, value):
     """Validate and convert an input value to its 'external' form"""
     if self.units is not None:
         q = Q_(value)
         if not q.dimensionality == self.units.dimensionality:
             raise DimensionalityError(q.units, self.units)
         return Q_(self.convert_raw_input(q.magnitude), q.units)
     else:
         return self.convert_raw_input(value)
Ejemplo n.º 9
0
    def test_errors(self):
        x = ('meter', )
        msg = "'meter' is not defined in the unit registry"
        self.assertEqual(str(UndefinedUnitError(x)), msg)
        self.assertEqual(str(UndefinedUnitError(list(x))), msg)
        self.assertEqual(str(UndefinedUnitError(set(x))), msg)

        msg = "Cannot convert from 'a' (c) to 'b' (d)msg"
        ex = DimensionalityError('a', 'b', 'c', 'd', 'msg')
        self.assertEqual(str(ex), msg)
Ejemplo n.º 10
0
    def write_converter(quantity):
        """Return the magnitude of quantity in terms of {unit}

        :param quantity: pint quantity
        :return: magnitude in terms of {unit}
        """
        try:
            base_unit_value = quantity.to(ureg(unit_str))
        except AttributeError:
            raise DimensionalityError(unit_str, None)
        return base_unit_value.magnitude
Ejemplo n.º 11
0
 def __setitem__(self, key, value):
     # Overrides pint's built-in version of this ... this is apparently way faster
     try:
         self.magnitude[key] = value.value_in(self.units)
     except AttributeError:
         if not hasattr(value, 'value_in'):  # deal with missing `value_in` method
             if self.dimensionless:  # case 1: this is OK if self is dimensionless
                 self.magnitude[key] = value
             else:  # case 2: User tried to pass a number without units
                 raise DimensionalityError('%s cannot be assigned to array with dimensions %s' %
                                           (value, self.units))
         else:  # case 3: attribute error is unrelated to this
             raise
Ejemplo n.º 12
0
 def of_division(self, numerator, denominator):
     "Cached unit division. Requires Quantity inputs."
     if numerator.units is denominator.units:
         return 1
     key = (id(numerator.units), id(denominator.units))
     if key not in self.division_cache:
         if numerator.units and denominator.units:
             conversion = numerator.units / denominator.units
         else:
             conversion = numerator.units or 1 / denominator.units
         try:
             self.division_cache[key] = float(conversion)
         except DimensionalityError:
             raise DimensionalityError(numerator, denominator)
     return self.division_cache[key]
Ejemplo n.º 13
0
 def __set__(self, instance, value):
     unit = getattr(instance, self.unit_name)
     if isinstance(value, ureg.Quantity) and unit is not None:
         try:
             value = value.to(unit)
         except DimensionalityError as e:
             raise DimensionalityError(
                 e.units1, e.units2, e.dim1, e.dim2,
                 'Wrong dimensions when setting {} with value {}'.format(
                     self.name, value))
     rng = getattr(instance, self.rng_name)
     if rng is not None:
         if not Guarded.in_range(value, rng):
             raise OutOfRangeError(value, rng, self.name)
     Guarded.cite_value(value)
     setattr(instance, self.guard_name, value)
Ejemplo n.º 14
0
 def __setitem__(self, key, value):
     # Overrides pint's built-in version of this ... this is apparently way faster
     try:
         self.magnitude[key] = value.value_in(self.units)
     except AttributeError:
         if not hasattr(value,
                        'value_in'):  # deal with missing `value_in` method
             if self.dimensionless:  # case 1: this is OK if self is dimensionless
                 self.magnitude[key] = value
             elif not isinstance(
                     value, numbers.Number):  # case 2: this is not a number
                 raise TypeError('"%s" is not a valid numeric value' %
                                 value)
             else:  # case 3: wrong units
                 raise DimensionalityError(self.units, ureg.dimensionless)
         else:  # case 3: attribute error is unrelated to this
             raise
    def convert(self, value):
        """ Returns quantity converted to these units

        Args:
            value (MdtQuantity or Numeric): value to convert

        Returns:
            MdtQuantity: converted value

        Raises:
            DimensionalityError: if the quantity does not have these units' dimensionality
        """
        if hasattr(value, 'to'):
            return value.to(self)
        elif self.dimensionless:
            return value * self
        else:
            raise DimensionalityError('Cannot convert "%s" to units of "%s"' % (value, self))
Ejemplo n.º 16
0
    def __init__(self, *args, **kwargs):
        self.base_units = kwargs.pop('base_units', None)
        if not self.base_units:
            raise ValueError(
                'QuantityFormField requires a base_units kwarg of a single unit type (eg: grams)'
            )
        self.units = kwargs.pop('unit_choices', [self.base_units])
        if self.base_units not in self.units:
            self.units.append(self.base_units)

        base_unit = getattr(ureg, self.base_units)

        for _unit in self.units:
            unit = getattr(ureg, _unit)
            if unit.dimensionality != base_unit.dimensionality:
                raise DimensionalityError(base_unit, unit)

        kwargs.update({'widget': QuantityWidget(allowed_types=self.units)})
        super(QuantityFormField, self).__init__(*args, **kwargs)
Ejemplo n.º 17
0
def conv2(quantity, fromunit, tounit):
    ''' Converts `quantity` from unit `fromunit` to unit `tounit`


    Parameters    
    ----------

    quantity: array
        quantity to convert

    fromunit: str
        input unit

    tounit: str
        output unit


    Note
    ----

    1.
    
    The output is still non dimensional. We don't transform `quantity` 
    into a pint array (or neq.phys.uarray) because this may create a performance
    drop in computationaly-expensive task. Instead, we assume we know for 
    sure the units in which some of our quantities will be created, and just
    want to let the users choose another output unit 

    2. 
    
    because angles are dimensionless a 'mW/cm2/sr/nm' > 'mW/cm2/nm' conversion 
    is considered  valid, while we expected the Luminance to be converted to 
    an exitance/irradiance and thus multiplied by Pi !
    Here we prevent this behavior by considering 
        
    

    '''

    try:
        a = Q_(quantity, fromunit)
        a = a.to(tounit)
        
        # Hardcoded: 'pint' considers angles to be dimensionless (which they are)
        # so a 'mW/cm2/sr/nm' > 'mW/cm2/nm' conversion is then considered  valid,
        # while we expected the Luminance to be converted to an Exitance/Irradiance 
        # and thus multiplied by Pi !! 
        # Here we prevent this behavior:
        
        if 'sr' in fromunit and 'sr' not in tounit:
            raise DimensionalityError(fromunit, tounit)
        if 'sr' in tounit and 'sr' not in fromunit:
            raise DimensionalityError(fromunit, tounit)
        
    except TypeError:
        if 'cm-1' in fromunit or 'cm-1' in tounit:
            #            raise TypeError('Use cm_1 instead of cm-1 else it triggers errors in '+\
            #                            'pint (symbolic unit converter)')
            return conv2(quantity, fromunit.replace('cm-1', 'cm_1'),
                  tounit.replace('cm-1', 'cm_1'))

        else:
            raise

    return a.magnitude
Ejemplo n.º 18
0
def xr_check_coords(coords: Union[xr.DataArray, Mapping[str, Any]],
                    ref: dict) -> bool:
    """Validate the coordinates of the DataArray against a reference dictionary.

    The reference dictionary should have the dimensions as keys and those contain
    dictionaries with the following keywords (all optional):

    ``values``
        Specify exact coordinate values to match.

    ``dtype`` : str or type
        Ensure coordinate dtype matches at least one of the given dtypes.

    ``optional`` : boolean
        default ``False`` - if ``True``, the dimension has to be in the DataArray dax

    ``dimensionality`` : str or pint.Unit
        Check if ``.attrs["units"]`` is the requested dimensionality

    ``units`` : str or pint.Unit
        Check if ``.attrs["units"]`` matches the requested unit

    Parameters
    ----------
    coords
        xarray object or coordinate mapping that should be validated
    ref
        reference dictionary

    Returns
    -------
    bool
        True, if the test was a success, else an exception is raised

    Examples
    --------
    >>> import numpy as np
    >>> import pandas as pd
    >>> import xarray as xr
    >>> import weldx as wx
    >>> dax = xr.DataArray(
    ...     data=np.ones((3, 2, 3)),
    ...     dims=["d1", "d2", "d3"],
    ...     coords={
    ...         "d1": np.array([-1, 0, 2], dtype=int),
    ...         "d2": pd.DatetimeIndex(["2020-05-01", "2020-05-03"]),
    ...         "d3": ["x", "y", "z"],
    ...     }
    ... )
    >>> ref = dict(
    ...     d1={"optional": True, "values": np.array([-1, 0, 2], dtype=int)},
    ...     d2={
    ...         "values": pd.DatetimeIndex(["2020-05-01", "2020-05-03"]),
    ...         "dtype": ["datetime64[ns]", "timedelta64[ns]"],
    ...     },
    ...     d3={"values": ["x", "y", "z"], "dtype": "<U1"},
    ... )
    >>> wx.util.xr_check_coords(dax, ref)
    True

    """
    # only process the coords of the xarray
    if isinstance(coords, (xr.DataArray, xr.Dataset)):
        coords = coords.coords

    for key, check in ref.items():
        # check if the optional key is set to true
        if "optional" in check and check["optional"] and key not in coords:
            # skip this key - it is not in dax
            continue

        if key not in coords:
            # Attributes not found in coords
            raise KeyError(f"Could not find required coordinate '{key}'.")

        # only if the key "values" is given do the validation
        if "values" in check and not np.all(
                coords[key].values == check["values"]):
            raise ValueError(f"Value mismatch in DataArray and ref['{key}']"
                             f"\n{coords[key].values}"
                             f"\n{check['values']}")

        # only if the key "dtype" is given do the validation
        if "dtype" in check:
            dtype_list = check["dtype"]
            if not isinstance(dtype_list, list):
                dtype_list = [dtype_list]
            if not any(
                    _check_dtype(coords[key].dtype, var_dtype)
                    for var_dtype in dtype_list):
                raise TypeError(
                    f"Mismatch in the dtype of the DataArray and ref['{key}']")

        if UNITS_KEY in check:
            units = coords[key].attrs.get(UNITS_KEY, None)
            if not units or not U_(units) == U_(check[UNITS_KEY]):
                raise ValueError(
                    f"Unit mismatch in coordinate '{key}'\n"
                    f"Coordinate has unit '{units}', expected '{check['units']}'"
                )

        if "dimensionality" in check:
            units = coords[key].attrs.get(UNITS_KEY, None)
            dim = check["dimensionality"]
            if units is None or not U_(units).is_compatible_with(dim):
                raise DimensionalityError(
                    units,
                    check["dimensionality"],
                    extra_msg=
                    f"\nDimensionality mismatch in coordinate '{key}'\n"
                    f"Coordinate has unit '{units}', expected '{dim}'",
                )

    return True