예제 #1
0
def match_2dhist_fit(imglist, reference_catalog, **fit_pars):
    """Perform cross-matching and final fit using 2dHistogram matching

    Parameters
    ----------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    reference_catalog : Table
        Astropy Table of reference sources for this field

    Returns
    --------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    """
    log.info("{} (match_2dhist_fit) Cross matching and fitting "
             "{}".format("-" * 20, "-" * 28))
    # Specify matching algorithm to use
    match = tweakwcs.TPMatch(**fit_pars)
    # Align images and correct WCS
    tweakwcs.align_wcs(imglist,
                       reference_catalog,
                       match=match,
                       expand_refcat=False)

    # Interpret RMS values from tweakwcs
    interpret_fit_rms(imglist, reference_catalog)

    return imglist
예제 #2
0
def match_relative_fit(imglist, reference_catalog, **fit_pars):
    """Perform cross-matching and final fit using relative matching algorithm

    Parameters
    ----------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    reference_catalog : Table
        Astropy Table of reference sources for this field

    Returns
    --------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    """
    log.info("{} (match_relative_fit) Cross matching and fitting {}".format(
        "-" * 20, "-" * 27))
    if 'fitgeom' in fit_pars:
        fitgeom = fit_pars['fitgeom']
        del fit_pars['fitgeom']
    else:
        fitgeom = 'general'

    # 0: Specify matching algorithm to use
    match = tweakwcs.TPMatch(**fit_pars)
    # match = tweakwcs.TPMatch(searchrad=250, separation=0.1,
    #                          tolerance=100, use2dhist=False)

    # Align images and correct WCS
    # NOTE: this invocation does not use an astrometric catalog. This call allows all the input images to be aligned in
    # a relative way using the first input image as the reference.
    # 1: Perform relative alignment
    tweakwcs.align_wcs(imglist,
                       None,
                       match=match,
                       expand_refcat=True,
                       fitgeom=fitgeom)

    # Set all the group_id values to be the same so the various images/chips will be aligned to the astrometric
    # reference catalog as an ensemble.
    # astrometric reference catalog as an ensemble. BEWARE: If additional iterations of solutions are to be
    # done, the group_id values need to be restored.
    for image in imglist:
        image.meta["group_id"] = 1234567
    # 2: Perform absolute alignment
    tweakwcs.align_wcs(imglist,
                       reference_catalog,
                       match=match,
                       fitgeom=fitgeom)

    # 3: Interpret RMS values from tweakwcs
    interpret_fit_rms(imglist, reference_catalog)

    return imglist
예제 #3
0
def match_default_fit(imglist, reference_catalog, **fit_pars):
    """Perform cross-matching and final fit using default tolerance matching

    Parameters
    ----------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    reference_catalog : Table
        Astropy Table of reference sources for this field

    Returns
    --------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    """
    if 'fitgeom' in fit_pars:
        fitgeom = fit_pars['fitgeom']
        del fit_pars['fitgeom']
    else:
        fitgeom = 'rscale'

    common_pars = fit_pars['pars']
    del fit_pars['pars']

    log.info("{} (match_default_fit) Cross matching and fitting "
             "{}".format("-" * 20, "-" * 27))
    # Specify matching algorithm to use
    match = tweakwcs.TPMatch(**fit_pars)

    # Align images and correct WCS
    matched_cat = tweakwcs.align_wcs(imglist,
                                     reference_catalog,
                                     match=match,
                                     minobj=common_pars['MIN_FIT_MATCHES'],
                                     expand_refcat=False,
                                     fitgeom=fitgeom)

    # Interpret RMS values from tweakwcs
    interpret_fit_rms(imglist, reference_catalog)

    del matched_cat

    return imglist
예제 #4
0
def match_relative_fit(imglist, reference_catalog, **fit_pars):
    """Perform cross-matching and final fit using relative matching algorithm

    Parameters
    ----------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    reference_catalog : Table
        Astropy Table of reference sources for this field

    Returns
    --------
    imglist : list
        List of input image `~tweakwcs.tpwcs.FITSWCS` objects with metadata and source catalogs

    """
    log.info("{} (match_relative_fit) Cross matching and fitting {}".format(
        "-" * 20, "-" * 27))
    if 'fitgeom' in fit_pars:
        fitgeom = fit_pars['fitgeom']
        del fit_pars['fitgeom']
    else:
        fitgeom = 'rscale'

    common_pars = fit_pars['pars']
    del fit_pars['pars']

    # 0: Specify matching algorithm to use
    match = tweakwcs.TPMatch(**fit_pars)
    # match = tweakwcs.TPMatch(searchrad=250, separation=0.1,
    #                          tolerance=100, use2dhist=False)

    # Align images and correct WCS
    # NOTE: this invocation does not use an astrometric catalog. This call
    #       allows all the input images to be aligned in
    #       a relative way using the first input image as the reference.
    # 1: Perform relative alignment
    match_relcat = tweakwcs.align_wcs(imglist,
                                      None,
                                      match=match,
                                      minobj=common_pars['MIN_FIT_MATCHES'],
                                      expand_refcat=True,
                                      fitgeom=fitgeom)

    log.info("Relative alignment found: ")
    for i in imglist:
        info = i.meta['fit_info']
        if 'shift' not in info:
            off = (0., 0.)
            rot = 0.
            scale = -1.
            nmatches = 0
        else:
            off = info['shift']
            rot = info['<rot>']
            scale = info['<scale>']
            nmatches = info['nmatches']
        msg = "Image {} --".format(i.meta['name'])
        msg += "\n    SHIFT:({:9.4f},{:9.4f})  NMATCHES: {} ".format(
            off[0], off[1], nmatches)
        msg += "\n    ROT:{:9.4f}  SCALE:{:9.4f}".format(rot, scale)
        msg += "\n Using fitgeom = '{}'".format(fitgeom)
        log.info(msg)

    # This logic enables performing only relative fitting and skipping fitting to GAIA
    if reference_catalog is not None:
        # Set all the group_id values to be the same so the various images/chips will be aligned to the astrometric
        # reference catalog as an ensemble.
        # astrometric reference catalog as an ensemble. BEWARE: If additional iterations of solutions are to be
        # done, the group_id values need to be restored.
        for image in imglist:
            image.meta["group_id"] = 1234567
        # 2: Perform absolute alignment

        matched_cat = tweakwcs.align_wcs(imglist,
                                         reference_catalog,
                                         match=match,
                                         minobj=common_pars['MIN_FIT_MATCHES'],
                                         fitgeom=fitgeom)
    else:
        # Insure the expanded reference catalog has all the information needed
        # to complete processing.
        # TODO: Work out how to get the 'mag' column from input source catalog
        #       into this extended reference catalog...
        reference_catalog = match_relcat
        reference_catalog['mag'] = np.array([-999.9] * len(reference_catalog),
                                            np.float32)
        reference_catalog.meta['catalog'] = 'relative'

    # 3: Interpret RMS values from tweakwcs
    interpret_fit_rms(imglist, reference_catalog)

    del match_relcat
    return imglist
예제 #5
0
def determine_alignment_residuals(input,
                                  files,
                                  catalogs=None,
                                  max_srcs=1000,
                                  json_timestamp=None,
                                  json_time_since_epoch=None,
                                  log_level=logutil.logging.INFO):
    """Determine the relative alignment between members of an association.

    Parameters
    -----------
    input : string
        Original pipeline input filename.  This filename will be used to
        define the output analysis results filename.

    files : list
        Set of files on which to actually perform comparison.  The original
        pipeline can work on both CTE-corrected and non-CTE-corrected files,
        but this comparison will only be performed on CTE-corrected
        products when available.

    catalogs : list, optional
        List of dictionaries containing the source catalogs for each input chip.
        The list NEEDS to be in the same order as the filenames given in `files`.
        Each dictionary for each file will need to have numerical (integer) keys
        for each 'sci' extension.  If left as `None`, this function will create
        it's own set of catalogs using `astrometric_utils.extract_point_sources`.

    json_timestamp: str, optional
        Universal .json file generation date and time (local timezone) that will be used in the instantiation
        of the HapDiagnostic object. Format: MM/DD/YYYYTHH:MM:SS (Example: 05/04/2020T13:46:35). If not
        specified, default value is logical 'None'

    json_time_since_epoch : float
        Universal .json file generation time that will be used in the instantiation of the HapDiagnostic
        object. Format: Time (in seconds) elapsed since January 1, 1970, 00:00:00 (UTC). If not specified,
        default value is logical 'None'

    log_level : int, optional
        The desired level of verboseness in the log statements displayed on the screen and written to the
        .log file. Default value is 'NOTSET'.

    Returns
    --------
    resids_files : list of string
        Name of JSON files containing all the extracted results from the comparisons
        being performed.
    """
    log.setLevel(log_level)

    if catalogs is None:
        # Open all files as HDUList objects
        hdus = [fits.open(f) for f in files]
        # Determine sources from each chip
        src_cats = []
        num_srcs = []
        for hdu in hdus:
            numsci = countExtn(hdu)
            nums = 0
            img_cats = {}
            if hdu[("SCI", 1)].data.max() == 0.0:
                log.info(
                    "SKIPPING point-source finding for blank image: {}".format(
                        hdu.filename()))
                continue
            log.info("Determining point-sources for {}".format(hdu.filename()))
            for chip in range(numsci):
                chip += 1
                img_cats[chip] = amutils.extract_point_sources(
                    hdu[("SCI", chip)].data, nbright=max_srcs)
                nums += len(img_cats[chip])

            log.info("Identified {} point-sources from {}".format(
                nums, hdu.filename()))
            num_srcs.append(nums)
            src_cats.append(img_cats)
    else:
        src_cats = catalogs
        num_srcs = []
        for img in src_cats:
            num_img = 0
            for chip in img:
                num_img += len(img[chip])
            num_srcs.append(num_img)

    if len(num_srcs) == 0 or (len(num_srcs) > 0 and max(num_srcs) <= 3):
        log.warning(
            "Not enough sources identified in input images for comparison")
        return []

    # Combine WCS from HDULists and source catalogs into tweakwcs-compatible input
    imglist = []
    for i, (f, cat) in enumerate(zip(files, src_cats)):
        imglist += amutils.build_wcscat(f, i, cat)

    # Setup matching algorithm using parameters tuned to well-aligned images
    match = tweakwcs.TPMatch(searchrad=5,
                             separation=4.0,
                             tolerance=1.0,
                             use2dhist=True)
    try:
        # perform relative fitting
        matchlist = tweakwcs.align_wcs(imglist,
                                       None,
                                       minobj=6,
                                       match=match,
                                       expand_refcat=False)
        del matchlist
    except Exception:
        try:
            # Try without 2dHist use to see whether we can get any matches at all
            match = tweakwcs.TPMatch(searchrad=5,
                                     separation=4.0,
                                     tolerance=1.0,
                                     use2dhist=False)
            matchlist = tweakwcs.align_wcs(imglist,
                                           None,
                                           minobj=6,
                                           match=match,
                                           expand_refcat=False)
            del matchlist

        except Exception:
            log.warning("Problem encountered during matching of sources")
            return []

    # Check to see whether there were any successful fits...
    align_success = False
    for img in imglist:
        wcsname = fits.getval(img.meta['filename'], 'wcsname', ext=("sci", 1))
        img.meta['wcsname'] = wcsname
        img.meta['fit_info']['aligned_to'] = imglist[0].meta['filename']
        img.meta['reference_catalog'] = None

    for img in imglist:
        if img.meta['fit_info']['status'] == 'SUCCESS' and '-FIT' in wcsname:
            align_success = True
            break
    resids_files = []
    if align_success:

        # extract results in the style of 'tweakreg'
        resids = extract_residuals(imglist)

        if resids is not None:
            resids_files = generate_output_files(
                resids,
                json_timestamp=json_timestamp,
                json_time_since_epoch=json_time_since_epoch,
                exclude_fields=['group_id'])

    return resids_files
예제 #6
0
def test_multichip_fitswcs_alignment():
    h1 = fits.Header.fromfile(get_pkg_data_filename('data/wfc3_uvis1.hdr'))
    w1 = wcs.WCS(h1)
    imcat1 = tweakwcs.FITSWCS(w1)
    imcat1.meta['catalog'] = table.Table.read(
        get_pkg_data_filename('data/wfc3_uvis1.cat'),
        format='ascii.csv',
        delimiter=' ',
        names=['x', 'y'])
    imcat1.meta['group_id'] = 1
    imcat1.meta['name'] = 'ext1'

    h2 = fits.Header.fromfile(get_pkg_data_filename('data/wfc3_uvis2.hdr'))
    w2 = wcs.WCS(h2)
    imcat2 = tweakwcs.FITSWCS(w2)
    imcat2.meta['catalog'] = table.Table.read(
        get_pkg_data_filename('data/wfc3_uvis2.cat'),
        format='ascii.csv',
        delimiter=' ',
        names=['x', 'y'])
    imcat2.meta['group_id'] = 1
    imcat2.meta['name'] = 'ext4'

    refcat = table.Table.read(get_pkg_data_filename('data/ref.cat'),
                              format='ascii.csv',
                              delimiter=' ',
                              names=['RA', 'DEC'])

    tweakwcs.align_wcs([imcat1, imcat2],
                       refcat,
                       match=_match,
                       nclip=None,
                       sigma=3,
                       fitgeom='general')

    fi1 = imcat1.meta['fit_info']
    fi2 = imcat2.meta['fit_info']

    w1 = imcat1.wcs
    w2 = imcat2.wcs

    assert np.allclose(w1.wcs.crval, (83.206917667519, -67.73275818507248),
                       rtol=0)
    assert np.allclose(
        w1.wcs.cd,
        np.array([[3.93222694902149e-06, -1.0106698270131359e-05],
                  [-1.0377001075437075e-05, -4.577945148472431e-06]]),
        atol=0.0,
        rtol=1e-8)

    assert np.allclose(w2.wcs.crval, (83.15167050722597, -67.74220306069903),
                       rtol=0)
    assert np.allclose(
        w2.wcs.cd,
        np.array([[3.834449806681195e-06, -9.996495217498745e-06],
                  [-1.0348147451241423e-05, -4.503496019301529e-06]]),
        atol=0.0,
        rtol=1e-8)

    assert np.allclose(fi1['<scale>'], 1.0025, rtol=0, atol=2e-8)
    assert np.allclose(fi2['<scale>'], 1.0025, rtol=0, atol=2e-8)

    assert fi1['rmse'] < 5e-5
    assert fi2['rmse'] < 5e-5

    cat1 = imcat1.meta['catalog']
    ra1, dec1 = w1.all_pix2world(cat1['x'], cat1['y'], 0)

    cat2 = imcat2.meta['catalog']
    ra2, dec2 = w2.all_pix2world(cat2['x'], cat2['y'], 0)

    ra = np.concatenate([ra1, ra2])
    dec = np.concatenate([dec1, dec2])

    rmse_ra = np.sqrt(np.mean((ra - refcat['RA'])**2))
    rmse_dec = np.sqrt(np.mean((dec - refcat['DEC'])**2))

    assert rmse_ra < 1e-9
    assert rmse_dec < 1e-9
예제 #7
0
def test_different_ref_tpwcs_fitswcs_alignment(wcsno, refscale, dra, ddec):
    # This test was designed to check that the results of alignment,
    # in particular and most importantly, the sky positions of sources in
    # aligned images do not depend on the tangent reference plane used
    # for alignment. [#125]
    h1 = fits.Header.fromfile(get_pkg_data_filename('data/wfc3_uvis1.hdr'))
    w1 = wcs.WCS(h1)
    imcat1 = tweakwcs.FITSWCS(w1)
    imcat1.meta['catalog'] = table.Table.read(
        get_pkg_data_filename('data/wfc3_uvis1.cat'),
        format='ascii.csv',
        delimiter=' ',
        names=['x', 'y'])
    imcat1.meta['group_id'] = 1
    imcat1.meta['name'] = 'ext1'

    h2 = fits.Header.fromfile(get_pkg_data_filename('data/wfc3_uvis2.hdr'))
    w2 = wcs.WCS(h2)
    imcat2 = tweakwcs.FITSWCS(w2)
    imcat2.meta['catalog'] = table.Table.read(
        get_pkg_data_filename('data/wfc3_uvis2.cat'),
        format='ascii.csv',
        delimiter=' ',
        names=['x', 'y'])
    imcat2.meta['group_id'] = 1
    imcat2.meta['name'] = 'ext4'

    refcat = table.Table.read(get_pkg_data_filename('data/ref.cat'),
                              format='ascii.csv',
                              delimiter=' ',
                              names=['RA', 'DEC'])

    refwcses = [wcs.WCS(h1), wcs.WCS(h2)]

    refwcs = refwcses[wcsno]

    # change pointing of the reference WCS (alignment tangent plane):
    refwcs.wcs.crval = refwcses[1 - wcsno].wcs.crval + np.asarray([dra, ddec])

    rotm = tweakwcs.linearfit.build_fit_matrix(*refscale)
    refwcs.wcs.cd = np.dot(refwcs.wcs.cd, rotm)
    refwcs.wcs.set()
    ref_tpwcs = tweakwcs.FITSWCS(refwcs)

    tweakwcs.align_wcs([imcat1, imcat2],
                       refcat,
                       ref_tpwcs=ref_tpwcs,
                       match=_match,
                       nclip=None,
                       sigma=3,
                       fitgeom='general')

    fi1 = imcat1.meta['fit_info']
    fi2 = imcat2.meta['fit_info']

    w1 = imcat1.wcs
    w2 = imcat2.wcs

    assert fi1['rmse'] < 1e-4
    assert fi2['rmse'] < 1e-4

    cat1 = imcat1.meta['catalog']
    ra1, dec1 = w1.all_pix2world(cat1['x'], cat1['y'], 0)

    cat2 = imcat2.meta['catalog']
    ra2, dec2 = w2.all_pix2world(cat2['x'], cat2['y'], 0)

    ra = np.concatenate([ra1, ra2])
    dec = np.concatenate([dec1, dec2])

    rmse_ra = np.sqrt(np.mean((ra - refcat['RA'])**2))
    rmse_dec = np.sqrt(np.mean((dec - refcat['DEC'])**2))

    assert rmse_ra < 5e-9
    assert rmse_dec < 5e-9
예제 #8
0
def test_multichip_jwst_alignment():
    w1 = _make_gwcs_wcs('data/wfc3_uvis1.hdr')

    imcat1 = tweakwcs.JWSTgWCS(w1, {'v2_ref': 0, 'v3_ref': 0, 'roll_ref': 0})
    imcat1.meta['catalog'] = table.Table.read(
        get_pkg_data_filename('data/wfc3_uvis1.cat'),
        format='ascii.csv',
        delimiter=' ',
        names=['x', 'y'])
    imcat1.meta['catalog']['x'] += 1
    imcat1.meta['catalog']['y'] += 1
    imcat1.meta['group_id'] = 1
    imcat1.meta['name'] = 'ext1'

    w2 = _make_gwcs_wcs('data/wfc3_uvis2.hdr')
    imcat2 = tweakwcs.JWSTgWCS(w2, {'v2_ref': 0, 'v3_ref': 0, 'roll_ref': 0})
    imcat2.meta['catalog'] = table.Table.read(
        get_pkg_data_filename('data/wfc3_uvis2.cat'),
        format='ascii.csv',
        delimiter=' ',
        names=['x', 'y'])
    imcat2.meta['catalog']['x'] += 1
    imcat2.meta['catalog']['y'] += 1
    imcat2.meta['group_id'] = 1
    imcat2.meta['name'] = 'ext4'

    refcat = table.Table.read(get_pkg_data_filename('data/ref.cat'),
                              format='ascii.csv',
                              delimiter=' ',
                              names=['RA', 'DEC'])

    tweakwcs.align_wcs([imcat1, imcat2],
                       refcat,
                       match=_match,
                       nclip=None,
                       sigma=3,
                       fitgeom='general')

    fi1 = imcat1.meta['fit_info']
    fi2 = imcat2.meta['fit_info']

    w1m = imcat1.wcs
    w2m = imcat2.wcs

    assert np.allclose(w1m(*w1.crpix), (83.206917667519, -67.73275818507248),
                       rtol=0)
    assert np.allclose(w2m(*w2.crpix), (83.15167050722597, -67.74220306069903),
                       rtol=0)

    assert np.allclose(fi1['<scale>'], 1.0025, rtol=0, atol=2e-8)
    assert np.allclose(fi2['<scale>'], 1.0025, rtol=0, atol=2e-8)

    assert fi1['rmse'] < 5e-5
    assert fi2['rmse'] < 5e-5

    ra1, dec1 = imcat1.wcs(imcat1.meta['catalog']['x'],
                           imcat1.meta['catalog']['y'])
    ra2, dec2 = imcat2.wcs(imcat2.meta['catalog']['x'],
                           imcat2.meta['catalog']['y'])
    ra = np.concatenate([ra1, ra2])
    dec = np.concatenate([dec1, dec2])
    rra = refcat['RA']
    rdec = refcat['DEC']
    rmse_ra = np.sqrt(np.mean((ra - rra)**2))
    rmse_dec = np.sqrt(np.mean((dec - rdec)**2))

    assert rmse_ra < 3e-9
    assert rmse_dec < 3e-10
예제 #9
0
def determine_alignment_residuals(input, files, max_srcs=2000):
    """Determine the relative alignment between members of an association.

    Parameters
    -----------
    input : string
        Original pipeline input filename.  This filename will be used to
        define the output analysis results filename.

    files : list
        Set of files on which to actually perform comparison.  The original
        pipeline can work on both CTE-corrected and non-CTE-corrected files,
        but this comparison will only be performed on CTE-corrected
        products when available.

    Returns
    --------
    results : string
        Name of JSON file containing all the extracted results from the comparisons
        being performed.
    """
    # Open all files as HDUList objects
    hdus = [fits.open(f) for f in files]
    # Determine sources from each chip
    src_cats = []
    num_srcs = []
    for hdu in hdus:
        numsci = countExtn(hdu)
        nums = 0
        img_cats = {}
        for chip in range(numsci):
            chip += 1
            img_cats[chip] = amutils.extract_point_sources(hdu[("SCI",
                                                                chip)].data,
                                                           nbright=max_srcs)
            nums += len(img_cats[chip])
        num_srcs.append(nums)
        src_cats.append(img_cats)

    if len(num_srcs) == 0 or (len(num_srcs) > 0 and max(num_srcs) <= 3):
        return None

    # src_cats = [amutils.generate_source_catalog(hdu) for hdu in hdus]
    # Combine WCS from HDULists and source catalogs into tweakwcs-compatible input
    imglist = []
    for i, (f, cat) in enumerate(zip(files, src_cats)):
        imglist += amutils.build_wcscat(f, i, cat)

    # Setup matching algorithm using parameters tuned to well-aligned images
    match = tweakwcs.TPMatch(searchrad=5,
                             separation=1.0,
                             tolerance=4.0,
                             use2dhist=True)
    try:
        # perform relative fitting
        matchlist = tweakwcs.align_wcs(imglist,
                                       None,
                                       match=match,
                                       expand_refcat=False)
        del matchlist
    except Exception:
        return None
    # Check to see whether there were any successful fits...
    align_success = False
    for img in imglist:
        if img.meta['fit_info']['status'] == 'SUCCESS':
            align_success = True
            break
    if align_success:
        # extract results in the style of 'tweakreg'
        resids = extract_residuals(imglist)
        if resids is None:
            resids_file = None
        else:
            # Define name for output JSON file...
            resids_file = "{}_astrometry_resids.json".format(input[:9])
            # Remove any previously computed results
            if os.path.exists(resids_file):
                os.remove(resids_file)
            # Dump the results to a JSON file now...
            with open(resids_file, 'w') as jfile:
                json.dump(resids, jfile)
    else:
        resids_file = None

    return resids_file