Example #1
0
    def _spectrum_from_component(self, layer, component, wcs, mask=None):
        data = SpectralCube(component.data, wcs)

        if mask is not None:
            data = data.with_mask(mask)

        if self._data_operation.currentIndex() == 1:
            spec_data = data.mean((1, 2))
        elif self._data_operation.currentIndex() == 2:
            spec_data = data.median((1, 2))
        else:
            spec_data = data.sum((1, 2))

        spec_data = Spectrum1DRef(spec_data.data,
                                  unit=spec_data.unit,
                                  dispersion=data.spectral_axis.data,
                                  dispersion_unit=data.spectral_axis.unit,
                                  wcs=data.wcs,
                                  name=layer.label)

        # Store the relation between the component and the specviz data. If
        # the data exists, first remove the component from specviz and then
        # re-add it.
        if layer in self._specviz_data_cache:
            old_spec_data = self._specviz_data_cache[layer]
            dispatch.on_remove_data.emit(old_spec_data)

        self._specviz_data_cache[layer] = spec_data

        dispatch.on_add_to_window.emit(data=spec_data,
                                       style={'color': layer.style.rgba[:3]})
Example #2
0
    def _spectrum_from_component(self,
                                 layer,
                                 component,
                                 wcs,
                                 mask=None,
                                 cid=None):
        data = SpectralCube(component.data, wcs)

        if mask is not None:
            data = data.with_mask(mask)

        # Update the associated data attribute in the plugin
        self._spec_ops.spectral_data = data
        self._spec_ops.component_id = cid

        if self._data_operation.currentIndex() == 1:
            spec_data = data.mean((1, 2))
        elif self._data_operation.currentIndex() == 2:
            spec_data = data.median((1, 2))
        else:
            spec_data = data.sum((1, 2))

        spec_data = Spectrum1DRef(spec_data.data,
                                  unit=spec_data.unit,
                                  dispersion=data.spectral_axis.data,
                                  dispersion_unit=data.spectral_axis.unit,
                                  wcs=data.wcs,
                                  name=layer.label)

        spec_layer = Spectrum1DRefLayer.from_parent(spec_data)

        # Store the relation between the component and the specviz data. If
        # the data exists, first remove the component from specviz and then
        # re-add it.
        old_spec_layer = self._specviz_data_cache.get(layer)

        self._specviz_data_cache[layer] = spec_layer

        if old_spec_layer is None:
            dispatch.on_add_to_window.emit(layer=spec_layer,
                                           style={
                                               'color': layer.style.rgba[:3],
                                               'line_width': 3
                                           },
                                           vertical_line=True)
        else:
            dispatch.replace_layer.emit(old_layer=old_spec_layer,
                                        new_layer=spec_layer,
                                        style={
                                            'color': layer.style.rgba[:3],
                                            'line_width': 3
                                        })
Example #3
0
    def _spectrum_from_component(self, layer, component, wcs, mask=None):
        data = SpectralCube(component.data, wcs)

        if mask is not None:
            data = data.with_mask(mask)

        spec_data = data.sum((1, 2))

        spec_data = Spectrum1DRef(spec_data.data,
                                  unit=spec_data.unit,
                                  dispersion=data.spectral_axis.data,
                                  dispersion_unit=data.spectral_axis.unit,
                                  wcs=data.wcs)

        # Store the relation between the component and the specviz data. If
        # the data exists, first remove the component from specviz and then
        # re-add it.
        if layer in self._specviz_data_cache:
            old_spec_data = self._specviz_data_cache[layer]
            dispatch.on_remove_data.emit(old_spec_data)

        self._specviz_data_cache[layer] = spec_data

        dispatch.on_add_to_window.emit(spec_data)
Example #4
0
class MultiResObs(object):
    """
    Object to hold observations of the same object at different resolutions.
    This is intended for matching and analyzing high-res (interferometric)
    and low-res (single dish) observations.
    """
    def __init__(self, highres, lowres):
        super(MultiResObs, self).__init__()
        self.highres = SpectralCube.read(highres)
        self.lowres = SpectralCube.read(lowres)

        self.highres_convolved = None
        self.lowres_convolved = None

        self.lowbeam = self.lowres.beam
        self.highbeam = self.highres.beam

        self.combined_beam = self.lowbeam.convolve(self.highbeam)

    def apply_mask(self, highres_mask=None, lowres_mask=None):
        '''
        Apply a pre-made mask to either of the data cubes.
        '''

        if highres_mask is not None:
            self.highres = self.highres.with_mask(highres_mask)

        if lowres_mask is not None:
            self.lowres = self.lowres.with_mask(lowres_mask)

    def match_coords(self):
        '''
        Match the spatial and spectral coordinates of the cubes.
        '''

        # TODO: use Skycoords to convert extrema into the same frame

        # Are either of the cubes in the correct frame?
        if self.highres.header['CTYPE1'] != self.lowres.header['CTYPE1']:
            raise TypeError("ctypes do not match. Are observations in the "
                            "same projection? Highres: " +
                            self.highres.header['CTYPE1'] +
                            " Lowres: " + self.lowres.header['CTYPE1'])
        elif self.highres.header['CTYPE2'] != self.lowres.header['CTYPE2']:
            raise TypeError("ctypes do not match. Are observations in the "
                            "same projection? Highres: " +
                            self.highres.header['CTYPE2'] +
                            " Lowres: " + self.lowres.header['CTYPE2'])

        # Determine which cube should be slice down so both have the same
        # spatial coverage.

        limits_high = []
        limits_low = []

        low_long = self.lowres.longitude_extrema
        high_long = self.highres.longitude_extrema

        low_lat = self.lowres.latitude_extrema
        high_lat = self.highres.latitude_extrema

        if low_long[0] < high_long[0]:
            limits_low.append(high_long[0])
            limits_high.append("min")
        else:
            limits_high.append(low_long[0])
            limits_low.append("min")

        if low_long[1] > high_long[1]:
            limits_low.append(high_long[1])
            limits_high.append("max")
        else:
            limits_high.append(low_long[0])
            limits_low.append("min")

        if low_lat[1] > high_lat[1]:
            limits_low.append(high_lat[1])
            limits_high.append("min")
        else:
            limits_high.append(low_lat[0])
            limits_low.append("min")

        if low_lat[0] < high_lat[0]:
            limits_low.append(high_lat[0])
            limits_high.append("max")
        else:
            limits_high.append(low_lat[0])
            limits_low.append("max")

        # Apply common slicing to both

        self.highres = \
            self.highres.subcube(xlo=limits_high[0], xhi=limits_high[1],
                                 ylo=limits_high[2], yhi=limits_high[3])

        self.lowres = \
            self.lowres.subcube(xlo=limits_low[0], xhi=limits_low[1],
                                ylo=limits_low[2], yhi=limits_low[3])

        # Now match the spectral extends

        low_spec = \
            self.highres.spectral_extrema[0] if \
            self.highres.spectral_extrema[0] > self.lowres.spectral_extrema[0]\
            else self.lowres.spectral_extrema[0]

        high_spec = \
            self.highres.spectral_extrema[1] if \
            self.highres.spectral_extrema[1] < self.lowres.spectral_extrema[1]\
            else self.lowres.spectral_extrema[1]

        self.highres = self.highres.spectral_slab(low_spec, high_spec)
        self.lowres = self.lowres.spectral_slab(low_spec, high_spec)

    def convert_to(self, unit=u.K, freq=1420.40575177*u.MHz):
        '''
        Convert both sets to common brightness units.
        '''

        convert_high = unit != self.highres.unit
        convert_low = unit != self.lowres.unit

        high_unit = self.highres.unit
        low_unit = self.lowres.unit

        if unit == u.K:

            if convert_high and 'Jy' in high_unit.name:

                self.highres = \
                    self.highres.to(unit, self.highbeam.jtok_equiv(freq))

            if convert_low and 'Jy' in low_unit.name:

                self.lowres = \
                    self.lowres.to(unit, self.lowbeam.jtok_equiv(freq))
        else:
            raise NotImplementedError("Only supporting Jy/beam -> K right now.")

    def convolve_to_common(self, verbose=False, use_dask=True,
                           block=(256, 256)):
        '''
        Convolve cubes to a common resolution using the combined beam.
        '''

        # Create convolution kernels from the combined beam
        conv_kernel_high = \
            self.combined_beam.as_kernel(wcs_to_platescale(self.highres.wcs))

        # if use_dask:
        #     assert np.alltrue([bl > kern for bl, kern in
        #                        zip(block, conv_kernel_high.shape)])

        conv_kernel_low = \
            self.combined_beam.as_kernel(wcs_to_platescale(self.lowres.wcs))

        # if use_dask:
        #     assert np.alltrue([bl > kern for bl, kern in
        #                        zip(block, conv_kernel_low.shape)])

        high_pad = np.ceil(conv_kernel_high.shape[0] / 2).astype(int)

        highres_convolved = np.empty(self.highres.shape)

        high_chans = len(self.highres.spectral_axis)

        if verbose:
            print("Convolving high resolution cube.")

        if use_dask:
            highres_convolved = auto_dask_map(self.highres, blocks=block,
                                              args=[conv_kernel_high])

        # for chan in range(high_chans):
        #     if verbose:
        #         print("On Channel: "+str(chan)+" of "+str(high_chans))

        #     if use_dask:
        #         da_arr = \
        #             da.from_array(np.pad(self.highres.filled_data[chan, :, :],
        #                                  high_pad, padwithnans),
        #                           chunks=block)

        #         highres_convolved[chan, high_pad:-high_pad,
        #                           high_pad:-high_pad] = \
        #             da_arr.map_overlap(
        #                 lambda a:
        #                     convolve_fft(a,
        #                                  conv_kernel_high,
        #                                  boundary='fill',
        #                                  interpolate_nan=True,
        #                                  normalize_kernel=True),
        #                 depth=2*high_pad,
        #                 boundary=np.nan).compute()

        #     else:
        #         highres_convolved[chan, :, :] = \
        #             convolve_fft(self.highres.filled_data[chan, :, :],
        #                          conv_kernel_high, boundary='fill',
        #                          interpolate_nan=True, normalize_kernel=True)
        update_high_hdr = \
            _update_beam_in_hdr(self.highres.header, self.combined_beam)

        self.highres_convolved = \
            SpectralCube(highres_convolved*self.highres.unit, self.highres.wcs,
                         header=update_high_hdr)

        # Cleanup a bit

        del highres_convolved

        # Now the low resolution data

        lowres_convolved = np.empty(self.lowres.shape)

        low_chans = len(self.lowres.spectral_axis)

        if verbose:
            print("Convolving low resolution cube.")

        if use_dask:
            lowres_convolved = auto_dask_map(self.highres, blocks=block,
                                             args=[conv_kernel_low])

        # for chan in range(low_chans):
        #     if verbose:
        #         print("On Channel: "+str(chan)+" of "+str(low_chans))

        #     lowres_convolved[chan, :, :] = \
        #         convolve_fft(self.lowres.filled_data[chan, :, :],
        #                      conv_kernel_low, boundary='fill',
        #                      interpolate_nan=True, normalize_kernel=True)

        update_low_hdr = \
            _update_beam_in_hdr(self.lowres.header, self.combined_beam)

        self.lowres_convolved = \
            SpectralCube(lowres_convolved*self.lowres.unit, self.lowres.wcs,
                         header=update_low_hdr)

    def flux_recovered(self, plot=True, filename=None, enable_interp=True,
                       interp_to='lower', diff_tol=1e-4*u.m/u.s):
        '''
        Check the amount of flux recovered in the high resolution image versus
        the low resolution data. If the spectral axes don't match, one is
        interpolated onto the other.

        Parameters
        ----------
        plot : bool, optional
            Enable plotting.
        filename : str, optional
            Give filename for the plot save file. When specified, the plot
            is automatically saved.
        interp_to : 'lower' or 'upper', optional
            If the spectral axes don't match, interpolated onto the same.
            The default 'lower' interpolates to the spectral axis with the
            lowest resolution.
        '''

        # Add up the total intensity in the cubes and compare
        # Assumes that there is some masking such that noise
        # doesn't dominate

        if self.highres_convolved is not None:
            high_channel_intensity = \
                self.highres_convolved.sum(axis=(1, 2))
        else:
            high_channel_intensity = self.highres.sum(axis=(1, 2))
            Warning("Should run convolve_to_common before. Using unconvolved"
                    " cube.")

        if self.lowres_convolved is not None:
            low_channel_intensity = self.lowres_convolved.sum(axis=(1, 2))
        else:
            low_channel_intensity = self.lowres.sum(axis=(1, 2))
            Warning("Should run convolve_to_common before. Using unconvolved"
                    " cube.")

        # If the spectral axes are not the same, try interpolating to match
        if enable_interp:

            better_vres_high = \
                np.abs(self.lowres.header['CDELT3']) > \
                np.abs(self.highres.header['CDELT3'])

            spec_diff = np.abs(np.abs(self.lowres.header['CDELT3']) -
                               np.abs(self.highres.header['CDELT3']))

            spec_unit = self.highres.spectral_axis.unit

            if spec_diff * spec_unit < diff_tol:
                warnings.warn("Channels are essentially the same. "
                              "Skipping interpolation. Lower diff_tol"
                              " to re-enable interpolation.")

            else:
                # Invert which to interpolate to
                if interp_to == "higher":
                    better_vres_high = not better_vres_high

                if better_vres_high:
                    f = interp1d(np.round(self.highres.spectral_axis.value, 3),
                                 high_channel_intensity.value)
                    high_channel_intensity = \
                        f(np.round(self.lowres.spectral_axis.value, 3)) *\
                        self.highres.unit
                else:
                    f = interp1d(np.round(self.lowres.spectral_axis.value, 3),
                                 low_channel_intensity.value)
                    low_channel_intensity = \
                        f(np.round(self.highres.spectral_axis.value, 3)) *\
                        self.lowres.unit


        self.fraction_flux_recovered = \
            high_channel_intensity.sum()/low_channel_intensity.sum()

        if plot:
            p.plot(self.highres.spectral_axis.value,
                   high_channel_intensity.value)

            p.plot(self.lowres.spectral_axis.value,
                   low_channel_intensity.value)

            p.xlabel("Spectral Axis ("+self.highres.spectral_axis.unit.to_string()+")")
            p.ylabel("Intensity ("+self.highres.unit.to_string()+")")

            if filename is None:
                p.show()
            else:
                p.savefig(filename)

        def run_all(self, highres_mask=None, lowres_mask=None, plot=True,
                    unit=u.K, freq=1420.40575177*u.MHz, filename=True,
                    use_dask=False, verbose=True):
            '''
            Run the complete comparisons.
            '''

            self.apply_mask(highres_mask=highres_mask, lowres_mask=lowres_mask)

            self.match_coords()

            self.convert_to(unit=unit, freq=freq)

            self.convolve_to_common(verbose=verbose, use_dask=use_dask)

            self.flux_recovered(plot=plot, filename=filename)
    denscube = SpectralCube.read(paths.dpath("H2CO_ParameterFits_{0}dens.fits".format(meastype)))
    denscube = denscube.with_mask(okmask)
    colcube  = SpectralCube.read(paths.dpath("H2CO_ParameterFits_{0}col.fits".format(meastype)))
    colcube = colcube.with_mask(okmask)
    goodmask_std = stdcube < 0.5

    flathead = denscube.wcs.dropaxis(2).to_header()

    denscube_lin = SpectralCube(10**denscube.filled_data[:].value,
                                              wcs=denscube.wcs,
                                              mask=okmask)
    colcube_lin = SpectralCube(10**colcube.filled_data[:].value,
                                             wcs=denscube.wcs, mask=okmask)


    totalcol = colcube_lin.sum(axis=0)
    totalcolgood = colcube_lin.with_mask(goodmask).sum(axis=0)
    totalcolgoodstd = colcube_lin.with_mask(goodmask_std).sum(axis=0)

    denscol = SpectralCube(denscube_lin.filled_data[:] * colcube_lin.filled_data[:], wcs=denscube.wcs,
                                         mask=okmask)
    wtdmeandens = np.log10(denscol.sum(axis=0) / totalcol)

    mindens_std = denscube.with_mask(goodmask_std).min(axis=0)
    mindens_chi2 = denscube.with_mask(goodmask).min(axis=0)

    hdu1 = fits.PrimaryHDU(data=wtdmeandens.value,
                           header=flathead)
    hdu1.writeto(paths.dpath("H2CO_ParameterFits_weighted_mean_{0}_density.fits".format(meastype)), clobber=True)

    masked_wtdmeans = np.log10(denscol.with_mask(goodmask).sum(axis=0) / totalcolgood)