[yt-svn] commit/yt: 21 new changesets

commits-noreply at bitbucket.org commits-noreply at bitbucket.org
Mon May 5 19:13:27 PDT 2014


21 new commits in yt:

https://bitbucket.org/yt_analysis/yt/commits/3c68ecf615aa/
Changeset:   3c68ecf615aa
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 00:52:53
Summary:     A convenient place to put on-demand imports
Affected #:  5 files

diff -r d1046b287d10a028e36a7b1aaf0cfc9f6bc59c63 -r 3c68ecf615aa4c2eb84f2182b2bd6d5f3843c710 yt/utilities/ondemand_imports.py
--- /dev/null
+++ b/yt/utilities/ondemand_imports.py
@@ -0,0 +1,62 @@
+"""
+A set of convenient on-demand imports
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+class astropy_imports:
+    _pyfits = None
+    @property
+    def pyfits(self):
+        if self._pyfits is None:
+            try:
+                import astropy.io.fits as pyfits
+                self.log
+            except ImportError:
+                pyfits = None
+            self._pyfits = pyfits
+        return self._pyfits
+
+    _pywcs = None
+    @property
+    def pywcs(self):
+        if self._pywcs is None:
+            try:
+                import astropy.wcs as pywcs
+                self.log
+            except ImportError:
+                pywcs = None
+            self._pywcs = pywcs
+        return self._pywcs
+
+    _log = None
+    @property
+    def log(self):
+        if self._log is None:
+            try:
+                from astropy import log
+                if log.exception_logging_enabled():
+                    log.disable_exception_logging()
+            except ImportError:
+                log = None
+            self._log = log
+        return self._log
+
+    _units = None
+    @property
+    def units(self):
+        if self._units is None:
+            try:
+                from astropy import units
+            except ImportError:
+                units = None
+            self._units = units
+        return self._units
+
+ap = astropy_imports()
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt/commits/fae52935f7d5/
Changeset:   fae52935f7d5
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 17:53:04
Summary:     Fixing PEP8 issues and adding some units for AstroPy compatibility
Affected #:  5 files

diff -r 3c68ecf615aa4c2eb84f2182b2bd6d5f3843c710 -r fae52935f7d5fd63dab4f4852fa6530de5f97643 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 3c68ecf615aa4c2eb84f2182b2bd6d5f3843c710 -r fae52935f7d5fd63dab4f4852fa6530de5f97643 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 3c68ecf615aa4c2eb84f2182b2bd6d5f3843c710 -r fae52935f7d5fd63dab4f4852fa6530de5f97643 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 3c68ecf615aa4c2eb84f2182b2bd6d5f3843c710 -r fae52935f7d5fd63dab4f4852fa6530de5f97643 yt/units/unit_lookup_table.py
--- a/yt/units/unit_lookup_table.py
+++ b/yt/units/unit_lookup_table.py
@@ -59,12 +59,12 @@
     "yr":  (sec_per_year, dimensions.time),
 
     # Solar units
-    "Msun": ( mass_sun_grams, dimensions.mass),
-    "msun": ( mass_sun_grams, dimensions.mass),
-    "Rsun": ( cm_per_rsun, dimensions.length),
-    "rsun": ( cm_per_rsun, dimensions.length),
-    "Lsun": ( luminosity_sun_ergs_per_sec, dimensions.power),
-    "Tsun": ( temp_sun_kelvin, dimensions.temperature),
+    "Msun": (mass_sun_grams, dimensions.mass),
+    "msun": (mass_sun_grams, dimensions.mass),
+    "Rsun": (cm_per_rsun, dimensions.length),
+    "rsun": (cm_per_rsun, dimensions.length),
+    "Lsun": (luminosity_sun_ergs_per_sec, dimensions.power),
+    "Tsun": (temp_sun_kelvin, dimensions.temperature),
     "Zsun": (metallicity_sun, dimensions.dimensionless),
     "Mjup": (mass_jupiter_grams, dimensions.mass),
     "Mearth": (mass_earth_grams, dimensions.mass),
@@ -89,6 +89,20 @@
     "angstrom": (cm_per_ang, dimensions.length),
     "Jy": (jansky_cgs, dimensions.specific_flux),
     "beam": (1.0, dimensions.dimensionless),
+
+    # for AstroPy compatibility
+    "solMass": (mass_sun_grams, dimensions.mass),
+    "solRad": (cm_per_rsun, dimensions.length),
+    "solLum": (luminosity_sun_ergs_per_sec, dimensions.power),
+    "dyn": (1.0, dimensions.force),
+    "sr": (1.0, dimensions.solid_angle),
+    "rad": (1.0, dimensions.solid_angle),
+    "deg": (np.pi/180., dimensions.angle),
+    "Fr":  (1.0, dimensions.charge),
+    "G": (1.0, dimensions.magnetic_field),
+    "d": (1.0, dimensions.time),
+    "Angstrom": (cm_per_ang, dimensions.length),
+
 }
 
 # Add LaTeX representations for units with trivial representations.


https://bitbucket.org/yt_analysis/yt/commits/f3550b78cc8a/
Changeset:   f3550b78cc8a
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 17:53:46
Summary:     Import AstroPy from on_demand_imports
Affected #:  6 files

diff -r fae52935f7d5fd63dab4f4852fa6530de5f97643 -r f3550b78cc8a90269a1b91cf057e420bdff657bb yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r fae52935f7d5fd63dab4f4852fa6530de5f97643 -r f3550b78cc8a90269a1b91cf057e420bdff657bb yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r fae52935f7d5fd63dab4f4852fa6530de5f97643 -r f3550b78cc8a90269a1b91cf057e420bdff657bb yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r fae52935f7d5fd63dab4f4852fa6530de5f97643 -r f3550b78cc8a90269a1b91cf057e420bdff657bb yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -35,46 +35,7 @@
 from yt.utilities.decompose import \
     decompose_array, get_psize
 from yt.units.unit_lookup_table import default_unit_symbol_lut
-
-class astropy_imports:
-    _pyfits = None
-    @property
-    def pyfits(self):
-        if self._pyfits is None:
-            try:
-                import astropy.io.fits as pyfits
-                self.log
-            except ImportError:
-                pyfits = None
-            self._pyfits = pyfits
-        return self._pyfits
-
-    _pywcs = None
-    @property
-    def pywcs(self):
-        if self._pywcs is None:
-            try:
-                import astropy.wcs as pywcs
-                self.log
-            except ImportError:
-                pywcs = None
-            self._pywcs = pywcs
-        return self._pywcs
-
-    _log = None
-    @property
-    def log(self):
-        if self._log is None:
-            try:
-                from astropy import log
-                if log.exception_logging_enabled():
-                    log.disable_exception_logging()
-            except ImportError:
-                log = None
-            self._log = log
-        return self._log
-
-ap = astropy_imports()
+from yt.utilities.on_demand_imports import ap
 
 known_units = dict([(unit.lower(),unit) for unit in default_unit_symbol_lut])
 axes_prefixes = ["RA","DEC","V","ENER","FREQ"]

diff -r fae52935f7d5fd63dab4f4852fa6530de5f97643 -r f3550b78cc8a90269a1b91cf057e420bdff657bb yt/utilities/fits_image.py
--- a/yt/utilities/fits_image.py
+++ b/yt/utilities/fits_image.py
@@ -14,7 +14,7 @@
 from yt.funcs import mylog, iterable, fix_axis, ensure_list
 from yt.visualization.fixed_resolution import FixedResolutionBuffer
 from yt.data_objects.construction_data_containers import YTCoveringGridBase
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 from yt.units.yt_array import YTQuantity
 
 pyfits = ap.pyfits


https://bitbucket.org/yt_analysis/yt/commits/0a7e50c7f725/
Changeset:   0a7e50c7f725
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 17:53:55
Summary:     Changed the name
Affected #:  6 files

diff -r f3550b78cc8a90269a1b91cf057e420bdff657bb -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r f3550b78cc8a90269a1b91cf057e420bdff657bb -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r f3550b78cc8a90269a1b91cf057e420bdff657bb -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r f3550b78cc8a90269a1b91cf057e420bdff657bb -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 yt/utilities/on_demand_imports.py
--- /dev/null
+++ b/yt/utilities/on_demand_imports.py
@@ -0,0 +1,62 @@
+"""
+A set of convenient on-demand imports
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+class astropy_imports:
+    _pyfits = None
+    @property
+    def pyfits(self):
+        if self._pyfits is None:
+            try:
+                import astropy.io.fits as pyfits
+                self.log
+            except ImportError:
+                pyfits = None
+            self._pyfits = pyfits
+        return self._pyfits
+
+    _pywcs = None
+    @property
+    def pywcs(self):
+        if self._pywcs is None:
+            try:
+                import astropy.wcs as pywcs
+                self.log
+            except ImportError:
+                pywcs = None
+            self._pywcs = pywcs
+        return self._pywcs
+
+    _log = None
+    @property
+    def log(self):
+        if self._log is None:
+            try:
+                from astropy import log
+                if log.exception_logging_enabled():
+                    log.disable_exception_logging()
+            except ImportError:
+                log = None
+            self._log = log
+        return self._log
+
+    _units = None
+    @property
+    def units(self):
+        if self._units is None:
+            try:
+                from astropy import units
+            except ImportError:
+                units = None
+            self._units = units
+        return self._units
+
+ap = astropy_imports()
\ No newline at end of file

diff -r f3550b78cc8a90269a1b91cf057e420bdff657bb -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 yt/utilities/ondemand_imports.py
--- a/yt/utilities/ondemand_imports.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""
-A set of convenient on-demand imports
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-class astropy_imports:
-    _pyfits = None
-    @property
-    def pyfits(self):
-        if self._pyfits is None:
-            try:
-                import astropy.io.fits as pyfits
-                self.log
-            except ImportError:
-                pyfits = None
-            self._pyfits = pyfits
-        return self._pyfits
-
-    _pywcs = None
-    @property
-    def pywcs(self):
-        if self._pywcs is None:
-            try:
-                import astropy.wcs as pywcs
-                self.log
-            except ImportError:
-                pywcs = None
-            self._pywcs = pywcs
-        return self._pywcs
-
-    _log = None
-    @property
-    def log(self):
-        if self._log is None:
-            try:
-                from astropy import log
-                if log.exception_logging_enabled():
-                    log.disable_exception_logging()
-            except ImportError:
-                log = None
-            self._log = log
-        return self._log
-
-    _units = None
-    @property
-    def units(self):
-        if self._units is None:
-            try:
-                from astropy import units
-            except ImportError:
-                units = None
-            self._units = units
-        return self._units
-
-ap = astropy_imports()
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt/commits/387c00196366/
Changeset:   387c00196366
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 17:57:59
Summary:     Replacing AstroPy import location
Affected #:  6 files

diff -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 -r 387c001963667fa7faf8c307d1251b61f2049865 yt/analysis_modules/photon_simulator/photon_simulator.py
--- a/yt/analysis_modules/photon_simulator/photon_simulator.py
+++ b/yt/analysis_modules/photon_simulator/photon_simulator.py
@@ -21,20 +21,17 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from numpy.testing import assert_allclose
 from yt.funcs import *
-from yt.utilities.physical_constants import clight, \
-     cm_per_km, erg_per_keV
+from yt.utilities.physical_constants import clight
 from yt.utilities.cosmology import Cosmology
 from yt.utilities.orientation import Orientation
-from yt.utilities.definitions import mpc_conversion
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
      communication_system, parallel_root_only, get_mpi_type, \
-     op_names, parallel_capable
+     parallel_capable
 from yt import units
 from yt.units.yt_array import YTQuantity
 import h5py
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 pyfits = ap.pyfits
 pywcs = ap.pywcs
 
@@ -471,7 +468,9 @@
                         "but not both!")
         
         if sky_center is None:
-             sky_center = YTArray([30.,45.], "degree")
+            sky_center = YTArray([30.,45.], "degree")
+        else:
+            sky_center = YTArray(sky_center, "degree")
 
         dx = self.photons["dx"].ndarray_view()
         nx = self.parameters["Dimension"]
@@ -897,39 +896,42 @@
         tbhdu = pyfits.new_table(coldefs)
         tbhdu.update_ext_name("EVENTS")
 
-        tbhdu.header.update("MTYPE1", "sky")
-        tbhdu.header.update("MFORM1", "x,y")        
-        tbhdu.header.update("MTYPE2", "EQPOS")
-        tbhdu.header.update("MFORM2", "RA,DEC")
-        tbhdu.header.update("TCTYP2", "RA---TAN")
-        tbhdu.header.update("TCTYP3", "DEC--TAN")
-        tbhdu.header.update("TCRVL2", float(self.parameters["sky_center"][0]))
-        tbhdu.header.update("TCRVL3", float(self.parameters["sky_center"][1]))
-        tbhdu.header.update("TCDLT2", -float(self.parameters["dtheta"]))
-        tbhdu.header.update("TCDLT3", float(self.parameters["dtheta"]))
-        tbhdu.header.update("TCRPX2", self.parameters["pix_center"][0])
-        tbhdu.header.update("TCRPX3", self.parameters["pix_center"][1])
-        tbhdu.header.update("TLMIN2", 0.5)
-        tbhdu.header.update("TLMIN3", 0.5)
-        tbhdu.header.update("TLMAX2", 2.*self.parameters["pix_center"][0]-0.5)
-        tbhdu.header.update("TLMAX3", 2.*self.parameters["pix_center"][1]-0.5)
-        tbhdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
-        tbhdu.header.update("AREA", float(self.parameters["Area"]))
-        tbhdu.header.update("D_A", float(self.parameters["AngularDiameterDistance"]))
-        tbhdu.header.update("REDSHIFT", self.parameters["Redshift"])
-        tbhdu.header.update("HDUVERS", "1.1.0")
-        tbhdu.header.update("RADECSYS", "FK5")
-        tbhdu.header.update("EQUINOX", 2000.0)
+        tbhdu.header["MTYPE1"] = "sky"
+        tbhdu.header["MFORM1"] = "x,y"
+        tbhdu.header["MTYPE2"] = "EQPOS"
+        tbhdu.header["MFORM2"] = "RA,DEC"
+        tbhdu.header["TCTYP2"] = "RA---TAN"
+        tbhdu.header["TCTYP3"] = "DEC--TAN"
+        tbhdu.header["TCRVL2"] = float(self.parameters["sky_center"][0])
+        tbhdu.header["TCRVL3"] = float(self.parameters["sky_center"][1])
+        tbhdu.header["TCDLT2"] = -float(self.parameters["dtheta"])
+        tbhdu.header["TCDLT3"] = float(self.parameters["dtheta"])
+        tbhdu.header["TCRPX2"] = self.parameters["pix_center"][0]
+        tbhdu.header["TCRPX3"] = self.parameters["pix_center"][1]
+        tbhdu.header["TLMIN2"] = 0.5
+        tbhdu.header["TLMIN3"] = 0.5
+        tbhdu.header["TLMAX2"] = 2.*self.parameters["pix_center"][0]-0.5
+        tbhdu.header["TLMAX3"] = 2.*self.parameters["pix_center"][1]-0.5
+        tbhdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
+        if isinstance(self.parameters["Area"], basestring):
+            tbhdu.header["AREA"] = self.parameters["Area"]
+        else:
+            tbhdu.header["AREA"] = float(self.parameters["Area"])
+        tbhdu.header["D_A"] = float(self.parameters["AngularDiameterDistance"])
+        tbhdu.header["REDSHIFT"] = self.parameters["Redshift"]
+        tbhdu.header["HDUVERS"] = "1.1.0"
+        tbhdu.header["RADECSYS"] = "FK5"
+        tbhdu.header["EQUINOX"] = 2000.0
         if "RMF" in self.parameters:
-            tbhdu.header.update("RMF", self.parameters["RMF"])
+            tbhdu.header["RMF"] = self.parameters["RMF"]
         if "ARF" in self.parameters:
-            tbhdu.header.update("ARF", self.parameters["ARF"])
+            tbhdu.header["ARF"] = self.parameters["ARF"]
         if "ChannelType" in self.parameters:
-            tbhdu.header.update("CHANTYPE", self.parameters["ChannelType"])
+            tbhdu.header["CHANTYPE"] = self.parameters["ChannelType"]
         if "Telescope" in self.parameters:
-            tbhdu.header.update("TELESCOP", self.parameters["Telescope"])
+            tbhdu.header["TELESCOP"] = self.parameters["Telescope"]
         if "Instrument" in self.parameters:
-            tbhdu.header.update("INSTRUME", self.parameters["Instrument"])
+            tbhdu.header["INSTRUME"] = self.parameters["Instrument"]
             
         tbhdu.writeto(fitsfile, clobber=clobber)
 
@@ -978,15 +980,15 @@
         tbhdu = pyfits.new_table(coldefs)
         tbhdu.update_ext_name("PHLIST")
 
-        tbhdu.header.update("HDUCLASS", "HEASARC/SIMPUT")
-        tbhdu.header.update("HDUCLAS1", "PHOTONS")
-        tbhdu.header.update("HDUVERS", "1.1.0")
-        tbhdu.header.update("EXTVER", 1)
-        tbhdu.header.update("REFRA", 0.0)
-        tbhdu.header.update("REFDEC", 0.0)
-        tbhdu.header.update("TUNIT1", "keV")
-        tbhdu.header.update("TUNIT2", "deg")
-        tbhdu.header.update("TUNIT3", "deg")                
+        tbhdu.header["HDUCLASS"] = "HEASARC/SIMPUT"
+        tbhdu.header["HDUCLAS1"] = "PHOTONS"
+        tbhdu.header["HDUVERS"] = "1.1.0"
+        tbhdu.header["EXTVER"] = 1
+        tbhdu.header["REFRA"] = 0.0
+        tbhdu.header["REFDEC"] = 0.0
+        tbhdu.header["TUNIT1"] = "keV"
+        tbhdu.header["TUNIT2"] = "deg"
+        tbhdu.header["TUNIT3"] = "deg"
 
         phfile = prefix+"_phlist.fits"
 
@@ -1006,17 +1008,17 @@
         wrhdu = pyfits.new_table(coldefs)
         wrhdu.update_ext_name("SRC_CAT")
                                 
-        wrhdu.header.update("HDUCLASS", "HEASARC")
-        wrhdu.header.update("HDUCLAS1", "SIMPUT")
-        wrhdu.header.update("HDUCLAS2", "SRC_CAT")        
-        wrhdu.header.update("HDUVERS", "1.1.0")
-        wrhdu.header.update("RADECSYS", "FK5")
-        wrhdu.header.update("EQUINOX", 2000.0)
-        wrhdu.header.update("TUNIT2", "deg")
-        wrhdu.header.update("TUNIT3", "deg")
-        wrhdu.header.update("TUNIT4", "keV")
-        wrhdu.header.update("TUNIT5", "keV")
-        wrhdu.header.update("TUNIT6", "erg/s/cm**2")
+        wrhdu.header["HDUCLASS"] = "HEASARC"
+        wrhdu.header["HDUCLAS1"] = "SIMPUT"
+        wrhdu.header["HDUCLAS2"] = "SRC_CAT"
+        wrhdu.header["HDUVERS"] = "1.1.0"
+        wrhdu.header["RADECSYS"] = "FK5"
+        wrhdu.header["EQUINOX"] = 2000.0
+        wrhdu.header["TUNIT2"] = "deg"
+        wrhdu.header["TUNIT3"] = "deg"
+        wrhdu.header["TUNIT4"] = "keV"
+        wrhdu.header["TUNIT5"] = "keV"
+        wrhdu.header["TUNIT6"] = "erg/s/cm**2"
 
         simputfile = prefix+"_simput.fits"
                 
@@ -1100,19 +1102,19 @@
         
         hdu = pyfits.PrimaryHDU(H.T)
         
-        hdu.header.update("MTYPE1", "EQPOS")
-        hdu.header.update("MFORM1", "RA,DEC")
-        hdu.header.update("CTYPE1", "RA---TAN")
-        hdu.header.update("CTYPE2", "DEC--TAN")
-        hdu.header.update("CRPIX1", 0.5*(nx+1))
-        hdu.header.update("CRPIX2", 0.5*(nx+1))                
-        hdu.header.update("CRVAL1", float(self.parameters["sky_center"][0]))
-        hdu.header.update("CRVAL2", float(self.parameters["sky_center"][1]))
-        hdu.header.update("CUNIT1", "deg")
-        hdu.header.update("CUNIT2", "deg")
-        hdu.header.update("CDELT1", -float(self.parameters["dtheta"]))
-        hdu.header.update("CDELT2", float(self.parameters["dtheta"]))
-        hdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
+        hdu.header["MTYPE1"] = "EQPOS"
+        hdu.header["MFORM1"] = "RA,DEC"
+        hdu.header["CTYPE1"] = "RA---TAN"
+        hdu.header["CTYPE2"] = "DEC--TAN"
+        hdu.header["CRPIX1"] = 0.5*(nx+1)
+        hdu.header["CRPIX2"] = 0.5*(nx+1)
+        hdu.header["CRVAL1"] = float(self.parameters["sky_center"][0])
+        hdu.header["CRVAL2"] = float(self.parameters["sky_center"][1])
+        hdu.header["CUNIT1"] = "deg"
+        hdu.header["CUNIT2"] = "deg"
+        hdu.header["CDELT1"] = -float(self.parameters["dtheta"])
+        hdu.header["CDELT2"] = float(self.parameters["dtheta"])
+        hdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
         
         hdu.writeto(imagefile, clobber=clobber)
                                     
@@ -1183,41 +1185,41 @@
         tbhdu.update_ext_name("SPECTRUM")
 
         if not energy_bins:
-            tbhdu.header.update("DETCHANS", spec.shape[0])
-            tbhdu.header.update("TOTCTS", spec.sum())
-            tbhdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
-            tbhdu.header.update("LIVETIME", float(self.parameters["ExposureTime"]))
-            tbhdu.header.update("CONTENT", spectype)
-            tbhdu.header.update("HDUCLASS", "OGIP")
-            tbhdu.header.update("HDUCLAS1", "SPECTRUM")
-            tbhdu.header.update("HDUCLAS2", "TOTAL")
-            tbhdu.header.update("HDUCLAS3", "TYPE:I")
-            tbhdu.header.update("HDUCLAS4", "COUNT")
-            tbhdu.header.update("HDUVERS", "1.1.0")
-            tbhdu.header.update("HDUVERS1", "1.1.0")
-            tbhdu.header.update("CHANTYPE", spectype)
-            tbhdu.header.update("BACKFILE", "none")
-            tbhdu.header.update("CORRFILE", "none")
-            tbhdu.header.update("POISSERR", True)
+            tbhdu.header["DETCHANS"] = spec.shape[0]
+            tbhdu.header["TOTCTS"] = spec.sum()
+            tbhdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
+            tbhdu.header["LIVETIME"] = float(self.parameters["ExposureTime"])
+            tbhdu.header["CONTENT"] = spectype
+            tbhdu.header["HDUCLASS"] = "OGIP"
+            tbhdu.header["HDUCLAS1"] = "SPECTRUM"
+            tbhdu.header["HDUCLAS2"] = "TOTAL"
+            tbhdu.header["HDUCLAS3"] = "TYPE:I"
+            tbhdu.header["HDUCLAS4"] = "COUNT"
+            tbhdu.header["HDUVERS"] = "1.1.0"
+            tbhdu.header["HDUVERS1"] = "1.1.0"
+            tbhdu.header["CHANTYPE"] = spectype
+            tbhdu.header["BACKFILE"] = "none"
+            tbhdu.header["CORRFILE"] = "none"
+            tbhdu.header["POISSERR"] = True
             if self.parameters.has_key("RMF"):
-                 tbhdu.header.update("RESPFILE", self.parameters["RMF"])
+                 tbhdu.header["RESPFILE"] = self.parameters["RMF"]
             else:
-                 tbhdu.header.update("RESPFILE", "none")
+                 tbhdu.header["RESPFILE"] = "none"
             if self.parameters.has_key("ARF"):
-                tbhdu.header.update("ANCRFILE", self.parameters["ARF"])
+                tbhdu.header["ANCRFILE"] = self.parameters["ARF"]
             else:        
-                tbhdu.header.update("ANCRFILE", "none")
+                tbhdu.header["ANCRFILE"] = "none"
             if self.parameters.has_key("Telescope"):
-                tbhdu.header.update("TELESCOP", self.parameters["Telescope"])
+                tbhdu.header["TELESCOP"] = self.parameters["Telescope"]
             else:
-                tbhdu.header.update("TELESCOP", "none")
+                tbhdu.header["TELESCOP"] = "none"
             if self.parameters.has_key("Instrument"):
-                tbhdu.header.update("INSTRUME", self.parameters["Instrument"])
+                tbhdu.header["INSTRUME"] = self.parameters["Instrument"]
             else:
-                tbhdu.header.update("INSTRUME", "none")
-            tbhdu.header.update("AREASCAL", 1.0)
-            tbhdu.header.update("CORRSCAL", 0.0)
-            tbhdu.header.update("BACKSCAL", 1.0)
+                tbhdu.header["INSTRUME"] = "none"
+            tbhdu.header["AREASCAL"] = 1.0
+            tbhdu.header["CORRSCAL"] = 0.0
+            tbhdu.header["BACKSCAL"] = 1.0
                                 
         hdulist = pyfits.HDUList([pyfits.PrimaryHDU(), tbhdu])
         

diff -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 -r 387c001963667fa7faf8c307d1251b61f2049865 yt/analysis_modules/photon_simulator/spectral_models.py
--- a/yt/analysis_modules/photon_simulator/spectral_models.py
+++ b/yt/analysis_modules/photon_simulator/spectral_models.py
@@ -28,7 +28,7 @@
     from scipy import stats        
 except ImportError:
     pass
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 pyfits = ap.pyfits
 
 from yt.utilities.physical_constants import hcgs, clight, erg_per_keV, amu_cgs

diff -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 -r 387c001963667fa7faf8c307d1251b61f2049865 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 -r 387c001963667fa7faf8c307d1251b61f2049865 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.frontends.fits.data_structures import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 0a7e50c7f7254c76640ba1c60add08980525dbf4 -r 387c001963667fa7faf8c307d1251b61f2049865 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config


https://bitbucket.org/yt_analysis/yt/commits/c441519fc0fe/
Changeset:   c441519fc0fe
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 18:00:01
Summary:     Changed AstroPy import location
Affected #:  4 files

diff -r 387c001963667fa7faf8c307d1251b61f2049865 -r c441519fc0fe8104a201d6343d842804780947df yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 387c001963667fa7faf8c307d1251b61f2049865 -r c441519fc0fe8104a201d6343d842804780947df yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ b/yt/analysis_modules/ppv_cube/ppv_cube.py
@@ -11,7 +11,7 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 from yt.utilities.orientation import Orientation
 from yt.utilities.fits_image import FITSImageBuffer
 from yt.visualization.volume_rendering.camera import off_axis_projection

diff -r 387c001963667fa7faf8c307d1251b61f2049865 -r c441519fc0fe8104a201d6343d842804780947df yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config


https://bitbucket.org/yt_analysis/yt/commits/7817fa2d32c3/
Changeset:   7817fa2d32c3
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-19 18:00:40
Summary:     Round-trip AstroPy unit conversions.
Affected #:  5 files

diff -r c441519fc0fe8104a201d6343d842804780947df -r 7817fa2d32c33f3c46322b87c79a3b0764de695b yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r c441519fc0fe8104a201d6343d842804780947df -r 7817fa2d32c33f3c46322b87c79a3b0764de695b yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r c441519fc0fe8104a201d6343d842804780947df -r 7817fa2d32c33f3c46322b87c79a3b0764de695b yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -35,6 +35,8 @@
     YTUnitOperationError, YTUnitConversionError, \
     YTUfuncUnitError
 from numbers import Number as numeric_type
+from yt.utilities.on_demand_imports import ap
+from sympy import Rational
 
 # redefine this here to avoid a circular import from yt.funcs
 def iterable(obj):
@@ -258,6 +260,16 @@
             else:
                 input_array.units = Unit(input_units, registry=registry)
             return input_array
+        elif isinstance(input_array, ap.units.quantity.Quantity):
+            # Converting from AstroPy Quantity
+            ap_units = input_array.unit
+            ap_units = "*".join(["%s**(%s)" % (base.to_string(), Rational(power))
+                                 for base, power in zip(ap_units.bases,
+                                                        ap_units.powers)])
+            if isinstance(input_array.value, np.ndarray):
+                return YTArray(input_array.value, ap_units)
+            else:
+                return YTQuantity(input_array.value, ap_units)
         elif isinstance(input_array, np.ndarray):
             pass
         elif iterable(input_array):
@@ -421,6 +433,17 @@
 
         """
         return np.array(self)
+
+    def to_astropy(self, alt_unit=None, **kwargs):
+        """
+        Creates a new AstroPy quantity with the same unit information.
+        """
+        if alt_unit is None:
+            units = str(self.units)
+        else:
+            units = alt_unit
+        return self.value*ap.units.Unit(units, **kwargs)
+
     #
     # End unit conversion methods
     #


https://bitbucket.org/yt_analysis/yt/commits/b620f64b5444/
Changeset:   b620f64b5444
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-20 01:02:30
Summary:     Make sure we don't throw an error if AstroPy isn't installed.
Affected #:  5 files

diff -r 7817fa2d32c33f3c46322b87c79a3b0764de695b -r b620f64b54441fb040a8e406b9b7c43e38b507bc yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 7817fa2d32c33f3c46322b87c79a3b0764de695b -r b620f64b54441fb040a8e406b9b7c43e38b507bc yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.utilities.on_demand_imports import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 7817fa2d32c33f3c46322b87c79a3b0764de695b -r b620f64b54441fb040a8e406b9b7c43e38b507bc yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 7817fa2d32c33f3c46322b87c79a3b0764de695b -r b620f64b54441fb040a8e406b9b7c43e38b507bc yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -249,6 +249,17 @@
                     "Perhaps you meant to do something like this instead: \n"
                     "ds.arr(%s, \"%s\")" % (input_array, input_units)
                     )
+        if ap.units is not None:
+            if isinstance(input_array, ap.units.quantity.Quantity):
+                # Converting from AstroPy Quantity
+                ap_units = input_array.unit
+                ap_units = "*".join(["%s**(%s)" % (base.to_string(), Rational(power))
+                                     for base, power in zip(ap_units.bases,
+                                                            ap_units.powers)])
+                if isinstance(input_array.value, np.ndarray):
+                    return YTArray(input_array.value, ap_units)
+                else:
+                    return YTQuantity(input_array.value, ap_units)
         if isinstance(input_array, YTArray):
             if input_units is None:
                 if registry is None:
@@ -260,16 +271,6 @@
             else:
                 input_array.units = Unit(input_units, registry=registry)
             return input_array
-        elif isinstance(input_array, ap.units.quantity.Quantity):
-            # Converting from AstroPy Quantity
-            ap_units = input_array.unit
-            ap_units = "*".join(["%s**(%s)" % (base.to_string(), Rational(power))
-                                 for base, power in zip(ap_units.bases,
-                                                        ap_units.powers)])
-            if isinstance(input_array.value, np.ndarray):
-                return YTArray(input_array.value, ap_units)
-            else:
-                return YTQuantity(input_array.value, ap_units)
         elif isinstance(input_array, np.ndarray):
             pass
         elif iterable(input_array):


https://bitbucket.org/yt_analysis/yt/commits/8d663c4c250e/
Changeset:   8d663c4c250e
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-20 02:44:16
Summary:     Working around some AstroPy issues
Affected #:  5 files

diff -r b620f64b54441fb040a8e406b9b7c43e38b507bc -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r b620f64b54441fb040a8e406b9b7c43e38b507bc -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.utilities.on_demand_imports import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r b620f64b54441fb040a8e406b9b7c43e38b507bc -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r b620f64b54441fb040a8e406b9b7c43e38b507bc -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -252,10 +252,15 @@
         if ap.units is not None:
             if isinstance(input_array, ap.units.quantity.Quantity):
                 # Converting from AstroPy Quantity
-                ap_units = input_array.unit
-                ap_units = "*".join(["%s**(%s)" % (base.to_string(), Rational(power))
-                                     for base, power in zip(ap_units.bases,
-                                                            ap_units.powers)])
+                u = input_array.unit
+                ap_units = []
+                for base, power in zip(u.bases, u.powers):
+                    unit_str = base.to_string()
+                    # we have to do this because AstroPy is silly and defines
+                    # hour as "h"
+                    if unit_str == "h": unit_str = "hr"
+                    ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
+                ap_units = "*".join(ap_units)
                 if isinstance(input_array.value, np.ndarray):
                     return YTArray(input_array.value, ap_units)
                 else:


https://bitbucket.org/yt_analysis/yt/commits/641a89ed8ca7/
Changeset:   641a89ed8ca7
Branch:      yt-3.0
User:        jzuhone
Date:        2014-04-20 06:54:58
Summary:     Tests for AstroPy unit conversions
Affected #:  5 files

diff -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 -r 641a89ed8ca7669c2a4ad9d50f37a583617e8751 yt/analysis_modules/ppv_cube/api.py
--- a/yt/analysis_modules/ppv_cube/api.py
+++ /dev/null
@@ -1,12 +0,0 @@
-"""
-API for ppv_cube
-"""
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-from ppv_cube import PPVCube

diff -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 -r 641a89ed8ca7669c2a4ad9d50f37a583617e8751 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ /dev/null
@@ -1,167 +0,0 @@
-"""
-Generating PPV FITS cubes
-"""
-
-#-----------------------------------------------------------------------------
-# Copyright (c) 2013, yt Development Team.
-#
-# Distributed under the terms of the Modified BSD License.
-#
-# The full license is in the file COPYING.txt, distributed with this software.
-#-----------------------------------------------------------------------------
-
-import numpy as np
-from yt.utilities.on_demand_imports import ap
-from yt.utilities.orientation import Orientation
-from yt.utilities.fits_image import FITSImageBuffer
-from yt.visualization.volume_rendering.camera import off_axis_projection
-from yt.funcs import get_pbar
-
-def create_intensity(vmin, vmax, ifield):
-    def _intensity(field, data):
-        idxs = np.logical_and(data["v_los"] >= vmin, data["v_los"] < vmax)
-        f = np.zeros(data[ifield].shape)
-        f[idxs] = data[ifield][idxs]
-        return f
-    return _intensity
-
-def create_vlos(z_hat):
-    def _v_los(field, data):
-        vz = data["velocity_x"]*z_hat[0] + \
-             data["velocity_y"]*z_hat[1] + \
-             data["velocity_z"]*z_hat[2]
-        return -vz
-    return _v_los
-
-class PPVCube(object):
-    def __init__(self, ds, normal, field, width=(1.0,"unitary"),
-                 dims=(100,100,100), velocity_bounds=None):
-        r""" Initialize a PPVCube object.
-
-        Parameters
-        ----------
-        ds : dataset
-            The dataset.
-        normal : array_like
-            The normal vector along with to make the projections.
-        field : string
-            The field to project.
-        width : float or tuple, optional
-            The width of the projection in length units. Specify a float
-            for code_length units or a tuple (value, units).
-        dims : tuple, optional
-            A 3-tuple of dimensions (nx,ny,nv) for the cube.
-        velocity_bounds : tuple, optional
-            A 3-tuple of (vmin, vmax, units) for the velocity bounds to
-            integrate over. If None, the largest velocity of the
-            dataset will be used, e.g. velocity_bounds = (-v.max(), v.max())
-
-        Examples
-        --------
-        >>> i = 60*np.pi/180.
-        >>> L = [0.0,np.sin(i),np.cos(i)]
-        >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"),
-        ...                velocity_bounds=(-5.,4.,"km/s"))
-        """
-        self.ds = ds
-        self.field = field
-        self.width = width
-
-        self.nx = dims[0]
-        self.ny = dims[1]
-        self.nv = dims[2]
-
-        normal = np.array(normal)
-        normal /= np.sqrt(np.dot(normal, normal))
-        vecs = np.identity(3)
-        t = np.cross(normal, vecs).sum(axis=1)
-        ax = t.argmax()
-        north = np.cross(normal, vecs[ax,:]).ravel()
-        orient = Orientation(normal, north_vector=north)
-
-        dd = ds.all_data()
-
-        fd = dd._determine_fields(field)[0]
-
-        self.field_units = ds._get_field_info(fd).units
-
-        if velocity_bounds is None:
-            vmin, vmax = dd.quantities.extrema("velocity_magnitude")
-            self.v_bnd = -vmax, vmax
-        else:
-            self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]),
-                     ds.quan(velocity_bounds[1], velocity_bounds[2]))
-
-        vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv+1)
-
-        _vlos = create_vlos(orient.unit_vectors[2])
-        ds.field_info.add_field(("gas","v_los"), function=_vlos, units="cm/s")
-
-        self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.field_units)
-        pbar = get_pbar("Generating cube.", self.nv)
-        for i in xrange(self.nv):
-            v1 = vbins[i]
-            v2 = vbins[i+1]
-            _intensity = create_intensity(v1, v2, field)
-            ds.field_info.add_field(("gas","intensity"),
-                                    function=_intensity, units=self.field_units)
-            prj = off_axis_projection(ds, ds.domain_center, normal, width,
-                                      (self.nx, self.ny), "intensity")
-            self.data[:,:,i] = prj[:,:]
-            ds.field_info.pop(("gas","intensity"))
-            pbar.update(i)
-
-        pbar.finish()
-
-    def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
-        r""" Write the PPVCube to a FITS file.
-
-        Parameters
-        ----------
-        filename : string
-            The name of the file to write.
-        clobber : boolean
-            Whether or not to clobber an existing file with the same name.
-        length_unit : tuple, optional
-            The length that corresponds to the width of the projection in
-            (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
-        sky_center : tuple, optional
-            The (RA, Dec) coordinate in degrees of the central pixel if
-            *length_unit* is 'deg'.
-
-        Examples
-        --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
-        """
-        if length_unit[1] == "deg":
-            center = sky_center
-            types = ["RA---SIN","DEC--SIN"]
-        else:
-            center = [0.0,0.0]
-            types = ["LINEAR","LINEAR"]
-
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
-
-        dx = length_unit[0]/self.nx
-        dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
-
-        if length_unit[1] == "deg":
-            dx *= -1.
-
-        w = ap.pywcs.WCS(naxis=3)
-        w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
-        w.wcs.cdelt = [dx,dy,dv]
-        w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
-        w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
-
-        fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)
-        fib[0].header["bunit"] = self.field_units
-        fib[0].header["btype"] = self.field
-
-        fib.writeto(filename, clobber=clobber)

diff -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 -r 641a89ed8ca7669c2a4ad9d50f37a583617e8751 yt/analysis_modules/ppv_cube/setup.py
--- a/yt/analysis_modules/ppv_cube/setup.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-import setuptools
-import os
-import sys
-import os.path
-
-
-def configuration(parent_package='', top_path=None):
-    from numpy.distutils.misc_util import Configuration
-    config = Configuration('ppv_cube', parent_package, top_path)
-    #config.add_subpackage("tests")
-    config.make_config_py()  # installs __config__.py
-    #config.make_svn_version_py()
-    return config

diff -r 8d663c4c250eae6e4807ee565bc81e32b849dd37 -r 641a89ed8ca7669c2a4ad9d50f37a583617e8751 yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -26,7 +26,7 @@
 from yt.units.unit_object import Unit
 from yt.utilities.exceptions import \
     YTUnitOperationError, YTUfuncUnitError
-from yt.testing import fake_random_pf
+from yt.testing import fake_random_pf, requires_module
 from yt.funcs import fix_length
 import numpy as np
 import copy
@@ -592,3 +592,24 @@
 
     yield assert_array_equal, arr.value, np.array(arr)
     yield assert_array_equal, arr.v, np.array(arr)
+
+ at requires_module("astropy")
+def test_astropy():
+    from yt.utilities.on_demand_imports import ap
+
+    ap_arr = np.arange(10)*ap.units.km/ap.units.hr
+    yt_arr = YTArray(np.arange(10), "km/hr")
+
+    ap_quan = 10.*ap.units.Msun**0.5/(ap.units.kpc**3)
+    yt_quan = YTQuantity(10.,"sqrt(Msun)/kpc**3")
+
+    yield assert_array_equal, ap_arr, yt_arr.to_astropy()
+    yield assert_array_equal, yt_arr, YTArray(ap_arr)
+
+    yield assert_equal, ap_quan, yt_quan.to_astropy()
+    yield assert_equal, yt_quan, YTQuantity(ap_quan)
+
+    yield assert_array_equal, yt_arr, YTArray(yt_arr.to_astropy())
+    yield assert_equal, yt_quan, YTQuantity(yt_quan.to_astropy())
+
+


https://bitbucket.org/yt_analysis/yt/commits/2616c3135890/
Changeset:   2616c3135890
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 05:08:32
Summary:     Merge
Affected #:  9 files

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/analysis_modules/photon_simulator/photon_simulator.py
--- a/yt/analysis_modules/photon_simulator/photon_simulator.py
+++ b/yt/analysis_modules/photon_simulator/photon_simulator.py
@@ -21,20 +21,17 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from numpy.testing import assert_allclose
 from yt.funcs import *
-from yt.utilities.physical_constants import clight, \
-     cm_per_km, erg_per_keV
+from yt.utilities.physical_constants import clight
 from yt.utilities.cosmology import Cosmology
 from yt.utilities.orientation import Orientation
-from yt.utilities.definitions import mpc_conversion
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
      communication_system, parallel_root_only, get_mpi_type, \
-     op_names, parallel_capable
+     parallel_capable
 from yt import units
 from yt.units.yt_array import YTQuantity
 import h5py
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 pyfits = ap.pyfits
 pywcs = ap.pywcs
 
@@ -471,7 +468,9 @@
                         "but not both!")
         
         if sky_center is None:
-             sky_center = YTArray([30.,45.], "degree")
+            sky_center = YTArray([30.,45.], "degree")
+        else:
+            sky_center = YTArray(sky_center, "degree")
 
         dx = self.photons["dx"].ndarray_view()
         nx = self.parameters["Dimension"]
@@ -897,39 +896,42 @@
         tbhdu = pyfits.new_table(coldefs)
         tbhdu.update_ext_name("EVENTS")
 
-        tbhdu.header.update("MTYPE1", "sky")
-        tbhdu.header.update("MFORM1", "x,y")        
-        tbhdu.header.update("MTYPE2", "EQPOS")
-        tbhdu.header.update("MFORM2", "RA,DEC")
-        tbhdu.header.update("TCTYP2", "RA---TAN")
-        tbhdu.header.update("TCTYP3", "DEC--TAN")
-        tbhdu.header.update("TCRVL2", float(self.parameters["sky_center"][0]))
-        tbhdu.header.update("TCRVL3", float(self.parameters["sky_center"][1]))
-        tbhdu.header.update("TCDLT2", -float(self.parameters["dtheta"]))
-        tbhdu.header.update("TCDLT3", float(self.parameters["dtheta"]))
-        tbhdu.header.update("TCRPX2", self.parameters["pix_center"][0])
-        tbhdu.header.update("TCRPX3", self.parameters["pix_center"][1])
-        tbhdu.header.update("TLMIN2", 0.5)
-        tbhdu.header.update("TLMIN3", 0.5)
-        tbhdu.header.update("TLMAX2", 2.*self.parameters["pix_center"][0]-0.5)
-        tbhdu.header.update("TLMAX3", 2.*self.parameters["pix_center"][1]-0.5)
-        tbhdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
-        tbhdu.header.update("AREA", float(self.parameters["Area"]))
-        tbhdu.header.update("D_A", float(self.parameters["AngularDiameterDistance"]))
-        tbhdu.header.update("REDSHIFT", self.parameters["Redshift"])
-        tbhdu.header.update("HDUVERS", "1.1.0")
-        tbhdu.header.update("RADECSYS", "FK5")
-        tbhdu.header.update("EQUINOX", 2000.0)
+        tbhdu.header["MTYPE1"] = "sky"
+        tbhdu.header["MFORM1"] = "x,y"
+        tbhdu.header["MTYPE2"] = "EQPOS"
+        tbhdu.header["MFORM2"] = "RA,DEC"
+        tbhdu.header["TCTYP2"] = "RA---TAN"
+        tbhdu.header["TCTYP3"] = "DEC--TAN"
+        tbhdu.header["TCRVL2"] = float(self.parameters["sky_center"][0])
+        tbhdu.header["TCRVL3"] = float(self.parameters["sky_center"][1])
+        tbhdu.header["TCDLT2"] = -float(self.parameters["dtheta"])
+        tbhdu.header["TCDLT3"] = float(self.parameters["dtheta"])
+        tbhdu.header["TCRPX2"] = self.parameters["pix_center"][0]
+        tbhdu.header["TCRPX3"] = self.parameters["pix_center"][1]
+        tbhdu.header["TLMIN2"] = 0.5
+        tbhdu.header["TLMIN3"] = 0.5
+        tbhdu.header["TLMAX2"] = 2.*self.parameters["pix_center"][0]-0.5
+        tbhdu.header["TLMAX3"] = 2.*self.parameters["pix_center"][1]-0.5
+        tbhdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
+        if isinstance(self.parameters["Area"], basestring):
+            tbhdu.header["AREA"] = self.parameters["Area"]
+        else:
+            tbhdu.header["AREA"] = float(self.parameters["Area"])
+        tbhdu.header["D_A"] = float(self.parameters["AngularDiameterDistance"])
+        tbhdu.header["REDSHIFT"] = self.parameters["Redshift"]
+        tbhdu.header["HDUVERS"] = "1.1.0"
+        tbhdu.header["RADECSYS"] = "FK5"
+        tbhdu.header["EQUINOX"] = 2000.0
         if "RMF" in self.parameters:
-            tbhdu.header.update("RMF", self.parameters["RMF"])
+            tbhdu.header["RMF"] = self.parameters["RMF"]
         if "ARF" in self.parameters:
-            tbhdu.header.update("ARF", self.parameters["ARF"])
+            tbhdu.header["ARF"] = self.parameters["ARF"]
         if "ChannelType" in self.parameters:
-            tbhdu.header.update("CHANTYPE", self.parameters["ChannelType"])
+            tbhdu.header["CHANTYPE"] = self.parameters["ChannelType"]
         if "Telescope" in self.parameters:
-            tbhdu.header.update("TELESCOP", self.parameters["Telescope"])
+            tbhdu.header["TELESCOP"] = self.parameters["Telescope"]
         if "Instrument" in self.parameters:
-            tbhdu.header.update("INSTRUME", self.parameters["Instrument"])
+            tbhdu.header["INSTRUME"] = self.parameters["Instrument"]
             
         tbhdu.writeto(fitsfile, clobber=clobber)
 
@@ -978,15 +980,15 @@
         tbhdu = pyfits.new_table(coldefs)
         tbhdu.update_ext_name("PHLIST")
 
-        tbhdu.header.update("HDUCLASS", "HEASARC/SIMPUT")
-        tbhdu.header.update("HDUCLAS1", "PHOTONS")
-        tbhdu.header.update("HDUVERS", "1.1.0")
-        tbhdu.header.update("EXTVER", 1)
-        tbhdu.header.update("REFRA", 0.0)
-        tbhdu.header.update("REFDEC", 0.0)
-        tbhdu.header.update("TUNIT1", "keV")
-        tbhdu.header.update("TUNIT2", "deg")
-        tbhdu.header.update("TUNIT3", "deg")                
+        tbhdu.header["HDUCLASS"] = "HEASARC/SIMPUT"
+        tbhdu.header["HDUCLAS1"] = "PHOTONS"
+        tbhdu.header["HDUVERS"] = "1.1.0"
+        tbhdu.header["EXTVER"] = 1
+        tbhdu.header["REFRA"] = 0.0
+        tbhdu.header["REFDEC"] = 0.0
+        tbhdu.header["TUNIT1"] = "keV"
+        tbhdu.header["TUNIT2"] = "deg"
+        tbhdu.header["TUNIT3"] = "deg"
 
         phfile = prefix+"_phlist.fits"
 
@@ -1006,17 +1008,17 @@
         wrhdu = pyfits.new_table(coldefs)
         wrhdu.update_ext_name("SRC_CAT")
                                 
-        wrhdu.header.update("HDUCLASS", "HEASARC")
-        wrhdu.header.update("HDUCLAS1", "SIMPUT")
-        wrhdu.header.update("HDUCLAS2", "SRC_CAT")        
-        wrhdu.header.update("HDUVERS", "1.1.0")
-        wrhdu.header.update("RADECSYS", "FK5")
-        wrhdu.header.update("EQUINOX", 2000.0)
-        wrhdu.header.update("TUNIT2", "deg")
-        wrhdu.header.update("TUNIT3", "deg")
-        wrhdu.header.update("TUNIT4", "keV")
-        wrhdu.header.update("TUNIT5", "keV")
-        wrhdu.header.update("TUNIT6", "erg/s/cm**2")
+        wrhdu.header["HDUCLASS"] = "HEASARC"
+        wrhdu.header["HDUCLAS1"] = "SIMPUT"
+        wrhdu.header["HDUCLAS2"] = "SRC_CAT"
+        wrhdu.header["HDUVERS"] = "1.1.0"
+        wrhdu.header["RADECSYS"] = "FK5"
+        wrhdu.header["EQUINOX"] = 2000.0
+        wrhdu.header["TUNIT2"] = "deg"
+        wrhdu.header["TUNIT3"] = "deg"
+        wrhdu.header["TUNIT4"] = "keV"
+        wrhdu.header["TUNIT5"] = "keV"
+        wrhdu.header["TUNIT6"] = "erg/s/cm**2"
 
         simputfile = prefix+"_simput.fits"
                 
@@ -1100,19 +1102,19 @@
         
         hdu = pyfits.PrimaryHDU(H.T)
         
-        hdu.header.update("MTYPE1", "EQPOS")
-        hdu.header.update("MFORM1", "RA,DEC")
-        hdu.header.update("CTYPE1", "RA---TAN")
-        hdu.header.update("CTYPE2", "DEC--TAN")
-        hdu.header.update("CRPIX1", 0.5*(nx+1))
-        hdu.header.update("CRPIX2", 0.5*(nx+1))                
-        hdu.header.update("CRVAL1", float(self.parameters["sky_center"][0]))
-        hdu.header.update("CRVAL2", float(self.parameters["sky_center"][1]))
-        hdu.header.update("CUNIT1", "deg")
-        hdu.header.update("CUNIT2", "deg")
-        hdu.header.update("CDELT1", -float(self.parameters["dtheta"]))
-        hdu.header.update("CDELT2", float(self.parameters["dtheta"]))
-        hdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
+        hdu.header["MTYPE1"] = "EQPOS"
+        hdu.header["MFORM1"] = "RA,DEC"
+        hdu.header["CTYPE1"] = "RA---TAN"
+        hdu.header["CTYPE2"] = "DEC--TAN"
+        hdu.header["CRPIX1"] = 0.5*(nx+1)
+        hdu.header["CRPIX2"] = 0.5*(nx+1)
+        hdu.header["CRVAL1"] = float(self.parameters["sky_center"][0])
+        hdu.header["CRVAL2"] = float(self.parameters["sky_center"][1])
+        hdu.header["CUNIT1"] = "deg"
+        hdu.header["CUNIT2"] = "deg"
+        hdu.header["CDELT1"] = -float(self.parameters["dtheta"])
+        hdu.header["CDELT2"] = float(self.parameters["dtheta"])
+        hdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
         
         hdu.writeto(imagefile, clobber=clobber)
                                     
@@ -1183,41 +1185,41 @@
         tbhdu.update_ext_name("SPECTRUM")
 
         if not energy_bins:
-            tbhdu.header.update("DETCHANS", spec.shape[0])
-            tbhdu.header.update("TOTCTS", spec.sum())
-            tbhdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
-            tbhdu.header.update("LIVETIME", float(self.parameters["ExposureTime"]))
-            tbhdu.header.update("CONTENT", spectype)
-            tbhdu.header.update("HDUCLASS", "OGIP")
-            tbhdu.header.update("HDUCLAS1", "SPECTRUM")
-            tbhdu.header.update("HDUCLAS2", "TOTAL")
-            tbhdu.header.update("HDUCLAS3", "TYPE:I")
-            tbhdu.header.update("HDUCLAS4", "COUNT")
-            tbhdu.header.update("HDUVERS", "1.1.0")
-            tbhdu.header.update("HDUVERS1", "1.1.0")
-            tbhdu.header.update("CHANTYPE", spectype)
-            tbhdu.header.update("BACKFILE", "none")
-            tbhdu.header.update("CORRFILE", "none")
-            tbhdu.header.update("POISSERR", True)
+            tbhdu.header["DETCHANS"] = spec.shape[0]
+            tbhdu.header["TOTCTS"] = spec.sum()
+            tbhdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
+            tbhdu.header["LIVETIME"] = float(self.parameters["ExposureTime"])
+            tbhdu.header["CONTENT"] = spectype
+            tbhdu.header["HDUCLASS"] = "OGIP"
+            tbhdu.header["HDUCLAS1"] = "SPECTRUM"
+            tbhdu.header["HDUCLAS2"] = "TOTAL"
+            tbhdu.header["HDUCLAS3"] = "TYPE:I"
+            tbhdu.header["HDUCLAS4"] = "COUNT"
+            tbhdu.header["HDUVERS"] = "1.1.0"
+            tbhdu.header["HDUVERS1"] = "1.1.0"
+            tbhdu.header["CHANTYPE"] = spectype
+            tbhdu.header["BACKFILE"] = "none"
+            tbhdu.header["CORRFILE"] = "none"
+            tbhdu.header["POISSERR"] = True
             if self.parameters.has_key("RMF"):
-                 tbhdu.header.update("RESPFILE", self.parameters["RMF"])
+                 tbhdu.header["RESPFILE"] = self.parameters["RMF"]
             else:
-                 tbhdu.header.update("RESPFILE", "none")
+                 tbhdu.header["RESPFILE"] = "none"
             if self.parameters.has_key("ARF"):
-                tbhdu.header.update("ANCRFILE", self.parameters["ARF"])
+                tbhdu.header["ANCRFILE"] = self.parameters["ARF"]
             else:        
-                tbhdu.header.update("ANCRFILE", "none")
+                tbhdu.header["ANCRFILE"] = "none"
             if self.parameters.has_key("Telescope"):
-                tbhdu.header.update("TELESCOP", self.parameters["Telescope"])
+                tbhdu.header["TELESCOP"] = self.parameters["Telescope"]
             else:
-                tbhdu.header.update("TELESCOP", "none")
+                tbhdu.header["TELESCOP"] = "none"
             if self.parameters.has_key("Instrument"):
-                tbhdu.header.update("INSTRUME", self.parameters["Instrument"])
+                tbhdu.header["INSTRUME"] = self.parameters["Instrument"]
             else:
-                tbhdu.header.update("INSTRUME", "none")
-            tbhdu.header.update("AREASCAL", 1.0)
-            tbhdu.header.update("CORRSCAL", 0.0)
-            tbhdu.header.update("BACKSCAL", 1.0)
+                tbhdu.header["INSTRUME"] = "none"
+            tbhdu.header["AREASCAL"] = 1.0
+            tbhdu.header["CORRSCAL"] = 0.0
+            tbhdu.header["BACKSCAL"] = 1.0
                                 
         hdulist = pyfits.HDUList([pyfits.PrimaryHDU(), tbhdu])
         

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/analysis_modules/photon_simulator/spectral_models.py
--- a/yt/analysis_modules/photon_simulator/spectral_models.py
+++ b/yt/analysis_modules/photon_simulator/spectral_models.py
@@ -28,7 +28,7 @@
     from scipy import stats        
 except ImportError:
     pass
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 pyfits = ap.pyfits
 
 from yt.utilities.physical_constants import hcgs, clight, erg_per_keV, amu_cgs

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ b/yt/analysis_modules/ppv_cube/ppv_cube.py
@@ -11,7 +11,7 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 from yt.utilities.orientation import Orientation
 from yt.utilities.fits_image import FITSImageBuffer
 from yt.visualization.volume_rendering.camera import off_axis_projection

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -39,58 +39,7 @@
     unit_prefixes
 from yt.units import dimensions
 from yt.units.yt_array import YTQuantity
-
-class astropy_imports:
-    _pyfits = None
-    @property
-    def pyfits(self):
-        if self._pyfits is None:
-            try:
-                import astropy.io.fits as pyfits
-                self.log
-            except ImportError:
-                pyfits = None
-            self._pyfits = pyfits
-        return self._pyfits
-
-    _pywcs = None
-    @property
-    def pywcs(self):
-        if self._pywcs is None:
-            try:
-                import astropy.wcs as pywcs
-                self.log
-            except ImportError:
-                pywcs = None
-            self._pywcs = pywcs
-        return self._pywcs
-
-    _log = None
-    @property
-    def log(self):
-        if self._log is None:
-            try:
-                from astropy import log
-                if log.exception_logging_enabled():
-                    log.disable_exception_logging()
-            except ImportError:
-                log = None
-            self._log = log
-        return self._log
-
-    _conv = None
-    @property
-    def conv(self):
-        if self._conv is None:
-            try:
-                import astropy.convolution as conv
-                self.log
-            except ImportError:
-                conv = None
-            self._conv = conv
-        return self._conv
-
-ap = astropy_imports()
+from yt.utilities.on_demand_imports import ap
 
 lon_prefixes = ["X","RA","GLON"]
 lat_prefixes = ["Y","DEC","GLAT"]

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -26,7 +26,7 @@
 from yt.units.unit_object import Unit
 from yt.utilities.exceptions import \
     YTUnitOperationError, YTUfuncUnitError
-from yt.testing import fake_random_pf
+from yt.testing import fake_random_pf, requires_module
 from yt.funcs import fix_length
 import numpy as np
 import copy
@@ -627,3 +627,24 @@
 
     for op in [operator.abs, operator.neg, operator.pos]:
         yield unary_op_registry_comparison, op
+
+ at requires_module("astropy")
+def test_astropy():
+    from yt.utilities.on_demand_imports import ap
+
+    ap_arr = np.arange(10)*ap.units.km/ap.units.hr
+    yt_arr = YTArray(np.arange(10), "km/hr")
+
+    ap_quan = 10.*ap.units.Msun**0.5/(ap.units.kpc**3)
+    yt_quan = YTQuantity(10.,"sqrt(Msun)/kpc**3")
+
+    yield assert_array_equal, ap_arr, yt_arr.to_astropy()
+    yield assert_array_equal, yt_arr, YTArray(ap_arr)
+
+    yield assert_equal, ap_quan, yt_quan.to_astropy()
+    yield assert_equal, yt_quan, YTQuantity(ap_quan)
+
+    yield assert_array_equal, yt_arr, YTArray(yt_arr.to_astropy())
+    yield assert_equal, yt_quan, YTQuantity(yt_quan.to_astropy())
+
+

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/units/unit_lookup_table.py
--- a/yt/units/unit_lookup_table.py
+++ b/yt/units/unit_lookup_table.py
@@ -59,12 +59,12 @@
     "yr":  (sec_per_year, dimensions.time),
 
     # Solar units
-    "Msun": ( mass_sun_grams, dimensions.mass),
-    "msun": ( mass_sun_grams, dimensions.mass),
-    "Rsun": ( cm_per_rsun, dimensions.length),
-    "rsun": ( cm_per_rsun, dimensions.length),
-    "Lsun": ( luminosity_sun_ergs_per_sec, dimensions.power),
-    "Tsun": ( temp_sun_kelvin, dimensions.temperature),
+    "Msun": (mass_sun_grams, dimensions.mass),
+    "msun": (mass_sun_grams, dimensions.mass),
+    "Rsun": (cm_per_rsun, dimensions.length),
+    "rsun": (cm_per_rsun, dimensions.length),
+    "Lsun": (luminosity_sun_ergs_per_sec, dimensions.power),
+    "Tsun": (temp_sun_kelvin, dimensions.temperature),
     "Zsun": (metallicity_sun, dimensions.dimensionless),
     "Mjup": (mass_jupiter_grams, dimensions.mass),
     "Mearth": (mass_earth_grams, dimensions.mass),
@@ -89,6 +89,20 @@
     "angstrom": (cm_per_ang, dimensions.length),
     "Jy": (jansky_cgs, dimensions.specific_flux),
     "counts": (1.0, dimensions.dimensionless),
+
+    # for AstroPy compatibility
+    "solMass": (mass_sun_grams, dimensions.mass),
+    "solRad": (cm_per_rsun, dimensions.length),
+    "solLum": (luminosity_sun_ergs_per_sec, dimensions.power),
+    "dyn": (1.0, dimensions.force),
+    "sr": (1.0, dimensions.solid_angle),
+    "rad": (1.0, dimensions.solid_angle),
+    "deg": (np.pi/180., dimensions.angle),
+    "Fr":  (1.0, dimensions.charge),
+    "G": (1.0, dimensions.magnetic_field),
+    "d": (1.0, dimensions.time),
+    "Angstrom": (cm_per_ang, dimensions.length),
+
 }
 
 # Add LaTeX representations for units with trivial representations.

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -35,6 +35,8 @@
     YTUnitOperationError, YTUnitConversionError, \
     YTUfuncUnitError
 from numbers import Number as numeric_type
+from yt.utilities.on_demand_imports import ap
+from sympy import Rational
 
 # redefine this here to avoid a circular import from yt.funcs
 def iterable(obj):
@@ -249,6 +251,22 @@
                     "Perhaps you meant to do something like this instead: \n"
                     "ds.arr(%s, \"%s\")" % (input_array, input_units)
                     )
+        if ap.units is not None:
+            if isinstance(input_array, ap.units.quantity.Quantity):
+                # Converting from AstroPy Quantity
+                u = input_array.unit
+                ap_units = []
+                for base, power in zip(u.bases, u.powers):
+                    unit_str = base.to_string()
+                    # we have to do this because AstroPy is silly and defines
+                    # hour as "h"
+                    if unit_str == "h": unit_str = "hr"
+                    ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
+                ap_units = "*".join(ap_units)
+                if isinstance(input_array.value, np.ndarray):
+                    return YTArray(input_array.value, ap_units)
+                else:
+                    return YTQuantity(input_array.value, ap_units)
         if isinstance(input_array, YTArray):
             if input_units is None:
                 if registry is None:
@@ -423,6 +441,17 @@
 
         """
         return np.array(self)
+
+    def to_astropy(self, alt_unit=None, **kwargs):
+        """
+        Creates a new AstroPy quantity with the same unit information.
+        """
+        if alt_unit is None:
+            units = str(self.units)
+        else:
+            units = alt_unit
+        return self.value*ap.units.Unit(units, **kwargs)
+
     #
     # End unit conversion methods
     #

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/utilities/fits_image.py
--- a/yt/utilities/fits_image.py
+++ b/yt/utilities/fits_image.py
@@ -14,7 +14,7 @@
 from yt.funcs import mylog, iterable, fix_axis, ensure_list
 from yt.visualization.fixed_resolution import FixedResolutionBuffer
 from yt.data_objects.construction_data_containers import YTCoveringGridBase
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import ap
 from yt.units.yt_array import YTQuantity
 
 pyfits = ap.pyfits

diff -r 7d0770838d8cd3cfadde1570b3b900669f944bdb -r 2616c3135890abaca7d64a5a19592cad985e8041 yt/utilities/on_demand_imports.py
--- /dev/null
+++ b/yt/utilities/on_demand_imports.py
@@ -0,0 +1,74 @@
+"""
+A set of convenient on-demand imports
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+class astropy_imports:
+    _pyfits = None
+    @property
+    def pyfits(self):
+        if self._pyfits is None:
+            try:
+                import astropy.io.fits as pyfits
+                self.log
+            except ImportError:
+                pyfits = None
+            self._pyfits = pyfits
+        return self._pyfits
+
+    _pywcs = None
+    @property
+    def pywcs(self):
+        if self._pywcs is None:
+            try:
+                import astropy.wcs as pywcs
+                self.log
+            except ImportError:
+                pywcs = None
+            self._pywcs = pywcs
+        return self._pywcs
+
+    _log = None
+    @property
+    def log(self):
+        if self._log is None:
+            try:
+                from astropy import log
+                if log.exception_logging_enabled():
+                    log.disable_exception_logging()
+            except ImportError:
+                log = None
+            self._log = log
+        return self._log
+
+    _units = None
+    @property
+    def units(self):
+        if self._units is None:
+            try:
+                from astropy import units
+            except ImportError:
+                units = None
+            self._units = units
+        return self._units
+
+    _conv = None
+    @property
+    def conv(self):
+        if self._conv is None:
+            try:
+                import astropy.convolution as conv
+                self.log
+            except ImportError:
+                conv = None
+            self._conv = conv
+        return self._conv
+
+ap = astropy_imports()
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt/commits/9eb4cd73277b/
Changeset:   9eb4cd73277b
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 05:09:17
Summary:     Merge
Affected #:  3 files

diff -r 2616c3135890abaca7d64a5a19592cad985e8041 -r 9eb4cd73277baccd49d9d5ad6ff569535d0da503 doc/source/analyzing/analysis_modules/PPVCube.ipynb
--- a/doc/source/analyzing/analysis_modules/PPVCube.ipynb
+++ b/doc/source/analyzing/analysis_modules/PPVCube.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:20464f4ff5125b848cb3934f78e207b648090473be98ab1315da63d3d290a760"
+  "signature": "sha256:3a720e0a18272564522f9fc23553431908d6f2b4f3e3e7dfe5b3e690e2e37677"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -163,7 +163,7 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "cube.write_fits(\"cube.fits\", clobber=True, length_unit=(5.0,\"deg\"), velocity_unit=\"km/s\")"
+      "cube.write_fits(\"cube.fits\", clobber=True, length_unit=(5.0,\"deg\"))"
      ],
      "language": "python",
      "metadata": {},
@@ -180,8 +180,8 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "pf = load(\"cube.fits\")\n",
-      "slc = SlicePlot(pf, \"z\", [\"density\"], center=\"c\") # sliced at the center of the domain\n",
+      "ds = load(\"cube.fits\")\n",
+      "slc = SlicePlot(ds, \"z\", [\"density\"], center=\"c\") # sliced at the center of the domain\n",
       "slc.show()"
      ],
      "language": "python",
@@ -193,8 +193,8 @@
      "collapsed": false,
      "input": [
       "# To figure out what the domain center and width is in pixel (code length) units:\n",
-      "print pf.domain_center\n",
-      "print pf.domain_width"
+      "print ds.domain_center\n",
+      "print ds.domain_width"
      ],
      "language": "python",
      "metadata": {},
@@ -204,7 +204,7 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "slc = SlicePlot(pf, \"z\", [\"density\"], center=[100.5,50.5,10.0]) # \"z\" slice is in pixel (code length) units\n",
+      "slc = SlicePlot(ds, \"z\", [\"density\"], center=[100.5,50.5,-250.0]) # \"z\" slice is in m/s\n",
       "slc.show()"
      ],
      "language": "python",
@@ -215,12 +215,20 @@
      "cell_type": "code",
      "collapsed": false,
      "input": [
-      "slc = SlicePlot(pf, \"z\", [\"density\"], center=[100.5,50.5,40.0])\n",
+      "slc = SlicePlot(ds, \"z\", [\"density\"], center=[100.5,50.5,300.0])\n",
       "slc.show()"
      ],
      "language": "python",
      "metadata": {},
      "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
     }
    ],
    "metadata": {}

diff -r 2616c3135890abaca7d64a5a19592cad985e8041 -r 9eb4cd73277baccd49d9d5ad6ff569535d0da503 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ b/yt/analysis_modules/ppv_cube/ppv_cube.py
@@ -114,7 +114,7 @@
         pbar.finish()
 
     def write_fits(self, filename, clobber=True, length_unit=(10.0, "kpc"),
-                   velocity_unit="m/s", sky_center=(30.,45.)):
+                   sky_center=(30.,45.)):
         r""" Write the PPVCube to a FITS file.
 
         Parameters
@@ -126,16 +126,13 @@
         length_unit : tuple, optional
             The length that corresponds to the width of the projection in
             (value, unit) form. Accepts a length unit or 'deg'.
-        velocity_unit : string, optional
-            The units for the velocity axis.
         sky_center : tuple, optional
             The (RA, Dec) coordinate in degrees of the central pixel if
             *length_unit* is 'deg'.
 
         Examples
         --------
-        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"),
-        ...                 velocity_unit="km/s")
+        >>> cube.write_fits("my_cube.fits", clobber=False, length_unit=(5,"deg"))
         """
         if length_unit[1] == "deg":
             center = sky_center
@@ -144,11 +141,11 @@
             center = [0.0,0.0]
             types = ["LINEAR","LINEAR"]
 
-        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units(velocity_unit).value
+        v_center = 0.5*(self.v_bnd[0]+self.v_bnd[1]).in_units("m/s").value
 
         dx = length_unit[0]/self.nx
         dy = length_unit[0]/self.ny
-        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units(velocity_unit).value/self.nv
+        dv = (self.v_bnd[1]-self.v_bnd[0]).in_units("m/s").value/self.nv
 
         if length_unit[1] == "deg":
             dx *= -1.
@@ -157,7 +154,7 @@
         w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
         w.wcs.cdelt = [dx,dy,dv]
         w.wcs.crval = [center[0], center[1], v_center]
-        w.wcs.cunit = [length_unit[1],length_unit[1],velocity_unit]
+        w.wcs.cunit = [length_unit[1],length_unit[1],"m/s"]
         w.wcs.ctype = [types[0],types[1],"VELO-LSR"]
 
         fib = FITSImageBuffer(self.data.transpose(), fields=self.field, wcs=w)

diff -r 2616c3135890abaca7d64a5a19592cad985e8041 -r 9eb4cd73277baccd49d9d5ad6ff569535d0da503 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -102,7 +102,7 @@
                     n += 1
             if n != len(units): field_units = "dimensionless"
             return field_units
-        except:
+        except KeyError:
             return "dimensionless"
 
     def _ensure_same_dims(self, hdu):
@@ -153,7 +153,7 @@
                     try:
                         # Grab field name from btype
                         fname = hdu.header["btype"].lower()
-                    except:
+                    except KeyError:
                         # Try to guess the name from the units
                         fname = self._guess_name_from_units(units)
                         # When all else fails
@@ -178,6 +178,9 @@
                         self.field_list.append(("fits", fname))
                         self.parameter_file.field_units[fname] = units
                         mylog.info("Adding field %s to the list of fields." % (fname))
+                        if units == "dimensionless":
+                            mylog.warning("Could not determine dimensions for field %s, " % (fname) +
+                                          "setting to dimensionless.")
                 else:
                     mylog.warning("Image block %s does not have " % (hdu.name.lower()) +
                                   "the same dimensions as the primary and will not be " +


https://bitbucket.org/yt_analysis/yt/commits/a6d1aa94e346/
Changeset:   a6d1aa94e346
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 05:11:12
Summary:     Fixing import
Affected #:  1 file

diff -r 9eb4cd73277baccd49d9d5ad6ff569535d0da503 -r a6d1aa94e34605094e93e78511fe5bb897d6d876 yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -14,7 +14,7 @@
 from yt.fields.api import add_field
 from yt.fields.derived_field import ValidateSpatial
 from yt.funcs import mylog
-from .data_structures import ap
+from yt.utilities.on_demand_imports import ap
 
 def _make_counts(emin, emax):
     def _counts(field, data):


https://bitbucket.org/yt_analysis/yt/commits/b8017f88bd6f/
Changeset:   b8017f88bd6f
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 06:10:33
Summary:     Documenting the AstroPy unit conversions, cleaning up the to_astropy method a little bit
Affected #:  2 files

diff -r a6d1aa94e34605094e93e78511fe5bb897d6d876 -r b8017f88bd6f53fcbdce9729d2342b1059fce6de doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
--- a/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
+++ b/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:9e7ac626b3609cf5f3fb2d4ebc6e027ed923ab1c22f0acc212e42fc7535e3205"
+  "signature": "sha256:29046b1f2a13c62992ee4b7413fac78782a397df6b0b66488d4d880fa18426a9"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -296,6 +296,162 @@
      "language": "python",
      "metadata": {},
      "outputs": []
+    },
+    {
+     "cell_type": "heading",
+     "level": 3,
+     "metadata": {},
+     "source": [
+      "Round-Trip Conversions to and from AstroPy's Units System"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Finally, a `YTArray` or `YTQuantity` may be converted to an [AstroPy quantity](http://astropy.readthedocs.org/en/latest/units/), which is a NumPy array or a scalar associated with units from AstroPy's units system. You may use this facility if you have AstroPy installed. "
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Some examples of converting from AstroPy units to yt:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from astropy import units as u\n",
+      "x = 42.0 * u.meter\n",
+      "y = YTQuantity(x)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print x, type(x)\n",
+      "print y, type(y)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "a = np.random.random(size=10) * u.km/u.s\n",
+      "b = YTArray(a)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print a, type(a)\n",
+      "print b, type(b)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "It also works the other way around, converting a `YTArray` or `YTQuantity` to an AstroPy quantity via the method `to_astropy`. For arrays:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "temp = dd[\"temperature\"]\n",
+      "atemp = temp.to_astropy()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print temp, type(temp)\n",
+      "print atemp, type(atemp)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "and quantities:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.utilities.physical_constants import kboltz\n",
+      "kb = kboltz.to_astropy()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print kboltz, type(kboltz)\n",
+      "print kb, type(kb)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "As a sanity check, you can show that it works round-trip:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "k1 = kboltz.to_astropy()\n",
+      "k2 = YTQuantity(kb)\n",
+      "print k1 == k2"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "c = YTArray(a)\n",
+      "d = c.to_astropy()\n",
+      "print a == d"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
     }
    ],
    "metadata": {}

diff -r a6d1aa94e34605094e93e78511fe5bb897d6d876 -r b8017f88bd6f53fcbdce9729d2342b1059fce6de yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -442,15 +442,14 @@
         """
         return np.array(self)
 
-    def to_astropy(self, alt_unit=None, **kwargs):
+    def to_astropy(self, **kwargs):
         """
         Creates a new AstroPy quantity with the same unit information.
         """
-        if alt_unit is None:
-            units = str(self.units)
-        else:
-            units = alt_unit
-        return self.value*ap.units.Unit(units, **kwargs)
+        if ap.units is None:
+            raise ImportError("You don't have AstroPy installed, so you can't convert to " +
+                              "an AstroPy quantity.")
+        return self.value*ap.units.Unit(str(self.units), **kwargs)
 
     #
     # End unit conversion methods


https://bitbucket.org/yt_analysis/yt/commits/278bd83fe853/
Changeset:   278bd83fe853
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 06:54:34
Summary:     Cleanup
Affected #:  1 file

diff -r b8017f88bd6f53fcbdce9729d2342b1059fce6de -r 278bd83fe8539d3c8d38cf7e9081a390b53179ba yt/frontends/fits/fields.py
--- a/yt/frontends/fits/fields.py
+++ b/yt/frontends/fits/fields.py
@@ -25,17 +25,17 @@
 
     def _setup_ppv_fields(self):
 
-        def _get_2d_wcs(self, data, axis):
+        def _get_2d_wcs(data, axis):
             w_coords = data.pf.wcs_2d.wcs_pix2world(data["x"], data["y"], 1)
             return w_coords[axis]
 
         def world_f(axis, unit):
             def _world_f(field, data):
-                return data.pf.arr(self._get_2d_wcs(data, axis), unit)
+                return data.pf.arr(_get_2d_wcs(data, axis), unit)
             return _world_f
 
         for (i, axis), name in zip(enumerate([self.pf.lon_axis, self.pf.lat_axis]),
-                             [self.pf.lon_name, self.pf.lat_name]):
+                                             [self.pf.lon_name, self.pf.lat_name]):
             unit = str(self.pf.wcs_2d.wcs.cunit[i])
             if unit.lower() == "deg": unit = "degree"
             if unit.lower() == "rad": unit = "radian"


https://bitbucket.org/yt_analysis/yt/commits/2d699b4ec62d/
Changeset:   2d699b4ec62d
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 06:57:56
Summary:     Creating dataset-specific add_field
Affected #:  2 files

diff -r 278bd83fe8539d3c8d38cf7e9081a390b53179ba -r 2d699b4ec62d60f9d8671d292f54732613e5901f yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -653,6 +653,15 @@
                 registry = self.unit_registry)
         return self._quan
 
+    def add_field(self, name, function=None, **kwargs):
+        """
+        Dataset-specific call to add_field
+        """
+        self.index
+        self.field_info.add_field(name, function=function, **kwargs)
+        deps, _ = self.field_info.check_derived_fields([name])
+        self.field_dependencies.update(deps)
+
 def _reconstruct_pf(*args, **kwargs):
     pfs = ParameterFileStore()
     pf = pfs.get_pf_hash(*args)

diff -r 278bd83fe8539d3c8d38cf7e9081a390b53179ba -r 2d699b4ec62d60f9d8671d292f54732613e5901f yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -35,26 +35,29 @@
         return data.pf.arr(img, "counts/pixel")
     return _counts
 
-def setup_counts_fields(ebounds):
+def setup_counts_fields(ds, ebounds):
     r"""
     Create deposited image fields from X-ray count data in energy bands.
 
     Parameters
     ----------
+    ds : Dataset
+        The FITS events file dataset to add the counts fields to.
     ebounds : list of tuples
         A list of tuples, one for each field, with (emin, emax) as the
         energy bounds for the image.
 
     Examples
     --------
+    >>> ds = yt.load("evt.fits")
     >>> ebounds = [(0.1,2.0),(2.0,3.0)]
-    >>> setup_counts_fields(ebounds)
+    >>> setup_counts_fields(ds, ebounds)
     """
     for (emin, emax) in ebounds:
         cfunc = _make_counts(emin, emax)
         fname = "counts_%s-%s" % (emin, emax)
         mylog.info("Creating counts field %s." % fname)
-        add_field(("gas",fname), function=cfunc,
-                  units="counts/pixel",
-                  validators = [ValidateSpatial()],
-                  display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file
+        ds.add_field(("gas",fname), function=cfunc,
+                     units="counts/pixel",
+                     validators = [ValidateSpatial()],
+                     display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt/commits/d56434135ea5/
Changeset:   d56434135ea5
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 16:45:46
Summary:     Bugfix
Affected #:  1 file

diff -r 2d699b4ec62d60f9d8671d292f54732613e5901f -r d56434135ea5d74a12cbe45fe6f7ed3675b7c00e yt/utilities/fits_image.py
--- a/yt/utilities/fits_image.py
+++ b/yt/utilities/fits_image.py
@@ -295,7 +295,7 @@
     """
     def __init__(self, ds, axis, fields, coord, **kwargs):
         fields = ensure_list(fields)
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, ds)
         if isinstance(coord, tuple):
             coord = ds.quan(coord[0], coord[1]).in_units("code_length").value
         elif isinstance(coord, YTQuantity):
@@ -321,7 +321,7 @@
     """
     def __init__(self, ds, axis, fields, weight_field=None, **kwargs):
         fields = ensure_list(fields)
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, ds)
         prj = ds.proj(fields[0], axis, weight_field=weight_field, **kwargs)
         w, frb = construct_image(prj)
         super(FITSProjection, self).__init__(frb, fields=fields, wcs=w)


https://bitbucket.org/yt_analysis/yt/commits/894dc99ff7e5/
Changeset:   894dc99ff7e5
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 17:10:13
Summary:     Fixing some bugs I discovered from the last PR
Affected #:  2 files

diff -r d56434135ea5d74a12cbe45fe6f7ed3675b7c00e -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -94,7 +94,8 @@
             # FITS units always return upper-case, so we need to get
             # the right case by comparing against known units. This
             # only really works for common units.
-            units = re.split(regex_pattern, field_units)
+            units = set(re.split(regex_pattern, field_units))
+            units.remove('')
             n = int(0)
             for unit in units:
                 if unit in known_units:
@@ -211,7 +212,7 @@
                                                        pf.domain_right_edge)])
             dims = np.array(pf.domain_dimensions)
             # If we are creating a dataset of lines, only decompose along the position axes
-            if pf.line_database is not None:
+            if len(pf.line_database) > 0:
                 dims[pf.vel_axis] = 1
             psize = get_psize(dims, pf.nprocs)
             gle, gre, shapes, slices = decompose_array(dims, psize, bbox)
@@ -219,7 +220,7 @@
             self.grid_right_edge = self.pf.arr(gre, "code_length")
             self.grid_dimensions = np.array([shape for shape in shapes], dtype="int32")
             # If we are creating a dataset of lines, only decompose along the position axes
-            if pf.line_database is not None:
+            if len(pf.line_database) > 0:
                 self.grid_left_edge[:,pf.vel_axis] = pf.domain_left_edge[pf.vel_axis]
                 self.grid_right_edge[:,pf.vel_axis] = pf.domain_right_edge[pf.vel_axis]
                 self.grid_dimensions[:,pf.vel_axis] = pf.domain_dimensions[pf.vel_axis]
@@ -480,6 +481,8 @@
                                     32**self.dimensionality).astype("int")
             self.nprocs = max(min(self.nprocs, 512), 1)
 
+        self.reversed = False
+
         # Check to see if this data is in some kind of (Lat,Lon,Vel) format
         self.ppv_data = False
         x = 0
@@ -540,7 +543,6 @@
                 le = self.dims[self.vel_axis]+0.5
                 re = 0.5
             else:
-                self.reversed = False
                 le = 0.5
                 re = self.dims[self.vel_axis]+0.5
             self.domain_left_edge[self.vel_axis] = (le-x0)*dz + z0

diff -r d56434135ea5d74a12cbe45fe6f7ed3675b7c00e -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 yt/utilities/fits_image.py
--- a/yt/utilities/fits_image.py
+++ b/yt/utilities/fits_image.py
@@ -303,6 +303,8 @@
         slc = ds.slice(axis, coord, **kwargs)
         w, frb = construct_image(slc)
         super(FITSSlice, self).__init__(frb, fields=fields, wcs=w)
+        for i, field in enumerate(fields):
+            self[i].header["bunit"] = str(frb[field].units)
 
 class FITSProjection(FITSImageBuffer):
     r"""
@@ -325,6 +327,8 @@
         prj = ds.proj(fields[0], axis, weight_field=weight_field, **kwargs)
         w, frb = construct_image(prj)
         super(FITSProjection, self).__init__(frb, fields=fields, wcs=w)
+        for i, field in enumerate(fields):
+            self[i].header["bunit"] = str(frb[field].units)
 
 
 


https://bitbucket.org/yt_analysis/yt/commits/199042322e69/
Changeset:   199042322e69
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-05 22:18:54
Summary:     Responding to comments from Matt and Nathan
Affected #:  9 files

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/analysis_modules/photon_simulator/photon_simulator.py
--- a/yt/analysis_modules/photon_simulator/photon_simulator.py
+++ b/yt/analysis_modules/photon_simulator/photon_simulator.py
@@ -31,9 +31,9 @@
 from yt import units
 from yt.units.yt_array import YTQuantity
 import h5py
-from yt.utilities.on_demand_imports import ap
-pyfits = ap.pyfits
-pywcs = ap.pywcs
+from yt.utilities.on_demand_imports import _astropy
+pyfits = _astropy.pyfits
+pywcs = _astropy.pywcs
 
 comm = communication_system.communicators[-1]
 

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/analysis_modules/photon_simulator/spectral_models.py
--- a/yt/analysis_modules/photon_simulator/spectral_models.py
+++ b/yt/analysis_modules/photon_simulator/spectral_models.py
@@ -28,8 +28,8 @@
     from scipy import stats        
 except ImportError:
     pass
-from yt.utilities.on_demand_imports import ap
-pyfits = ap.pyfits
+from yt.utilities.on_demand_imports import _astropy
+pyfits = _astropy.pyfits
 
 from yt.utilities.physical_constants import hcgs, clight, erg_per_keV, amu_cgs
 

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ b/yt/analysis_modules/ppv_cube/ppv_cube.py
@@ -11,7 +11,7 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from yt.utilities.on_demand_imports import ap
+from yt.utilities.on_demand_imports import _astropy
 from yt.utilities.orientation import Orientation
 from yt.utilities.fits_image import FITSImageBuffer
 from yt.visualization.volume_rendering.camera import off_axis_projection
@@ -150,7 +150,7 @@
         if length_unit[1] == "deg":
             dx *= -1.
 
-        w = ap.pywcs.WCS(naxis=3)
+        w = _astropy.pywcs.WCS(naxis=3)
         w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
         w.wcs.cdelt = [dx,dy,dv]
         w.wcs.crval = [center[0], center[1], v_center]

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -39,7 +39,7 @@
     unit_prefixes
 from yt.units import dimensions
 from yt.units.yt_array import YTQuantity
-from yt.utilities.on_demand_imports import ap
+from yt.utilities.on_demand_imports import _astropy
 
 lon_prefixes = ["X","RA","GLON"]
 lat_prefixes = ["Y","DEC","GLAT"]
@@ -323,7 +323,7 @@
         elif isinstance(nan_mask, dict):
             self.nan_mask = nan_mask
         self.nprocs = nprocs
-        self._handle = ap.pyfits.open(self.filenames[0],
+        self._handle = _astropy.pyfits.open(self.filenames[0],
                                       memmap=True,
                                       do_not_scale_image_data=True,
                                       ignore_blank=True)
@@ -334,7 +334,7 @@
                     fn = fits_file
                 else:
                     fn = os.path.join(ytcfg.get("yt","test_data_dir"),fits_file)
-                f = ap.pyfits.open(fn, memmap=True,
+                f = _astropy.pyfits.open(fn, memmap=True,
                                    do_not_scale_image_data=True,
                                    ignore_blank=True)
                 self._fits_files.append(f)
@@ -344,7 +344,7 @@
             self.first_image = 1
             self.primary_header = self._handle[self.first_image].header
             self.naxis = 2
-            self.wcs = ap.pywcs.WCS(naxis=2)
+            self.wcs = _astropy.pywcs.WCS(naxis=2)
             self.events_info = {}
             for k,v in self.primary_header.items():
                 if k.startswith("TTYP"):
@@ -378,7 +378,7 @@
             self.events_data = False
             self.first_image = 0
             self.primary_header = self._handle[self.first_image].header
-            self.wcs = ap.pywcs.WCS(header=self.primary_header)
+            self.wcs = _astropy.pywcs.WCS(header=self.primary_header)
             self.naxis = self.primary_header["naxis"]
             self.axis_names = [self.primary_header["ctype%d" % (i+1)]
                                for i in xrange(self.naxis)]
@@ -524,7 +524,7 @@
             self.vel_axis = np.where(self.vel_axis)[0][0]
             self.vel_name = ctypes[self.vel_axis].split("-")[0].lower()
 
-            self.wcs_2d = ap.pywcs.WCS(naxis=2)
+            self.wcs_2d = _astropy.pywcs.WCS(naxis=2)
             self.wcs_2d.wcs.crpix = self.wcs.wcs.crpix[[self.lon_axis, self.lat_axis]]
             self.wcs_2d.wcs.cdelt = self.wcs.wcs.cdelt[[self.lon_axis, self.lat_axis]]
             self.wcs_2d.wcs.crval = self.wcs.wcs.crval[[self.lon_axis, self.lat_axis]]
@@ -583,7 +583,7 @@
         try:
             with warnings.catch_warnings():
                 warnings.filterwarnings('ignore', category=UserWarning, append=True)
-                fileh = ap.pyfits.open(args[0])
+                fileh = _astropy.pyfits.open(args[0])
             valid = fileh[0].header["naxis"] >= 2
             if len(fileh) > 1 and fileh[1].name == "EVENTS":
                 valid = fileh[1].header["naxis"] >= 2

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -14,7 +14,7 @@
 from yt.fields.api import add_field
 from yt.fields.derived_field import ValidateSpatial
 from yt.funcs import mylog
-from yt.utilities.on_demand_imports import ap
+from yt.utilities.on_demand_imports import _astropy
 
 def _make_counts(emin, emax):
     def _counts(field, data):
@@ -30,12 +30,12 @@
         else:
             sigma = None
         if sigma is not None and sigma > 0.0:
-            kern = ap.conv.Gaussian2DKernel(stddev=sigma)
-            img[:,:,0] = ap.conv.convolve(img[:,:,0], kern)
+            kern = _astropy.conv.Gaussian2DKernel(stddev=sigma)
+            img[:,:,0] = _astropy.conv.convolve(img[:,:,0], kern)
         return data.pf.arr(img, "counts/pixel")
     return _counts
 
-def setup_counts_fields(ds, ebounds):
+def setup_counts_fields(ds, ebounds, ftype="gas"):
     r"""
     Create deposited image fields from X-ray count data in energy bands.
 
@@ -57,7 +57,7 @@
         cfunc = _make_counts(emin, emax)
         fname = "counts_%s-%s" % (emin, emax)
         mylog.info("Creating counts field %s." % fname)
-        ds.add_field(("gas",fname), function=cfunc,
+        ds.add_field((ftype,fname), function=cfunc,
                      units="counts/pixel",
                      validators = [ValidateSpatial()],
                      display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -630,12 +630,12 @@
 
 @requires_module("astropy")
 def test_astropy():
-    from yt.utilities.on_demand_imports import ap
+    from yt.utilities.on_demand_imports import _astropy
 
-    ap_arr = np.arange(10)*ap.units.km/ap.units.hr
+    ap_arr = np.arange(10)*_astropy.units.km/_astropy.units.hr
     yt_arr = YTArray(np.arange(10), "km/hr")
 
-    ap_quan = 10.*ap.units.Msun**0.5/(ap.units.kpc**3)
+    ap_quan = 10.*_astropy.units.Msun**0.5/(_astropy.units.kpc**3)
     yt_quan = YTQuantity(10.,"sqrt(Msun)/kpc**3")
 
     yield assert_array_equal, ap_arr, yt_arr.to_astropy()

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -35,7 +35,7 @@
     YTUnitOperationError, YTUnitConversionError, \
     YTUfuncUnitError
 from numbers import Number as numeric_type
-from yt.utilities.on_demand_imports import ap
+from yt.utilities.on_demand_imports import _astropy
 from sympy import Rational
 
 # redefine this here to avoid a circular import from yt.funcs
@@ -251,8 +251,8 @@
                     "Perhaps you meant to do something like this instead: \n"
                     "ds.arr(%s, \"%s\")" % (input_array, input_units)
                     )
-        if ap.units is not None:
-            if isinstance(input_array, ap.units.quantity.Quantity):
+        if _astropy.units is not None:
+            if isinstance(input_array, _astropy.units.quantity.Quantity):
                 # Converting from AstroPy Quantity
                 u = input_array.unit
                 ap_units = []
@@ -446,10 +446,10 @@
         """
         Creates a new AstroPy quantity with the same unit information.
         """
-        if ap.units is None:
+        if _astropy.units is None:
             raise ImportError("You don't have AstroPy installed, so you can't convert to " +
                               "an AstroPy quantity.")
-        return self.value*ap.units.Unit(str(self.units), **kwargs)
+        return self.value*_astropy.units.Unit(str(self.units), **kwargs)
 
     #
     # End unit conversion methods

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/utilities/fits_image.py
--- a/yt/utilities/fits_image.py
+++ b/yt/utilities/fits_image.py
@@ -14,11 +14,11 @@
 from yt.funcs import mylog, iterable, fix_axis, ensure_list
 from yt.visualization.fixed_resolution import FixedResolutionBuffer
 from yt.data_objects.construction_data_containers import YTCoveringGridBase
-from yt.utilities.on_demand_imports import ap
+from yt.utilities.on_demand_imports import _astropy
 from yt.units.yt_array import YTQuantity
 
-pyfits = ap.pyfits
-pywcs = ap.pywcs
+pyfits = _astropy.pyfits
+pywcs = _astropy.pywcs
 
 class FITSImageBuffer(pyfits.HDUList):
 

diff -r 894dc99ff7e5efe357b25197d0b99bad4ba2d935 -r 199042322e69b10a5989f2073dc4ed0e6c20e583 yt/utilities/on_demand_imports.py
--- a/yt/utilities/on_demand_imports.py
+++ b/yt/utilities/on_demand_imports.py
@@ -71,4 +71,4 @@
             self._conv = conv
         return self._conv
 
-ap = astropy_imports()
\ No newline at end of file
+_astropy = astropy_imports()
\ No newline at end of file


https://bitbucket.org/yt_analysis/yt/commits/917b239cc5cd/
Changeset:   917b239cc5cd
Branch:      yt-3.0
User:        jzuhone
Date:        2014-05-06 01:41:09
Summary:     Adding a from_astropy classmethod
Affected #:  3 files

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r 917b239cc5cdbdb9865b36185e3e1839fbe54cb0 doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
--- a/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
+++ b/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:29046b1f2a13c62992ee4b7413fac78782a397df6b0b66488d4d880fa18426a9"
+  "signature": "sha256:b7541e0167001c6dd74306c8490385ace7bdb0533a829286f0505c0b24c67f16"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -325,7 +325,8 @@
      "input": [
       "from astropy import units as u\n",
       "x = 42.0 * u.meter\n",
-      "y = YTQuantity(x)"
+      "y = YTQuantity(x)\n",
+      "y2 = YTQuantity.from_astropy(x) # Another way to create the quantity"
      ],
      "language": "python",
      "metadata": {},
@@ -336,7 +337,8 @@
      "collapsed": false,
      "input": [
       "print x, type(x)\n",
-      "print y, type(y)"
+      "print y, type(y)\n",
+      "print y2, type(y2)"
      ],
      "language": "python",
      "metadata": {},
@@ -347,7 +349,8 @@
      "collapsed": false,
      "input": [
       "a = np.random.random(size=10) * u.km/u.s\n",
-      "b = YTArray(a)"
+      "b = YTArray(a)\n",
+      "b2 = YTArray.from_astropy(a) # Another way to create the quantity"
      ],
      "language": "python",
      "metadata": {},
@@ -358,7 +361,8 @@
      "collapsed": false,
      "input": [
       "print a, type(a)\n",
-      "print b, type(b)"
+      "print b, type(b)\n",
+      "print b2, type(b2)"
      ],
      "language": "python",
      "metadata": {},

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r 917b239cc5cdbdb9865b36185e3e1839fbe54cb0 yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -634,15 +634,19 @@
 
     ap_arr = np.arange(10)*_astropy.units.km/_astropy.units.hr
     yt_arr = YTArray(np.arange(10), "km/hr")
+    yt_arr2 = YTArray.from_astropy(ap_arr)
 
     ap_quan = 10.*_astropy.units.Msun**0.5/(_astropy.units.kpc**3)
     yt_quan = YTQuantity(10.,"sqrt(Msun)/kpc**3")
+    yt_quan2 = YTQuantity.from_astropy(ap_quan)
 
     yield assert_array_equal, ap_arr, yt_arr.to_astropy()
     yield assert_array_equal, yt_arr, YTArray(ap_arr)
+    yield assert_array_equal, yt_arr, yt_arr2
 
     yield assert_equal, ap_quan, yt_quan.to_astropy()
     yield assert_equal, yt_quan, YTQuantity(ap_quan)
+    yield assert_equal, yt_quan, yt_quan2
 
     yield assert_array_equal, yt_arr, YTArray(yt_arr.to_astropy())
     yield assert_equal, yt_quan, YTQuantity(yt_quan.to_astropy())

diff -r 199042322e69b10a5989f2073dc4ed0e6c20e583 -r 917b239cc5cdbdb9865b36185e3e1839fbe54cb0 yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -253,20 +253,7 @@
                     )
         if _astropy.units is not None:
             if isinstance(input_array, _astropy.units.quantity.Quantity):
-                # Converting from AstroPy Quantity
-                u = input_array.unit
-                ap_units = []
-                for base, power in zip(u.bases, u.powers):
-                    unit_str = base.to_string()
-                    # we have to do this because AstroPy is silly and defines
-                    # hour as "h"
-                    if unit_str == "h": unit_str = "hr"
-                    ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
-                ap_units = "*".join(ap_units)
-                if isinstance(input_array.value, np.ndarray):
-                    return YTArray(input_array.value, ap_units)
-                else:
-                    return YTQuantity(input_array.value, ap_units)
+                return cls.from_astropy(input_array)
         if isinstance(input_array, YTArray):
             if input_units is None:
                 if registry is None:
@@ -442,6 +429,28 @@
         """
         return np.array(self)
 
+    @classmethod
+    def from_astropy(cls, arr):
+        """
+        Creates a new YTArray with the same unit information from an
+        AstroPy quantity *arr*.
+        """
+        # Converting from AstroPy Quantity
+        u = arr.unit
+        ap_units = []
+        for base, power in zip(u.bases, u.powers):
+            unit_str = base.to_string()
+            # we have to do this because AstroPy is silly and defines
+            # hour as "h"
+            if unit_str == "h": unit_str = "hr"
+            ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
+        ap_units = "*".join(ap_units)
+        if isinstance(arr.value, np.ndarray):
+            return YTArray(arr.value, ap_units)
+        else:
+            return YTQuantity(arr.value, ap_units)
+
+
     def to_astropy(self, **kwargs):
         """
         Creates a new AstroPy quantity with the same unit information.


https://bitbucket.org/yt_analysis/yt/commits/907cb91838fe/
Changeset:   907cb91838fe
Branch:      yt-3.0
User:        MatthewTurk
Date:        2014-05-06 04:13:06
Summary:     Merged in jzuhone/yt-3.x/yt-3.0 (pull request #879)

Round-trip unit conversions to AstroPy, on-demand imports module, Dataset-specific add_field
Affected #:  13 files

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
--- a/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
+++ b/doc/source/analyzing/units/2)_Data_Selection_and_fields.ipynb
@@ -1,7 +1,7 @@
 {
  "metadata": {
   "name": "",
-  "signature": "sha256:9e7ac626b3609cf5f3fb2d4ebc6e027ed923ab1c22f0acc212e42fc7535e3205"
+  "signature": "sha256:b7541e0167001c6dd74306c8490385ace7bdb0533a829286f0505c0b24c67f16"
  },
  "nbformat": 3,
  "nbformat_minor": 0,
@@ -296,6 +296,166 @@
      "language": "python",
      "metadata": {},
      "outputs": []
+    },
+    {
+     "cell_type": "heading",
+     "level": 3,
+     "metadata": {},
+     "source": [
+      "Round-Trip Conversions to and from AstroPy's Units System"
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Finally, a `YTArray` or `YTQuantity` may be converted to an [AstroPy quantity](http://astropy.readthedocs.org/en/latest/units/), which is a NumPy array or a scalar associated with units from AstroPy's units system. You may use this facility if you have AstroPy installed. "
+     ]
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "Some examples of converting from AstroPy units to yt:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from astropy import units as u\n",
+      "x = 42.0 * u.meter\n",
+      "y = YTQuantity(x)\n",
+      "y2 = YTQuantity.from_astropy(x) # Another way to create the quantity"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print x, type(x)\n",
+      "print y, type(y)\n",
+      "print y2, type(y2)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "a = np.random.random(size=10) * u.km/u.s\n",
+      "b = YTArray(a)\n",
+      "b2 = YTArray.from_astropy(a) # Another way to create the quantity"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print a, type(a)\n",
+      "print b, type(b)\n",
+      "print b2, type(b2)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "It also works the other way around, converting a `YTArray` or `YTQuantity` to an AstroPy quantity via the method `to_astropy`. For arrays:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "temp = dd[\"temperature\"]\n",
+      "atemp = temp.to_astropy()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print temp, type(temp)\n",
+      "print atemp, type(atemp)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "and quantities:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "from yt.utilities.physical_constants import kboltz\n",
+      "kb = kboltz.to_astropy()"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "print kboltz, type(kboltz)\n",
+      "print kb, type(kb)"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "markdown",
+     "metadata": {},
+     "source": [
+      "As a sanity check, you can show that it works round-trip:"
+     ]
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "k1 = kboltz.to_astropy()\n",
+      "k2 = YTQuantity(kb)\n",
+      "print k1 == k2"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
+    },
+    {
+     "cell_type": "code",
+     "collapsed": false,
+     "input": [
+      "c = YTArray(a)\n",
+      "d = c.to_astropy()\n",
+      "print a == d"
+     ],
+     "language": "python",
+     "metadata": {},
+     "outputs": []
     }
    ],
    "metadata": {}

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/analysis_modules/photon_simulator/photon_simulator.py
--- a/yt/analysis_modules/photon_simulator/photon_simulator.py
+++ b/yt/analysis_modules/photon_simulator/photon_simulator.py
@@ -21,22 +21,19 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from numpy.testing import assert_allclose
 from yt.funcs import *
-from yt.utilities.physical_constants import clight, \
-     cm_per_km, erg_per_keV
+from yt.utilities.physical_constants import clight
 from yt.utilities.cosmology import Cosmology
 from yt.utilities.orientation import Orientation
-from yt.utilities.definitions import mpc_conversion
 from yt.utilities.parallel_tools.parallel_analysis_interface import \
      communication_system, parallel_root_only, get_mpi_type, \
-     op_names, parallel_capable
+     parallel_capable
 from yt import units
 from yt.units.yt_array import YTQuantity
 import h5py
-from yt.frontends.fits.data_structures import ap
-pyfits = ap.pyfits
-pywcs = ap.pywcs
+from yt.utilities.on_demand_imports import _astropy
+pyfits = _astropy.pyfits
+pywcs = _astropy.pywcs
 
 comm = communication_system.communicators[-1]
 
@@ -471,7 +468,9 @@
                         "but not both!")
         
         if sky_center is None:
-             sky_center = YTArray([30.,45.], "degree")
+            sky_center = YTArray([30.,45.], "degree")
+        else:
+            sky_center = YTArray(sky_center, "degree")
 
         dx = self.photons["dx"].ndarray_view()
         nx = self.parameters["Dimension"]
@@ -897,39 +896,42 @@
         tbhdu = pyfits.new_table(coldefs)
         tbhdu.update_ext_name("EVENTS")
 
-        tbhdu.header.update("MTYPE1", "sky")
-        tbhdu.header.update("MFORM1", "x,y")        
-        tbhdu.header.update("MTYPE2", "EQPOS")
-        tbhdu.header.update("MFORM2", "RA,DEC")
-        tbhdu.header.update("TCTYP2", "RA---TAN")
-        tbhdu.header.update("TCTYP3", "DEC--TAN")
-        tbhdu.header.update("TCRVL2", float(self.parameters["sky_center"][0]))
-        tbhdu.header.update("TCRVL3", float(self.parameters["sky_center"][1]))
-        tbhdu.header.update("TCDLT2", -float(self.parameters["dtheta"]))
-        tbhdu.header.update("TCDLT3", float(self.parameters["dtheta"]))
-        tbhdu.header.update("TCRPX2", self.parameters["pix_center"][0])
-        tbhdu.header.update("TCRPX3", self.parameters["pix_center"][1])
-        tbhdu.header.update("TLMIN2", 0.5)
-        tbhdu.header.update("TLMIN3", 0.5)
-        tbhdu.header.update("TLMAX2", 2.*self.parameters["pix_center"][0]-0.5)
-        tbhdu.header.update("TLMAX3", 2.*self.parameters["pix_center"][1]-0.5)
-        tbhdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
-        tbhdu.header.update("AREA", float(self.parameters["Area"]))
-        tbhdu.header.update("D_A", float(self.parameters["AngularDiameterDistance"]))
-        tbhdu.header.update("REDSHIFT", self.parameters["Redshift"])
-        tbhdu.header.update("HDUVERS", "1.1.0")
-        tbhdu.header.update("RADECSYS", "FK5")
-        tbhdu.header.update("EQUINOX", 2000.0)
+        tbhdu.header["MTYPE1"] = "sky"
+        tbhdu.header["MFORM1"] = "x,y"
+        tbhdu.header["MTYPE2"] = "EQPOS"
+        tbhdu.header["MFORM2"] = "RA,DEC"
+        tbhdu.header["TCTYP2"] = "RA---TAN"
+        tbhdu.header["TCTYP3"] = "DEC--TAN"
+        tbhdu.header["TCRVL2"] = float(self.parameters["sky_center"][0])
+        tbhdu.header["TCRVL3"] = float(self.parameters["sky_center"][1])
+        tbhdu.header["TCDLT2"] = -float(self.parameters["dtheta"])
+        tbhdu.header["TCDLT3"] = float(self.parameters["dtheta"])
+        tbhdu.header["TCRPX2"] = self.parameters["pix_center"][0]
+        tbhdu.header["TCRPX3"] = self.parameters["pix_center"][1]
+        tbhdu.header["TLMIN2"] = 0.5
+        tbhdu.header["TLMIN3"] = 0.5
+        tbhdu.header["TLMAX2"] = 2.*self.parameters["pix_center"][0]-0.5
+        tbhdu.header["TLMAX3"] = 2.*self.parameters["pix_center"][1]-0.5
+        tbhdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
+        if isinstance(self.parameters["Area"], basestring):
+            tbhdu.header["AREA"] = self.parameters["Area"]
+        else:
+            tbhdu.header["AREA"] = float(self.parameters["Area"])
+        tbhdu.header["D_A"] = float(self.parameters["AngularDiameterDistance"])
+        tbhdu.header["REDSHIFT"] = self.parameters["Redshift"]
+        tbhdu.header["HDUVERS"] = "1.1.0"
+        tbhdu.header["RADECSYS"] = "FK5"
+        tbhdu.header["EQUINOX"] = 2000.0
         if "RMF" in self.parameters:
-            tbhdu.header.update("RMF", self.parameters["RMF"])
+            tbhdu.header["RMF"] = self.parameters["RMF"]
         if "ARF" in self.parameters:
-            tbhdu.header.update("ARF", self.parameters["ARF"])
+            tbhdu.header["ARF"] = self.parameters["ARF"]
         if "ChannelType" in self.parameters:
-            tbhdu.header.update("CHANTYPE", self.parameters["ChannelType"])
+            tbhdu.header["CHANTYPE"] = self.parameters["ChannelType"]
         if "Telescope" in self.parameters:
-            tbhdu.header.update("TELESCOP", self.parameters["Telescope"])
+            tbhdu.header["TELESCOP"] = self.parameters["Telescope"]
         if "Instrument" in self.parameters:
-            tbhdu.header.update("INSTRUME", self.parameters["Instrument"])
+            tbhdu.header["INSTRUME"] = self.parameters["Instrument"]
             
         tbhdu.writeto(fitsfile, clobber=clobber)
 
@@ -978,15 +980,15 @@
         tbhdu = pyfits.new_table(coldefs)
         tbhdu.update_ext_name("PHLIST")
 
-        tbhdu.header.update("HDUCLASS", "HEASARC/SIMPUT")
-        tbhdu.header.update("HDUCLAS1", "PHOTONS")
-        tbhdu.header.update("HDUVERS", "1.1.0")
-        tbhdu.header.update("EXTVER", 1)
-        tbhdu.header.update("REFRA", 0.0)
-        tbhdu.header.update("REFDEC", 0.0)
-        tbhdu.header.update("TUNIT1", "keV")
-        tbhdu.header.update("TUNIT2", "deg")
-        tbhdu.header.update("TUNIT3", "deg")                
+        tbhdu.header["HDUCLASS"] = "HEASARC/SIMPUT"
+        tbhdu.header["HDUCLAS1"] = "PHOTONS"
+        tbhdu.header["HDUVERS"] = "1.1.0"
+        tbhdu.header["EXTVER"] = 1
+        tbhdu.header["REFRA"] = 0.0
+        tbhdu.header["REFDEC"] = 0.0
+        tbhdu.header["TUNIT1"] = "keV"
+        tbhdu.header["TUNIT2"] = "deg"
+        tbhdu.header["TUNIT3"] = "deg"
 
         phfile = prefix+"_phlist.fits"
 
@@ -1006,17 +1008,17 @@
         wrhdu = pyfits.new_table(coldefs)
         wrhdu.update_ext_name("SRC_CAT")
                                 
-        wrhdu.header.update("HDUCLASS", "HEASARC")
-        wrhdu.header.update("HDUCLAS1", "SIMPUT")
-        wrhdu.header.update("HDUCLAS2", "SRC_CAT")        
-        wrhdu.header.update("HDUVERS", "1.1.0")
-        wrhdu.header.update("RADECSYS", "FK5")
-        wrhdu.header.update("EQUINOX", 2000.0)
-        wrhdu.header.update("TUNIT2", "deg")
-        wrhdu.header.update("TUNIT3", "deg")
-        wrhdu.header.update("TUNIT4", "keV")
-        wrhdu.header.update("TUNIT5", "keV")
-        wrhdu.header.update("TUNIT6", "erg/s/cm**2")
+        wrhdu.header["HDUCLASS"] = "HEASARC"
+        wrhdu.header["HDUCLAS1"] = "SIMPUT"
+        wrhdu.header["HDUCLAS2"] = "SRC_CAT"
+        wrhdu.header["HDUVERS"] = "1.1.0"
+        wrhdu.header["RADECSYS"] = "FK5"
+        wrhdu.header["EQUINOX"] = 2000.0
+        wrhdu.header["TUNIT2"] = "deg"
+        wrhdu.header["TUNIT3"] = "deg"
+        wrhdu.header["TUNIT4"] = "keV"
+        wrhdu.header["TUNIT5"] = "keV"
+        wrhdu.header["TUNIT6"] = "erg/s/cm**2"
 
         simputfile = prefix+"_simput.fits"
                 
@@ -1100,19 +1102,19 @@
         
         hdu = pyfits.PrimaryHDU(H.T)
         
-        hdu.header.update("MTYPE1", "EQPOS")
-        hdu.header.update("MFORM1", "RA,DEC")
-        hdu.header.update("CTYPE1", "RA---TAN")
-        hdu.header.update("CTYPE2", "DEC--TAN")
-        hdu.header.update("CRPIX1", 0.5*(nx+1))
-        hdu.header.update("CRPIX2", 0.5*(nx+1))                
-        hdu.header.update("CRVAL1", float(self.parameters["sky_center"][0]))
-        hdu.header.update("CRVAL2", float(self.parameters["sky_center"][1]))
-        hdu.header.update("CUNIT1", "deg")
-        hdu.header.update("CUNIT2", "deg")
-        hdu.header.update("CDELT1", -float(self.parameters["dtheta"]))
-        hdu.header.update("CDELT2", float(self.parameters["dtheta"]))
-        hdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
+        hdu.header["MTYPE1"] = "EQPOS"
+        hdu.header["MFORM1"] = "RA,DEC"
+        hdu.header["CTYPE1"] = "RA---TAN"
+        hdu.header["CTYPE2"] = "DEC--TAN"
+        hdu.header["CRPIX1"] = 0.5*(nx+1)
+        hdu.header["CRPIX2"] = 0.5*(nx+1)
+        hdu.header["CRVAL1"] = float(self.parameters["sky_center"][0])
+        hdu.header["CRVAL2"] = float(self.parameters["sky_center"][1])
+        hdu.header["CUNIT1"] = "deg"
+        hdu.header["CUNIT2"] = "deg"
+        hdu.header["CDELT1"] = -float(self.parameters["dtheta"])
+        hdu.header["CDELT2"] = float(self.parameters["dtheta"])
+        hdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
         
         hdu.writeto(imagefile, clobber=clobber)
                                     
@@ -1183,41 +1185,41 @@
         tbhdu.update_ext_name("SPECTRUM")
 
         if not energy_bins:
-            tbhdu.header.update("DETCHANS", spec.shape[0])
-            tbhdu.header.update("TOTCTS", spec.sum())
-            tbhdu.header.update("EXPOSURE", float(self.parameters["ExposureTime"]))
-            tbhdu.header.update("LIVETIME", float(self.parameters["ExposureTime"]))
-            tbhdu.header.update("CONTENT", spectype)
-            tbhdu.header.update("HDUCLASS", "OGIP")
-            tbhdu.header.update("HDUCLAS1", "SPECTRUM")
-            tbhdu.header.update("HDUCLAS2", "TOTAL")
-            tbhdu.header.update("HDUCLAS3", "TYPE:I")
-            tbhdu.header.update("HDUCLAS4", "COUNT")
-            tbhdu.header.update("HDUVERS", "1.1.0")
-            tbhdu.header.update("HDUVERS1", "1.1.0")
-            tbhdu.header.update("CHANTYPE", spectype)
-            tbhdu.header.update("BACKFILE", "none")
-            tbhdu.header.update("CORRFILE", "none")
-            tbhdu.header.update("POISSERR", True)
+            tbhdu.header["DETCHANS"] = spec.shape[0]
+            tbhdu.header["TOTCTS"] = spec.sum()
+            tbhdu.header["EXPOSURE"] = float(self.parameters["ExposureTime"])
+            tbhdu.header["LIVETIME"] = float(self.parameters["ExposureTime"])
+            tbhdu.header["CONTENT"] = spectype
+            tbhdu.header["HDUCLASS"] = "OGIP"
+            tbhdu.header["HDUCLAS1"] = "SPECTRUM"
+            tbhdu.header["HDUCLAS2"] = "TOTAL"
+            tbhdu.header["HDUCLAS3"] = "TYPE:I"
+            tbhdu.header["HDUCLAS4"] = "COUNT"
+            tbhdu.header["HDUVERS"] = "1.1.0"
+            tbhdu.header["HDUVERS1"] = "1.1.0"
+            tbhdu.header["CHANTYPE"] = spectype
+            tbhdu.header["BACKFILE"] = "none"
+            tbhdu.header["CORRFILE"] = "none"
+            tbhdu.header["POISSERR"] = True
             if self.parameters.has_key("RMF"):
-                 tbhdu.header.update("RESPFILE", self.parameters["RMF"])
+                 tbhdu.header["RESPFILE"] = self.parameters["RMF"]
             else:
-                 tbhdu.header.update("RESPFILE", "none")
+                 tbhdu.header["RESPFILE"] = "none"
             if self.parameters.has_key("ARF"):
-                tbhdu.header.update("ANCRFILE", self.parameters["ARF"])
+                tbhdu.header["ANCRFILE"] = self.parameters["ARF"]
             else:        
-                tbhdu.header.update("ANCRFILE", "none")
+                tbhdu.header["ANCRFILE"] = "none"
             if self.parameters.has_key("Telescope"):
-                tbhdu.header.update("TELESCOP", self.parameters["Telescope"])
+                tbhdu.header["TELESCOP"] = self.parameters["Telescope"]
             else:
-                tbhdu.header.update("TELESCOP", "none")
+                tbhdu.header["TELESCOP"] = "none"
             if self.parameters.has_key("Instrument"):
-                tbhdu.header.update("INSTRUME", self.parameters["Instrument"])
+                tbhdu.header["INSTRUME"] = self.parameters["Instrument"]
             else:
-                tbhdu.header.update("INSTRUME", "none")
-            tbhdu.header.update("AREASCAL", 1.0)
-            tbhdu.header.update("CORRSCAL", 0.0)
-            tbhdu.header.update("BACKSCAL", 1.0)
+                tbhdu.header["INSTRUME"] = "none"
+            tbhdu.header["AREASCAL"] = 1.0
+            tbhdu.header["CORRSCAL"] = 0.0
+            tbhdu.header["BACKSCAL"] = 1.0
                                 
         hdulist = pyfits.HDUList([pyfits.PrimaryHDU(), tbhdu])
         

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/analysis_modules/photon_simulator/spectral_models.py
--- a/yt/analysis_modules/photon_simulator/spectral_models.py
+++ b/yt/analysis_modules/photon_simulator/spectral_models.py
@@ -28,8 +28,8 @@
     from scipy import stats        
 except ImportError:
     pass
-from yt.frontends.fits.data_structures import ap
-pyfits = ap.pyfits
+from yt.utilities.on_demand_imports import _astropy
+pyfits = _astropy.pyfits
 
 from yt.utilities.physical_constants import hcgs, clight, erg_per_keV, amu_cgs
 

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/analysis_modules/ppv_cube/ppv_cube.py
--- a/yt/analysis_modules/ppv_cube/ppv_cube.py
+++ b/yt/analysis_modules/ppv_cube/ppv_cube.py
@@ -11,7 +11,7 @@
 #-----------------------------------------------------------------------------
 
 import numpy as np
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import _astropy
 from yt.utilities.orientation import Orientation
 from yt.utilities.fits_image import FITSImageBuffer
 from yt.visualization.volume_rendering.camera import off_axis_projection
@@ -150,7 +150,7 @@
         if length_unit[1] == "deg":
             dx *= -1.
 
-        w = ap.pywcs.WCS(naxis=3)
+        w = _astropy.pywcs.WCS(naxis=3)
         w.wcs.crpix = [0.5*(self.nx+1), 0.5*(self.ny+1), 0.5*(self.nv+1)]
         w.wcs.cdelt = [dx,dy,dv]
         w.wcs.crval = [center[0], center[1], v_center]

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/data_objects/static_output.py
--- a/yt/data_objects/static_output.py
+++ b/yt/data_objects/static_output.py
@@ -653,6 +653,15 @@
                 registry = self.unit_registry)
         return self._quan
 
+    def add_field(self, name, function=None, **kwargs):
+        """
+        Dataset-specific call to add_field
+        """
+        self.index
+        self.field_info.add_field(name, function=function, **kwargs)
+        deps, _ = self.field_info.check_derived_fields([name])
+        self.field_dependencies.update(deps)
+
 def _reconstruct_pf(*args, **kwargs):
     pfs = ParameterFileStore()
     pf = pfs.get_pf_hash(*args)

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/frontends/fits/data_structures.py
--- a/yt/frontends/fits/data_structures.py
+++ b/yt/frontends/fits/data_structures.py
@@ -39,58 +39,7 @@
     unit_prefixes
 from yt.units import dimensions
 from yt.units.yt_array import YTQuantity
-
-class astropy_imports:
-    _pyfits = None
-    @property
-    def pyfits(self):
-        if self._pyfits is None:
-            try:
-                import astropy.io.fits as pyfits
-                self.log
-            except ImportError:
-                pyfits = None
-            self._pyfits = pyfits
-        return self._pyfits
-
-    _pywcs = None
-    @property
-    def pywcs(self):
-        if self._pywcs is None:
-            try:
-                import astropy.wcs as pywcs
-                self.log
-            except ImportError:
-                pywcs = None
-            self._pywcs = pywcs
-        return self._pywcs
-
-    _log = None
-    @property
-    def log(self):
-        if self._log is None:
-            try:
-                from astropy import log
-                if log.exception_logging_enabled():
-                    log.disable_exception_logging()
-            except ImportError:
-                log = None
-            self._log = log
-        return self._log
-
-    _conv = None
-    @property
-    def conv(self):
-        if self._conv is None:
-            try:
-                import astropy.convolution as conv
-                self.log
-            except ImportError:
-                conv = None
-            self._conv = conv
-        return self._conv
-
-ap = astropy_imports()
+from yt.utilities.on_demand_imports import _astropy
 
 lon_prefixes = ["X","RA","GLON"]
 lat_prefixes = ["Y","DEC","GLAT"]
@@ -145,7 +94,8 @@
             # FITS units always return upper-case, so we need to get
             # the right case by comparing against known units. This
             # only really works for common units.
-            units = re.split(regex_pattern, field_units)
+            units = set(re.split(regex_pattern, field_units))
+            units.remove('')
             n = int(0)
             for unit in units:
                 if unit in known_units:
@@ -262,7 +212,7 @@
                                                        pf.domain_right_edge)])
             dims = np.array(pf.domain_dimensions)
             # If we are creating a dataset of lines, only decompose along the position axes
-            if pf.line_database is not None:
+            if len(pf.line_database) > 0:
                 dims[pf.vel_axis] = 1
             psize = get_psize(dims, pf.nprocs)
             gle, gre, shapes, slices = decompose_array(dims, psize, bbox)
@@ -270,7 +220,7 @@
             self.grid_right_edge = self.pf.arr(gre, "code_length")
             self.grid_dimensions = np.array([shape for shape in shapes], dtype="int32")
             # If we are creating a dataset of lines, only decompose along the position axes
-            if pf.line_database is not None:
+            if len(pf.line_database) > 0:
                 self.grid_left_edge[:,pf.vel_axis] = pf.domain_left_edge[pf.vel_axis]
                 self.grid_right_edge[:,pf.vel_axis] = pf.domain_right_edge[pf.vel_axis]
                 self.grid_dimensions[:,pf.vel_axis] = pf.domain_dimensions[pf.vel_axis]
@@ -373,7 +323,7 @@
         elif isinstance(nan_mask, dict):
             self.nan_mask = nan_mask
         self.nprocs = nprocs
-        self._handle = ap.pyfits.open(self.filenames[0],
+        self._handle = _astropy.pyfits.open(self.filenames[0],
                                       memmap=True,
                                       do_not_scale_image_data=True,
                                       ignore_blank=True)
@@ -384,7 +334,7 @@
                     fn = fits_file
                 else:
                     fn = os.path.join(ytcfg.get("yt","test_data_dir"),fits_file)
-                f = ap.pyfits.open(fn, memmap=True,
+                f = _astropy.pyfits.open(fn, memmap=True,
                                    do_not_scale_image_data=True,
                                    ignore_blank=True)
                 self._fits_files.append(f)
@@ -394,7 +344,7 @@
             self.first_image = 1
             self.primary_header = self._handle[self.first_image].header
             self.naxis = 2
-            self.wcs = ap.pywcs.WCS(naxis=2)
+            self.wcs = _astropy.pywcs.WCS(naxis=2)
             self.events_info = {}
             for k,v in self.primary_header.items():
                 if k.startswith("TTYP"):
@@ -428,7 +378,7 @@
             self.events_data = False
             self.first_image = 0
             self.primary_header = self._handle[self.first_image].header
-            self.wcs = ap.pywcs.WCS(header=self.primary_header)
+            self.wcs = _astropy.pywcs.WCS(header=self.primary_header)
             self.naxis = self.primary_header["naxis"]
             self.axis_names = [self.primary_header["ctype%d" % (i+1)]
                                for i in xrange(self.naxis)]
@@ -531,6 +481,8 @@
                                     32**self.dimensionality).astype("int")
             self.nprocs = max(min(self.nprocs, 512), 1)
 
+        self.reversed = False
+
         # Check to see if this data is in some kind of (Lat,Lon,Vel) format
         self.ppv_data = False
         x = 0
@@ -572,7 +524,7 @@
             self.vel_axis = np.where(self.vel_axis)[0][0]
             self.vel_name = ctypes[self.vel_axis].split("-")[0].lower()
 
-            self.wcs_2d = ap.pywcs.WCS(naxis=2)
+            self.wcs_2d = _astropy.pywcs.WCS(naxis=2)
             self.wcs_2d.wcs.crpix = self.wcs.wcs.crpix[[self.lon_axis, self.lat_axis]]
             self.wcs_2d.wcs.cdelt = self.wcs.wcs.cdelt[[self.lon_axis, self.lat_axis]]
             self.wcs_2d.wcs.crval = self.wcs.wcs.crval[[self.lon_axis, self.lat_axis]]
@@ -591,7 +543,6 @@
                 le = self.dims[self.vel_axis]+0.5
                 re = 0.5
             else:
-                self.reversed = False
                 le = 0.5
                 re = self.dims[self.vel_axis]+0.5
             self.domain_left_edge[self.vel_axis] = (le-x0)*dz + z0
@@ -632,7 +583,7 @@
         try:
             with warnings.catch_warnings():
                 warnings.filterwarnings('ignore', category=UserWarning, append=True)
-                fileh = ap.pyfits.open(args[0])
+                fileh = _astropy.pyfits.open(args[0])
             valid = fileh[0].header["naxis"] >= 2
             if len(fileh) > 1 and fileh[1].name == "EVENTS":
                 valid = fileh[1].header["naxis"] >= 2

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/frontends/fits/fields.py
--- a/yt/frontends/fits/fields.py
+++ b/yt/frontends/fits/fields.py
@@ -25,17 +25,17 @@
 
     def _setup_ppv_fields(self):
 
-        def _get_2d_wcs(self, data, axis):
+        def _get_2d_wcs(data, axis):
             w_coords = data.pf.wcs_2d.wcs_pix2world(data["x"], data["y"], 1)
             return w_coords[axis]
 
         def world_f(axis, unit):
             def _world_f(field, data):
-                return data.pf.arr(self._get_2d_wcs(data, axis), unit)
+                return data.pf.arr(_get_2d_wcs(data, axis), unit)
             return _world_f
 
         for (i, axis), name in zip(enumerate([self.pf.lon_axis, self.pf.lat_axis]),
-                             [self.pf.lon_name, self.pf.lat_name]):
+                                             [self.pf.lon_name, self.pf.lat_name]):
             unit = str(self.pf.wcs_2d.wcs.cunit[i])
             if unit.lower() == "deg": unit = "degree"
             if unit.lower() == "rad": unit = "radian"

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/frontends/fits/misc.py
--- a/yt/frontends/fits/misc.py
+++ b/yt/frontends/fits/misc.py
@@ -14,7 +14,7 @@
 from yt.fields.api import add_field
 from yt.fields.derived_field import ValidateSpatial
 from yt.funcs import mylog
-from .data_structures import ap
+from yt.utilities.on_demand_imports import _astropy
 
 def _make_counts(emin, emax):
     def _counts(field, data):
@@ -30,31 +30,34 @@
         else:
             sigma = None
         if sigma is not None and sigma > 0.0:
-            kern = ap.conv.Gaussian2DKernel(stddev=sigma)
-            img[:,:,0] = ap.conv.convolve(img[:,:,0], kern)
+            kern = _astropy.conv.Gaussian2DKernel(stddev=sigma)
+            img[:,:,0] = _astropy.conv.convolve(img[:,:,0], kern)
         return data.pf.arr(img, "counts/pixel")
     return _counts
 
-def setup_counts_fields(ebounds):
+def setup_counts_fields(ds, ebounds, ftype="gas"):
     r"""
     Create deposited image fields from X-ray count data in energy bands.
 
     Parameters
     ----------
+    ds : Dataset
+        The FITS events file dataset to add the counts fields to.
     ebounds : list of tuples
         A list of tuples, one for each field, with (emin, emax) as the
         energy bounds for the image.
 
     Examples
     --------
+    >>> ds = yt.load("evt.fits")
     >>> ebounds = [(0.1,2.0),(2.0,3.0)]
-    >>> setup_counts_fields(ebounds)
+    >>> setup_counts_fields(ds, ebounds)
     """
     for (emin, emax) in ebounds:
         cfunc = _make_counts(emin, emax)
         fname = "counts_%s-%s" % (emin, emax)
         mylog.info("Creating counts field %s." % fname)
-        add_field(("gas",fname), function=cfunc,
-                  units="counts/pixel",
-                  validators = [ValidateSpatial()],
-                  display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file
+        ds.add_field((ftype,fname), function=cfunc,
+                     units="counts/pixel",
+                     validators = [ValidateSpatial()],
+                     display_name="Counts (%s-%s keV)" % (emin, emax))
\ No newline at end of file

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/units/tests/test_ytarray.py
--- a/yt/units/tests/test_ytarray.py
+++ b/yt/units/tests/test_ytarray.py
@@ -26,7 +26,7 @@
     unary_operators, binary_operators
 from yt.utilities.exceptions import \
     YTUnitOperationError, YTUfuncUnitError
-from yt.testing import fake_random_pf
+from yt.testing import fake_random_pf, requires_module
 from yt.funcs import fix_length
 import numpy as np
 import copy
@@ -650,3 +650,28 @@
 
     for op in [operator.abs, operator.neg, operator.pos]:
         yield unary_op_registry_comparison, op
+
+ at requires_module("astropy")
+def test_astropy():
+    from yt.utilities.on_demand_imports import _astropy
+
+    ap_arr = np.arange(10)*_astropy.units.km/_astropy.units.hr
+    yt_arr = YTArray(np.arange(10), "km/hr")
+    yt_arr2 = YTArray.from_astropy(ap_arr)
+
+    ap_quan = 10.*_astropy.units.Msun**0.5/(_astropy.units.kpc**3)
+    yt_quan = YTQuantity(10.,"sqrt(Msun)/kpc**3")
+    yt_quan2 = YTQuantity.from_astropy(ap_quan)
+
+    yield assert_array_equal, ap_arr, yt_arr.to_astropy()
+    yield assert_array_equal, yt_arr, YTArray(ap_arr)
+    yield assert_array_equal, yt_arr, yt_arr2
+
+    yield assert_equal, ap_quan, yt_quan.to_astropy()
+    yield assert_equal, yt_quan, YTQuantity(ap_quan)
+    yield assert_equal, yt_quan, yt_quan2
+
+    yield assert_array_equal, yt_arr, YTArray(yt_arr.to_astropy())
+    yield assert_equal, yt_quan, YTQuantity(yt_quan.to_astropy())
+
+

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/units/unit_lookup_table.py
--- a/yt/units/unit_lookup_table.py
+++ b/yt/units/unit_lookup_table.py
@@ -59,12 +59,12 @@
     "yr":  (sec_per_year, dimensions.time),
 
     # Solar units
-    "Msun": ( mass_sun_grams, dimensions.mass),
-    "msun": ( mass_sun_grams, dimensions.mass),
-    "Rsun": ( cm_per_rsun, dimensions.length),
-    "rsun": ( cm_per_rsun, dimensions.length),
-    "Lsun": ( luminosity_sun_ergs_per_sec, dimensions.power),
-    "Tsun": ( temp_sun_kelvin, dimensions.temperature),
+    "Msun": (mass_sun_grams, dimensions.mass),
+    "msun": (mass_sun_grams, dimensions.mass),
+    "Rsun": (cm_per_rsun, dimensions.length),
+    "rsun": (cm_per_rsun, dimensions.length),
+    "Lsun": (luminosity_sun_ergs_per_sec, dimensions.power),
+    "Tsun": (temp_sun_kelvin, dimensions.temperature),
     "Zsun": (metallicity_sun, dimensions.dimensionless),
     "Mjup": (mass_jupiter_grams, dimensions.mass),
     "Mearth": (mass_earth_grams, dimensions.mass),
@@ -89,6 +89,20 @@
     "angstrom": (cm_per_ang, dimensions.length),
     "Jy": (jansky_cgs, dimensions.specific_flux),
     "counts": (1.0, dimensions.dimensionless),
+
+    # for AstroPy compatibility
+    "solMass": (mass_sun_grams, dimensions.mass),
+    "solRad": (cm_per_rsun, dimensions.length),
+    "solLum": (luminosity_sun_ergs_per_sec, dimensions.power),
+    "dyn": (1.0, dimensions.force),
+    "sr": (1.0, dimensions.solid_angle),
+    "rad": (1.0, dimensions.solid_angle),
+    "deg": (np.pi/180., dimensions.angle),
+    "Fr":  (1.0, dimensions.charge),
+    "G": (1.0, dimensions.magnetic_field),
+    "d": (1.0, dimensions.time),
+    "Angstrom": (cm_per_ang, dimensions.length),
+
 }
 
 # Add LaTeX representations for units with trivial representations.

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/units/yt_array.py
--- a/yt/units/yt_array.py
+++ b/yt/units/yt_array.py
@@ -35,6 +35,8 @@
     YTUnitOperationError, YTUnitConversionError, \
     YTUfuncUnitError
 from numbers import Number as numeric_type
+from yt.utilities.on_demand_imports import _astropy
+from sympy import Rational
 
 # redefine this here to avoid a circular import from yt.funcs
 def iterable(obj):
@@ -249,6 +251,9 @@
                     "Perhaps you meant to do something like this instead: \n"
                     "ds.arr(%s, \"%s\")" % (input_array, input_units)
                     )
+        if _astropy.units is not None:
+            if isinstance(input_array, _astropy.units.quantity.Quantity):
+                return cls.from_astropy(input_array)
         if isinstance(input_array, YTArray):
             if input_units is None:
                 if registry is None:
@@ -423,6 +428,38 @@
 
         """
         return np.array(self)
+
+    @classmethod
+    def from_astropy(cls, arr):
+        """
+        Creates a new YTArray with the same unit information from an
+        AstroPy quantity *arr*.
+        """
+        # Converting from AstroPy Quantity
+        u = arr.unit
+        ap_units = []
+        for base, power in zip(u.bases, u.powers):
+            unit_str = base.to_string()
+            # we have to do this because AstroPy is silly and defines
+            # hour as "h"
+            if unit_str == "h": unit_str = "hr"
+            ap_units.append("%s**(%s)" % (unit_str, Rational(power)))
+        ap_units = "*".join(ap_units)
+        if isinstance(arr.value, np.ndarray):
+            return YTArray(arr.value, ap_units)
+        else:
+            return YTQuantity(arr.value, ap_units)
+
+
+    def to_astropy(self, **kwargs):
+        """
+        Creates a new AstroPy quantity with the same unit information.
+        """
+        if _astropy.units is None:
+            raise ImportError("You don't have AstroPy installed, so you can't convert to " +
+                              "an AstroPy quantity.")
+        return self.value*_astropy.units.Unit(str(self.units), **kwargs)
+
     #
     # End unit conversion methods
     #

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/utilities/fits_image.py
--- a/yt/utilities/fits_image.py
+++ b/yt/utilities/fits_image.py
@@ -14,11 +14,11 @@
 from yt.funcs import mylog, iterable, fix_axis, ensure_list
 from yt.visualization.fixed_resolution import FixedResolutionBuffer
 from yt.data_objects.construction_data_containers import YTCoveringGridBase
-from yt.frontends.fits.data_structures import ap
+from yt.utilities.on_demand_imports import _astropy
 from yt.units.yt_array import YTQuantity
 
-pyfits = ap.pyfits
-pywcs = ap.pywcs
+pyfits = _astropy.pyfits
+pywcs = _astropy.pywcs
 
 class FITSImageBuffer(pyfits.HDUList):
 
@@ -295,7 +295,7 @@
     """
     def __init__(self, ds, axis, fields, coord, **kwargs):
         fields = ensure_list(fields)
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, ds)
         if isinstance(coord, tuple):
             coord = ds.quan(coord[0], coord[1]).in_units("code_length").value
         elif isinstance(coord, YTQuantity):
@@ -303,6 +303,8 @@
         slc = ds.slice(axis, coord, **kwargs)
         w, frb = construct_image(slc)
         super(FITSSlice, self).__init__(frb, fields=fields, wcs=w)
+        for i, field in enumerate(fields):
+            self[i].header["bunit"] = str(frb[field].units)
 
 class FITSProjection(FITSImageBuffer):
     r"""
@@ -321,10 +323,12 @@
     """
     def __init__(self, ds, axis, fields, weight_field=None, **kwargs):
         fields = ensure_list(fields)
-        axis = fix_axis(axis)
+        axis = fix_axis(axis, ds)
         prj = ds.proj(fields[0], axis, weight_field=weight_field, **kwargs)
         w, frb = construct_image(prj)
         super(FITSProjection, self).__init__(frb, fields=fields, wcs=w)
+        for i, field in enumerate(fields):
+            self[i].header["bunit"] = str(frb[field].units)
 
 
 

diff -r ffe8407ff931962371b1aed113f363fcaa412ff5 -r 907cb91838fe6a2ef52306d9a0c98dab2dc23c1f yt/utilities/on_demand_imports.py
--- /dev/null
+++ b/yt/utilities/on_demand_imports.py
@@ -0,0 +1,74 @@
+"""
+A set of convenient on-demand imports
+"""
+
+#-----------------------------------------------------------------------------
+# Copyright (c) 2013, yt Development Team.
+#
+# Distributed under the terms of the Modified BSD License.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#-----------------------------------------------------------------------------
+
+class astropy_imports:
+    _pyfits = None
+    @property
+    def pyfits(self):
+        if self._pyfits is None:
+            try:
+                import astropy.io.fits as pyfits
+                self.log
+            except ImportError:
+                pyfits = None
+            self._pyfits = pyfits
+        return self._pyfits
+
+    _pywcs = None
+    @property
+    def pywcs(self):
+        if self._pywcs is None:
+            try:
+                import astropy.wcs as pywcs
+                self.log
+            except ImportError:
+                pywcs = None
+            self._pywcs = pywcs
+        return self._pywcs
+
+    _log = None
+    @property
+    def log(self):
+        if self._log is None:
+            try:
+                from astropy import log
+                if log.exception_logging_enabled():
+                    log.disable_exception_logging()
+            except ImportError:
+                log = None
+            self._log = log
+        return self._log
+
+    _units = None
+    @property
+    def units(self):
+        if self._units is None:
+            try:
+                from astropy import units
+            except ImportError:
+                units = None
+            self._units = units
+        return self._units
+
+    _conv = None
+    @property
+    def conv(self):
+        if self._conv is None:
+            try:
+                import astropy.convolution as conv
+                self.log
+            except ImportError:
+                conv = None
+            self._conv = conv
+        return self._conv
+
+_astropy = astropy_imports()
\ No newline at end of file

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