summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHernan Grecco <hernan.grecco@gmail.com>2013-08-20 00:03:59 -0300
committerHernan Grecco <hernan.grecco@gmail.com>2013-08-20 00:05:52 -0300
commit59b59860a0c775de8c5192617699703409c014c8 (patch)
tree4e1fba9b2c513d913acf0ebf90bfac9faf6520b7
parentfe596b4c23542c27cdcdc59f527001dd5791ab11 (diff)
downloadpint-59b59860a0c775de8c5192617699703409c014c8.tar.gz
Support for mathematical operations on dimensionless (but not simplified quantities)
fixes #45
-rw-r--r--CHANGES3
-rw-r--r--pint/quantity.py62
-rw-r--r--pint/testsuite/test_issues.py14
-rw-r--r--pint/testsuite/test_umath.py15
4 files changed, 62 insertions, 32 deletions
diff --git a/CHANGES b/CHANGES
index b9a3303..49a41fa 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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):