Merge #515
515: … r=hgrecco See #500 BaseRegistry.auto_reduce_dimensions was added to configure whether to automatically reduce dimensionality. The reduction was implemented using decorators, one for inplace and one for not. The only operations wrapped were multiplication and division. Is this correct?
This commit is contained in:
@@ -44,6 +44,25 @@ class _Exception(Exception): # pragma: no cover
|
||||
self.internal = internal
|
||||
|
||||
|
||||
def reduce_dimensions(f):
|
||||
def wrapped(self, *args, **kwargs):
|
||||
result = f(self, *args, **kwargs)
|
||||
if result._REGISTRY.auto_reduce_dimensions:
|
||||
return result.to_root_units()
|
||||
else:
|
||||
return result
|
||||
return wrapped
|
||||
|
||||
|
||||
def ireduce_dimensions(f):
|
||||
def wrapped(self, *args, **kwargs):
|
||||
result = f(self, *args, **kwargs)
|
||||
if result._REGISTRY.auto_reduce_dimensions:
|
||||
result.ito_root_units()
|
||||
return result
|
||||
return wrapped
|
||||
|
||||
|
||||
@fix_str_conversions
|
||||
class _Quantity(SharedRegistryObject):
|
||||
"""Implements a class to describe a physical quantity:
|
||||
@@ -657,6 +676,7 @@ class _Quantity(SharedRegistryObject):
|
||||
def __rsub__(self, other):
|
||||
return -self._add_sub(other, operator.sub)
|
||||
|
||||
@ireduce_dimensions
|
||||
def _imul_div(self, other, magnitude_op, units_op=None):
|
||||
"""Perform multiplication or division operation in-place and return the
|
||||
result.
|
||||
@@ -714,6 +734,7 @@ class _Quantity(SharedRegistryObject):
|
||||
|
||||
return self
|
||||
|
||||
@reduce_dimensions
|
||||
def _mul_div(self, other, magnitude_op, units_op=None):
|
||||
"""Perform multiplication or division operation and return the result.
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ class BaseRegistry(meta.with_metaclass(_Meta)):
|
||||
:param on_redefinition: action to take in case a unit is redefined.
|
||||
'warn', 'raise', 'ignore'
|
||||
:type on_redefinition: str
|
||||
:param auto_reduce_dimensions: If True, reduce dimensionality on appropriate operations.
|
||||
"""
|
||||
|
||||
#: Map context prefix to function
|
||||
@@ -111,7 +112,7 @@ class BaseRegistry(meta.with_metaclass(_Meta)):
|
||||
'parse_unit_name', 'parse_units', 'parse_expression',
|
||||
'convert']
|
||||
|
||||
def __init__(self, filename='', force_ndarray=False, on_redefinition='warn'):
|
||||
def __init__(self, filename='', force_ndarray=False, on_redefinition='warn', auto_reduce_dimensions=False):
|
||||
|
||||
self._register_parsers()
|
||||
|
||||
@@ -129,6 +130,9 @@ class BaseRegistry(meta.with_metaclass(_Meta)):
|
||||
#: Action to take in case a unit is redefined. 'warn', 'raise', 'ignore'
|
||||
self._on_redefinition = on_redefinition
|
||||
|
||||
#: Determines if dimensionality should be reduced on appropriate operations.
|
||||
self.auto_reduce_dimensions = auto_reduce_dimensions
|
||||
|
||||
#: Map between name (string) and value (string) of defaults stored in the definitions file.
|
||||
self._defaults = {}
|
||||
|
||||
@@ -1435,17 +1439,20 @@ class UnitRegistry(SystemRegistry, ContextRegistry, NonMultiplicativeRegistry):
|
||||
:param on_redefinition: action to take in case a unit is redefined.
|
||||
'warn', 'raise', 'ignore'
|
||||
:type on_redefinition: str
|
||||
:param auto_reduce_dimensions: If True, reduce dimensionality on appropriate operations.
|
||||
"""
|
||||
|
||||
def __init__(self, filename='', force_ndarray=False, default_as_delta=True,
|
||||
autoconvert_offset_to_baseunit=False,
|
||||
on_redefinition='warn', system=None):
|
||||
on_redefinition='warn', system=None,
|
||||
auto_reduce_dimensions=False):
|
||||
|
||||
super(UnitRegistry, self).__init__(filename=filename, force_ndarray=force_ndarray,
|
||||
on_redefinition=on_redefinition,
|
||||
default_as_delta=default_as_delta,
|
||||
autoconvert_offset_to_baseunit=autoconvert_offset_to_baseunit,
|
||||
system=system)
|
||||
system=system,
|
||||
auto_reduce_dimensions=auto_reduce_dimensions)
|
||||
|
||||
def pi_theorem(self, quantities):
|
||||
"""Builds dimensionless quantities using the Buckingham π theorem
|
||||
|
||||
@@ -1168,3 +1168,40 @@ class TestOffsetUnitMath(QuantityTestCase, ParameterizedTestCase):
|
||||
|
||||
in1_cp = copy.copy(in1)
|
||||
self.assertQuantityAlmostEqual(op.ipow(in1_cp, in2), expected)
|
||||
|
||||
|
||||
class TestDimensionReduction(QuantityTestCase):
|
||||
def _calc_mass(self, ureg):
|
||||
density = 3 * ureg.g / ureg.L
|
||||
volume = 32 * ureg.milliliter
|
||||
return density * volume
|
||||
|
||||
def _icalc_mass(self, ureg):
|
||||
res = ureg.Quantity(3.0, 'gram/liter')
|
||||
res *= ureg.Quantity(32.0, 'milliliter')
|
||||
return res
|
||||
|
||||
def test_mul_and_div_reduction(self):
|
||||
ureg = UnitRegistry(auto_reduce_dimensions=True)
|
||||
mass = self._calc_mass(ureg)
|
||||
self.assertEqual(mass.units, ureg.g)
|
||||
ureg = UnitRegistry(auto_reduce_dimensions=False)
|
||||
mass = self._calc_mass(ureg)
|
||||
self.assertEqual(mass.units, ureg.g / ureg.L * ureg.milliliter)
|
||||
|
||||
@helpers.requires_numpy()
|
||||
def test_imul_and_div_reduction(self):
|
||||
ureg = UnitRegistry(auto_reduce_dimensions=True, force_ndarray=True)
|
||||
mass = self._icalc_mass(ureg)
|
||||
self.assertEqual(mass.units, ureg.g)
|
||||
ureg = UnitRegistry(auto_reduce_dimensions=False, force_ndarray=True)
|
||||
mass = self._icalc_mass(ureg)
|
||||
self.assertEqual(mass.units, ureg.g / ureg.L * ureg.milliliter)
|
||||
|
||||
def test_reduction_to_dimensionless(self):
|
||||
ureg = UnitRegistry(auto_reduce_dimensions=True)
|
||||
x = (10 * ureg.feet) / (3 * ureg.inches)
|
||||
self.assertEqual(x.units, UnitsContainer({}))
|
||||
ureg = UnitRegistry(auto_reduce_dimensions=False)
|
||||
x = (10 * ureg.feet) / (3 * ureg.inches)
|
||||
self.assertEqual(x.units, ureg.feet / ureg.inches)
|
||||
|
||||
Reference in New Issue
Block a user