summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig8
-rw-r--r--pint/default_en.txt2
-rw-r--r--pint/quantity.py187
3 files changed, 117 insertions, 80 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..b0d1ce9
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,8 @@
+root = true
+
+[*.py]
+charset = utf-8
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+end_of_line = lf
diff --git a/pint/default_en.txt b/pint/default_en.txt
index fba87d2..34f0d61 100644
--- a/pint/default_en.txt
+++ b/pint/default_en.txt
@@ -117,7 +117,7 @@ international_steam_table_calorie = 4.1868 * joule
ton_TNT = 4.184e9 * joule = tTNT
US_therm = 1.054804e8 * joule
watt_hour = watt * hour = Wh = watthour
-hartree = 4.35974394e-18 * joule = E_h = hartree_energy
+hartree = 4.35974394e-18 * joule = = Eh = E_h = hartree_energy
toe = 41.868e9 * joule = tonne_of_oil_equivalent
# Force
diff --git a/pint/quantity.py b/pint/quantity.py
index 624c7e3..90a9076 100644
--- a/pint/quantity.py
+++ b/pint/quantity.py
@@ -319,7 +319,7 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
def check(self, dimension):
"""Return true if the quantity's dimension matches passed dimension.
"""
- return self.dimensionality == dimension
+ return self.dimensionality == self._REGISTRY.get_dimensionality(dimension)
@classmethod
def from_tuple(cls, tup):
@@ -1431,6 +1431,111 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
__array_priority__ = 17
+ def _call_ufunc(self, ufunc, *inputs, **kwargs):
+ # Store the destination units
+ dst_units = None
+ # List of magnitudes of Quantities with the right units
+ # to be used as argument of the ufunc
+ mobjs = None
+
+ if ufunc.__name__ in self.__require_units:
+ # ufuncs in __require_units
+ # require specific units
+ # This is more complex that it should be due to automatic
+ # conversion between radians/dimensionless
+ # TODO: maybe could be simplified using Contexts
+ dst_units = self.__require_units[ufunc.__name__]
+ if dst_units == 'radian':
+ mobjs = []
+ for other in inputs:
+ unt = getattr(other, '_units', '')
+ if unt == 'radian':
+ mobjs.append(getattr(other, 'magnitude', other))
+ else:
+ factor, units = self._REGISTRY._get_root_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(inputs) > 1 and ufunc.__name__ not in self.__skip_other_args:
+ # ufunc with multiple arguments require that all inputs have
+ # the same arguments unless they are in __skip_other_args
+ dst_units = getattr(inputs[0], "_units", None)
+
+ # Do the conversion (if needed) and extract the magnitude for each input.
+ 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 inputs)
+ else:
+ mobjs = tuple(getattr(other, 'magnitude', other)
+ for other in inputs)
+
+ # call the ufunc
+ try:
+ return ufunc(*mobjs)
+ except Exception as ex:
+ raise _Exception(ex)
+
+
+ def _wrap_output(self, ufname, i, objs, out):
+ """we set the units of the output value"""
+ if i > 0:
+ ufname = "{}__{}".format(ufname, i)
+
+ if ufname in self.__set_units:
+ try:
+ out = self.__class__(out, self.__set_units[ufname])
+ except:
+ raise _Exception(ValueError)
+ elif ufname in self.__copy_units:
+ try:
+ out = self.__class__(out, self._units)
+ except:
+ raise _Exception(ValueError)
+ elif ufname in self.__prod_units:
+ tmp = self.__prod_units[ufname]
+ if tmp == 'size':
+ out = self.__class__(out, self._units ** self._magnitude.size)
+ elif tmp == 'div':
+ units1 = objs[0]._units if isinstance(objs[0], self.__class__) else UnitsContainer()
+ units2 = objs[1]._units if isinstance(objs[1], self.__class__) else UnitsContainer()
+ out = self.__class__(out, units1 / units2)
+ elif tmp == 'mul':
+ units1 = objs[0]._units if isinstance(objs[0], self.__class__) else UnitsContainer()
+ units2 = objs[1]._units if isinstance(objs[1], self.__class__) else UnitsContainer()
+ out = self.__class__(out, units1 * units2)
+ else:
+ out = self.__class__(out, self._units ** tmp)
+
+ return out
+
+
+ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
+ if method != "__call__":
+ return NotImplemented
+
+ try:
+ out = self._call_ufunc(ufunc, *inputs, **kwargs)
+ if isinstance(out, tuple):
+ ret = tuple(self._wrap_output(ufunc.__name__, i, inputs, o)
+ for i, o in enumerate(out))
+ return ret
+ else:
+ return self._wrap_output(ufunc.__name__, 0, inputs, out)
+ except (DimensionalityError, UndefinedUnitError):
+ raise
+ except _Exception as ex:
+ raise ex.internal
+ except:
+ return NotImplemented
+
+
def __array_prepare__(self, obj, context=None):
# If this uf is handled by Pint, write it down in the handling dictionary.
@@ -1460,60 +1565,10 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
return self.magnitude.__array_wrap__(obj, context)
try:
- ufname = uf.__name__ if i_out == 0 else '{}__{}'.format(uf.__name__, i_out)
-
# First, we check the units of the input arguments.
if i_out == 0:
- # Do this only when the wrap is called for the first ouput.
-
- # Store the destination units
- dst_units = None
- # List of magnitudes of Quantities with the right units
- # to be used as argument of the ufunc
- mobjs = None
-
- if uf.__name__ in self.__require_units:
- # ufuncs in __require_units
- # require specific units
- # This is more complex that it should be due to automatic
- # conversion between radians/dimensionless
- # TODO: maybe could be simplified using Contexts
- dst_units = self.__require_units[uf.__name__]
- 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_root_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:
- # ufunc with multiple arguments require that all inputs have
- # the same arguments unless they are in __skip_other_args
- dst_units = objs[0]._units
-
- # Do the conversion (if needed) and extract the magnitude for each input.
- 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)
-
- # call the ufunc
- out = uf(*mobjs)
-
+ out = self._call_ufunc(uf, *objs)
# If there are multiple outputs,
# store them in __handling (uf, objs, i_out, out0, out1, ...)
# and return the first
@@ -1525,33 +1580,7 @@ class _Quantity(PrettyIPython, SharedRegistryObject):
# just grab the result that was previously calculated.
out = self.__handling[3 + i_out]
- # Second, we set the units of the output value.
- if ufname in self.__set_units:
- try:
- out = self.__class__(out, self.__set_units[ufname])
- except:
- raise _Exception(ValueError)
- elif ufname in self.__copy_units:
- try:
- out = self.__class__(out, self._units)
- except:
- raise _Exception(ValueError)
- elif ufname in self.__prod_units:
- tmp = self.__prod_units[ufname]
- if tmp == 'size':
- out = self.__class__(out, self._units ** self._magnitude.size)
- elif tmp == 'div':
- units1 = objs[0]._units if isinstance(objs[0], self.__class__) else UnitsContainer()
- units2 = objs[1]._units if isinstance(objs[1], self.__class__) else UnitsContainer()
- out = self.__class__(out, units1 / units2)
- elif tmp == 'mul':
- units1 = objs[0]._units if isinstance(objs[0], self.__class__) else UnitsContainer()
- units2 = objs[1]._units if isinstance(objs[1], self.__class__) else UnitsContainer()
- out = self.__class__(out, units1 * units2)
- else:
- out = self.__class__(out, self._units ** tmp)
-
- return out
+ return self._wrap_output(uf.__name__, i_out, objs, out)
except (DimensionalityError, UndefinedUnitError) as ex:
raise ex
except _Exception as ex: