Skip to content

Commit e21b153

Browse files
committed
move reproject to top-level dask class
1 parent 672245e commit e21b153

File tree

1 file changed

+92
-87
lines changed

1 file changed

+92
-87
lines changed

spectral_cube/dask_spectral_cube.py

Lines changed: 92 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1447,6 +1447,98 @@ def convfunc(img, **kwargs):
14471447
accepts_chunks=True,
14481448
**kwargs).with_beam(beam, raise_error_jybm=False)
14491449

1450+
def reproject(self, header, order='bilinear', use_memmap=False,
1451+
filled=True, **kwargs):
1452+
"""
1453+
Spatially reproject the cube into a new header. Fills the data with
1454+
the cube's ``fill_value`` to replace bad values before reprojection.
1455+
1456+
If you want to reproject a cube both spatially and spectrally, you need
1457+
to use `spectral_interpolate` as well.
1458+
1459+
.. warning::
1460+
The current implementation of ``reproject`` requires that the whole
1461+
cube be loaded into memory. Issue #506 notes that this is a
1462+
problem, and it is on our to-do list to fix.
1463+
1464+
Parameters
1465+
----------
1466+
header : `astropy.io.fits.Header`
1467+
A header specifying a cube in valid WCS
1468+
order : int or str, optional
1469+
The order of the interpolation (if ``mode`` is set to
1470+
``'interpolation'``). This can be either one of the following
1471+
strings:
1472+
1473+
* 'nearest-neighbor'
1474+
* 'bilinear'
1475+
* 'biquadratic'
1476+
* 'bicubic'
1477+
1478+
or an integer. A value of ``0`` indicates nearest neighbor
1479+
interpolation.
1480+
use_memmap : bool
1481+
If specified, a memory mapped temporary file on disk will be
1482+
written to rather than storing the intermediate spectra in memory.
1483+
filled : bool
1484+
Fill the masked values with the cube's fill value before
1485+
reprojection? Note that setting ``filled=False`` will use the raw
1486+
data array, which can be a workaround that prevents loading large
1487+
data into memory.
1488+
kwargs : dict
1489+
Passed to `reproject.reproject_interp`.
1490+
"""
1491+
1492+
try:
1493+
from reproject.version import version
1494+
except ImportError:
1495+
raise ImportError("Requires the reproject package to be"
1496+
" installed.")
1497+
1498+
reproj_kwargs = kwargs
1499+
# Need version > 0.2 to work with cubes, >= 0.5 for memmap
1500+
from distutils.version import LooseVersion
1501+
if LooseVersion(version) < "0.5":
1502+
raise Warning("Requires version >=0.5 of reproject. The current "
1503+
"version is: {}".format(version))
1504+
elif LooseVersion(version) >= "0.6":
1505+
pass # no additional kwargs, no warning either
1506+
else:
1507+
reproj_kwargs['independent_celestial_slices'] = True
1508+
1509+
from reproject import reproject_interp
1510+
1511+
# TODO: Find the minimal subcube that contains the header and only reproject that
1512+
# (see FITS_tools.regrid_cube for a guide on how to do this)
1513+
1514+
newwcs = wcs.WCS(header)
1515+
shape_out = tuple([header['NAXIS{0}'.format(i + 1)] for i in
1516+
range(header['NAXIS'])][::-1])
1517+
1518+
def reproject_interp_wrapper(img_slice):
1519+
# What exactly is the wrapper getting here?
1520+
# I think it is given a _cube_ that is a cutout?
1521+
if filled:
1522+
data = img_slice.filled_data[:]
1523+
else:
1524+
data = img_slice._data
1525+
return reproject_interp((data, img_slice.header),
1526+
newwcs, shape_out=shape_out, **kwargs)
1527+
1528+
newcube, newcube_valid = self.apply_function_parallel_spatial(
1529+
reproject_interp_wrapper,
1530+
accepts_chunks=True,
1531+
order=order,
1532+
**reproj_kwargs)
1533+
1534+
return self._new_cube_with(data=newcube,
1535+
wcs=newwcs,
1536+
mask=BooleanArrayMask(newcube_valid.astype('bool'),
1537+
newwcs),
1538+
meta=self.meta,
1539+
)
1540+
1541+
14501542

14511543
class DaskVaryingResolutionSpectralCube(DaskSpectralCubeMixin, VaryingResolutionSpectralCube):
14521544

@@ -1632,90 +1724,3 @@ def _mask_include(self):
16321724
chunks=self._data.chunksize),
16331725
wcs=self.wcs,
16341726
shape=self.shape)
1635-
1636-
def reproject(self, header, order='bilinear', use_memmap=False,
1637-
filled=True, **kwargs):
1638-
"""
1639-
Spatially reproject the cube into a new header. Fills the data with
1640-
the cube's ``fill_value`` to replace bad values before reprojection.
1641-
1642-
If you want to reproject a cube both spatially and spectrally, you need
1643-
to use `spectral_interpolate` as well.
1644-
1645-
Parameters
1646-
----------
1647-
header : `astropy.io.fits.Header`
1648-
A header specifying a cube in valid WCS
1649-
order : int or str, optional
1650-
The order of the interpolation (if ``mode`` is set to
1651-
``'interpolation'``). This can be either one of the following
1652-
strings:
1653-
1654-
* 'nearest-neighbor'
1655-
* 'bilinear'
1656-
* 'biquadratic'
1657-
* 'bicubic'
1658-
1659-
or an integer. A value of ``0`` indicates nearest neighbor
1660-
interpolation.
1661-
use_memmap : bool
1662-
If specified, a memory mapped temporary file on disk will be
1663-
written to rather than storing the intermediate spectra in memory.
1664-
filled : bool
1665-
Fill the masked values with the cube's fill value before
1666-
reprojection? Note that setting ``filled=False`` will use the raw
1667-
data array, which can be a workaround that prevents loading large
1668-
data into memory.
1669-
kwargs : dict
1670-
Passed to `reproject.reproject_interp`.
1671-
"""
1672-
1673-
try:
1674-
from reproject.version import version
1675-
except ImportError:
1676-
raise ImportError("Requires the reproject package to be"
1677-
" installed.")
1678-
1679-
reproj_kwargs = kwargs
1680-
# Need version > 0.2 to work with cubes, >= 0.5 for memmap
1681-
from distutils.version import LooseVersion
1682-
if LooseVersion(version) < "0.5":
1683-
raise Warning("Requires version >=0.5 of reproject. The current "
1684-
"version is: {}".format(version))
1685-
elif LooseVersion(version) >= "0.6":
1686-
pass # no additional kwargs, no warning either
1687-
else:
1688-
reproj_kwargs['independent_celestial_slices'] = True
1689-
1690-
from reproject import reproject_interp
1691-
1692-
# TODO: Find the minimal subcube that contains the header and only reproject that
1693-
# (see FITS_tools.regrid_cube for a guide on how to do this)
1694-
1695-
newwcs = wcs.WCS(header)
1696-
shape_out = tuple([header['NAXIS{0}'.format(i + 1)] for i in
1697-
range(header['NAXIS'])][::-1])
1698-
1699-
def reproject_interp_wrapper(img_slice):
1700-
# What exactly is the wrapper getting here?
1701-
# I think it is given a _cube_ that is a cutout?
1702-
if filled:
1703-
data = img_slice.filled_data[:]
1704-
else:
1705-
data = img_slice._data
1706-
return reproject_interp((data, img_slice.header),
1707-
newwcs, shape_out=shape_out, **kwargs)
1708-
1709-
newcube, newcube_valid = self.apply_function_parallel_spatial(
1710-
reproject_interp_wrapper,
1711-
accepts_chunks=True,
1712-
order=order,
1713-
**reproj_kwargs)
1714-
1715-
return self._new_cube_with(data=newcube,
1716-
wcs=newwcs,
1717-
mask=BooleanArrayMask(newcube_valid.astype('bool'),
1718-
newwcs),
1719-
meta=self.meta,
1720-
)
1721-

0 commit comments

Comments
 (0)