diff options
author | Hernan Grecco <hernan.grecco@gmail.com> | 2013-08-20 00:03:59 -0300 |
---|---|---|
committer | Hernan Grecco <hernan.grecco@gmail.com> | 2013-08-20 00:05:52 -0300 |
commit | 59b59860a0c775de8c5192617699703409c014c8 (patch) | |
tree | 4e1fba9b2c513d913acf0ebf90bfac9faf6520b7 | |
parent | fe596b4c23542c27cdcdc59f527001dd5791ab11 (diff) | |
download | pint-59b59860a0c775de8c5192617699703409c014c8.tar.gz |
Support for mathematical operations on dimensionless (but not simplified quantities)
fixes #45
-rw-r--r-- | CHANGES | 3 | ||||
-rw-r--r-- | pint/quantity.py | 62 | ||||
-rw-r--r-- | pint/testsuite/test_issues.py | 14 | ||||
-rw-r--r-- | pint/testsuite/test_umath.py | 15 |
4 files changed, 62 insertions, 32 deletions
@@ -25,7 +25,8 @@ Pint Changelog (Issue #42) - support for application of numpy function on non-ndarray magnitudes. (Issue #44) - +- support for math operations on dimensionless Quantities (writen with units) + (Issue #45) 0.2.1 (2013-07-02) ------------------ diff --git a/pint/quantity.py b/pint/quantity.py index 68673af..2cd9d11 100644 --- a/pint/quantity.py +++ b/pint/quantity.py @@ -213,12 +213,12 @@ class _Quantity(object): # Mathematical operations def __float__(self): if self.dimensionless: - return float(self._magnitude) + return float(self._REGISTRY.convert(self._magnitude, self.units, UnitsContainer())) raise DimensionalityError(self.units, 'dimensionless') def __complex__(self): if self.dimensionless: - return complex(self._magnitude) + return complex(self._REGISTRY.convert(self._magnitude, self.units, UnitsContainer())) raise DimensionalityError(self.units, 'dimensionless') def iadd_sub(self, other, fun): @@ -378,7 +378,7 @@ class _Quantity(object): __nonzero__ = __bool__ # NumPy Support - + __radian = 'radian' __same_units = 'equal greater greater_equal less less_equal not_equal arctan2'.split() #: Dictionary mapping ufunc/attributes names to the units that they #: require (conversion will be tried). @@ -387,23 +387,23 @@ class _Quantity(object): 'arccosh': '', 'arcsinh': '', 'arctanh': '', 'exp': '', 'expm1': '', 'exp2': '', 'log': '', 'log10': '', 'log1p': '', 'log2': '', - 'sin': 'radian', 'cos': 'radian', 'tan': 'radian', - 'sinh': 'radian', 'cosh': 'radian', 'tanh': 'radian', - 'radians': 'degree', 'degrees': 'radian', - 'deg2rad': 'degree', 'rad2deg': 'radian', + 'sin': __radian, 'cos': __radian, 'tan': __radian, + 'sinh': __radian, 'cosh': __radian, 'tanh': __radian, + 'radians': 'degree', 'degrees': __radian, + 'deg2rad': 'degree', 'rad2deg': __radian, 'logaddexp': '', 'logaddexp2': ''} #: Dictionary mapping ufunc/attributes names to the units that they #: will set on output. __set_units = {'cos': '', 'sin': '', 'tan': '', 'cosh': '', 'sinh': '', 'tanh': '', - 'arccos': 'radian', 'arcsin': 'radian', - 'arctan': 'radian', 'arctan2': 'radian', - 'arccosh': 'radian', 'arcsinh': 'radian', - 'arctanh': 'radian', - 'degrees': 'degree', 'radians': 'radian', + 'arccos': __radian, 'arcsin': __radian, + 'arctan': __radian, 'arctan2': __radian, + 'arccosh': __radian, 'arcsinh': __radian, + 'arctanh': __radian, + 'degrees': 'degree', 'radians': __radian, 'expm1': '', 'cumprod': '', - 'rad2deg': 'degree', 'deg2rad': 'radian'} + 'rad2deg': 'degree', 'deg2rad': __radian} #: List of ufunc/attributes names in which units are copied from the #: original. @@ -575,7 +575,9 @@ class _Quantity(object): ufname = uf.__name__ if huh == 0 else '{}__{}'.format(uf.__name__, huh) if uf.__name__ in self.__handled and huh == 0: if self.__handling: - raise Exception('Cannot handled nested ufuncs.\nCurrent: {}\nNew: {}'.format(context, self.__handling)) + raise Exception('Cannot handled nested ufuncs.\n' + 'Current: {}\n' + 'New: {}'.format(context, self.__handling)) self.__handling = context return obj @@ -591,23 +593,35 @@ class _Quantity(object): if huh == 0: dst_units = None + mobjs = None if uf.__name__ in self.__require_units: dst_units = self.__require_units[uf.__name__] - if self.unitless and dst_units == 'radian': - dst_units = None + if dst_units == 'radian': + mobjs = [] + for other in objs: + unt = getattr(other, 'units', '') + if unt == 'radian': + mobjs.append(getattr(other, 'magnitude', other)) + else: + factor, units = self._REGISTRY.get_base_units(unt) + if units and units != UnitsContainer({'radian': 1}): + raise DimensionalityError(units, dst_units) + mobjs.append(getattr(other, 'magnitude', other) * factor) + mobjs = tuple(mobjs) else: dst_units = self._REGISTRY.parse_expression(dst_units).units elif len(objs) > 1 and uf.__name__ not in self.__skip_other_args: dst_units = objs[0].units - if dst_units is not None: - mobjs = tuple(self._REGISTRY.convert(getattr(other, 'magnitude', other), - getattr(other, 'units', ''), - dst_units) - for other in objs) - else: - mobjs = tuple(getattr(other, 'magnitude', other) - for other in objs) + if mobjs is None: + if dst_units is not None: + mobjs = tuple(self._REGISTRY.convert(getattr(other, 'magnitude', other), + getattr(other, 'units', ''), + dst_units) + for other in objs) + else: + mobjs = tuple(getattr(other, 'magnitude', other) + for other in objs) out = uf(*mobjs) diff --git a/pint/testsuite/test_issues.py b/pint/testsuite/test_issues.py index add88c0..e1c54eb 100644 --- a/pint/testsuite/test_issues.py +++ b/pint/testsuite/test_issues.py @@ -93,3 +93,17 @@ class TestIssuesNP(TestCase): np.sqrt(x) self.assertAlmostEqual(np.sqrt([4.] * ureg.dimensionless), [2.] * ureg.dimensionless) self.assertAlmostEqual(np.sqrt(4. * ureg.dimensionless), 2. * ureg.dimensionless) + + def test_issue45(self): + import math + ureg = UnitRegistry() + self.assertAlmostEqual(math.sqrt(4 * ureg.m/ureg.cm), math.sqrt(4 * 100)) + self.assertAlmostEqual(float(ureg.V / ureg.mV), 1000.) + + def test_issue45b(self): + ureg = UnitRegistry() + self.assertAlmostEqual(np.sin([np.pi/2] * ureg.m / ureg.m ), np.sin([np.pi/2] * ureg.dimensionless)) + self.assertAlmostEqual(np.sin([np.pi/2] * ureg.cm / ureg.m ), np.sin([np.pi/2] * ureg.dimensionless * 0.01)) + + + diff --git a/pint/testsuite/test_umath.py b/pint/testsuite/test_umath.py index 041150c..db394ed 100644 --- a/pint/testsuite/test_umath.py +++ b/pint/testsuite/test_umath.py @@ -365,7 +365,7 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.sin, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), '') + ), (self.ureg.m, ), '', results=(None, None, np.sin(np.arange(0, pi/2, pi/4)*0.001))) self._test1(np.sin, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees, ), results=(np.sin(np.arange(0, pi/2, pi/4)), )) @@ -373,7 +373,7 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.cos, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), '') + ), (self.ureg.m, ), '', results=(None, None, np.cos(np.arange(0, pi/2, pi/4)*0.001))) self._test1(np.cos, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees, ), results=(np.cos(np.arange(0, pi/2, pi/4)), )) @@ -381,7 +381,7 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.tan, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), '') + ), (self.ureg.m, ), '', results=(None, None, np.tan(np.arange(0, pi/2, pi/4)*0.001))) self._test1(np.tan, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees, ), results=(np.tan(np.arange(0, pi/2, pi/4)), )) @@ -421,7 +421,7 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.sinh, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), '') + ), (self.ureg.m, ), '', results=(None, None, np.sinh(np.arange(0, pi/2, pi/4)*0.001))) self._test1(np.sinh, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees, ), results=(np.sinh(np.arange(0, pi/2, pi/4)), )) @@ -429,7 +429,7 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.cosh, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), '') + ), (self.ureg.m, ), '', results=(None, None, np.cosh(np.arange(0, pi/2, pi/4)*0.001))) self._test1(np.cosh, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees, ), results=(np.cosh(np.arange(0, pi/2, pi/4)), )) @@ -437,7 +437,7 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.tanh, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), '') + ), (self.ureg.m, ), '', results=(None, None, np.tanh(np.arange(0, pi/2, pi/4)*0.001))) self._test1(np.tanh, (np.rad2deg(np.arange(0, pi/2, pi/4)) * self.ureg.degrees, ), results=(np.tanh(np.arange(0, pi/2, pi/4)), )) @@ -464,7 +464,8 @@ class TestTrigUfuncs(TestUFuncs): self._test1(np.rad2deg, (np.arange(0, pi/2, pi/4) * self.ureg.dimensionless, np.arange(0, pi/2, pi/4) * self.ureg.radian, np.arange(0, pi/2, pi/4) * self.ureg.mm / self.ureg.m - ), (self.ureg.m, ), 'degree') + ), (self.ureg.m, ), 'degree', results=(None, None, np.rad2deg(np.arange(0, pi/2, pi/4)*0.001))) + class TestComparisonUfuncs(TestUFuncs): |