Exemple #1
0
class UnitAdaptor(Adaptor):
    """Scalar conversion of units
    """
    def __init__(self, name):
        self._register = UnitRegistry()
        super().__init__(name)

    def before_model_run(self, data_handle: DataHandle):
        """Register unit definitions in registry before model run
        """
        units = data_handle.read_unit_definitions()
        for unit in units:
            self._register.define(unit)

    def convert(self, data_array, to_spec, coefficients):
        data = data_array.data
        from_spec = data_array.spec

        try:
            quantity = self._register.Quantity(data, from_spec.unit)
        except UndefinedUnitError:
            raise ValueError('Cannot convert from undefined unit {}'.format(
                from_spec.unit))

        try:
            converted_quantity = quantity.to(to_spec.unit)
        except UndefinedUnitError as ex:
            raise ValueError('Cannot convert undefined unit {}'.format(
                to_spec.unit)) from ex
        except DimensionalityError as ex:
            msg = 'Cannot convert unit from {} to {}'
            raise ValueError(msg.format(from_spec.unit, to_spec.unit)) from ex

        return converted_quantity.magnitude

    def get_coefficients(self, data_handle, from_spec, to_spec):
        # override with no-op - all the work is done in convert with scalar operations
        pass

    def generate_coefficients(self, from_spec, to_spec):
        # override with no-op - all the work is done in convert with scalar operations
        pass

    def parse_unit(self, unit_string):
        """Parse a unit string (abbreviation or full) into a Unit object

        Parameters
        ----------
        unit : str

        Returns
        -------
        quantity : :class:`pint.Unit`
        """
        try:
            unit = self._register.parse_units(unit_string)
        except UndefinedUnitError:
            self.logger.warning("Unrecognised unit: %s", unit_string)
            unit = None
        return unit
    def depths(self):
        if self.__depths is None:
            var = None
            for v in ['depth', 'deptht']:
                if v in self._dataset.variables:
                    var = self._dataset.variables[v]
                    break

            ureg = UnitRegistry()
            unit = ureg.parse_units(var.units.lower())
            self.__depths = ureg.Quantity(var[:],
                                          unit).to(ureg.meters).magnitude
            self.__depths.flags.writeable = False

        return self.__depths
Exemple #3
0
    def depths(self):
        if self.__depths is None:
            var = None
            for v in ['depth', 'deptht']:
                if v in self._dataset.variables:
                    var = self._dataset.variables[v]
                    break

            ureg = UnitRegistry()
            unit = ureg.parse_units(var.units.lower())
            self.__depths = ureg.Quantity(
                var[:], unit
            ).to(ureg.meters).magnitude
            self.__depths.flags.writeable = False

        return self.__depths
def test_service_port_units(osparc_simcore_root_dir):
    ureg = UnitRegistry()

    data = yaml.safe_load(
        (osparc_simcore_root_dir /
         "packages/models-library/tests/image-meta.yaml").read_text())
    print(ServiceDockerData.schema_json(indent=2))

    service_meta = ServiceDockerData.parse_obj(data)
    for input_nameid, input_meta in service_meta.inputs.items():
        assert input_nameid

        # validation
        valid_unit: Unit = ureg.parse_units(input_meta.unit)
        assert isinstance(valid_unit, Unit)

        assert valid_unit.dimensionless
def test_service_port_units(project_tests_dir: Path):
    ureg = UnitRegistry()

    data = yaml.safe_load(
        (project_tests_dir / "data" / "image-meta.yaml").read_text())
    print(ServiceDockerData.schema_json(indent=2))

    service_meta = ServiceDockerData.parse_obj(data)
    assert service_meta.inputs

    for input_nameid, input_meta in service_meta.inputs.items():
        assert input_nameid

        # validation
        valid_unit: Unit = ureg.parse_units(input_meta.unit)
        assert isinstance(valid_unit, Unit)

        assert valid_unit.dimensionless
Exemple #6
0
    def depths(self) -> np.ndarray:
        if self.__depths is None:
            var = None
            # Look through possible dimension names
            for v in self.depth_dimensions:
                # Depth is usually a "coordinate" variable
                if v in list(self._dataset.coords.keys()):
                    # Get DataArray for depth
                    var = self.get_dataset_variable(v)
                    break
            if var is not None:
                ureg = UnitRegistry()
                unit = ureg.parse_units(var.attrs['units'].lower())
                self.__depths = ureg.Quantity(var.values,
                                              unit).to(ureg.meters).magnitude
            else:
                self.__depths = np.array([0])
            self.__depths.setflags(write=False)  # Make immutable

        return self.__depths
    def depths(self) -> np.ndarray:
        """Finds, caches, and returns the valid depths for the dataset.
        """
        if self.__depths is None:
            var = None
            for v in self.nc_data.depth_dimensions:
                # Depth is usually a "coordinate" variable
                if v in self.nc_data.dataset.coords:
                    # Get DataArray for depth
                    var = self.nc_data.get_dataset_variable(v)
                    break

            if var is not None:
                ureg = UnitRegistry()
                unit = ureg.parse_units(var.attrs['units'].lower())
                self.__depths = ureg.Quantity(var[:].values, unit).to(ureg.meters).magnitude
            else:
                self.__depths = np.array([0])

            self.__depths.flags.writeable = False

        return self.__depths
    def depths(self):
        if self.__depths is None:
            var = None
            for v in self.depth_dimensions:
                # Depth is usually a "coordinate" variable
                if v in list(self._dataset.coords.keys()):
                    # Get DataArray for depth
                    var = self._dataset.variables[v]
                    break

            if var is not None:
                ureg = UnitRegistry()
                unit = ureg.parse_units(var.attrs['units'].lower())
                self.__depths = ureg.Quantity(
                    var[:].values, unit
                ).to(ureg.meters).magnitude
            else:
                self.__depths = np.array([0])

            self.__depths.flags.writeable = False

        return self.__depths
    def depths(self):
        """Finds, caches, and returns the valid depths for the dataset.
        """
        if self.__depths is None:
            var = None
            # Look through possible dimension names
            for v in self.nc_data.depth_dimensions:
                # Depth is usually a "coordinate" variable
                if v in self.nc_data.dataset.coords:
                    # Get DataArray for depth
                    var = self.nc_data.get_dataset_variable(v)
                    break
            if var is not None:
                ureg = UnitRegistry()
                unit = ureg.parse_units(var.attrs['units'].lower())
                self.__depths = ureg.Quantity(var.values,
                                              unit).to(ureg.meters).magnitude
            else:
                self.__depths = np.array([0])

            # Make immutable
            self.__depths.setflags(write=False)

        return self.__depths
Exemple #10
0
    def __post_init__(self, reg: pint.UnitRegistry) -> None:
        # VSS uses some Pascal-cased data types, so lower-case them then let super type check them.
        # noinspection PyCallByClass
        object.__setattr__(self, 'datatype', self.datatype.lower())

        # Process enum into a more agreeable format.
        if self.enum is not None:
            if self.datatype != 'string':
                raise ValueError(
                    f'enum provided for non-string datatype {self.datatype}')

            # noinspection PyCallByClass
            object.__setattr__(self, 'enum', set(self.enum))

        # Set min and max based on datatype for numeric signals.
        if self.datatype not in ('string', 'boolean'):
            if 'int' in self.datatype:
                try:
                    low, high = INT_BOUNDS[self.datatype]
                except KeyError:
                    raise ValueError(
                        f'unrecognized datatype {self.datatype}') from None
            elif self.datatype == 'float':
                low, high = FLOAT_BOUNDS
            elif self.datatype == 'double':
                low, high = DOUBLE_BOUNDS
            else:
                raise ValueError(f'unrecognized datatype {self.datatype}')

            if self.min is None:
                object.__setattr__(self, 'min', low)
            else:
                object.__setattr__(self, 'min', max(self.min, low))
            if self.max is None:
                object.__setattr__(self, 'max', high)
            else:
                object.__setattr__(self, 'max', min(self.max, high))

        # Ensure default value matches datatype and bounds.
        if self.default is not None:
            if (isinstance(self.default, float) and self.datatype not in ('float', 'double')) or \
                    (isinstance(self.default, int) and 'int' not in self.datatype) or \
                    (isinstance(self.default, bool) and self.datatype != 'boolean') or \
                    (isinstance(self.default, str) and self.datatype != 'string'):
                raise ValueError(
                    f'default value type {type(self.default)} does not match '
                    f'expected datatype {self.datatype}')

            if self.datatype == 'string':
                if self.enum is not None and self.default not in self.enum:
                    raise ValueError(
                        f'default value {self.default} is illegal for enum {self.enum}'
                    )
            elif self.datatype != 'bool':
                if self.clamp(self.default) != self.default:
                    raise ValueError(
                        f'default value {self.default} is illegal for datatype {self.datatype}'
                    )

        # Parse pint unit from unit string.
        try:
            # noinspection PyCallByClass
            object.__setattr__(self, 'pint_unit', reg.parse_units(self.unit))
        except Exception:
            raise ValueError(f'illegal unit {self.unit!r}') from None

        # Non-numeric data types must not have a unit.
        if self.datatype in ('string',
                             'boolean') and not self.pint_unit.dimensionless:
            raise ValueError(
                f'datatype {self.datatype} is not compatible with unit {self.pint_unit:~}'
            )

        # Ensure namespace is valid.
        if len(self.namespace) == 0:
            raise ValueError('namespace must contain at least one key')
        for key in self.namespace:
            if len(key) == 0:
                raise ValueError('namespace cannot contain an empty key')

        self.__type_check()