Пример #1
0
def compute_sregion(image, extname='SCI'):
    """Compute the S_REGION keyword for a given WCS.

    Parameters
    -----------
    image : Astropy io.fits  HDUList object
        Image to update with the S_REGION keyword in each of the SCI extensions.

    extname : str, optional
        EXTNAME value for extension containing the WCS(s) to be updated
    """
    # This function could, conceivably, be called directly...
    hdu, closefits = _process_input(image)

    # Find all extensions to be updated
    numext = countExtn(hdu, extname=extname)

    for extnum in range(1, numext + 1):
        sregion_str = 'POLYGON ICRS '
        sciext = (extname, extnum)
        extwcs = wcsutil.HSTWCS(hdu, ext=sciext)
        footprint = extwcs.calc_footprint(center=True)
        for corner in footprint:
            sregion_str += '{} {} '.format(corner[0], corner[1])
        hdu[sciext].header['s_region'] = sregion_str

    # close file if opened by this functions
    if closefits:
        hdu.close()
Пример #2
0
def archive_prefix_OPUS_WCS(fobj, extname='SCI'):
    """ Identifies WCS keywords which were generated by OPUS and archived
        using a prefix of 'O' for all 'SCI' extensions in the file

        Parameters
        ----------
        fobj : str or `astropy.io.fits.HDUList`
            Filename or fits object of a file

    """
    if stwcs is None:
        print('=====================')
        print(
            'The STWCS package is needed to convert an old-style OPUS WCS to an alternate WCS'
        )
        print('=====================')
        raise ImportError

    closefits = False
    if isinstance(fobj, str):
        # A filename was provided as input
        fobj = fits.open(fobj, mode='update')
        closefits = True

    # Define the header
    ext = ('sci', 1)
    hdr = fobj[ext].header

    numextn = fileutil.countExtn(fobj)
    extlist = []
    for e in range(1, numextn + 1):
        extlist.append(('sci', e))

    # Insure that the 'O' alternate WCS is present
    if 'O' not in wcsutil.wcskeys(hdr):
        # if not, archive the Primary WCS as the default OPUS WCS
        wcsutil.archiveWCS(fobj, extlist, wcskey='O', wcsname='OPUS')

    # find out how many SCI extensions are in the image
    numextn = fileutil.countExtn(fobj, extname=extname)
    if numextn == 0:
        extname = 'PRIMARY'

    # create HSTWCS object from PRIMARY WCS
    wcsobj = wcsutil.HSTWCS(fobj, ext=ext, wcskey='O')
    # get list of WCS keywords
    wcskeys = list(wcsobj.wcs2header().keys())

    # For each SCI extension...
    for e in range(1, numextn + 1):
        # Now, look for any WCS keywords with a prefix of 'O'
        for key in wcskeys:
            okey = 'O' + key[:7]
            hdr = fobj[(extname, e)].header
            if okey in hdr:
                # Update alternate WCS keyword with prefix-O OPUS keyword value
                hdr[key] = hdr[okey]

    if closefits:
        fobj.close()
Пример #3
0
def get_hstwcs(filename, hdulist, extnum):
    """ Return the HSTWCS object for a given chip. """
    hdrwcs = wcsutil.HSTWCS(hdulist, ext=extnum)
    hdrwcs.filename = filename
    hdrwcs.expname = hdulist[extnum].header['expname']
    hdrwcs.extver = hdulist[extnum].header['extver']

    return hdrwcs
Пример #4
0
def get_hstwcs(filename, extnum):
    """ Return the HSTWCS object for a given chip. """
    hdrwcs = wcsutil.HSTWCS(filename, ext=extnum)
    hdrwcs.filename = filename
    hdrwcs.expname = pyfits.getval(filename, 'expname', ext=extnum)
    hdrwcs.extver = pyfits.getval(filename, 'extver', ext=extnum)

    return hdrwcs
Пример #5
0
def findWCSExtn(filename):
    """ Return new filename with extension that points to an extension with a
        valid WCS.

        Returns
        =======
        extnum : str, None
            Value of extension name as a string either as provided by the user
            or based on the extension number for the first extension which
            contains a valid HSTWCS object.  Returns None if no extension can be
            found with a valid WCS.

        Notes
        =====
        The return value from this function can be used as input to
            create another HSTWCS with the syntax::

                `HSTWCS('{}[{}]'.format(filename,extnum))

    """
    rootname, extroot = fileutil.parseFilename(filename)
    extnum = None
    if extroot is None:
        fimg = fits.open(rootname, memmap=False)
        for i, extn in enumerate(fimg):
            if 'crval1' in extn.header:
                refwcs = wcsutil.HSTWCS('{}[{}]'.format(rootname, i))
                if refwcs.wcs.has_cd():
                    extnum = '{}'.format(i)
                    break
        fimg.close()
    else:
        try:
            refwcs = wcsutil.HSTWCS(filename)
            if refwcs.wcs.has_cd():
                extnum = extroot
        except:
            extnum = None

    return extnum
Пример #6
0
def read_hlet_wcs(filename, ext):
    """Insure HSTWCS includes all attributes of a full image WCS.

    For headerlets, the WCS does not contain information about the size of the
    image, as the image array is not present in the headerlet.
    """
    hstwcs = wcsutil.HSTWCS(filename, ext=ext)
    if hstwcs.naxis1 is None:
        hstwcs.naxis1 = int(hstwcs.wcs.crpix[0] *
                            2.)  # Assume crpix is center of chip
        hstwcs.naxis2 = int(hstwcs.wcs.crpix[1] * 2.)

    return hstwcs
Пример #7
0
def create_image_footprint(image, refwcs, border=0.):
    """ Create the footprint of the image in the reference WCS frame

    Parameters
    ----------
    image : HDUList or filename
        Image to extract sources for matching to
        the external astrometric catalog

    refwcs : object
        Reference WCS for coordinate frame of image

    border : float
        Buffer (in arcseconds) around edge of image to exclude astrometric
        sources. Default: 0.

    """
    # Interpret input image to generate initial source catalog and WCS
    if isinstance(image, str):
        image = pf.open(image)
    numSci = countExtn(image, extname='SCI')
    ref_x = refwcs._naxis1
    ref_y = refwcs._naxis2
    # convert border value into pixels
    border_pixels = int(border / refwcs.pscale)

    mask_arr = np.zeros((ref_y, ref_x), dtype=int)

    for chip in range(numSci):
        chip += 1
        # Build arrays of pixel positions for all edges of chip
        chip_y, chip_x = image['sci', chip].data.shape
        chipwcs = wcsutil.HSTWCS(image, ext=('sci', chip))
        xpix = np.arange(chip_x) + 1
        ypix = np.arange(chip_y) + 1
        edge_x = np.hstack([[1] * chip_y, xpix, [chip_x] * chip_y, xpix])
        edge_y = np.hstack([ypix, [1] * chip_x, ypix, [chip_y] * chip_x])
        edge_ra, edge_dec = chipwcs.all_pix2world(edge_x, edge_y, 1)
        edge_x_out, edge_y_out = refwcs.all_world2pix(edge_ra, edge_dec, 0)
        edge_x_out = np.clip(edge_x_out.astype(np.int32), 0, ref_x - 1)
        edge_y_out = np.clip(edge_y_out.astype(np.int32), 0, ref_y - 1)
        mask_arr[edge_y_out, edge_x_out] = 1

    # Fill in outline of each chip
    mask_arr = ndimage.binary_fill_holes(
        ndimage.binary_dilation(mask_arr, iterations=2))

    if border > 0.:
        mask_arr = ndimage.binary_erosion(mask_arr, iterations=border_pixels)

    return mask_arr
Пример #8
0
def compute_sregion(image, extname='SCI'):
    """Compute the S_REGION keyword for a given WCS.

    Parameters
    -----------
    image : Astropy io.fits  HDUList object
        Image to update with the S_REGION keyword in each of the SCI extensions.

    extname : str, optional
        EXTNAME value for extension containing the WCS(s) to be updated
    """
    # This function could, conceivably, be called directly...
    hdu, closefits = _process_input(image)

    # Find all extensions to be updated
    numext = countExtn(hdu, extname=extname)

    for extnum in range(1, numext + 1):
        sciext = (extname, extnum)
        if 'd001data' not in hdu[0].header:
            sregion_str = 'POLYGON ICRS '
            # Working with FLT/FLC file, so simply use
            #  the array corners directly
            extwcs = wcsutil.HSTWCS(hdu, ext=sciext)
            footprint = extwcs.calc_footprint(center=True)
            for corner in footprint:
                sregion_str += '{} {} '.format(corner[0], corner[1])
        else:
            if hdu[(extname,
                    extnum)].data.min() == 0 and hdu[(extname,
                                                      extnum)].data.max() == 0:
                continue
            # Working with a drizzled image, so we need to
            # get all the corners from each of the input files
            footprint = find_footprint(hdu, extname=extname, extnum=extnum)
            sregion_str = ''
            for region in footprint.corners:
                # S_REGION string should contain a separate POLYGON
                # for each region or chip in the SCI array
                sregion_str += 'POLYGON ICRS '
                for corner in region:
                    sregion_str += '{} {} '.format(corner[0], corner[1])

        hdu[sciext].header['s_region'] = sregion_str

    # close file if opened by this functions
    if closefits:
        hdu.close()
Пример #9
0
def build_hstwcs(crval1, crval2, crpix1, crpix2, naxis1, naxis2, pscale, orientat):
    """ Create an HSTWCS object for a default instrument without distortion
        based on user provided parameter values.
    """
    wcsout = wcsutil.HSTWCS()
    wcsout.wcs.crval = np.array([crval1, crval2])
    wcsout.wcs.crpix = np.array([crpix1, crpix2])
    wcsout.naxis1 = naxis1
    wcsout.naxis2 = naxis2
    wcsout.wcs.cd = fileutil.buildRotMatrix(orientat) * [-1, 1] * pscale / 3600.0
    # Synchronize updates with astropy.wcs/WCSLIB objects
    wcsout.wcs.set()
    wcsout.setPscale()
    wcsout.setOrient()
    wcsout.wcs.ctype = ['RA---TAN', 'DEC--TAN']

    return wcsout
Пример #10
0
def build_hstwcs(crval, crpix, naxis1, naxis2, pscale, orientat):
    """ Create an `~stwcs.wcsutil.HSTWCS` object for a default instrument without
    distortion based on user provided parameter values.
    """
    wcsout = wcsutil.HSTWCS()
    wcsout.wcs.crval = crval.copy()
    wcsout.wcs.crpix = crpix.copy()
    wcsout.naxis1 = naxis1
    wcsout.naxis2 = naxis2
    wcsout.wcs.cd = fu.buildRotMatrix(orientat) * [-1, 1] * pscale / 3600.0
    # Synchronize updates with astropy.wcs objects
    wcsout.wcs.set()
    wcsout.setPscale()
    wcsout.setOrient()
    wcsout.wcs.ctype = ['RA---TAN', 'DEC--TAN']

    return wcsout
Пример #11
0
def verifyRefimage(refimage):
    """
    Verify that the value of refimage specified by the user points to an
    extension with a proper WCS defined. It starts by making sure an extension gets
    specified by the user when using a MEF file. The final check comes by looking
    for a CD matrix in the WCS object itself. If either test fails, it returns
    a value of False.
    """
    valid = True

    # start by trying to see whether the code can even find the file
    if is_blank(refimage):
        return True

    if isinstance(refimage, astropy.wcs.WCS):
        return True

    refroot, extroot = fileutil.parseFilename(refimage)
    if not os.path.exists(refroot):
        return False

    # if a MEF has been specified, make sure extension contains a valid WCS
    if valid:
        if extroot is None:
            extn = findWCSExtn(refimage)
            if extn is None:
                valid = False
            else:
                valid = True
        else:
            # check for CD matrix in WCS object
            refwcs = wcsutil.HSTWCS(refimage)
            if not refwcs.wcs.has_cd():
                valid = False
            else:
                valid = True
            del refwcs

    return valid
Пример #12
0
def build_reference_wcs(inputs, sciname='sci'):
    """Create the reference WCS based on all the inputs for a field"""
    # start by creating a composite field-of-view for all inputs
    wcslist = []
    for img in inputs:
        nsci = countExtn(img)
        for num in range(nsci):
            extname = (sciname, num + 1)
            if sciname == 'sci':
                extwcs = wcsutil.HSTWCS(img, ext=extname)
            else:
                # Working with HDRLET as input and do the best we can...
                extwcs = read_hlet_wcs(img, ext=extname)

            wcslist.append(extwcs)

    # This default output WCS will have the same plate-scale and orientation
    # as the first chip in the list, which for WFPC2 data means the PC.
    # Fortunately, for alignment, this doesn't matter since no resampling of
    # data will be performed
    outwcs = utils.output_wcs(wcslist)

    return outwcs
Пример #13
0
def find_footprint(hdu, extname='SCI', extnum=1):
    """Extract the footprints from each input file

    Determine the composite of all the input chip's corners
    as the footprint for the entire set of overlapping images
    that went into creating this drizzled image.

    Parameters
    ===========
    hdu : str or `fits.HDUList`
        Filename or HDUList for a drizzled image

    extname : str, optional
        Name of science array extension (extname value)

    extnum : int, optional
        EXTVER value for science array extension

    Returns
    ========
    footprint : ndarray
        Array of RA/Dec for the 4 corners that comprise the
        footprint on the sky for this mosaic.  Values were
        determined from northern-most corner counter-clockwise
        to the rest.

    """
    # extract WCS from this product
    meta_wcs = wcsutil.HSTWCS(hdu, ext=(extname, extnum))
    # create SkyFootprint object for all input_files to determine footprint
    footprint = SkyFootprint(meta_wcs=meta_wcs)
    # create mask of all input chips as they overlap on the product WCS
    footprint.extract_mask(hdu.filename())
    # Now, find the corners from this mask
    footprint.find_corners()

    return footprint
Пример #14
0
def run_sourcelist_flagging(filter_product_obj,
                            filter_product_catalogs,
                            log_level,
                            diagnostic_mode=False):
    """
    Super-basic and profoundly inelegant interface to hla_flag_filter.py.

    Execute haputils.hla_flag_filter.run_source_list_flaging() to populate the "Flags" column in the catalog tables
    generated by HAPcatalogs.measure().

    Parameters
    ----------
    filter_product_obj : drizzlepac.hlautils.product.FilterProduct object
        object containing all the relevant info for the drizzled filter product

    filter_product_catalogs : drizzlepac.hlautils.catalog_utils.HAPCatalogs object
        drizzled filter product catalog object

    log_level : int
        The desired level of verboseness in the log statements displayed on the screen and written to the .log file.

    diagnostic_mode : Boolean, optional.
        create intermediate diagnostic files? Default value is False.

    Returns
    -------
    filter_product_catalogs : drizzlepac.hlautils.catalog_utils.HAPCatalogs object
        updated version of filter_product_catalogs object with fully populated source flags

    """
    drizzled_image = filter_product_obj.drizzle_filename
    flt_list = []
    for edp_obj in filter_product_obj.edp_list:
        flt_list.append(edp_obj.full_filename)
    param_dict = filter_product_obj.configobj_pars.as_single_giant_dict()
    plate_scale = wcsutil.HSTWCS(drizzled_image, ext=('sci', 1)).pscale
    median_sky = filter_product_catalogs.image.bkg_median

    # Create mask array that will be used by hla_flag_filter.hla_nexp_flags() for both point and segment catalogs.
    if not hasattr(filter_product_obj, 'hla_flag_msk'):
        filter_product_obj.hla_flag_msk = hla_flag_filter.make_mask_array(
            drizzled_image)

    if filter_product_obj.configobj_pars.use_defaults:
        ci_lookup_file_path = "default_parameters/any"
    else:
        ci_lookup_file_path = "user_parameters/any"
    output_custom_pars_file = filter_product_obj.configobj_pars.output_custom_pars_file
    for cat_type in filter_product_catalogs.catalogs.keys():
        exptime = filter_product_catalogs.catalogs[cat_type].image.imghdu[
            0].header[
                'exptime']  # TODO: This works for ACS. Make sure that it also works for WFC3. Look at "TEXPTIME"
        catalog_name = filter_product_catalogs.catalogs[
            cat_type].sourcelist_filename
        catalog_data = filter_product_catalogs.catalogs[cat_type].source_cat
        drz_root_dir = os.getcwd()
        log.info("Run source list flagging on catalog file {}.".format(
            catalog_name))
        filter_product_catalogs.catalogs[
            cat_type].source_cat = hla_flag_filter.run_source_list_flagging(
                drizzled_image, flt_list, param_dict, exptime, plate_scale,
                median_sky, catalog_name, catalog_data, cat_type, drz_root_dir,
                filter_product_obj.hla_flag_msk, ci_lookup_file_path,
                output_custom_pars_file, log_level, diagnostic_mode)

    return filter_product_catalogs
Пример #15
0
def rd2xy(input,
          ra=None,
          dec=None,
          coordfile=None,
          colnames=None,
          precision=6,
          output=None,
          verbose=True):
    """ Primary interface to perform coordinate transformations from
        pixel to sky coordinates using STWCS and full distortion models
        read from the input image header.
    """
    single_coord = False
    if coordfile is not None:
        if colnames in blank_list:
            colnames = ['c1', 'c2']
        elif isinstance(colnames, type('a')):
            colnames = colnames.split(',')
        # convert input file coordinates to lists of decimal degrees values
        xlist, ylist = tweakutils.readcols(coordfile, cols=colnames)
    else:
        if isinstance(ra, np.ndarray):
            ralist = ra.tolist()
            declist = dec.tolist()
        elif not isinstance(ra, list):
            ralist = [ra]
            declist = [dec]
        else:
            ralist = ra
            declist = dec
        xlist = [0] * len(ralist)
        ylist = [0] * len(ralist)
        if len(xlist) == 1:
            single_coord = True
        for i, (r, d) in enumerate(zip(ralist, declist)):
            # convert input value into decimal degrees value
            xval, yval = tweakutils.parse_skypos(r, d)
            xlist[i] = xval
            ylist[i] = yval

    # start by reading in WCS+distortion info for input image
    inwcs = wcsutil.HSTWCS(input)
    if inwcs.wcs.is_unity():
        print(
            "####\nNo valid WCS found in {}.\n  Results may be invalid.\n####\n"
            .format(input))

    # Now, convert pixel coordinates into sky coordinates
    try:
        outx, outy = inwcs.all_world2pix(xlist, ylist, 1)
    except RuntimeError:
        outx, outy = inwcs.wcs_world2pix(xlist, ylist, 1)

    # add formatting based on precision here...
    xstr = []
    ystr = []
    fmt = "%." + repr(precision) + "f"
    for x, y in zip(outx, outy):
        xstr.append(fmt % x)
        ystr.append(fmt % y)

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ', input)
        print('# X      Y         RA             Dec\n')
        for x, y, r, d in zip(xstr, ystr, xlist, ylist):
            print("%s  %s    %s  %s" % (x, y, r, d))

    # Create output file, if specified
    if output:
        f = open(output, mode='w')
        f.write("# Coordinates converted from %s\n" % input)
        for x, y in zip(xstr, ystr):
            f.write('%s    %s\n' % (x, y))
        f.close()
        print('Wrote out results to: ', output)

    if single_coord:
        outx = outx[0]
        outy = outy[0]
    return outx, outy
    """ Convert colnames input into list of column numbers
    """
    cols = []
    if not isinstance(colnames, list):
        colnames = colnames.split(',')

    # parse column names from coords file and match to input values
    if coordfile is not None and fileutil.isFits(coordfile)[0]:
        # Open FITS file with table
        ftab = fits.open(coordfile)
        # determine which extension has the table
        for extn in ftab:
            if isinstance(extn, fits.BinTableHDU):
                # parse column names from table and match to inputs
                cnames = extn.columns.names
                if colnames is not None:
                    for c in colnames:
                        for name, i in zip(cnames, list(range(len(cnames)))):
                            if c == name.lower(): cols.append(i)
                    if len(cols) < len(colnames):
                        errmsg = "Not all input columns found in table..."
                        ftab.close()
                        raise ValueError(errmsg)
                else:
                    cols = cnames[:2]
                break
        ftab.close()
    else:
        for c in colnames:
            if isinstance(c, str):
                if c[0].lower() == 'c':
                    cols.append(int(c[1:]) - 1)
                else:
                    cols.append(int(c))
            else:
                if isinstance(c, int):
                    cols.append(c)
                else:
                    errmsg = "Unsupported column names..."
                    raise ValueError(errmsg)
    return cols
Пример #16
0
def create_product_page(prodname,
                        zoom_size=128,
                        wcsname="",
                        gcolor='magenta',
                        fsize=8):
    """Create a matplotlib Figure() object which summarizes this product FITS file."""

    # obtain image data to display
    with fits.open(prodname) as prod:
        data = prod[1].data
        phdr = prod[0].header
        if 'texptime' not in phdr:
            return None, None
        targname = phdr['targname']
        inst = phdr['instrume']
        det = phdr['detector']
        texptime = phdr['texptime']
        inexp = phdr['d001data'].split('[')[0]
        wcstype = prod[1].header['wcstype']
        wcs = wcsutil.HSTWCS(prod, ext=1)
        hdrtab = prod['hdrtab'].data
        filters = ';'.join([phdr[f] for f in phdr['filter*']])
        dateobs = phdr['date-obs']  # human-readable date
        expstart = phdr['expstart']  # MJD float value
        asnid = phdr.get('asn_id', '')

    center = (data.shape[0] // 2, data.shape[1] // 2)
    prod_path = os.path.split(prodname)[0]

    data = np.nan_to_num(data, 0.0)

    # Get GAIA catalog
    refcat = amutils.create_astrometric_catalog(prodname,
                                                existing_wcs=wcs,
                                                output=None)
    refx, refy = wcs.all_world2pix(refcat['RA'], refcat['DEC'], 0)
    # Remove points outside the full-size image area
    rx = []
    ry = []
    zx = []
    zy = []
    for x, y in zip(refx, refy):
        if 0 < x < data.shape[1] and 0 < y < data.shape[0]:
            rx.append(x)
            ry.append(y)
        if -zoom_size < x - center[1] < zoom_size and -zoom_size < y - center[
                0] < zoom_size:
            zx.append(x - center[1] + zoom_size)
            zy.append(y - center[0] + zoom_size)

    # Define subplot regions on page
    fig = plt.figure(constrained_layout=True, figsize=(8.5, 11))
    gs = fig.add_gridspec(ncols=4, nrows=5)

    # title plots
    rootname = os.path.basename(prodname)
    img_title = "{} image of {} with WCSNAME={}".format(
        rootname, targname, wcsname)
    fig.suptitle(img_title, ha='center', va='top', fontsize=fsize)

    # Define image display
    fig_img = fig.add_subplot(gs[:3, :])
    fig_zoom = fig.add_subplot(gs[3:, 2:])
    fig_summary = fig.add_subplot(gs[3:, :2])

    # Compute display range
    dmax = (data.max() // 10) if data.max() <= 1000. else 100
    dscaled = np.log10(np.clip(data, -0.1, dmax) + 0.10001)
    # identify zoom region around center of data
    zoom = dscaled[center[0] - zoom_size:center[0] + zoom_size,
                   center[1] - zoom_size:center[1] + zoom_size]

    # display full image
    fig_img.imshow(dscaled, cmap='gray', origin='lower')
    # display zoomed section
    fig_zoom.imshow(zoom, cmap='gray', origin='lower')

    # define markerstyle
    mstyle = markers.MarkerStyle(marker='o')
    mstyle.set_fillstyle('none')
    # plot GAIA sources onto full size image
    fig_img.scatter(rx, ry, marker=mstyle, alpha=0.35, c=gcolor, s=3)
    fig_zoom.scatter(zx, zy, marker=mstyle, alpha=0.35, c=gcolor)

    # Print summary info
    pname = os.path.split(prodname)[1]
    fig_summary.text(0.01,
                     0.95,
                     "Summary for {}".format(pname),
                     fontsize=fsize)
    fig_summary.text(0.01, 0.9, "WCSNAME: {}".format(wcsname), fontsize=fsize)
    fig_summary.text(0.01, 0.85, "TARGET: {}".format(targname), fontsize=fsize)
    fig_summary.text(0.01,
                     0.8,
                     "Instrument: {}/{}".format(inst, det),
                     fontsize=fsize)
    fig_summary.text(0.01, 0.75, "Filters: {}".format(filters), fontsize=fsize)
    fig_summary.text(0.01,
                     0.7,
                     "Total Exptime: {}".format(texptime),
                     fontsize=fsize)
    fig_summary.text(0.01, 0.65, "WCSTYPE: {}".format(wcstype), fontsize=fsize)
    fig_summary.text(0.01,
                     0.5,
                     "Total # of GAIA sources: {}".format(len(refx)),
                     fontsize=fsize)
    fig_summary.text(0.01,
                     0.45,
                     "# of GAIA matches: {}".format(len(rx)),
                     fontsize=fsize)

    # Get extended information about observation
    hdrtab_cols = hdrtab.columns.names
    mtflag = get_col_val(hdrtab, 'mtflag', default="")
    gyromode = get_col_val(hdrtab, 'gyromode', default='N/A')

    # populate JSON summary info
    summary = dict(wcsname=wcsname,
                   targname=targname,
                   asnid=asnid,
                   dateobs=dateobs,
                   expstart=expstart,
                   instrument=(inst, det),
                   exptime=texptime,
                   wcstype=wcstype,
                   num_gaia=len(refx),
                   filters=filters,
                   rms_ra=-1,
                   rms_dec=-1,
                   nmatch=-1,
                   catalog="")
    obs_kws = [
        'gyromode', 'fgslock', 'aperture', 'mtflag', 'subarray', 'obstype',
        'obsmode', 'scan_typ', 'photmode'
    ]
    for kw in obs_kws:
        summary[kw] = get_col_val(hdrtab, kw, default="")

    if 'FIT' in wcsname:
        # Look for FIT RMS and other stats from headerlet
        exp = fits.open(os.path.join(prod_path, inexp))
        for ext in exp:
            if 'extname' in ext.header and ext.header['extname'] == 'HDRLET' \
                and ext.header['wcsname'] == wcsname:
                hdrlet = ext.headerlet
                rms_ra = hdrlet[0].header['rms_ra']
                rms_dec = hdrlet[0].header['rms_dec']
                nmatch = hdrlet[0].header['nmatch']
                catalog = hdrlet[0].header['catalog']

                fit_vals = dict(rms_ra=rms_ra,
                                rms_dec=rms_dec,
                                nmatch=nmatch,
                                catalog=catalog)
                summary.update(fit_vals)
                break
        exp.close()
        try:
            fig_summary.text(0.01,
                             0.4,
                             "RMS: RA={:0.3f}mas, DEC={:0.3f}mas".format(
                                 rms_ra, rms_dec),
                             fontsize=fsize)
            fig_summary.text(0.01,
                             0.35,
                             "# matches: {}".format(nmatch),
                             fontsize=fsize)
            fig_summary.text(0.01,
                             0.3,
                             "Matched to {} catalog".format(catalog),
                             fontsize=fsize)
        except:
            fig_summary.text(0.01, 0.35, "No MATCH to GAIA")
            print("Data without a match to GAIA: {},{}".format(inexp, wcsname))

    return fig, summary
Пример #17
0
def generate_sky_catalog(image, refwcs, **kwargs):
    """Build source catalog from input image using photutils.

    This script borrows heavily from build_source_catalog

    The catalog returned by this function includes sources found in all chips
    of the input image with the positions translated to the coordinate frame
    defined by the reference WCS `refwcs`.  The sources will be
      - identified using photutils segmentation-based source finding code
      - ignore any input pixel which has been flagged as 'bad' in the DQ
        array, should a DQ array be found in the input HDUList.
      - classified as probable cosmic-rays (if enabled) using central_moments
        properties of each source, with these sources being removed from the
        catalog.

    Parameters
    -----------
    image : HDUList object
        Input image as an astropy.io.fits HDUList object

    refwcs : HSTWCS object
        Definition of the reference frame WCS.

    dqname : string
        EXTNAME for the DQ array, if present, in the input image HDUList.

    output : boolean
        Specify whether or not to write out a separate catalog file for all the
        sources found in each chip.  Default: None (False)

    Optional Parameters
    --------------------
    threshold : float, optional
        This parameter controls the S/N threshold used for identifying sources in
        the image relative to the background RMS in much the same way that
        the 'threshold' parameter in 'tweakreg' works.
        Default: 1000.

    fwhm : float, optional
        FWHM (in pixels) of the expected sources from the image, comparable to the
        'conv_width' parameter from 'tweakreg'.  Objects with FWHM closest to
        this value will be identified as sources in the catalog. Default: 3.0.

    Returns
    --------
    master_cat : astropy.Table object
        Source catalog for all 'valid' sources identified from all chips of the
        input image with positions translated to the reference WCS coordinate
        frame.


    """
    # Extract source catalogs for each chip
    source_cats = generate_source_catalog(image, **kwargs)

    # Build source catalog for entire image
    master_cat = None
    numSci = countExtn(image, extname='SCI')
    # if no refwcs specified, build one now...
    if refwcs is None:
        refwcs = build_reference_wcs([image])
    for chip in range(numSci):
        chip += 1
        # work with sources identified from this specific chip
        seg_tab_phot = source_cats[chip]

        # Convert pixel coordinates from this chip to sky coordinates
        chip_wcs = wcsutil.HSTWCS(image, ext=('sci', chip))
        seg_ra, seg_dec = chip_wcs.all_pix2world(seg_tab_phot['xcentroid'],
                                                 seg_tab_phot['ycentroid'], 1)
        # Convert sky positions to pixel positions in the reference WCS frame
        seg_xy_out = refwcs.all_world2pix(seg_ra, seg_dec, 1)
        seg_tab_phot['xcentroid'] = seg_xy_out[0]
        seg_tab_phot['ycentroid'] = seg_xy_out[1]
        if master_cat is None:
            master_cat = seg_tab_phot
        else:
            master_cat = vstack([master_cat, seg_tab_phot])

    return master_cat
Пример #18
0
def rd2xy(input,
          ra=None,
          dec=None,
          coordfile=None,
          colnames=None,
          precision=6,
          output=None,
          verbose=True):
    """ Primary interface to perform coordinate transformations from
        pixel to sky coordinates using STWCS and full distortion models
        read from the input image header.
    """
    single_coord = False
    if coordfile is not None:
        if colnames in blank_list:
            colnames = ['c1', 'c2']
        elif isinstance(colnames, type('a')):
            colnames = colnames.split(',')
        # convert input file coordinates to lists of decimal degrees values
        xlist, ylist = tweakutils.readcols(coordfile, cols=colnames)
    else:
        if isinstance(ra, np.ndarray):
            ralist = ra.tolist()
            declist = dec.tolist()
        elif not isinstance(ra, list):
            ralist = [ra]
            declist = [dec]
        else:
            ralist = ra
            declist = dec
        xlist = [0] * len(ralist)
        ylist = [0] * len(ralist)
        if len(xlist) == 1:
            single_coord = True
        for i, (r, d) in enumerate(zip(ralist, declist)):
            # convert input value into decimal degrees value
            xval, yval = tweakutils.parse_skypos(r, d)
            xlist[i] = xval
            ylist[i] = yval

    # start by reading in WCS+distortion info for input image
    inwcs = wcsutil.HSTWCS(input)
    if inwcs.wcs.is_unity():
        print(
            "####\nNo valid WCS found in {}.\n  Results may be invalid.\n####\n"
            .format(input))

    # Now, convert pixel coordinates into sky coordinates
    try:
        outx, outy = inwcs.all_world2pix(xlist, ylist, 1)
    except RuntimeError:
        outx, outy = inwcs.wcs_world2pix(xlist, ylist, 1)

    # add formatting based on precision here...
    xstr = []
    ystr = []
    fmt = "%." + repr(precision) + "f"
    for x, y in zip(outx, outy):
        xstr.append(fmt % x)
        ystr.append(fmt % y)

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ', input)
        print('# X      Y         RA             Dec\n')
        for x, y, r, d in zip(xstr, ystr, xlist, ylist):
            print("%s  %s    %s  %s" % (x, y, r, d))

    # Create output file, if specified
    if output:
        f = open(output, mode='w')
        f.write("# Coordinates converted from %s\n" % input)
        for x, y in zip(xstr, ystr):
            f.write('%s    %s\n' % (x, y))
        f.close()
        print('Wrote out results to: ', output)

    if single_coord:
        outx = outx[0]
        outy = outy[0]

    return outx, outy
Пример #19
0
def build(outname,
          wcsname,
          refimage,
          undistort=False,
          applycoeffs=False,
          coeffsfile=None,
          **wcspars):
    """ Core functionality to create a WCS instance from a reference image WCS,
        user supplied parameters or user adjusted reference WCS.
        The distortion information can either be read in as part of the reference
        image WCS or given in 'coeffsfile'.

        Parameters
        ----------
        outname   : string
            filename of output WCS
        wcsname   : string
            WCSNAME ID for generated WCS
        refimage  : string
            filename of image with source WCS used as basis for output WCS
        undistort : bool
            Create an undistorted WCS?
        applycoeffs : bool
            Apply coefficients from refimage to generate undistorted WCS?
        coeffsfile  : string
            If specified, read distortion coeffs from separate file


    """

    # Insure that the User WCS parameters have values for all the parameters,
    # even if that value is 'None'
    user_wcs_pars = convert_user_pars(wcspars)
    userwcs = wcspars['userwcs']
    """
    Use cases to document the logic required to interpret the parameters

    WCS generation based on refimage/userwcs parameters
    -------------------------------------------------------------
    refimage == None, userwcs == False:
        *NO WCS specified*
        => print a WARNING message and return without doing anything
    refimage == None, userwcs == True:
        => Create WCS without a distortion model entirely from user parameters*
    refimage != None, userwcs == False:
        => No user WCS parameters specified
        => Simply use refimage WCS as specified
    refimage != None, userwcs == True:
        => Update refimage WCS with user specified values*

    Apply distortion and generate final headerlet using processed WCS
    -----------------------------------------------------------------
    refimage == None, userwcs == True:
        *Output WCS generated entirely from user supplied parameters*
        Case 1: applycoeffs == False, undistort == True/False (ignored)
            => no distortion model to interpret
            => generate undistorted headerlet with no distortion model
        Case 2: applycoeffs == True/False, undistort == True
            => ignore any user specified distortion model
            => generate undistorted headerlet with no distortion model
        Case 3: applycoeffs == True, undistort == False
            => WCS from scratch combined with distortion model from another image
            => generate headerlet with distortion model

    refimage != None, userwcs == True/False:
        *Output WCS generated from reference image possibly modified by user parameters*
        Case 4: applycoeffs == False, undistort == True
            => If refimage has distortion, remove it
            => generate undistorted headerlet with no distortion model
        Case 5: applycoeffs == False, undistort == False
            => Leave refimage distortion model (if any) unmodified
            => generate a headerlet using same distortion model (if any) as refimage
        Case 6: applycoeffs == True, undistort == False
            => Update refimage with distortion model with user-specified model
            => generate a headerlet with a distortion model
        Case 7: applycoeffs == True, undistort == True
            => ignore user specified distortion model and undistort WCS
            => generate a headerlet without a distortion model
    """
    ### Build WCS from refimage and/or user pars
    if util.is_blank(refimage) and not userwcs:
        print('WARNING: No WCS specified... No WCS created!')
        return
    customwcs = None
    if util.is_blank(refimage) and userwcs:
        # create HSTWCS object from user parameters
        complete_wcs = True
        for key in user_wcs_pars:
            if util.is_blank(user_wcs_pars[key]):
                complete_wcs = False
                break
        if complete_wcs:
            customwcs = wcs_functions.build_hstwcs(
                user_wcs_pars['crval1'], user_wcs_pars['crval2'],
                user_wcs_pars['crpix1'], user_wcs_pars['crpix2'],
                user_wcs_pars['naxis1'], user_wcs_pars['naxis2'],
                user_wcs_pars['pscale'], user_wcs_pars['orientat'])
        else:
            print('WARNING: Not enough WCS information provided by user!')
            raise ValueError

    if not util.is_blank(refimage):
        refwcs = stwcs.wcsutil.HSTWCS(refimage)
    else:
        refwcs = customwcs

    ### Apply distortion model (if any) to update WCS
    if applycoeffs and not util.is_blank(coeffsfile):
        if not util.is_blank(refimage):
            replace_model(refwcs, coeffsfile)
        else:
            if not undistort:
                add_model(refwcs, coeffsfile)
                # Only working with custom WCS from user, no distortion
                # so apply model to WCS, including modifying the CD matrix
                apply_model(refwcs)

    ### Create undistorted WCS, if requested
    if undistort:
        outwcs = undistortWCS(refwcs)
    else:
        outwcs = refwcs

    if userwcs:
        # replace (some/all?) WCS values from refimage with user WCS values
        # by running 'updatewcs' functions on input WCS
        outwcs = mergewcs(outwcs, customwcs, user_wcs_pars)

    ### Create the final headerlet and write it out, if specified
    if not util.is_blank(refimage):
        template = refimage
    elif not util.is_blank(coeffsfile):
        template = coeffsfile
    else:
        template = None

    # create default WCSNAME if None was given
    wcsname = create_WCSname(wcsname)
    print('Creating final headerlet with name ', wcsname, ' using template ',
          template)
    outhdr = generate_headerlet(outwcs, template, wcsname, outname=outname)

    # synchronize this new WCS with the rest of the chips in the image
    for ext in outhdr:
        if 'extname' in ext.header and ext.header['extname'] == 'SIPWCS':
            ext_wcs = wcsutil.HSTWCS(ext)
            stwcs.updatewcs.makewcs.MakeWCS.updateWCS(ext_wcs, outwcs)

    return outwcs
Пример #20
0
def build_wcscat(image, group_id, source_catalog):
    """ Return a list of `~tweakwcs.tpwcs.FITSWCS` objects for all chips in an image.

    Parameters
    ----------
    image : str, `~astropy.io.fits.HDUList`
        Either filename or HDUList of a single HST observation.

    group_id : int
        Integer ID for group this image should be associated with; primarily
        used when separate chips are in separate files to treat them all as one
        exposure.

    source_catalog : dict
        If provided, these catalogs will be attached as `catalog`
        entries in each chip's ``FITSWCS`` object.  It should be provided as a
        dict of astropy Tables identified by chip number with
        each table containing sources from image extension ``('sci', chip)`` as
        generated by `generate_source_catalog()`.

    Returns
    -------
    wcs_catalogs : list of `~tweakwcs.tpwcs.FITSWCS`
        List of `~tweakwcs.tpwcs.FITSWCS` objects defined for all chips in input image.

    """
    open_file = False
    if isinstance(image, str):
        hdulist = fits.open(image)
        open_file = True
    elif isinstance(image, fits.HDUList):
        hdulist = image
    else:
        log.info("Wrong type of input, {}, for build_wcscat...".format(
            type(image)))
        raise ValueError

    wcs_catalogs = []
    numsci = countExtn(hdulist)
    for chip in range(1, numsci + 1):
        w = wcsutil.HSTWCS(hdulist, ('SCI', chip))

        imcat = source_catalog[chip]
        # rename xcentroid/ycentroid columns, if necessary, to be consistent with tweakwcs
        if 'xcentroid' in imcat.colnames:
            imcat.rename_column('xcentroid', 'x')
            imcat.rename_column('ycentroid', 'y')

        wcscat = FITSWCS(w,
                         meta={
                             'chip': chip,
                             'group_id': group_id,
                             'filename': image,
                             'catalog': imcat,
                             'name': image
                         })

        wcs_catalogs.append(wcscat)

    if open_file:
        hdulist.close()

    return wcs_catalogs
Пример #21
0
def generate_gaia_catalog(hap_obj, columns_to_remove=None):
    """Uses astrometric_utils.create_astrometric_catalog() to create a catalog of all GAIA sources in the
    image footprint. This catalog contains right ascension, declination, and magnitude values, and is sorted
    in descending order by brightness.

    Parameters
    ----------
    hap_obj : drizzlepac.hlautils.Product.TotalProduct, drizzlepac.hlautils.Product.FilterProduct, or
        drizzlepac.hlautils.Product.ExposureProduct, depending on input.
        hap product object to process

    Returns
    -------
    gaia_table : astropy table
        table containing right ascension, declination, and magnitude of all GAIA sources identified in the
        image footprint, sorted in descending order by brightness.
    """
    # Gather list of input flc/flt images
    img_list = []
    log.debug("GAIA catalog will be created using the following input images:")
    # Create a list of the input flc.fits/flt.fits that were drizzled to create the final HAP product being
    # processed here. edp_item.info and hap_obj.info are both structured as follows:
    # <proposal id>_<visit #>_<instrument>_<detector>_<input filename>_<filter>_<drizzled product
    # image filetype>
    # Example: '10265_01_acs_wfc_j92c01b9q_flc.fits_f606w_drc'
    # what is being extracted here is just the input filename, which in this case is 'j92c01b9q_flc.fits'.
    if hasattr(hap_obj, "edp_list"):  # for total and filter product objects
        for edp_item in hap_obj.edp_list:
            parse_info = edp_item.info.split("_")
            imgname = "{}_{}".format(parse_info[4], parse_info[5])
            log.debug(imgname)
            img_list.append(imgname)
    else:  # For single-exposure product objects
        parse_info = hap_obj.info.split("_")
        imgname = "{}_{}".format(parse_info[4], parse_info[5])
        log.debug(imgname)
        img_list.append(imgname)

    # generate catalog of GAIA sources
    gaia_table = au.create_astrometric_catalog(img_list,
                                               gaia_only=True,
                                               use_footprint=True)

    # trim off specified columns
    if columns_to_remove:
        gaia_table.remove_columns(columns_to_remove)

    # remove sources outside image footprint
    outwcs = wcsutil.HSTWCS(hap_obj.drizzle_filename, ext=1)
    x, y = outwcs.all_world2pix(gaia_table['RA'], gaia_table['DEC'], 1)
    imghdu = fits.open(hap_obj.drizzle_filename)
    in_img_data = imghdu['WHT'].data.copy()
    in_img_data = np.where(in_img_data == 0, np.nan, in_img_data)
    mask = au.within_footprint(in_img_data, outwcs, x, y)
    gaia_table = gaia_table[mask]

    # Report results to log
    if len(gaia_table) == 0:
        log.warning("No GAIA sources were found!")
    elif len(gaia_table) == 1:
        log.info("1 GAIA source was found.")
    else:
        log.info("{} GAIA sources were found.".format(len(gaia_table)))
    return gaia_table
Пример #22
0
def generate_sky_catalog(image, refwcs, dqname="DQ", output=False):
    """Build source catalog from input image using photutils.

    This script borrows heavily from build_source_catalog.

    The catalog returned by this function includes sources found in all chips
    of the input image with the positions translated to the coordinate frame
    defined by the reference WCS `refwcs`.  The sources will be
    - identified using photutils segmentation-based source finding code
    - ignore any input pixel which has been flagged as 'bad' in the DQ
    array, should a DQ array be found in the input HDUList.
    - classified as probable cosmic-rays (if enabled) using central_moments
    properties of each source, with these sources being removed from the
    catalog.

    Parameters
    ----------
    image : `~astropy.io.fits.HDUList`
        Input image.
    refwcs : `~stwcs.wcsutil.HSTWCS`
        Definition of the reference frame WCS.
    dqname : str, optional
        EXTNAME for the DQ array, if present, in the input image.
    output : bool, optional
        Specify whether or not to write out a separate catalog file for all the
        sources found in each chip.

    Returns
    --------
    master_cat : `~astropy.table.Table`
        Source catalog for all 'valid' sources identified from all chips of the
        input image with positions translated to the reference WCS coordinate
        frame.

    """
    # Extract source catalogs for each chip
    source_cats = generate_source_catalog(image, dqname=dqname, output=output)

    # Build source catalog for entire image
    master_cat = None
    numSci = countExtn(image, extname='SCI')
    # if no refwcs specified, build one now...
    if refwcs is None:
        refwcs = build_reference_wcs([image])
    for chip in range(numSci):
        chip += 1
        # work with sources identified from this specific chip
        seg_tab_phot = source_cats[chip]
        if seg_tab_phot is None:
            continue
        # Convert pixel coordinates from this chip to sky coordinates
        chip_wcs = wcsutil.HSTWCS(image, ext=('sci', chip))
        seg_ra, seg_dec = chip_wcs.all_pix2world(seg_tab_phot['xcentroid'],
                                                 seg_tab_phot['ycentroid'], 1)
        # Convert sky positions to pixel positions in the reference WCS frame
        seg_xy_out = refwcs.all_world2pix(seg_ra, seg_dec, 1)
        seg_tab_phot['xcentroid'] = seg_xy_out[0]
        seg_tab_phot['ycentroid'] = seg_xy_out[1]
        if master_cat is None:
            master_cat = seg_tab_phot
        else:
            master_cat = vstack([master_cat, seg_tab_phot])

    return master_cat
Пример #23
0
def create_product_page(prodname, zoom_size=128, wcsname=""):

    # obtain image data to display
    with fits.open(prodname) as prod:
        data = prod[1].data
        phdr = prod[0].header
        targname = phdr['targname']
        inst = phdr['instrume']
        det = phdr['detector']
        texptime = phdr['texptime']
        inexp = phdr['d001data'].split('[')[0]
        wcstype = prod[1].header['wcstype']
        wcs = wcsutil.HSTWCS(prod, ext=1)
    center = (data.shape[0] // 2, data.shape[1] // 2)
    prod_path = os.path.split(prodname)[0]

    data = np.nan_to_num(data, 0.0)

    # Get GAIA catalog
    refcat = amutils.create_astrometric_catalog(prodname,
                                                existing_wcs=wcs,
                                                output=None)
    refx, refy = wcs.all_world2pix(refcat['RA'], refcat['DEC'], 0)
    # Remove points outside the full-size image area
    rx = []
    ry = []
    zx = []
    zy = []
    for x, y in zip(refx, refy):
        if 0 < x < data.shape[1] and 0 < y < data.shape[0]:
            rx.append(x)
            ry.append(y)
        if -zoom_size < x - center[1] < zoom_size and -zoom_size < y - center[
                0] < zoom_size:
            zx.append(x - center[1] + zoom_size)
            zy.append(y - center[0] + zoom_size)

    # Define subplot regions on page
    fig = plt.figure(constrained_layout=True, figsize=(7, 10))
    gs = fig.add_gridspec(ncols=4, nrows=5)

    # title plots
    img_title = "{} image of {} with WCSNAME={}".format(
        prodname, targname, wcsname)
    plt.title(img_title, loc='center', fontsize=8)

    # Define image display
    fig_img = fig.add_subplot(gs[:3, :])
    fig_zoom = fig.add_subplot(gs[3:, 2:])
    fig_summary = fig.add_subplot(gs[3:, :2])

    # Compute display range
    dmax = (data.max() // 10)
    dscaled = np.log10(np.clip(data, -0.9, dmax) + 1)
    # identify zoom region around center of data
    zoom = dscaled[center[0] - zoom_size:center[0] + zoom_size,
                   center[1] - zoom_size:center[1] + zoom_size]

    # display full image
    fig_img.imshow(dscaled, cmap='gray', origin='lower')
    # display zoomed section
    fig_zoom.imshow(zoom, cmap='gray', origin='lower')

    # define markerstyle
    mstyle = markers.MarkerStyle(marker='o')
    mstyle.set_fillstyle('none')
    # plot GAIA sources onto full size image
    fig_img.scatter(rx, ry, marker=mstyle, alpha=0.25, c='cyan', s=3)
    fig_zoom.scatter(zx, zy, marker=mstyle, alpha=0.25, c='cyan')

    # Print summary info
    fsize = 8
    pname = os.path.split(prodname)[1]
    fig_summary.text(0.01,
                     0.95,
                     "Summary for {}".format(pname),
                     fontsize=fsize)
    fig_summary.text(0.01, 0.9, "WCSNAME: {}".format(wcsname), fontsize=fsize)
    fig_summary.text(0.01, 0.85, "TARGET: {}".format(targname), fontsize=fsize)
    fig_summary.text(0.01,
                     0.8,
                     "Instrument: {}/{}".format(inst, det),
                     fontsize=fsize)
    fig_summary.text(0.01,
                     0.7,
                     "Total Exptime: {}".format(texptime),
                     fontsize=fsize)
    fig_summary.text(0.01, 0.65, "WCSTYPE: {}".format(wcstype), fontsize=fsize)
    fig_summary.text(0.01,
                     0.5,
                     "# of GAIA sources: {}".format(len(rx)),
                     fontsize=fsize)

    if 'FIT' in wcsname:
        # Look for FIT RMS and other stats from headerlet
        exp = fits.open(os.path.join(prod_path, inexp))
        for ext in exp:
            if 'extname' in ext.header and ext.header['extname'] == 'HDRLET' \
                and ext.header['wcsname'] == wcsname:
                hdrlet = ext.headerlet
                rms_ra = hdrlet[0].header['rms_ra']
                rms_dec = hdrlet[0].header['rms_dec']
                nmatch = hdrlet[0].header['nmatch']
                catalog = hdrlet[0].header['catalog']
                break
        exp.close()
        fig_summary.text(0.01,
                         0.4,
                         "RMS: RA={:0.3}mas, DEC={:0.3}mas".format(
                             rms_ra, rms_dec),
                         fontsize=fsize)
        fig_summary.text(0.01,
                         0.35,
                         "# matches: {}".format(nmatch),
                         fontsize=fsize)
        fig_summary.text(0.01,
                         0.3,
                         "Matched to {} catalog".format(catalog),
                         fontsize=fsize)

    return fig
Пример #24
0
def make_outputwcs(imageObjectList, output, configObj=None, perfect=False):
    """ Computes the full output WCS based on the set of input imageObjects
        provided as input, along with the pre-determined output name from
        process_input.  The user specified output parameters are then used to
        modify the default WCS to produce the final desired output frame.
        The input imageObjectList has the outputValues dictionary
        updated with the information from the computed output WCS.
        It then returns this WCS as a WCSObject(imageObject)
        instance.

    """
    if not isinstance(imageObjectList, list):
        imageObjectList = [imageObjectList]

    # Compute default output WCS, replace later if user specifies a refimage
    hstwcs_list = []
    undistort = True
    for img in imageObjectList:
        chip_wcs = copy.deepcopy(img.getKeywordList('wcs'))
        # IF the user turned off use of coeffs (coeffs==False)
        if not configObj['coeffs']:
            for cw in chip_wcs:
                # Turn off distortion model for each input
                cw.sip = None
                cw.cpdis1 = None
                cw.cpdis2 = None
                cw.det2im = None
            undistort = False
        hstwcs_list += chip_wcs
    if not undistort and len(hstwcs_list) == 1:
        default_wcs = hstwcs_list[0].deepcopy()
    else:
        default_wcs = utils.output_wcs(hstwcs_list, undistort=undistort)

    if perfect:
        default_wcs.wcs.cd = make_perfect_cd(default_wcs)

    # Turn WCS instances into WCSObject instances
    outwcs = createWCSObject(output, default_wcs, imageObjectList)

    # Merge in user-specified attributes for the output WCS
    # as recorded in the input configObj object.
    final_pars = DEFAULT_WCS_PARS.copy()

    # More interpretation of the configObj needs to be done here to translate
    # the input parameter names to those understood by 'mergeWCS' as defined
    # by the DEFAULT_WCS_PARS dictionary.
    single_step = configObj[util.getSectionName(configObj, 3)]
    singleParDict = configObj[util.getSectionName(configObj, '3a')].copy()
    if single_step['driz_separate'] and singleParDict['driz_sep_wcs']:
        single_pars = DEFAULT_WCS_PARS.copy()
        del singleParDict['driz_sep_wcs']
        keyname = 'driz_sep_'
        for key in singleParDict:
            k = key[len(keyname):]
            if k != 'refimage':
                single_pars[k] = singleParDict[key]

        # Now, account for any user-specified reference image
        def_wcs = default_wcs.deepcopy()
        single_ref = singleParDict[keyname + 'refimage']
        if single_ref:
            if isinstance(single_ref, wcs.WCS):
                default_wcs = single_ref
            else:
                default_wcs = wcsutil.HSTWCS(singleParDict[keyname + 'refimage'])

        # ## Create single_wcs instance based on user parameters
        outwcs.single_wcs = mergeWCS(default_wcs, single_pars)
        # restore global default WCS to original value so single_drizzle WCS does not
        # influence final_drizzle WCS
        default_wcs = def_wcs.deepcopy()

    final_step = configObj[util.getSectionName(configObj, 7)]
    finalParDict = configObj[util.getSectionName(configObj, '7a')].copy()
    if final_step['driz_combine'] and finalParDict['final_wcs']:
        del finalParDict['final_wcs']
        keyname = 'final_'
        for key in finalParDict:
            k = key[len(keyname):]
            if k != 'refimage':
                final_pars[k] = finalParDict[key]

        # Now, account for any user-specified reference image
        final_ref = finalParDict[keyname + 'refimage']
        if final_ref:
            if isinstance(final_ref, wcs.WCS):
                default_wcs = final_ref
                if hasattr(final_ref, 'filename'):
                    rootname = final_ref.filename
                else:
                    rootname = ""
                print('Creating OUTPUT WCS from WCS object based on {}'.format(rootname))
            else:
                rootname, extnum = fileutil.parseFilename(finalParDict[keyname + 'refimage'])
                extnum = util.findWCSExtn(finalParDict[keyname + 'refimage'])
                print('Creating OUTPUT WCS from {}[{}]'.format(rootname, extnum))
                default_wcs = wcsutil.HSTWCS('{}[{}]'.format(rootname, extnum))

        # ## Create single_wcs instance based on user parameters
        outwcs.final_wcs = mergeWCS(default_wcs, final_pars)
        outwcs.wcs = outwcs.final_wcs.copy()

    # Apply user settings to create custom output_wcs instances
    # for each drizzle step
    updateImageWCS(imageObjectList, outwcs)

    return outwcs
Пример #25
0
def tweakback(drzfile,
              input=None,
              origwcs=None,
              newname=None,
              wcsname=None,
              extname='SCI',
              force=False,
              verbose=False):
    """
    Apply WCS solution recorded in drizzled file to distorted input images
    (``_flt.fits`` files) used to create the drizzled file.  This task relies on
    the original WCS and updated WCS to be recorded in the drizzled image's
    header as the last 2 alternate WCSs.

    Parameters
    ----------
    drzfile : str (Default = '')
        filename of undistorted image which contains the new WCS
        and WCS prior to being updated

    newname : str (Default = None)
        Value of ``WCSNAME`` to be used to label the updated solution in the
        output (eq., ``_flt.fits``) files.  If left blank or None, it will
        default to using the current ``WCSNAME`` value from the input drzfile.

    input : str (Default = '')
        filenames of distorted images to be updated using new WCS
        from 'drzfile'.  These can be provided either as an ``@-file``,
        a comma-separated list of filenames or using wildcards.

        .. note:: A blank value will indicate that the task should derive the
           filenames from the 'drzfile' itself, if possible. The filenames will be
           derived from the ``D*DATA`` keywords written out by
           ``AstroDrizzle``. If they can not be found, the task will quit.

    origwcs : str (Default = None)
        Value of ``WCSNAME`` keyword prior to the drzfile image being updated
        by ``TweakReg``.  If left blank or None, it will default to using the
        second to last ``WCSNAME*`` keyword value found in the header.

    wcsname : str (Default = None)
        Value of WCSNAME for updated solution written out by ``TweakReg`` as
        specified by the `wcsname` parameter from ``TweakReg``.  If this is
        left blank or `None`, it will default to the current ``WCSNAME``
        value from the input drzfile.

    extname : str (Default = 'SCI')
        Name of extension in `input` files to be updated with new WCS

    force : bool  (Default = False)
        This parameters specified whether or not to force an update of the WCS
        even though WCS already exists with this solution or `wcsname`?

    verbose : bool (Default = False)
        This parameter specifies whether or not to print out additional
        messages during processing.


    Notes
    -----
    The algorithm used by this function is based on linearization of
    the exact compound operator that converts input image coordinates
    to the coordinates (in the input image) that would result in
    alignment with the new drizzled image WCS.

    If no input distorted files are specified as input, this task will attempt
    to generate the list of filenames from the drizzled input file's own
    header.

    EXAMPLES
    --------
    An image named ``acswfc_mos2_drz.fits`` was created from 4 images using
    astrodrizzle. This drizzled image was then aligned to another image using
    tweakreg and the header was updated using the ``WCSNAME`` = ``TWEAK_DRZ``.
    The new WCS can then be used to update each of the 4 images that were
    combined to make up this drizzled image using:

    >>> from drizzlepac import tweakback
    >>> tweakback.tweakback('acswfc_mos2_drz.fits')

    If the same WCS should be applied to a specific set of images, those images
    can be updated using:

    >>> tweakback.tweakback('acswfc_mos2_drz.fits',
    ...                     input='img_mos2a_flt.fits,img_mos2e_flt.fits')

    See Also
    --------
    stwcs.wcsutil.altwcs: Alternate WCS implementation

    """
    print("TweakBack Version {:s} started at: {:s}\n".format(
        __version__,
        util._ptime()[0]))

    # Interpret input list/string into list of filename(s)
    fltfiles = parseinput.parseinput(input)[0]

    if fltfiles is None or len(fltfiles) == 0:
        # try to extract the filenames from the drizzled file's header
        fltfiles = extract_input_filenames(drzfile)
        if fltfiles is None:
            print('*' * 60)
            print('*')
            print('* ERROR:')
            print('*    No input filenames found! ')
            print(
                '*    Please specify "fltfiles" or insure that input drizzled')
            print('*    image contains D*DATA keywords. ')
            print('*')
            print('*' * 60)
            raise ValueError

    if not isinstance(fltfiles, list):
        fltfiles = [fltfiles]

    sciext = determine_extnum(drzfile, extname='SCI')
    scihdr = fits.getheader(drzfile, ext=sciext, memmap=False)

    ### Step 1: Read in updated and original WCS solutions
    # determine keys for all alternate WCS solutions in drizzled image header
    wkeys = wcsutil.altwcs.wcskeys(drzfile, ext=sciext)
    if len(wkeys) < 2:
        raise ValueError(
            f"'{drzfile}' must contain at least two valid WCS: original and updated."
        )
    wnames = wcsutil.altwcs.wcsnames(drzfile, ext=sciext)
    if not util.is_blank(newname):
        final_name = newname
    else:
        final_name = wnames[wkeys[-1]]

    # Read in HSTWCS objects for final,updated WCS and previous WCS from
    # from drizzled image header
    # The final solution also serves as reference WCS when using updatehdr

    if not util.is_blank(wcsname):
        for wkey, wname in wnames.items():
            if wname == wcsname:
                wcskey = wkey
                break
        else:
            raise ValueError(
                f"WCS with name '{wcsname}' not found in '{drzfile}'")
    else:
        wcskey = wkeys[-1]

    final_wcs = wcsutil.HSTWCS(drzfile, ext=sciext, wcskey=wcskey)

    if not util.is_blank(origwcs):
        for wkey, wname in wnames.items():
            if wname == origwcs:
                orig_wcskey = wkey
                break
        else:
            raise ValueError(
                f"WCS with name '{origwcs}' not found in '{drzfile}'")
    else:
        _, orig_wcskey = determine_orig_wcsname(scihdr, wnames, wkeys)

    orig_wcs = wcsutil.HSTWCS(drzfile, ext=sciext, wcskey=orig_wcskey)

    # read in RMS values reported for new solution
    crderr1kw = 'CRDER1' + wkeys[-1]
    crderr2kw = 'CRDER2' + wkeys[-1]

    if crderr1kw in scihdr:
        crderr1 = fits.getval(drzfile, crderr1kw, ext=sciext, memmap=False)
    else:
        crderr1 = 0.0

    if crderr2kw in scihdr:
        crderr2 = fits.getval(drzfile, crderr2kw, ext=sciext, memmap=False)
    else:
        crderr2 = 0.0
    del scihdr

    ### Step 2: Apply solution to input file headers
    for fname in fltfiles:
        logstr = "....Updating header for {:s}...".format(fname)
        if verbose:
            print("\n{:s}\n".format(logstr))
        else:
            log.info(logstr)

        # reset header WCS keywords to original (OPUS generated) values
        imhdulist = fits.open(fname, mode='update', memmap=False)
        extlist = get_ext_list(imhdulist, extname='SCI')
        if not extlist:
            extlist = [0]

        # Process MEF images...
        for ext in extlist:
            logstr = "Processing {:s}[{:s}]".format(imhdulist.filename(),
                                                    ext2str(ext))
            if verbose:
                print("\n{:s}\n".format(logstr))
            else:
                log.info(logstr)
            chip_wcs = wcsutil.HSTWCS(imhdulist, ext=ext)

            update_chip_wcs(chip_wcs,
                            orig_wcs,
                            final_wcs,
                            xrms=crderr1,
                            yrms=crderr2)

            # Update FITS file with newly updated WCS for this chip
            extnum = imhdulist.index(imhdulist[ext])
            updatehdr.update_wcs(imhdulist,
                                 extnum,
                                 chip_wcs,
                                 wcsname=final_name,
                                 reusename=False,
                                 verbose=verbose)

        imhdulist.close()
Пример #26
0
def build_nddata(image, group_id, source_catalog):
    """ Return a list of NDData objects for all chips in an image.

    Parameters
    ===========
    image : filename, HDUList
        Either filename or HDUList of a single HST observation

    group_id : int
        Integer ID for group this image should be associated with; primarily
        used when separate chips are in separate files to treat them all as one
        exposure.

    source_catalog : dict, optional
        If provided (default:None), these catalogs will be attached as `catalog`
        entries in each chip's NDData.meta.  It should be provided as a
        dict of astropy Tables identified by chip number with
        each table containing sources from image extension `('sci',chip)` as
        generated by `generate_source_catalog()`.

    Returns
    ========
    ndlist : list
        List of astropy NDData defined for all chips in input image

    """
    open_file = False
    if isinstance(image, str):
        hdulist = pf.open(image)
        open_file = True
    elif isinstance(image, pf.HDUList):
        hdulist = image
    else:
        print("Wrong type of input, {}, for build_nddata...".format(
            type(image)))
        raise ValueError

    images = []
    numsci = countExtn(hdulist)
    for chip in range(1, numsci + 1):
        im_data = hdulist[('SCI', chip)].data
        dq_data = hdulist[('DQ', chip)].data
        w = wcsutil.HSTWCS(hdulist, ('SCI', chip))

        # Below, simply consider non-zero DQ data as invalid.
        # A more sophisticated approach would use bitmask module.
        # Also, here we set group ID to a different number for each image,
        # but for ACS images, for example, we likely would assign
        # the same group ID to the images corresponding to different
        # SCI extensions *of the same FITS file* so that they can be
        # aligned together.
        img = NDData(data=im_data,
                     mask=dq_data != 0,
                     wcs=w,
                     meta={
                         'chip': chip,
                         'group_id': group_id
                     })
        # append source catalog, if provided
        if source_catalog:
            imcat = source_catalog[chip]
            # rename xcentroid/ycentroid columns, if necessary, to be consistent with tweakwcs
            if 'xcentroid' in imcat.colnames:
                imcat.rename_column('xcentroid', 'x')
                imcat.rename_column('ycentroid', 'y')
            imcat.meta['name'] = 'im{:d} sources'.format(group_id)
            img.meta['catalog'] = imcat
        images.append(img)

    if open_file:
        hdulist.close()

    return images
Пример #27
0
    def __init__(self,
                 image,
                 ext,
                 dq_bits=0,
                 dqimage=None,
                 dqext=None,
                 usermask=None,
                 usermask_ext=None):
        """
        Parameters
        ----------
        image : ImageRef
            An :py:class:`~stsci.skypac.utils.ImageRef` object that refers
            to an open FITS file

        ext : tuple, int, str
            Extension specification in the `image` the `SkyLineMember`
            object will be associated with.

            An int `ext` specifies extension number. A tuple in the form
            (str, int) specifies extension name and number. A string `ext`
            specifies extension name and the extension version is assumed
            to be 1. See documentation for `astropy.io.fits.getData`
            for examples.

        dq_bits : int, None (Default = 0)
            Integer sum of all the DQ bit values from the
            input `image`'s DQ array that should be considered "good"
            when building masks for sky computations. For example,
            if pixels in the DQ array can be combinations of 1, 2, 4,
            and 8 flags and one wants to consider DQ "defects" having
            flags 2 and 4 as being acceptable for sky computations,
            then `dq_bits` should be set to 2+4=6. Then a DQ pixel
            having values 2,4, or 6 will be considered a good pixel,
            while a DQ pixel with a value, e.g., 1+2=3, 4+8=12, etc.
            will be flagged as a "bad" pixel.

            | Default value (0) will make *all* non-zero
              pixels in the DQ mask to be considered "bad" pixels,
              and the corresponding image pixels will not be used
              for sky computations.

            | Set `dq_bits` to `None` to turn off the use of
              image's DQ array for sky computations.

            .. note::
                DQ masks (if used), *will be* combined with user masks
                specified by the `usermask` parameter.

        dqimage : ImageRef
            An :py:class:`~stsci.skypac.utils.ImageRef` object that refers
            to an open FITS file that has DQ data of the input `image`.

            .. note::
               When DQ data are located in the same FITS file as the
               science image data (e.g., HST/ACS, HST/WFC3, etc.),
               `dqimage` may point to the
               same :py:class:`~stsci.skypac.utils.ImageRef` object.
               In this case the reference count of the
               \ :py:class:`~stsci.skypac.utils.ImageRef` object must be
               increased adequately.

        dqext : tuple, int, str
            Extension specification of the `dqimage` that contains
            `image`'s DQ information. See help for `ext` for more
            details on acceptable formats for this parameter.

        usermask : ImageRef
            An :py:class:`~stsci.skypac.utils.ImageRef` object that refers
            to an open FITS file that has user mask data that indicate
            what pixels in the input `image` should be used for sky
            computations (``1``) and which pixels should **not** be used
            for sky computations (``0``).

        usermask_ext : tuple, int, str
            Extension specification of the `usermask` mask file that
            contains user's mask data that should be associated with
            the input `image` and `ext`. See help for `ext` for more
            details on acceptable formats for this parameter.

        """
        assert(hasattr(self.__class__, '_initialized') and \
               self.__class__._initialized)
        self._reset()

        # check that input images and extensions are valid --
        # either integers or tuples of strings and integers, e.g., ('sci',1):
        _check_valid_imgext(image, 'image', ext, 'ext', can_img_be_None=False)
        if dq_bits is not None:
            if dqimage is None:
                dq_bits = 0
            else:
                _check_valid_imgext(dqimage, 'dqimage', dqext, 'dqext')
        _check_valid_imgext(usermask, 'usermask', usermask_ext, 'usermask_ext')

        # get telescope, instrument, and detector info:
        self.telescope, self.instrument, self.detector = get_instrument_info(
            image, ext)

        # check dq_bits:
        if dq_bits is not None and not isinstance(dq_bits, int):
            if image: dqimage.release()
            if usermask: usermask.release()
            if dqimage: dqimage.release()
            raise TypeError(
                "Argument 'dq_bits' must be either an integer or None.")

        # buld mask:
        self._buildMask(image.original_fname, ext, dq_bits, dqimage, dqext,
                        usermask, usermask_ext)
        if dqimage: dqimage.release()
        if usermask: usermask.release()

        # save file, user mask, and DQ extension info:
        self._fname = image.original_fname
        self._basefname = basename(self._fname)
        self._image = image
        self._ext = ext
        self._can_free_image = image.can_reload_data and self.optimize != 'speed'

        # check extension and create a string representation:
        try:
            extstr = ext2str(ext)
        except ValueError:
            raise ValueError("Unexpected extension type \'{}\' for file {}.".\
                             format(ext,self._basefname))

        self._id = "{:s}[{:s}]".format(self._basefname, extstr)

        # extract WCS for bounding-box computation
        try:
            if hasattr(image.hdu[ext], 'wcs'):
                self._wcs = image.hdu[ext].wcs
            else:
                if self.telescope in supported_telescopes:
                    self._wcs = wcsutil.HSTWCS(image.hdu, ext)
                else:
                    self._wcs = pywcs.WCS(image.hdu[ext].header, image.hdu)
            if self._wcs is None:
                raise Exception("Invalid WCS.")
        except:
            msg = "Unable to obtain WCS information for the file {:s}." \
                .format(self._id)
            self._ml.error(msg)
            self._ml.flush()
            self._release_all()
            raise

        # determine pixel scale:
        self._get_pixel_scale()

        # see if image data are in counts or count-rate
        # and compute count(-rate) to flux (per arcsec^2) conversion factor:
        self._brightness_conv_from_hdu(image.hdu, self._idcscale)

        # process Sky user's keyword and its value:
        self._init_skyuser(image.hdu[ext].header)

        # Set polygon to be the bounding box of the chip:
        self._polygon = SphericalPolygon.from_wcs(self.wcs, steps=1)
Пример #28
0
def updatewcs_with_shift(image,reference,wcsname=None, reusename=False,
                         fitgeom='rscale',
                         rot=0.0,scale=1.0,xsh=0.0,ysh=0.0,fit=None,
                         xrms=None, yrms = None,
                         verbose=False,force=False,sciext='SCI'):

    """
    Update the SCI headers in 'image' based on the fit provided as determined
    in the WCS specified by 'reference'.  The fit should be a 2-D matrix as
    generated for use with 'make_vector_plot()'.

    Notes
    -----
    The algorithm used to apply the provided fit solution to the image
    involves applying the following steps to the WCS of each of the
    input image's chips:

    1. compute RA/Dec with full distortion correction for
            reference point as (Rc_i,Dc_i)

    2. find the Xc,Yc for each Rc_i,Dc_i and get the difference from the
            CRPIX position for the reference WCS as (dXc_i,dYc_i)

    3. apply fit (rot&scale) to (dXc_i,dYc_i) then apply shift, then add
            CRPIX back to get new (Xcs_i,Ycs_i) position

    4. compute (Rcs_i,Dcs_i) as the sky coordinates for (Xcs_i,Ycs_i)

    5. compute delta of (Rcs_i-Rc_i, Dcs_i-Dcs_i) as (dRcs_i,dDcs_i)

    6. apply the fit to the chip's undistorted CD matrix, the apply linear
            distortion terms back in to create a new CD matrix

    7. add (dRcs_i,dDcs_i) to CRVAL of the reference chip's WCS

    8. update header with new WCS values

    Parameters
    ----------
    image : str or PyFITS.HDUList object
        Filename, or PyFITS object, of image with WCS to be updated.
        All extensions with EXTNAME matches the value of the 'sciext'
        parameter value (by default, all 'SCI' extensions) will be updated.

    reference : str
        Filename of image/headerlet (FITS file) which contains the WCS
        used to define the tangent plane in which all the fit parameters
        (shift, rot, scale) were measured.

    wcsname : str
        Label to give to new WCS solution being created by this fit. If
        a value of None is given, it will automatically use 'TWEAK' as the
        label. If a WCS has a name with this specific value, the code will
        automatically append a version ID using the format '_n', such as
        'TWEAK_1', 'TWEAK_2',or 'TWEAK_update_1'.
        [Default =None]

    reusename : bool
        User can specify whether or not to over-write WCS with same name.
        [Default: False]

    rot : float
        Amount of rotation measured in fit to be applied.
        [Default=0.0]

    scale : float
        Amount of scale change measured in fit to be applied.
        [Default=1.0]

    xsh : float
        Offset in X pixels from defined tangent plane to be applied to image.
        [Default=0.0]

    ysh : float
        Offset in Y pixels from defined tangent plane to be applied to image.
        [Default=0.0]

    fit : arr
        Linear coefficients for fit
        [Default = None]

    xrms : float
        RMS of fit in RA (in decimal degrees) that will be recorded as
        CRDER1 in WCS and header
        [Default = None]

    yrms : float
        RMS of fit in Dec (in decimal degrees) that will be recorded as
        CRDER2 in WCS and header
        [Default = None]

    verbose : bool
        Print extra messages during processing? [Default=False]

    force : bool
        Update header even though WCS already exists with this solution or
        wcsname? [Default=False]

    sciext : string
        Value of FITS EXTNAME keyword for extensions with WCS headers to
        be updated with the fit values. [Default='SCI']

    """
    # if input reference is a ref_wcs file from tweakshifts, use it
    if isinstance(reference, wcsutil.HSTWCS) or isinstance(reference, pywcs.WCS):
        wref = reference
    else:
        refimg = fits.open(reference, memmap=False)
        wref = None
        for extn in refimg:
            if 'extname' in extn.header and extn.header['extname'] == 'WCS':
                wref = pywcs.WCS(refimg['wcs'].header)
                break
        refimg.close()
        # else, we have presumably been provided a full undistorted image
        # as a reference, so use it with HSTWCS instead
        if wref is None:
            wref = wcsutil.HSTWCS(reference)

    if isinstance(image, fits.HDUList):
        open_image = False
        filename = image.filename()
        if image.fileinfo(0)['filemode'] is 'update':
            image_update = True
        else:
            image_update = False
    else:
        open_image = True
        filename = image
        image_update = None

    # Now that we are sure we have a good reference WCS to use,
    # continue with the update
    logstr = "....Updating header for {:s}...".format(filename)
    if verbose:
        print("\n{:s}\n".format(logstr))
    else:
        log.info(logstr)

    # reset header WCS keywords to original (OPUS generated) values
    extlist = get_ext_list(image, extname='SCI')
    if extlist:
        if image_update:
            # Create initial WCSCORR extension
            wcscorr.init_wcscorr(image,force=force)
    else:
        extlist = [0]

    # insure that input PRIMARY WCS has been archived before overwriting
    # with new solution
    if open_image:
        fimg = fits.open(image, mode='update', memmap=False)
        image_update = True
    else:
        fimg = image

    if image_update:
        wcsutil.altwcs.archiveWCS(fimg,extlist,reusekey=True)

    # Process MEF images...
    for ext in extlist:
        logstr = "Processing {:s}[{:s}]".format(fimg.filename(),
                                                ext2str(ext))
        if verbose:
            print("\n{:s}\n".format(logstr))
        else:
            log.info(logstr)
        chip_wcs = wcsutil.HSTWCS(fimg,ext=ext)

        update_refchip_with_shift(chip_wcs, wref, fitgeom=fitgeom,
                    rot=rot, scale=scale, xsh=xsh, ysh=ysh,
                    fit=fit, xrms=xrms, yrms=yrms)
        #if util.is_blank(wcsname):
            #wcsname = 'TWEAK'

        # Update FITS file with newly updated WCS for this chip
        extnum = fimg.index(fimg[ext])
        update_wcs(fimg, extnum, chip_wcs, wcsname=wcsname,
                   reusename=reusename, verbose=verbose)

    if open_image:
        fimg.close()
Пример #29
0
def xy2rd(input,
          x=None,
          y=None,
          coords=None,
          coordfile=None,
          colnames=None,
          separator=None,
          hms=True,
          precision=6,
          output=None,
          verbose=True):
    """ Primary interface to perform coordinate transformations from
        pixel to sky coordinates using STWCS and full distortion models
        read from the input image header.
    """
    single_coord = False
    # Only use value provided in `coords` if nothing has been specified for coordfile
    if coords is not None and coordfile is None:
        coordfile = coords
        warnings.simplefilter('always', DeprecationWarning)
        warnings.warn(
            "Please update calling code to pass in `coordfile` instead of `coords`.",
            category=DeprecationWarning)
        warnings.simplefilter('default', DeprecationWarning)

    if coordfile is not None:
        if colnames in blank_list:
            colnames = ['c1', 'c2']
        # Determine columns which contain pixel positions
        cols = util.parse_colnames(colnames, coordfile)
        # read in columns from input coordinates file
        xyvals = np.loadtxt(coordfile, usecols=cols, delimiter=separator)
        if xyvals.ndim == 1:  # only 1 entry in coordfile
            xlist = [xyvals[0].copy()]
            ylist = [xyvals[1].copy()]
        else:
            xlist = xyvals[:, 0].copy()
            ylist = xyvals[:, 1].copy()
        del xyvals
    else:
        if isinstance(x, np.ndarray):
            xlist = x.tolist()
            ylist = y.tolist()
        elif not isinstance(x, list):
            xlist = [x]
            ylist = [y]
            single_coord = True
        else:
            xlist = x
            ylist = y

    # start by reading in WCS+distortion info for input image
    inwcs = wcsutil.HSTWCS(input)
    if inwcs.wcs.is_unity():
        print(
            "####\nNo valid WCS found in {}.\n  Results may be invalid.\n####\n"
            .format(input))

    # Now, convert pixel coordinates into sky coordinates
    dra, ddec = inwcs.all_pix2world(xlist, ylist, 1)

    # convert to HH:MM:SS.S format, if specified
    if hms:
        ra, dec = wcs_functions.ddtohms(dra, ddec, precision=precision)
        rastr = ra
        decstr = dec
    else:
        # add formatting based on precision here...
        rastr = []
        decstr = []
        fmt = "%." + repr(precision) + "f"
        for r, d in zip(dra, ddec):
            rastr.append(fmt % r)
            decstr.append(fmt % d)

        ra = dra
        dec = ddec

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ', input)
        print('# X      Y         RA             Dec\n')
        for x, y, r, d in zip(xlist, ylist, rastr, decstr):
            print("%.4f  %.4f    %s  %s" % (x, y, r, d))

    # Create output file, if specified
    if output:
        f = open(output, mode='w')
        f.write("# Coordinates converted from %s\n" % input)
        for r, d in zip(rastr, decstr):
            f.write('%s    %s\n' % (r, d))
        f.close()
        print('Wrote out results to: ', output)

    if single_coord:
        ra = ra[0]
        dec = dec[0]

    return ra, dec
Пример #30
0
def tran(inimage,
         outimage,
         direction='forward',
         x=None,
         y=None,
         coords=None,
         coordfile=None,
         colnames=None,
         separator=None,
         precision=6,
         output=None,
         verbose=True):
    """ Primary interface to perform coordinate transformations in pixel
        coordinates between 2 images using STWCS and full distortion models
        read from each image's header.
    """
    single_coord = False

    # Only use value provided in `coords` if nothing has been specified for coordfile
    if coords is not None and coordfile is None:
        coordfile = coords
        warnings.simplefilter('always', DeprecationWarning)
        warnings.warn(
            "Please update calling code to pass in `coordfile` instead of `coords`.",
            category=DeprecationWarning)
        warnings.simplefilter('default', DeprecationWarning)

    if coordfile is not None:
        if colnames in util.blank_list:
            colnames = ['c1', 'c2']
        # Determine columns which contain pixel positions
        cols = util.parse_colnames(colnames, coordfile)
        # read in columns from input coordinates file
        xyvals = np.loadtxt(coordfile, usecols=cols, delimiter=separator)
        if xyvals.ndim == 1:  # only 1 entry in coordfile
            xlist = [xyvals[0].copy()]
            ylist = [xyvals[1].copy()]
        else:
            xlist = xyvals[:, 0].copy()
            ylist = xyvals[:, 1].copy()
        del xyvals
    else:
        if isinstance(x, np.ndarray):
            xlist = x.tolist()
            ylist = y.tolist()
        elif not isinstance(x, list):
            xlist = [x]
            ylist = [y]
            single_coord = True
        else:
            xlist = x
            ylist = y

    # start by reading in WCS+distortion info for each image
    im1wcs = wcsutil.HSTWCS(inimage)
    if im1wcs.wcs.is_unity():
        print(
            "####\nNo valid input WCS found in {}.\n  Results may be invalid.\n####\n"
            .format(inimage))

    if util.is_blank(outimage):
        fname, fextn = fileutil.parseFilename(inimage)
        numsci = fileutil.countExtn(fname)
        chips = []
        for e in range(1, numsci + 1):
            chips.append(wcsutil.HSTWCS(fname, ext=('sci', e)))
        if len(chips) == 0:
            chips = [im1wcs]
        im2wcs = distortion.utils.output_wcs(chips)
    else:
        im2wcs = wcsutil.HSTWCS(outimage)

    if im2wcs.wcs.is_unity():
        print(
            "####\nNo valid output WCS found in {}.\n  Results may be invalid.\n####\n"
            .format(outimage))

    # Setup the transformation
    p2p = wcs_functions.WCSMap(im1wcs, im2wcs)

    if direction[0].lower() == 'f':
        outx, outy = p2p.forward(xlist, ylist)
    else:
        outx, outy = p2p.backward(xlist, ylist)

    if isinstance(outx, np.ndarray):
        outx = outx.tolist()
        outy = outy.tolist()

    # add formatting based on precision here...
    xstr = []
    ystr = []
    fmt = "%." + repr(precision) + "f"
    for ox, oy in zip(outx, outy):
        xstr.append(fmt % ox)
        ystr.append(fmt % oy)

    if verbose or (not verbose and util.is_blank(output)):
        print('# Coordinate transformations for ', inimage)
        print('# X(in)      Y(in)             X(out)         Y(out)\n')
        for xs, ys, a, b in zip(xlist, ylist, xstr, ystr):
            print("%.4f  %.4f    %s  %s" % (xs, ys, a, b))

    # Create output file, if specified
    if output:
        f = open(output, mode='w')
        f.write("# Coordinates converted from %s\n" % inimage)
        for xs, ys in zip(xstr, ystr):
            f.write('%s    %s\n' % (xs, ys))
        f.close()
        print('Wrote out results to: ', output)

    if single_coord:
        outx = outx[0]
        outy = outy[0]
    return outx, outy