[yt-svn] commit/yt: MatthewTurk: Merged in ngoldbaum/yt/yt-3.0 (pull request #993)

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Thu Jul 17 14:15:06 PDT 2014


1 new commit in yt:

https://bitbucket.org/yt_analysis/yt/commits/b58796ca1988/
Changeset:   b58796ca1988
Branch:      yt-3.0
User:        MatthewTurk
Date:        2014-07-17 23:14:53
Summary:     Merged in ngoldbaum/yt/yt-3.0 (pull request #993)

Adding boltzmann's constant, speed of light, Fahrenheit, Celsius, and Rankine units.
Affected #:  7 files

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/units/tests/test_units.py
--- a/yt/units/tests/test_units.py
+++ b/yt/units/tests/test_units.py
@@ -31,7 +31,8 @@
 # classes
 from yt.units.unit_object import Unit, UnitParseError
 # objects
-from yt.units.unit_lookup_table import default_unit_symbol_lut, unit_prefixes
+from yt.units.unit_lookup_table import \
+    default_unit_symbol_lut, unit_prefixes, prefixable_units
 # unit definitions
 from yt.utilities.physical_constants import \
     cm_per_pc, sec_per_year, cm_per_km, cm_per_mpc, \
@@ -46,13 +47,17 @@
 
     # go through all possible prefix combos
     for symbol in default_unit_symbol_lut.keys():
-        for prefix in unit_prefixes.keys():
+        if symbol in prefixable_units:
+            keys = unit_prefixes.keys()
+        else:
+            keys = [symbol]
+        for prefix in keys:
             new_symbol = "%s%s" % (prefix, symbol)
 
             # test if we have seen this symbol
             if new_symbol in full_set:
                 print "Duplicate symbol: %s" % new_symbol
-                yield assert_true, False
+                raise RuntimeError
 
             full_set.add(new_symbol)
     yield assert_true, True
@@ -417,7 +422,7 @@
     yield assert_true, u2.dimensions == mass_density
     yield assert_true, u3.dimensions == mass_density
 
-    yield assert_allclose, get_conversion_factor(u1, u3), \
+    yield assert_allclose, get_conversion_factor(u1, u3)[0], \
         Msun_cgs / Mpc_cgs**3, 1e-12
 
 def test_is_code_unit():

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -27,7 +27,8 @@
 from numpy.testing import \
     assert_array_equal, \
     assert_equal, assert_raises, \
-    assert_array_almost_equal_nulp
+    assert_array_almost_equal_nulp, \
+    assert_array_almost_equal
 from numpy import array
 from yt.units.yt_array import \
     YTArray, YTQuantity, \
@@ -418,7 +419,9 @@
     yield assert_equal, km_in_cm.in_mks(), 1e3
     yield assert_equal, km_in_cm.units, cm_unit
 
+    km_view = km.ndarray_view()
     km.convert_to_units('cm')
+    assert_true(km_view.base is km.base)
 
     yield assert_equal, km, YTQuantity(1, 'km')
     yield assert_equal, km.in_cgs(), 1e5
@@ -426,6 +429,7 @@
     yield assert_equal, km.units, cm_unit
 
     km.convert_to_units('kpc')
+    assert_true(km_view.base is km.base)
 
     yield assert_array_almost_equal_nulp, km, YTQuantity(1, 'km')
     yield assert_array_almost_equal_nulp, km.in_cgs(), YTQuantity(1e5, 'cm')
@@ -453,6 +457,49 @@
     yield assert_equal, str(em3.in_mks().units), 'kg/(m*s**2)'
     yield assert_equal, str(em3.in_cgs().units), 'g/(cm*s**2)'
 
+def test_temperature_conversions():
+    """
+    Test conversions between various supported temperatue scales.
+
+    Also ensure we only allow compound units with temperature
+    scales that have a proper zero point.
+
+    """
+    from yt.units.unit_object import InvalidUnitOperation
+
+    km = YTQuantity(1, 'km')
+    balmy = YTQuantity(300, 'K')
+    balmy_F = YTQuantity(80.33, 'F')
+    balmy_C = YTQuantity(26.85, 'C')
+    balmy_R = YTQuantity(540, 'R')
+
+    assert_array_almost_equal(balmy.in_units('F'), balmy_F)
+    assert_array_almost_equal(balmy.in_units('C'), balmy_C)
+    assert_array_almost_equal(balmy.in_units('R'), balmy_R)
+
+    balmy_view = balmy.ndarray_view()
+
+    balmy.convert_to_units('F')
+    yield assert_true, balmy_view.base is balmy.base
+    yield assert_array_almost_equal, np.array(balmy), np.array(balmy_F)
+
+    balmy.convert_to_units('C')
+    yield assert_true, balmy_view.base is balmy.base
+    yield assert_array_almost_equal, np.array(balmy), np.array(balmy_C)
+
+    balmy.convert_to_units('R')
+    yield assert_true, balmy_view.base is balmy.base
+    yield assert_array_almost_equal, np.array(balmy), np.array(balmy_R)
+
+    balmy.convert_to_units('F')
+    yield assert_true, balmy_view.base is balmy.base
+    yield assert_array_almost_equal, np.array(balmy), np.array(balmy_F)
+
+    yield assert_raises, InvalidUnitOperation, np.multiply, balmy, km
+
+    # Does CGS convergion from F to K work?
+    yield assert_array_almost_equal, balmy.in_cgs(), YTQuantity(300, 'K')
+
 
 def test_yt_array_yt_quantity_ops():
     """

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/units/unit_lookup_table.py
--- a/yt/units/unit_lookup_table.py
+++ b/yt/units/unit_lookup_table.py
@@ -18,7 +18,9 @@
     mass_sun_grams, sec_per_year, sec_per_day, sec_per_hr, \
     sec_per_min, temp_sun_kelvin, luminosity_sun_ergs_per_sec, \
     metallicity_sun, erg_per_eV, amu_grams, mass_electron_grams, \
-    cm_per_ang, jansky_cgs, mass_jupiter_grams, mass_earth_grams
+    cm_per_ang, jansky_cgs, mass_jupiter_grams, mass_earth_grams, \
+    boltzmann_constant_erg_per_K, kelvin_per_rankine, \
+    speed_of_light_cm_per_s
 import numpy as np
 
 # Lookup a unit symbol with the symbol string, and provide a tuple with the
@@ -37,6 +39,7 @@
     "erg":  (1.0, dimensions.energy),
     "esu":  (1.0, dimensions.charge),
     "gauss": (1.0, dimensions.magnetic_field),
+    "C" : (1.0, dimensions.temperature, -273.15),
 
     # some SI
     "m": (1.0e2, dimensions.length),
@@ -47,6 +50,8 @@
     # Imperial units
     "ft": (30.48, dimensions.length),
     "mile": (160934, dimensions.length),
+    "F": (kelvin_per_rankine, dimensions.temperature, -459.67),
+    "R": (kelvin_per_rankine, dimensions.temperature),
 
     # dimensionless stuff
     "h": (1.0, dimensions.dimensionless), # needs to be added for rho_crit_now
@@ -58,6 +63,9 @@
     "day": (sec_per_day, dimensions.time),
     "yr":  (sec_per_year, dimensions.time),
 
+    # Velocities
+    "c": (speed_of_light_cm_per_s, dimensions.velocity),
+
     # Solar units
     "Msun": (mass_sun_grams, dimensions.mass),
     "msun": (mass_sun_grams, dimensions.mass),
@@ -89,6 +97,8 @@
     "angstrom": (cm_per_ang, dimensions.length),
     "Jy": (jansky_cgs, dimensions.specific_flux),
     "counts": (1.0, dimensions.dimensionless),
+    "kB": (boltzmann_constant_erg_per_K,
+           dimensions.energy/dimensions.temperature),
     "photons": (1.0, dimensions.dimensionless),
 
     # for AstroPy compatibility

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/units/unit_object.py
--- a/yt/units/unit_object.py
+++ b/yt/units/unit_object.py
@@ -21,7 +21,8 @@
 from sympy.parsing.sympy_parser import \
     parse_expr, auto_number, rationalize
 from keyword import iskeyword
-from yt.units import dimensions as dimensions_mod
+from yt.units.dimensions import \
+    base_dimensions, temperature
 from yt.units.unit_lookup_table import \
     latex_symbol_lut, unit_prefixes, \
     prefixable_units, cgs_base_units, \
@@ -114,10 +115,11 @@
     is_number = False
 
     # Extra attributes
-    __slots__ = ["expr", "is_atomic", "cgs_value", "dimensions", "registry"]
+    __slots__ = ["expr", "is_atomic", "cgs_value", "cgs_offset", "dimensions",
+                 "registry"]
 
-    def __new__(cls, unit_expr=sympy_one, cgs_value=None, dimensions=None,
-                registry=None, **assumptions):
+    def __new__(cls, unit_expr=sympy_one, cgs_value=None, cgs_offset=0.0,
+                dimensions=None, registry=None, **assumptions):
         """
         Create a new unit. May be an atomic unit (like a gram) or combinations
         of atomic units (like g / cm**3).
@@ -130,7 +132,11 @@
             The unit's value in cgs.
         dimensions : sympy.core.expr.Expr
             A sympy expression representing the dimensionality of this unit.
-            It must contain only mass, length, time, temperature and angle symbols.
+            It must contain only mass, length, time, temperature and angle
+            symbols.
+        offset : float
+            The offset necessary to normalize temperature units to a common
+            zero point.
         registry : UnitRegistry object
             The unit registry we use to interpret unit symbols.
 
@@ -185,7 +191,12 @@
             validate_dimensions(dimensions)
         else:
             # lookup the unit symbols
-            cgs_value, dimensions = _get_unit_data_from_expr(unit_expr, registry.lut)
+            try:
+                cgs_value, dimensions = \
+                    _get_unit_data_from_expr(unit_expr, registry.lut)
+            except ValueError:
+                cgs_value, dimensions, cgs_offset = \
+                    _get_unit_data_from_expr(unit_expr, registry.lut)
 
         # Create obj with superclass construct.
         obj = Expr.__new__(cls, **assumptions)
@@ -194,6 +205,7 @@
         obj.expr = unit_expr
         obj.is_atomic = is_atomic
         obj.cgs_value = cgs_value
+        obj.cgs_offset = cgs_offset
         obj.dimensions = dimensions
         obj.registry = registry
 
@@ -240,24 +252,46 @@
     def __mul__(self, u):
         """ Multiply Unit with u (Unit object). """
         if not isinstance(u, Unit):
-            raise InvalidUnitOperation("Tried to multiply a Unit object with " \
-                                       "'%s' (type %s). This behavior is " \
-                                       "undefined." % (u, type(u)) )
+            raise InvalidUnitOperation("Tried to multiply a Unit object with "
+                                       "'%s' (type %s). This behavior is "
+                                       "undefined." % (u, type(u)))
+
+        cgs_offset = 0.0
+        if self.cgs_offset or u.cgs_offset:
+            if u.dimensions is temperature and self.is_dimensionless:
+                cgs_offset = u.cgs_offset
+            elif self.dimensions is temperature and u.is_dimensionless:
+                cgs_offset = self.cgs_offset
+            else:
+                raise InvalidUnitOperation("Quantities with units of Fahrenheit "
+                                           "and Celcius cannot be multiplied.")
 
         return Unit(self.expr * u.expr,
                     cgs_value=(self.cgs_value * u.cgs_value),
+                    cgs_offset=cgs_offset,
                     dimensions=(self.dimensions * u.dimensions),
                     registry=self.registry)
 
     def __div__(self, u):
         """ Divide Unit by u (Unit object). """
         if not isinstance(u, Unit):
-            raise InvalidUnitOperation("Tried to divide a Unit object by '%s' "\
+            raise InvalidUnitOperation("Tried to divide a Unit object by '%s' "
                                        "(type %s). This behavior is "
-                                       "undefined." % (u, type(u)) )
+                                       "undefined." % (u, type(u)))
+
+        cgs_offset = 0.0
+        if self.cgs_offset or u.cgs_offset:
+            if u.dimensions is dims.temperature and self.is_dimensionless:
+                cgs_offset = u.cgs_offset
+            elif self.dimensions is dims.temperature and u.is_dimensionless:
+                cgs_offset = self.cgs_offset
+            else:
+                raise InvalidUnitOperation("Quantities with units of Farhenheit "
+                                           "and Celcius cannot be multiplied.")
 
         return Unit(self.expr / u.expr,
                     cgs_value=(self.cgs_value / u.cgs_value),
+                    cgs_offset=cgs_offset,
                     dimensions=(self.dimensions / u.dimensions),
                     registry=self.registry)
 
@@ -294,10 +328,11 @@
             memodict = {}
         expr = str(self.expr)
         cgs_value = copy.deepcopy(self.cgs_value)
+        cgs_offset = copy.deepcopy(self.cgs_offset)
         dimensions = copy.deepcopy(self.dimensions)
         lut = copy.deepcopy(self.registry.lut)
         registry = UnitRegistry(lut=lut)
-        return Unit(expr, cgs_value, dimensions, registry)
+        return Unit(expr, cgs_value, cgs_offset, dimensions, registry)
 
     #
     # End unit operations
@@ -347,8 +382,8 @@
 
         """
         units_string = self._get_system_unit_string(mks_base_units)
-        cgs_value = (get_conversion_factor(self, self.get_cgs_equivalent()) /
-                     get_conversion_factor(self, units_string))
+        cgs_value = (get_conversion_factor(self, self.get_cgs_equivalent())[0] /
+                     get_conversion_factor(self, Unit(units_string))[0])
         return Unit(units_string, cgs_value=cgs_value,
                     dimensions=self.dimensions, registry=self.registry)
 
@@ -383,41 +418,20 @@
     -------
     conversion_factor : float
         `old_units / new_units`
+    offset : float or None
+        Offset between the old unit and new unit.
 
     """
-    # if args are not Unit objects, construct them
-    if not isinstance(old_units, Unit):
-        old_units = Unit(old_units)
-    if not isinstance(new_units, Unit):
-        new_units = Unit(new_units)
-
-    if not old_units.same_dimensions_as(new_units):
-        raise InvalidUnitOperation(
-            "Cannot convert from %s to %s because the dimensions do not "
-            "match: %s and %s" % (old_units, new_units, old_units.dimensions,
-                                  new_units.dimensions))
-
-    return old_units.cgs_value / new_units.cgs_value
-
-
-def convert_values(values, old_units, new_units):
-    """
-    Take data given in old units and convert to values in new units.
-
-    Parameters
-    ----------
-    values : array_like
-        The number or array we will convert.
-    old_units : str or Unit object
-        The units values are supplied in.
-    new_units : str or Unit object
-        The units values will be returned in.
-
-    Returns values in new units.
-
-    """
-    return values * get_conversion_factor(old_units, new_units)
-
+    ratio = old_units.cgs_value / new_units.cgs_value
+    if old_units.cgs_offset == 0 and new_units.cgs_offset == 0:
+        return (ratio, None)
+    else:
+        if old_units.dimensions is temperature:
+            return ratio, ratio*old_units.cgs_offset - new_units.cgs_offset
+        else:
+            raise InvalidUnitOperation(
+                "Fahrenheit and Celsius are not absoulte temperature scales "
+                "and cannot be used in compound unit symbols.")
 
 #
 # Helper functions
@@ -444,7 +458,6 @@
         return _lookup_unit_symbol(str(unit_expr), unit_symbol_lut)
 
     if isinstance(unit_expr, Number):
-        # not sure if this should be (1, 1)...
         return (float(unit_expr), sympy_one)
 
     if isinstance(unit_expr, Pow):
@@ -515,7 +528,7 @@
         for dim in dimensions.args:
             validate_dimensions(dim)
     elif isinstance(dimensions, Symbol):
-        if dimensions not in dimensions_mod.base_dimensions:
+        if dimensions not in base_dimensions:
             raise UnitParseError("Dimensionality expression contains an "
                                  "unknown symbol '%s'." % dimensions)
     elif isinstance(dimensions, Pow):

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -414,10 +414,14 @@
 
         """
         new_units = self._unit_repr_check_same(units)
-        conversion_factor = self.units.get_conversion_factor(new_units)
+        (conversion_factor, offset) = self.units.get_conversion_factor(new_units)
 
         self.units = new_units
         self *= conversion_factor
+
+        if offset:
+            np.subtract(self, offset*self.uq, self)
+
         return self
 
     def convert_to_cgs(self):
@@ -450,11 +454,14 @@
 
         """
         new_units = self._unit_repr_check_same(units)
-        conversion_factor = self.units.get_conversion_factor(new_units)
+        (conversion_factor, offset) = self.units.get_conversion_factor(new_units)
 
         new_array = self * conversion_factor
         new_array.units = new_units
 
+        if offset:
+            np.subtract(new_array, offset*new_array.uq, new_array)
+
         return new_array
 
     def in_cgs(self):
@@ -672,7 +679,8 @@
     def __iadd__(self, other):
         """ See __add__. """
         oth = sanitize_units_add(self, other, "addition")
-        return np.add(self, oth, out=self)
+        np.add(self, oth, out=self)
+        return self
 
     def __sub__(self, right_object):
         """
@@ -691,7 +699,8 @@
     def __isub__(self, other):
         """ See __sub__. """
         oth = sanitize_units_add(self, other, "subtraction")
-        return np.subtract(self, oth, out=self)
+        np.subtract(self, oth, out=self)
+        return self
 
     def __neg__(self):
         """ Negate the data. """
@@ -718,7 +727,8 @@
     def __imul__(self, other):
         """ See __mul__. """
         oth = sanitize_units_mul(self, other)
-        return np.multiply(self, oth, out=self)
+        np.multiply(self, oth, out=self)
+        return self
 
     def __div__(self, right_object):
         """
@@ -736,7 +746,8 @@
     def __idiv__(self, other):
         """ See __div__. """
         oth = sanitize_units_mul(self, other)
-        return np.divide(self, oth, out=self)
+        np.divide(self, oth, out=self)
+        return self
 
     def __truediv__(self, right_object):
         ro = sanitize_units_mul(self, right_object)
@@ -750,7 +761,8 @@
     def __itruediv__(self, other):
         """ See __div__. """
         oth = sanitize_units_mul(self, other)
-        return np.true_divide(self, oth, out=self)
+        np.true_divide(self, oth, out=self)
+        return self
 
     def __floordiv__(self, right_object):
         ro = sanitize_units_mul(self, right_object)
@@ -764,7 +776,8 @@
     def __ifloordiv__(self, other):
         """ See __div__. """
         oth = sanitize_units_mul(self, other)
-        return np.floor_divide(self, oth, out=self)
+        np.floor_divide(self, oth, out=self)
+        return self
 
     #Should these raise errors?  I need to come back and check this.
     def __or__(self, right_object):
@@ -774,7 +787,8 @@
         return YTArray(super(YTArray, self).__ror__(left_object))
 
     def __ior__(self, other):
-        return np.bitwise_or(self, other, out=self)
+        np.bitwise_or(self, other, out=self)
+        return self
 
     def __xor__(self, right_object):
         return YTArray(super(YTArray, self).__xor__(right_object))
@@ -783,7 +797,8 @@
         return YTArray(super(YTArray, self).__rxor__(left_object))
 
     def __ixor__(self, other):
-        return np.bitwise_xor(self, other, out=self)
+        np.bitwise_xor(self, other, out=self)
+        return self
 
     def __and__(self, right_object):
         return YTArray(super(YTArray, self).__and__(right_object))
@@ -792,7 +807,8 @@
         return YTArray(super(YTArray, self).__rand__(left_object))
 
     def __iand__(self, other):
-        return np.bitwise_and(self, other, out=self)
+        np.bitwise_and(self, other, out=self)
+        return self
 
     def __pow__(self, power):
         """

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/utilities/physical_constants.py
--- a/yt/utilities/physical_constants.py
+++ b/yt/utilities/physical_constants.py
@@ -6,7 +6,7 @@
 mass_hydrogen_cgs = 1.007947*amu_cgs
 
 # Velocities
-speed_of_light_cgs = YTQuantity(2.99792458e10, 'cm/s')
+speed_of_light_cgs = YTQuantity(speed_of_light_cm_per_s, 'cm/s')
 
 # Cross Sections
 # 8*pi/3 (alpha*hbar*c/(2*pi))**2
@@ -44,7 +44,9 @@
 qp = charge_proton_cgs
 mh = mp
 clight = speed_of_light_cgs
+speed_of_light = speed_of_light_cgs
 kboltz = boltzmann_constant_cgs
+kb = kboltz
 hcgs = planck_constant_cgs
 sigma_thompson = cross_section_thompson_cgs
 Na = 1 / amu_cgs

diff -r dd9c415ca94dcf54849b3760a290a783f5cd44e4 -r b58796ca19881fca5b1244e13152816ad2164200 yt/utilities/physical_ratios.py
--- a/yt/utilities/physical_ratios.py
+++ b/yt/utilities/physical_ratios.py
@@ -67,6 +67,9 @@
 sec_per_min  = 60.0
 day_per_year = 365.25
 
+# velocities
+speed_of_light_cm_per_s = 2.99792458e10
+
 # temperature / energy
 boltzmann_constant_erg_per_K = 1.3806488e-16
 erg_per_eV = 1.602176562e-12
@@ -75,6 +78,7 @@
 keV_per_K = 1.0 / K_per_keV
 keV_per_erg = 1.0 / erg_per_keV
 eV_per_erg = 1.0 / erg_per_eV
+kelvin_per_rankine = 5./9.
 
 # Solar System masses
 # Standish, E.M. (1995) "Report of the IAU WGAS Sub-Group on Numerical Standards",

Repository URL: https://bitbucket.org/yt_analysis/yt/

--

This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.



More information about the yt-svn mailing list