Beispiel #1
0
def regridData(baseCubeFits, otherDataFits, outDir, mask=False):
    '''
    regrids one data set to match the wcs of the base data set, which
    is assumed to be a cube. The regridded data set can be either 2d
    or 3d.
    '''

    # open the base cube
    try:
        baseCube = SpectralCube.read(baseCubeFits)
    except:
        print("Can't read in " + baseCubeFits + ".")

    # determine ndim and bunit for other data sets
    f = fits.open(otherDataFits)
    ndim = f[0].header['NAXIS']
    bunit = f[0].header['BUNIT']
    f.close()

    # output image name
    newFits = os.path.join(
        outDir,
        os.path.basename(otherDataFits).replace('.fits', '_regrid.fits'))

    # now regrid images appropriately
    if ndim == 3:

        # read in cube
        otherCube = SpectralCube.read(otherDataFits)

        # interpolate velocity axis. This needs to be done first.
        regridCube = otherCube.spectral_interpolate(baseCube.spectral_axis)

        regridCube.allow_huge_operations = True
        newCube = regridCube.reproject(baseCube.header)

        if mask:
            # if greater than 0.0 set value to 1. otherwise 0.
            newdata = np.where(newCube.unitless_filled_data[:, :, :] > 0.0, 1,
                               0)
            finalCube = SpectralCube(newdata, newCube.wcs, mask=baseCube.mask)

        else:
            newdata = newCube.filled_data[:, :, :]
            finalCube = SpectralCube(newdata, newCube.wcs, mask=baseCube.mask)

        finalCube.with_spectral_unit(baseCube.spectral_axis.unit).write(
            newFits, overwrite=True)

    elif ndim == 2:

        ## consider using Projection.from_hdu then Projection.reproject here?

        # regrid image
        newcube = reproject_interp(
            otherDataFits,
            output_projection=baseCube.wcs.dropaxis(2),
            shape_out=baseCube.wcs.dropaxis(2).array_shape,
            order='nearest-neighbor',
            return_footprint=False)

        if mask:
            # set to 1 where greater than 0.0.
            newdata = np.where(newcube > 0.0, 1.0, 0.0)
        else:
            newdata = newcube

        # get mask on original data
        baseMask = baseCube.get_mask_array()
        totalBaseMask = baseMask.max(axis=0)

        newdata[np.invert(totalBaseMask)] = np.nan

        # fix up header with input image units
        outHdr = baseCube.wcs.dropaxis(2).to_header()
        outHdr.append(('BUNIT', bunit))

        # write out regridded data
        fits.writeto(newFits, newdata, outHdr, overwrite=True)

    else:
        print("Number of dimensions of other data set is not 2 or 3.")
Beispiel #2
0
def rebaseline(filename, blorder=3,
               baselineRegion=[slice(0, 262, 1), slice(-512, 0, 1)],
               windowFunction=None, blankBaseline=False,
               flagSpike=True, v0=None, **kwargs):
    """
    Rebaseline a data cube using robust regression of Legendre polynomials.

    Parameters
    ----------
    filename : string
        FITS filename of the data cube
    blorder : int
        Order of the polynomial to fit to the data
    baselineRegion : list
        List of slices defining the default region of the spectrum, in
        channels, to be used for the baseline fitting.
    windowFunction : function
        Name of function to be used that will accept spectrum data, and
        velocity axis and will return a binary mask of the channels to be used
        in the  baseline fitting.  Extra **kwargs are passed to windowFunction
        to do with as it must.
    blankBaseline : boolean
        Blank the baseline region on a per-spectrum basis

    Returns
    -------
    Nothing.  A new FITS file is written out with the suffix 'rebaseN' where N
    is the baseline order

    """
    cube = SpectralCube.read(filename)
    originalUnit = cube.spectral_axis.unit
    cube = cube.with_spectral_unit(u.km / u.s, velocity_convention='radio')
    spaxis = cube.spectral_axis.to(u.km / u.s).value

    goodposition = np.isfinite(cube.apply_numpy_function(np.max, axis=0))
    y, x = np.where(goodposition)
    outcube = np.zeros(cube.shape) * np.nan
    RegionName = (filename.split('_'))[0]

    if hasattr(windowFunction, '__call__'):
        catalog = catalogs.GenerateRegions()

    nuindex = np.arange(cube.shape[0])
    runmin = nuindex[-1]
    runmax = nuindex[0]

    for thisy, thisx in console.ProgressBar(zip(y, x)):
        spectrum = cube[:, thisy, thisx].value

        if v0 is not None:
            baselineIndex = windowFunction(spectrum, spaxis,
                                           v0=v0, **kwargs)
        elif hasattr(windowFunction, '__call__'):
            _, Dec, RA = cube.world[0, thisy, thisx]
            # This determines a v0 appropriate for the region
            v0 = VlsrByCoord(RA.value, Dec.value, RegionName,
                             regionCatalog=catalog)
            baselineIndex = windowFunction(spectrum, spaxis,
                                           v0=v0, **kwargs)
        else:
            baselineIndex = np.zeros_like(spectrum,dtype=np.bool)
            for ss in baselineRegion:
                baselineIndex[ss] = True

        runmin = np.min([nuindex[baselineIndex].min(), runmin])
        runmax = np.max([nuindex[baselineIndex].max(), runmax])

        # Use channel-to-channel difference as the noise value.
        if flagSpike:
            jumps = (spectrum - np.roll(spectrum, -1))
            noise = mad1d(jumps) * 2**(-0.5)
            baselineIndex *= (np.abs(jumps) < 5 * noise)
            noise = mad1d((spectrum -
                           np.roll(spectrum, -2))[baselineIndex]) * 2**(-0.5)
        else:
            noise = mad1d((spectrum -
                           np.roll(spectrum, -2))[baselineIndex]) * 2**(-0.5)

        if blankBaseline:
            spectrum = robustBaseline(spectrum, baselineIndex,
                                      blorder=blorder,
                                      noiserms=noise)
            spectrum[baselineIndex] = np.nan
            outcube[:, thisy, thisx] = spectrum
        else:
            outcube[:, thisy, thisx] = robustBaseline(spectrum, baselineIndex,
                                                      blorder=blorder,
                                                      noiserms=noise)

    outsc = SpectralCube(outcube, cube.wcs, header=cube.header)
    outsc = outsc[runmin:runmax, :, :]  # cut beyond baseline edges
    # Return to original spectral unit
    outsc = outsc.with_spectral_unit(originalUnit)
    outsc.write(filename.replace('.fits', '_rebase{0}.fits'.format(blorder)),
                overwrite=True)
Beispiel #3
0
def rebaseline(filename,
               blorder=3,
               baselineRegion=[slice(0, 800, 1),
                               slice(-800, 0, 1)],
               windowFunction=None,
               blankBaseline=False,
               flagSpike=True,
               v0=None,
               VlsrByCoord=None,
               verbose=False,
               **kwargs):
    """
    Rebaseline a data cube using robust regression of Legendre polynomials.

    Parameters
    ----------
    filename : string
        FITS filename of the data cube
    blorder : int
        Order of the polynomial to fit to the data
    baselineRegion : list
        List of slices defining the default region of the spectrum, in
        channels, to be used for the baseline fitting.
    windowFunction : function
        Name of function to be used that will accept spectrum data, and
        velocity axis and will return a binary mask of the channels to be used
        in the  baseline fitting.  Extra **kwargs are passed to windowFunction
        to do with as it must.
    blankBaseline : boolean
        Blank the baseline region on a per-spectrum basis

    Returns
    -------
    Nothing.  A new FITS file is written out with the suffix 'rebaseN' where N
    is the baseline order

    """
    cube = SpectralCube.read(filename)
    originalUnit = cube.spectral_axis.unit
    cube = cube.with_spectral_unit(u.km / u.s, velocity_convention='radio')
    spaxis = cube.spectral_axis.to(u.km / u.s).value

    goodposition = np.isfinite(cube.apply_numpy_function(np.max, axis=0))
    y, x = np.where(goodposition)
    outcube = np.zeros(cube.shape) * np.nan
    RegionName = (filename.split('/'))[-1]
    RegionName = (RegionName.split('_'))[0]
    nuindex = np.arange(cube.shape[0])
    runmin = nuindex[-1]
    runmax = nuindex[0]
    if verbose:
        pb = console.ProgressBar(len(y))
    for thisy, thisx in zip(y, x):
        spectrum = cube[:, thisy, thisx].value

        if v0 is not None:
            baselineIndex = windowFunction(spectrum, spaxis, v0=v0, **kwargs)
        elif hasattr(windowFunction, '__call__') and \
                hasattr(VlsrByCoord, '__call__'):
            _, Dec, RA = cube.world[0, thisy, thisx]
            # This determines a v0 appropriate for the region
            v0 = VlsrByCoord(RA.value, Dec.value, RegionName, **kwargs)
            baselineIndex = windowFunction(spectrum, spaxis, v0=v0, **kwargs)
        else:
            baselineIndex = np.zeros_like(spectrum, dtype=np.bool)
            for ss in baselineRegion:
                baselineIndex[ss] = True

        runmin = np.min([nuindex[baselineIndex].min(), runmin])
        runmax = np.max([nuindex[baselineIndex].max(), runmax])

        # Use channel-to-channel difference as the noise value.
        if flagSpike:
            jumps = (spectrum - np.roll(spectrum, -1))
            noise = mad1d(jumps) * 2**(-0.5)
            baselineIndex *= (np.abs(jumps) < 5 * noise)
            noise = mad1d(
                (spectrum - np.roll(spectrum, -2))[baselineIndex]) * 2**(-0.5)
        else:
            noise = mad1d(
                (spectrum - np.roll(spectrum, -2))[baselineIndex]) * 2**(-0.5)

        if blankBaseline:
            spectrum = robustBaseline(spectrum,
                                      baselineIndex,
                                      blorder=blorder,
                                      noiserms=noise)
            spectrum[baselineIndex] = np.nan
            outcube[:, thisy, thisx] = spectrum
        else:
            outcube[:, thisy, thisx] = robustBaseline(spectrum,
                                                      baselineIndex,
                                                      blorder=blorder,
                                                      noiserms=noise)
        if verbose:
            pb.update()
    outsc = SpectralCube(outcube,
                         cube.wcs,
                         header=cube.header,
                         meta={'BUNIT': cube.header['BUNIT']})
    outsc = outsc[runmin:runmax, :, :]  # cut beyond baseline edges

    # Return to original spectral unit
    outsc = outsc.with_spectral_unit(originalUnit)
    outsc.write(filename.replace('.fits', '_rebase{0}.fits'.format(blorder)),
                overwrite=True)
Beispiel #4
0
def get_best_2comp_residual(reg):
    modbest = get_best_2comp_model(reg)
    best_res = reg.ucube.cube._data - modbest
    res_cube = SpectralCube(best_res, reg.ucube.cube.wcs)
    res_cube = res_cube.with_spectral_unit(u.km / u.s, velocity_convention='radio')
    return res_cube
Beispiel #5
0
def save_best_2comp_fit(reg):
    # should be renamed to determine_best_2comp_fit or something along that line
    # currently use np.nan for pixels with no models

    ncomp = [1, 2]

    # ideally, a copy function should be in place of reloading

    # a new Region object is created start fresh on some of the functions (e.g., aic comparison)
    reg_final = Region(reg.cubePath, reg.paraNameRoot, reg.paraDir)

    # start out clean, especially since the deepcopy function doesn't work well for pyspeckit cubes
    # load the file based on the passed in reg, rather than the default
    for nc in ncomp:
        if not str(nc) in reg.ucube.pcubes:
            reg_final.load_fits(ncomp=[nc])
        else:
            # load files using paths from reg if they exist
            print("loading model from: {}".format(reg.ucube.paraPaths[str(nc)]))
            reg_final.ucube.load_model_fit(filename=reg.ucube.paraPaths[str(nc)], ncomp=nc)

    pcube_final = reg_final.ucube.pcubes['2'].copy('deep')

    # make the 2-comp para maps with the best fit model
    lnk21 = reg_final.ucube.get_AICc_likelihood(2, 1)
    mask = lnk21 > 5
    print("2comp pix: {}".format(np.sum(mask)))
    pcube_final.parcube[:4, ~mask] = reg_final.ucube.pcubes['1'].parcube[:4, ~mask].copy()
    pcube_final.errcube[:4, ~mask] = reg_final.ucube.pcubes['1'].errcube[:4, ~mask].copy()
    pcube_final.parcube[4:8, ~mask] = np.nan
    pcube_final.errcube[4:8, ~mask] = np.nan

    lnk10 = reg_final.ucube.get_AICc_likelihood(1, 0)
    mask = lnk10 > 5
    pcube_final.parcube[:, ~mask] = np.nan
    pcube_final.errcube[:, ~mask] = np.nan

    # use the default file formate to save the finals
    nc = 2
    if not str(nc) in reg_final.ucube.paraPaths:
        reg_final.ucube.paraPaths[str(nc)] = '{}/{}_{}vcomp.fits'.format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot, nc)

    savename = "{}_final.fits".format(os.path.splitext(reg_final.ucube.paraPaths['2'])[0])
    UCube.save_fit(pcube_final, savename=savename, ncomp=2)

    hdr2D =reg.ucube.cube.wcs.celestial.to_header()

    # save the lnk21 map
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","lnk21"))
    save_map(lnk21, hdr2D, savename)

    # save the lnk10 map
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","lnk10"))
    save_map(lnk10, hdr2D, savename)

    # create and save the lnk20 map for reference:
    lnk20 = reg_final.ucube.get_AICc_likelihood(2, 0)
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","lnk20"))
    save_map(lnk20, hdr2D, savename)

    # save the SNR map
    snr_map = get_best_2comp_snr_mod(reg_final)
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para","SNR"))
    save_map(snr_map, hdr2D, savename)

    # create moment0 map
    modbest = get_best_2comp_model(reg_final)
    cube_mod = SpectralCube(data=modbest, wcs=reg_final.ucube.pcubes['2'].wcs.copy(),
                            header=reg_final.ucube.pcubes['2'].header.copy())
    # make sure the spectral unit is in km/s before making moment maps
    cube_mod = cube_mod.with_spectral_unit('km/s', velocity_convention='radio')
    mom0_mod = cube_mod.moment0()
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "model_mom0"))
    mom0_mod.write(savename, overwrite=True)

    # created masked mom0 map with model as the mask
    mom0 = UCube.get_masked_moment(cube=reg_final.ucube.cube, model=modbest, order=0, expand=20, mask=None)
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir, reg_final.ucube.paraNameRoot.replace("para", "mom0"))
    mom0.write(savename, overwrite=True)

    # save reduced chi-squred maps
    # would be useful to check if 3rd component is needed
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir,
                                   reg_final.ucube.paraNameRoot.replace("para", "chi2red_final"))
    chi_map = UCube.get_chisq(cube=reg_final.ucube.cube, model=modbest, expand=20, reduced=True, usemask=True,
                              mask=None)
    save_map(chi_map, hdr2D, savename)

    # save reduced chi-squred maps for 1 comp and 2 comp individually
    chiRed_1c = reg_final.ucube.get_reduced_chisq(1)
    chiRed_2c = reg_final.ucube.get_reduced_chisq(2)

    savename = "{}/{}.fits".format(reg_final.ucube.paraDir,
                                   reg_final.ucube.paraNameRoot.replace("para", "chi2red_1c"))
    save_map(chiRed_1c, hdr2D, savename)
    savename = "{}/{}.fits".format(reg_final.ucube.paraDir,
                                   reg_final.ucube.paraNameRoot.replace("para", "chi2red_2c"))
    save_map(chiRed_2c, hdr2D, savename)

    return reg
Beispiel #6
0
    # --------------------------------------------------- #
    # Find the (col,row) min/max limits of valid spaxels. #
    # Min/max will be used to crop the data and the WCS.  #
    # --------------------------------------------------- #
    wcsMinMax = pixMinMax(validPixels)


    # --------------------------------------------- #
    # Build the spectral cube using the contSubCube #
    # --------------------------------------------- #
    # NaNs and data to be ignored are FALSE.
    specCube = SpectralCube(data,pacsWcs,mask=cubeMask,fill_value=1.)

    # For convenience, convert the X-axis to km/s
    # (WCSLIB automatically converts to m/s even if you give it km/s)
    specCube = specCube.with_spectral_unit(u.km/u.s)


    # --------------------------------------------- #
    # Build the pySpecCube using the spectral cube. #
    # --------------------------------------------- #
    # NaN values are FALSE in the mask.
    pyCube = pyspeckit.Cube(cube=specCube,maskmap=np.ma.getmask(falseMask[mid,:,:]))


    # -------------------------------- #
    # Set up for line profile fitting. #
    # -------------------------------- #

    # Build the guesses array
    gc = buildGuessCube((nCols,nRows),
Beispiel #7
0
def deblend(para,
            specCubeRef,
            vmin=4.0,
            vmax=11.0,
            f_spcsamp=None,
            tau_wgt=0.1,
            n_cpu=None):
    '''
    Deblend hyperfine structures in a cube based on fitted models, i.e., reconstruct the fitted model with Gaussian
    lines with optical depths accounted for (e.g., similar to CO (J = 0-1))

    :param para: <ndarray>
        The fitted parameters in the order of vel, width, tex, and tau for each velocity slab.
        (Note: the size of the z axis for para must thus be in the multiple of 4)

    :param specCubeRef: <SpectralCube.Cube>
        The reference cube from which the deblended cube is constructed from

    :param vmin: <float>
        The lower veloicty limit on the deblended cube in the unit of km/s

    :param vmax: <float>
        The upper veloicty limit on the deblended cube in the unit of km/s

    :param f_spcsamp: <int>
        The scaling factor for the spectral sampling relative the reference cube
        (e.g., f_spcsamp = 2 give you twice the spectral resolution)

    :param tau_wgt:
        The scaling factor for the input tau
        (e.g., tau_wgt = 0.1 better represents the true optical depth of a NH3 (1,1) hyperfine group than the
         "fitted tau")

    :param n_cpu: <int>
        The number of cpus to use. If None, defaults to all the cpus available minus one.

    :return mcube: <SpectralCube.Cube>
        The deblended cube
    '''

    # open the reference cube file
    cube = specCubeRef
    cube = cube.with_spectral_unit(u.km / u.s, velocity_convention='radio')

    # trim the cube to the specified velocity range
    cube = cube.spectral_slab(vmin * u.km / u.s, vmax * u.km / u.s)

    # generate an empty SpectralCube to house the deblended cube
    if f_spcsamp is None:
        deblend = np.zeros(cube.shape)
        hdr = cube.wcs.to_header()
        wcs_new = cube.wcs
    else:
        deblend = np.zeros(
            (cube.shape[0] * int(f_spcsamp), cube.shape[1], cube.shape[2]))
        wcs_new = cube.wcs.deepcopy()
        # adjust the spectral reference value
        wcs_new.wcs.crpix[2] = wcs_new.wcs.crpix[2] * int(f_spcsamp)
        # adjust the spaxel size
        wcs_new.wcs.cdelt[2] = wcs_new.wcs.cdelt[2] / int(f_spcsamp)
        hdr = wcs_new.to_header()

    # retain the beam information
    hdr['BMAJ'] = cube.header['BMAJ']
    hdr['BMIN'] = cube.header['BMIN']
    hdr['BPA'] = cube.header['BPA']

    mcube = SpectralCube(deblend, wcs_new, header=hdr)

    # convert back to an unit that the ammonia hf model can handle (i.e. Hz) without having to create a
    # pyspeckit.spectrum.units.SpectroscopicAxis object (which runs rather slow for model building in comparison)
    mcube = mcube.with_spectral_unit(u.Hz, velocity_convention='radio')
    xarr = mcube.spectral_axis

    yy, xx = np.indices(para.shape[1:])
    # a pixel is valid as long as it has a single finite value
    isvalid = np.any(np.isfinite(para), axis=0)
    valid_pixels = zip(xx[isvalid], yy[isvalid])

    def model_a_pixel(xy):
        x, y = int(xy[0]), int(xy[1])
        # nh3_vtau_singlemodel_deblended takes Hz as the spectral unit
        models = [
            nh3_deblended.nh3_vtau_singlemodel_deblended(xarr,
                                                         Tex=tex,
                                                         tau=tau * tau_wgt,
                                                         xoff_v=vel,
                                                         width=width)
            for vel, width, tex, tau in zip(para[::4, y, x], para[1::4, y, x],
                                            para[2::4, y, x], para[3::4, y, x])
        ]

        mcube._data[:, y, x] = np.nansum(np.array(models), axis=0)
        return ((x, y), mcube._data[:, y, x])

    if n_cpu is None:
        n_cpu = cpu_count() - 1
    else:
        n_cpu = 1

    if n_cpu > 1:
        print("------------------ deblending cube -----------------")
        print("number of cpu used: {}".format(n_cpu))
        sequence = [(x, y) for x, y in valid_pixels]
        result = parallel_map(model_a_pixel, sequence, numcores=n_cpu)
        merged_result = [
            core_result for core_result in result if core_result is not None
        ]
        for mr in merged_result:
            ((x, y), model) = mr
            x = int(x)
            y = int(y)
            mcube._data[:, y, x] = model
    else:
        for xy in ProgressBar(list(valid_pixels)):
            model_a_pixel(xy)

    # convert back to km/s in units before saving
    mcube = mcube.with_spectral_unit(u.km / u.s, velocity_convention='radio')
    gc.collect()
    print("--------------- deblending completed ---------------")

    return mcube