示例#1
0
def match_to_gaia(imcat, refcat, product, output, searchrad=5.0):
    """Create a catalog with sources matched to GAIA sources
    
    Parameters
    ----------
    imcat : str or obj
        Filename or astropy.Table of source catalog written out as ECSV file
        
    refcat : str
        Filename of GAIA catalog files written out as ECSV file
        
    product : str
        Filename of drizzled product used to derive the source catalog
        
    output : str
        Rootname for matched catalog file to be written as an ECSV file 
    
    """
    if isinstance(imcat, str):
        imtab = Table.read(imcat, format='ascii.ecsv')
        imtab.rename_column('X-Center', 'x')
        imtab.rename_column('Y-Center', 'y')
    else:
        imtab = imcat
        if 'X-Center' in imtab.colnames:
            imtab.rename_column('X-Center', 'x')
            imtab.rename_column('Y-Center', 'y')
            
    
    reftab = Table.read(refcat, format='ascii.ecsv')
    
    # define WCS for matching
    tpwcs = tweakwcs.FITSWCS(HSTWCS(product, ext=1))
    
    # define matching parameters
    tpmatch = tweakwcs.TPMatch(searchrad=searchrad)
    
    # perform match
    ref_indx, im_indx = tpmatch(reftab, imtab, tpwcs)
    print('Found {} matches'.format(len(ref_indx)))
    
    # Obtain tangent plane positions for both image sources and reference sources
    im_x, im_y = tpwcs.det_to_tanp(imtab['x'][im_indx], imtab['y'][im_indx])
    ref_x, ref_y = tpwcs.world_to_tanp(reftab['RA'][ref_indx], reftab['DEC'][ref_indx])
    if 'RA' not in imtab.colnames:
        im_ra, im_dec = tpwcs.det_to_world(imtab['x'][im_indx], imtab['y'][im_indx])
    else:
        im_ra = imtab['RA'][im_indx]
        im_dec = imtab['DEC'][im_indx]
        

    # Compile match table
    match_tab = Table(data=[im_x, im_y, im_ra, im_dec, 
                            ref_x, ref_y, 
                            reftab['RA'][ref_indx], reftab['DEC'][ref_indx]],
                      names=['img_x','img_y', 'img_RA', 'img_DEC', 
                             'ref_x', 'ref_y', 'ref_RA', 'ref_DEC'])
    if not output.endswith('.ecsv'):
        output = '{}.ecsv'.format(output)                             
    match_tab.write(output, format='ascii.ecsv')
示例#2
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
示例#3
0
    def test_generate_catalog(self,input_filenames, truth_file):
        """ Verify whether sources from astrometric catalogs can be extracted from images.

        Success Criteria
        -----------------
            * Initially, source catalog matches >80% of 'truth' catalog sources

        """
        self.input_loc = 'catalog_tests'
        self.curdir = os.getcwd()
        truth_path = [self.input_repo, self.tree, self.input_loc, *self.ref_loc]

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

        try:
            # Make local copies of input files
            local_files = []
            for infile in input_filenames:
                downloaded_files = self.get_input_file(infile, docopy=True)
                local_files.extend(downloaded_files)
            
            test_image = local_files[0]
            print("Testing with {}".format(test_image))
            imghdu = fits.open(test_image)
            instrume = imghdu[0].header['instrume'].lower()
            detector = imghdu[0].header['detector'].lower()
            instr_pars = detector_specific_params[instrume][detector]
            reference_wcs = amutils.build_reference_wcs(local_files)
            imcat = amutils.generate_sky_catalog(imghdu, reference_wcs, **instr_pars)
            imcat.rename_column('xcentroid', 'x')
            imcat.rename_column('ycentroid', 'y')

            # create FITS WCS corrector object
            wcs_corrector = tweakwcs.FITSWCS(reference_wcs)

            # get reference catalog as 'truth' files
            reference_catalog = get_bigdata(*truth_path, truth_file, docopy=True)
            if os.path.basename(reference_catalog).endswith('ecsv'):
                tab_format = 'ascii.ecsv'
            else:
                tab_format = 'ascii.fast_commented_header'
            reference_table = Table.read(reference_catalog, format=tab_format)
            num_expected = len(reference_table)

            # Perform matching
            match = tweakwcs.TPMatch(searchrad=200, separation=0.1, tolerance=5, use2dhist=True)
            ridx, iidx = match(reference_table, imcat, wcs_corrector)
            nmatches = len(ridx)

        except Exception:
            exc_type, exc_value, exc_tb = sys.exc_info()
            traceback.print_exception(exc_type, exc_value, exc_tb, file=sys.stdout)
            sys.exit()

        assert (nmatches > 0.8*num_expected)
示例#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 = '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
示例#5
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
示例#6
0
def match_2dhist_fit(imglist, reference_catalog, print_fit_parameters=True):
    """Perform cross-matching and final fit using 2dHistogram matching

    Parameters
    ----------
    imglist : list
        List of input image NDData objects with metadata and source catalogs

    reference_catalog : Table
        Astropy Table of reference sources for this field

    print_fit_parameters : bool
        Specify whether or not to print out FIT results for each chip


    Returns
    --------
    fit_rms : float
        Visit level RMS for the FIT

    fit_num : int
        Number of sources used to generate visit level FIT and `fit_rms`

    """
    print(
        "-------------------- STEP 5b: (match_2dhist_fit) Cross matching and fitting --------------------"
    )
    # Specify matching algorithm to use
    match = tweakwcs.TPMatch(searchrad=75,
                             separation=0.1,
                             tolerance=2.0,
                             use2dhist=True)
    # Align images and correct WCS
    tweakwcs.tweak_image_wcs(imglist, reference_catalog, match=match)
    # Interpret RMS values from tweakwcs
    interpret_fit_rms(imglist, reference_catalog)

    # determine the quality of the fit
    fit_rms, fit_num = determine_fit_quality(
        imglist, print_fit_parameters=print_fit_parameters)

    return fit_rms, fit_num
示例#7
0
    def test_pipeline(self, input_filenames):
        """Test of new pipeline alignment components (call separately)

        This test performs separate fits to each chip separately.

        Success Criteria
        -----------------
          * nmatches > 0 on all chips
          * xrms and yrms < 30mas on all chips

        """
        self.input_loc = 'catalog_tests'
        self.curdir = os.getcwd()
        truth_path = [self.input_repo, self.tree, self.input_loc, *self.ref_loc]

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

        # Use this to collect all failures BEFORE throwing AssertionError
        failures=False
        try:
            # Make local copies of input files
            local_files = []
            for infile in input_filenames:
                downloaded_files = self.get_input_file(infile, docopy=True)
                local_files.extend(downloaded_files)

            # generate reference catalog
            refcat = amutils.create_astrometric_catalog(local_files, catalog='GAIADR2')

            # Generate source catalogs for each input image
            source_catalogs = generate_source_catalogs(local_files)

            # Convert input images to tweakwcs-compatible NDData objects and
            # attach source catalogs to them.
            imglist = []
            for group_id,image in enumerate(local_files):
                imglist.extend(amutils.build_nddata(image, group_id,
                                                    source_catalogs[image]['catalog_table']))

            # Specify matching algorithm to use
            match = tweakwcs.TPMatch(searchrad=250, separation=0.1,
                                     tolerance=5, use2dhist=True)

            # Align images and correct WCS
            tweakwcs.tweak_image_wcs(imglist, refcat, match=match)
            for chip in imglist:
                status = chip.meta['tweakwcs_info']['status']
                if status.startswith('FAIL'):
                    failures = True
                    print("STATUS for {}: {}".format(chip.meta['filename'], status))
                    break
        except Exception:
            failures = True
            print("ALIGNMENT EXCEPTION:  Failed to align {}".format(infile))

        if not failures:
            for chip in imglist:
                tweak_info = chip.meta.get('tweakwcs_info', None)
                chip_id = chip.meta.get('chip_id',1)

                # determine 30mas limit in pixels
                xylimit = 30
                # Perform comparisons
                nmatches = tweak_info['nmatches']
                xrms,yrms = tweak_info['rms']
                xrms *= chip.wcs.pscale*1000
                yrms *= chip.wcs.pscale*1000
                if any([nmatches==0, xrms>xylimit, yrms>xylimit]):
                    failures = True
                    msg1 = "Observation {}[{}] failed alignment with "
                    msg2 = "    RMS=({:.4f},{:.4f})mas [limit:{:.4f}mas] and NMATCHES={}"
                    print(msg1.format(infile, chip_id))
                    print(msg2.format(xrms, yrms, xylimit, nmatches))

        assert(not failures)
示例#8
0
def perform_align(input_list,
                  archive=False,
                  clobber=False,
                  update_hdr_wcs=False):
    """Main calling function.

    Parameters
    ----------
    input_list : list
        List of one or more IPPSSOOTs (rootnames) to align.

    archive : Boolean
        Retain copies of the downloaded files in the astroquery created sub-directories?

    clobber : Boolean
        Download and overwrite existing local copies of input files?

    update_hdr_wcs : Boolean
        Write newly computed WCS information to image image headers?

    Returns
    -------
    int value 0 if successful, int value 1 if unsuccessful

    """

    # Define astrometric catalog list in priority order
    catalogList = ['GAIADR2', 'GSC241']
    numCatalogs = len(catalogList)

    # 0: print git info
    print(
        "-------------------- STEP 0: Display Git revision info  --------------------"
    )
    full_path = os.path.dirname(__file__) + "/utils"
    repo_path = None
    if "hlapipeline/hlapipeline" in full_path:
        repo_path = full_path.split(
            "hlapipeline/hlapipeline")[0] + "hlapipeline"
    elif "hlapipeline" in full_path:
        repo_path = full_path.split("hlapipeline")[0] + "hlapipeline"
    else:
        pass
    if not os.path.exists(repo_path):
        repo_path = None  # protect against non-existent paths
    if repo_path:
        get_git_rev_info.print_rev_id(
            repo_path)  # Display git repository information
    else:
        print(
            "WARNING: Unable to display Git repository revision information.")

    # 1: Interpret input data and optional parameters
    print("-------------------- STEP 1: Get data --------------------")
    imglist = check_and_get_data(input_list, archive=archive, clobber=clobber)
    print("\nSUCCESS")

    # 2: Apply filter to input observations to insure that they meet minimum criteria for being able to be aligned
    print("-------------------- STEP 2: Filter data --------------------")
    filteredTable = filter.analyze_data(imglist)

    # Check the table to determine if there is any viable data to be aligned.  The
    # 'doProcess' column (bool) indicates the image/file should or should not be used
    # for alignment purposes.
    if filteredTable['doProcess'].sum() == 0:
        print("No viable images in filtered table - no processing done.\n")
        return (1)

    # Get the list of all "good" files to use for the alignment
    processList = filteredTable['imageName'][np.where(
        filteredTable['doProcess'])]
    processList = list(
        processList
    )  #Convert processList from numpy list to regular python list
    print("\nSUCCESS")

    # 3: Build WCS for full set of input observations
    print("-------------------- STEP 3: Build WCS --------------------")
    refwcs = amutils.build_reference_wcs(processList)
    print("\nSUCCESS")

    # 4: Retrieve list of astrometric sources from database
    # While loop to accommodate using multiple catalogs
    doneFitting = False
    catalogIndex = 0
    extracted_sources = None
    while not doneFitting:
        skip_all_other_steps = False
        retry_fit = False
        print(
            "-------------------- STEP 4: Detect astrometric sources --------------------"
        )
        print("Astrometric Catalog: ", catalogList[catalogIndex])
        reference_catalog = generate_astrometric_catalog(
            processList, catalog=catalogList[catalogIndex])
        # The table must have at least MIN_CATALOG_THRESHOLD entries to be useful
        if len(reference_catalog) >= MIN_CATALOG_THRESHOLD:
            print("\nSUCCESS")
        else:
            if catalogIndex < numCatalogs - 1:
                print("Not enough sources found in catalog " +
                      catalogList[catalogIndex])
                print("Try again with the next catalog")
                catalogIndex += 1
                retry_fit = True
                skip_all_other_steps = True
            else:
                print(
                    "Not enough sources found in any catalog - no processing done."
                )
                return (1)
        if not skip_all_other_steps:
            # 5: Extract catalog of observable sources from each input image
            print(
                "-------------------- STEP 5: Source finding --------------------"
            )
            if not extracted_sources:
                extracted_sources = generate_source_catalogs(processList)
                for imgname in extracted_sources.keys():
                    table = extracted_sources[imgname]["catalog_table"]
                    # The catalog of observable sources must have at least MIN_OBSERVABLE_THRESHOLD entries to be useful
                    total_num_sources = 0
                    for chipnum in table.keys():
                        total_num_sources += len(table[chipnum])
                    if total_num_sources < MIN_OBSERVABLE_THRESHOLD:
                        print(
                            "Not enough sources ({}) found in image {}".format(
                                total_num_sources, imgname))
                        return (1)
            # Convert input images to tweakwcs-compatible NDData objects and
            # attach source catalogs to them.
            imglist = []
            for group_id, image in enumerate(processList):
                imglist.extend(
                    amutils.build_nddata(
                        image, group_id,
                        extracted_sources[image]['catalog_table']))
            print("\nSUCCESS")

            # 6: Cross-match source catalog with astrometric reference source catalog, Perform fit between source catalog and reference catalog
            print(
                "-------------------- STEP 6: Cross matching and fitting --------------------"
            )
            # Specify matching algorithm to use
            match = tweakwcs.TPMatch(searchrad=250,
                                     separation=0.1,
                                     tolerance=100,
                                     use2dhist=False)
            # Align images and correct WCS
            tweakwcs.tweak_image_wcs(imglist, reference_catalog, match=match)
            # Interpret RMS values from tweakwcs
            interpret_fit_rms(imglist, reference_catalog)

            tweakwcs_info_keys = OrderedDict(
                imglist[0].meta['tweakwcs_info']).keys()
            imgctr = 0
            for item in imglist:
                retry_fit = False
                #Handle fitting failures (no matches found)
                if item.meta['tweakwcs_info']['status'].startswith(
                        "FAILED") == True:
                    if catalogIndex < numCatalogs - 1:
                        print(
                            "No cross matches found between astrometric catalog and sources found in images"
                        )
                        print("Try again with the next catalog")
                        catalogIndex += 1
                        retry_fit = True
                        break
                    else:
                        print(
                            "No cross matches found in any catalog - no processing done."
                        )
                        return (1)
                max_rms_val = item.meta['tweakwcs_info']['TOTAL_RMS']
                num_xmatches = item.meta['tweakwcs_info']['nmatches']
                # print fit params to screen
                print(
                    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FIT PARAMETERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
                )
                if item.meta['chip'] == 1:
                    image_name = processList[imgctr]
                    imgctr += 1
                print("image: {}".format(image_name))
                print("chip: {}".format(item.meta['chip']))
                print("group_id: {}".format(item.meta['group_id']))
                for tweakwcs_info_key in tweakwcs_info_keys:
                    if not tweakwcs_info_key.startswith("matched"):
                        print("{} : {}".format(
                            tweakwcs_info_key,
                            item.meta['tweakwcs_info'][tweakwcs_info_key]))
                # print("Radial shift: {}".format(math.sqrt(item.meta['tweakwcs_info']['shift'][0]**2+item.meta['tweakwcs_info']['shift'][1]**2)))
                print(
                    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
                )

                if num_xmatches < MIN_CROSS_MATCHES:
                    if catalogIndex < numCatalogs - 1:
                        print(
                            "Not enough cross matches found between astrometric catalog and sources found in images"
                        )
                        print("Try again with the next catalog")
                        catalogIndex += 1
                        retry_fit = True
                        break
                    else:
                        print(
                            "Not enough cross matches found in any catalog - no processing done."
                        )
                        return (1)
                elif max_rms_val > MAX_FIT_RMS:
                    if catalogIndex < numCatalogs - 1:
                        print(
                            "Fit RMS value = {}mas greater than the maximum threshold value {}."
                            .format(
                                item.meta['tweakwcs_info']['FIT_RMS'].value,
                                MAX_FIT_RMS))
                        print("Try again with the next catalog")
                        catalogIndex += 1
                        retry_fit = True
                        break
                    else:
                        print(
                            "Fit RMS values too large using any catalog - no processing done."
                        )
                        return (1)
                else:
                    print("Fit calculations successful.")
        if not retry_fit:
            print("\nSUCCESS")

            # 7: Write new fit solution to input image headers
            print(
                "-------------------- STEP 7: Update image headers with new WCS information --------------------"
            )
            if update_hdr_wcs:
                update_image_wcs_info(imglist, processList)
                print("\nSUCCESS")
            else:
                print("\n STEP SKIPPED")
            return (0)
示例#9
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
示例#10
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
示例#11
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