def __init__(self, value=None, units='', uncertainty=None, uncertainty_type='+|-'): Units.__init__(self, units) self.value = value if value is not None else np.array([0.0]) self.uncertainty_type = uncertainty_type if uncertainty is None or np.array_equal(uncertainty, np.array([0.0])): self.uncertainty = np.zeros_like(self.value) elif isinstance(uncertainty, (int, float)): self.uncertainty = np.ones_like(self.value) * uncertainty else: uncertainty = np.array(uncertainty) if uncertainty.ndim != self.value.ndim: raise QuantityError( 'The given uncertainty has {0:d} dimensions, while the given value has {1:d}' ' dimensions.'.format(uncertainty.ndim, self.value.ndim)) for i in range(self.value.ndim): if self.value.shape[i] != uncertainty.shape[i]: raise QuantityError( 'Dimension {0:d} has {1:d} elements for the given value, but {2:d} elements for' ' the given uncertainty.'.format( i, self.value.shape[i], uncertainty.shape[i])) else: self.uncertainty = uncertainty
def __call__(self, *args, **kwargs): # Make a ScalarQuantity or ArrayQuantity object out of the given parameter quantity = Quantity(*args, **kwargs) if quantity is None: return quantity units = quantity.units # If the units are in the common units, then we can do the conversion # very quickly and avoid the slow calls to the quantities package if units == self.units or units in self.common_units: return quantity # Check that the units are consistent with this unit type # This uses the quantities package (slow!) units = pq.Quantity(1.0, units) dimensionality = units.simplified.dimensionality if dimensionality == self.dimensionality: pass elif dimensionality in self.extra_dimensionality: quantity.value_si *= self.extra_dimensionality[dimensionality] quantity.units = self.units else: raise QuantityError( 'Invalid units {0!r}. Try common units: {1}'.format( quantity.units, self.common_units)) # Return the Quantity or ArrayQuantity object object return quantity
def uncertainty_type(self, v): """ Check the uncertainty type is valid, then set it. """ if v not in ['+|-', '*|/']: raise QuantityError('Unexpected uncertainty type "{0}"; valid values are "+|-" and "*|/".'.format(v)) self._uncertainty_type = v
def uncertainty_type(self, v): """ Check the uncertainty type is valid, then set it. If you set the uncertainty then change the type, we have no idea what to do with the units. This ensures you set the type first. """ if v not in ['+|-', '*|/']: raise QuantityError('Unexpected uncertainty type "{0}"; valid values are "+|-" and "*|/".'.format(v)) self._uncertainty_type = v
def SurfaceRateCoefficient(*args, **kwargs): # Make a ScalarQuantity or ArrayQuantity object out of the given parameter quantity = Quantity(*args, **kwargs) if quantity is None: return quantity units = quantity.units # If the units are in the common units, then we can do the conversion # very quickly and avoid the slow calls to the quantities package if units in SURFACERATECOEFFICIENT_COMMON_UNITS: return quantity dimensionality = pq.Quantity(1.0, quantity.units).simplified.dimensionality try: factor = SURFACERATECOEFFICIENT_CONVERSION_FACTORS[dimensionality] quantity.value_si *= factor except KeyError: raise QuantityError('Invalid units {0!r}.'.format(quantity.units)) # Return the Quantity or ArrayQuantity object object return quantity
def Quantity(*args, **kwargs): """ Create a :class:`ScalarQuantity` or :class:`ArrayQuantity` object for a given physical quantity. The physical quantity can be specified in several ways: * A scalar-like or array-like value (for a dimensionless quantity) * An array of arguments (including keyword arguments) giving some or all of the `value`, `units`, `uncertainty`, and/or `uncertainty_type`. * A tuple of the form ``(value,)``, ``(value,units)``, ``(value,units,uncertainty)``, or ``(value,units,uncertainty_type,uncertainty)`` * An existing :class:`ScalarQuantity` or :class:`ArrayQuantity` object, for which a copy is made """ # Initialize attributes value = None units = '' uncertainty_type = '+|-' uncertainty = None if len(args) == 1 and len(kwargs) == 0 and args[0] is None: return None # Unpack args if necessary if isinstance(args, tuple) and len(args) == 1 and isinstance( args[0], tuple): args = args[0] # Process args n_args = len(args) if n_args == 1 and isinstance(args[0], (ScalarQuantity, ArrayQuantity)): # We were given another quantity object, so make a (shallow) copy of it other = args[0] value = other.value units = other.units uncertainty_type = other.uncertainty_type uncertainty = other.uncertainty elif n_args == 1: # If one parameter is given, it should be a single value value, = args elif n_args == 2: # If two parameters are given, it should be a value and units value, units = args elif n_args == 3: # If three parameters are given, it should be a value, units and uncertainty value, units, uncertainty = args elif n_args == 4: # If four parameters are given, it should be a value, units, uncertainty type, and uncertainty value, units, uncertainty_type, uncertainty = args elif n_args != 0: raise QuantityError( 'Invalid parameters {0!r} passed to ArrayQuantity.__init__() method.' .format(args)) # Process kwargs for k, v in kwargs.items(): if k == 'value': if len(args) >= 1: raise QuantityError( 'Multiple values for argument {0} passed to ArrayQuantity.__init__() method.' .format(k)) else: value = v elif k == 'units': if len(args) >= 2: raise QuantityError( 'Multiple values for argument {0} passed to ArrayQuantity.__init__() method.' .format(k)) else: units = v elif k == 'uncertainty': if len(args) >= 3: raise QuantityError( 'Multiple values for argument {0} passed to ArrayQuantity.__init__() method.' .format(k)) else: uncertainty = v elif k == 'uncertainty_type': if len(args) >= 4: raise QuantityError( 'Multiple values for argument {0} passed to ArrayQuantity.__init__() method.' .format(k)) else: uncertainty_type = v else: raise QuantityError( 'Invalid keyword argument {0} passed to ArrayQuantity.__init__() method.' .format(k)) # Process units and uncertainty type parameters if uncertainty_type not in ['+|-', '*|/']: raise QuantityError( 'Unexpected uncertainty type "{0}"; valid values are "+|-" and "*|/".' .format(uncertainty_type)) if isinstance(value, (list, tuple, np.ndarray)): return ArrayQuantity(value, units, uncertainty, uncertainty_type) try: value = float(value) except TypeError: return ArrayQuantity(value, units, uncertainty, uncertainty_type) uncertainty = 0.0 if uncertainty is None else float(uncertainty) return ScalarQuantity(value, units, uncertainty, uncertainty_type)