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')
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
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)
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
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
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
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)
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)
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
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
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