def apply_pst(args, photfile): # Temporary file with tempfile.NamedTemporaryFile(suffix=".pst.1") as fd: pst_file = fd.name hdr = args.image.header # for short seeing, sigma = utils.get_from_header(args.image.im_name, hdr.seeingk, hdr.sigmak) iraf.pstselect( args.image.im_name, photfile=photfile, pstfile=pst_file, fwhm=seeing, sigma=sigma, ccdread=hdr.ccdronk, gain=hdr.gaink, exposure=hdr.exptimek, function="auto", nclean=1, psfrad=6 * seeing, fitrad=3 * seeing, verbose="no", verify="no", ) print "\n Pst file: ", pst_file return pst_file
def subtract_stars(args): """ Routine to subtract a set of stars defined by the user. We will model the PSF of some suitable stars in the images, then use that """ # First substitute the names of the image in args.image by the corresponding astroim object, with more information args.image = astroim.Astroim(args.image) # Do photometry on the stars to be used to model the PSF phot_modstars, phot_subtstars = apply_phot(args) pst_file = apply_pst(args, phot_modstars) psf_file = apply_psf(args, phot_modstars, pst_file) hdr = args.image.header # for short seeing, sigma = utils.get_from_header(args.image.im_name, hdr.seeingk, hdr.sigmak) utils.if_exists_remove(args.output) iraf.allstar( args.image.im_name, photfile=phot_subtstars, psfimage=psf_file, subimage=args.output, psfrad=6 * seeing, fitrad=3 * seeing, wcsin="physical", fitsky="yes", sannulus=4 * seeing, wsannulus=3 * seeing, verify="no", )
def match(args): """ Match the PSF of a group of images with the PSF of a reference image. """ sort_by_seeing(args) # Get seeing from header and calculate psf of reference image, the first one since we sorted the input ref_seeing = utils.get_from_header(args.input[0], args.FWHM_key) ref_psf = psf.main(arguments=[args.input[0], "--stars", args.input_stars[0], "--sigma_key", args.sigma, "--gain_key", args.gain_key, "--ron_key", args.ron_key, "--expt_key", args.expt_key, "--airm_key", args.airm_key, "--FWHM_key", args.FWHM_key]) output_list = [] for image, stars in zip(args.input, args.input_stars): output = utils.add_suffix_prefix(image, suffix=args.suffix) # Too small differences of seeing are not worh doing any matching current_seeing = utils.get_from_header(image, args.FWHM_key) if abs(ref_seeing - current_seeing) < args.limit: # Not worth equating PSFs for small differences shutil.copy(image, output) # copy old file into new one else: # Calculate psf of the other images psf_object = psf.main(arguments=[image, "--stars", stars, "--sigma_key", args.sigma, "--gain_key", args.gain_key, "--ron_key", args.ron_key, "--expt_key", args.expt_key, "--airm_key", args.airm_key, "--FWHM_key", args.FWHM_key]) utils.if_exists_remove("kernel.fits", output) iraf.psfmatch(image, ref_psf, psf_object, "kernel.fits", convolution="psf", filter="cosbell") iraf.psfmatch(image, ref_psf, psf_object, convolution="kernel", kernel="kernel.fits", output=output, verbose="no") utils.if_exists_remove("kernel.fits") mssg = "Before equating PSFs: " + str(current_seeing) utils.header_update_keyword(output, args.FWHM_key, ref_seeing, comment=mssg) output_list.append(output) return output_list
def psf(args): """ Calculate the PSF of an image. """ # Load iraf packages: phot, pstselect, psf will be needed iraf.noao(_doprint=0) iraf.digiphot(_doprint=0) iraf.module.daophot(_doprint=0) # Read the seeing and sigma of the sky from the header seeing, sigma = utils.get_from_header(args.input, args.FWHM_key, args.sigma) # Do photometry on the image #print "photometry: \n" photfile_name = args.input + ".mag.1" utils.if_exists_remove(photfile_name) iraf.module.phot(args.input, output=photfile_name, coords=args.stars, wcsin=args.coords, fwhm=seeing, sigma=sigma, datamax=args.maxval, datamin=args.minval, ccdread=args.ron_key, gain=args.gain_key, exposure=args.expt_key, airmass=args.airm_key, annulus=6*seeing, dannulus=3*seeing, apert=2*seeing, verbose="no", verify="no", interac="no") # Select stars on the image #print "pstselect: \n" pstfile_name = args.input + ".pst.1" utils.if_exists_remove(pstfile_name) iraf.module.pstselect(args.input, photfile=photfile_name, pstfile=pstfile_name, maxnpsf=20, fwhm=seeing, sigma=sigma, datamax=args.maxval, ccdread=args.ron_key, gain=args.gain_key, exposure=args.expt_key, function="auto", nclean=1, psfrad=2*seeing, fitrad=seeing, maxnstar=20, verbose="no", verify="no") # Build psf of the stars #print "psf: \n" psffile_table = args.input + ".psf.1.fits" # iraf keeps adding the .fits :( psgfile_name = args.input + ".psg.1" pstfile_name2 = args.input + ".pst.2" utils.if_exists_remove(psffile_table,psgfile_name, pstfile_name2) iraf.module.psf( args.input, photfile=photfile_name, pstfile=pstfile_name, groupfile=psgfile_name, opstfile=pstfile_name2, psfimage=psffile_table,fwhm=seeing, sigma=sigma, datamax=args.maxval, datamin=args.minval, ccdread=args.ron_key, gain=args.gain_key, exposure=args.expt_key, function="moffat25", nclean=1, psfrad=12, fitrad=seeing, maxnstar=20, interactive="no", varorder=-1, verbose="no",verify="no") # Use seepsf to build the image of the psf psffile_name = args.input + ".psf.fits" utils.if_exists_remove(psffile_name) iraf.module.seepsf(psffile_table, psffile_name) return psffile_name
def apply_phot(args): # Temporary file with tempfile.NamedTemporaryFile(suffix=".mag.1") as fd: phot_modstars = fd.name with tempfile.NamedTemporaryFile(suffix=".mag.1") as fd2: phot_subtstars = fd2.name hdr = args.image.header # for short seeing, sigma = utils.get_from_header(args.image.im_name, hdr.seeingk, hdr.sigmak) iraf.phot( args.image.im_name, output=phot_modstars, coords=args.model_stars, wcsin=args.coords, fwhmpsf=seeing, sigma=sigma, ccdread=hdr.ccdronk, gain=hdr.gaink, exposure=hdr.exptimek, airmass=hdr.airmassk, annulus=6 * seeing, dannulus=3 * seeing, apert=3 * seeing, verbose="no", verify="no", interac="no", ) iraf.phot( args.image.im_name, output=phot_subtstars, coords=args.subt_stars, wcsin=args.coords, fwhmpsf=seeing, sigma=sigma, ccdread=hdr.ccdronk, gain=hdr.gaink, exposure=hdr.exptimek, airmass=hdr.airmassk, annulus=6 * seeing, dannulus=3 * seeing, apert=3 * seeing, verbose="no", verify="no", interac="no", ) return phot_modstars, phot_subtstars
def main(im_name, ra=None, dec=None, FoV=None): if ra == None or dec == None: if FoV == None: FoV = 20 # Largest image I've seen, 20 degrees, just in case # User passed the keywords? try: ra, dec = utilities.get_from_header(im_name, ra, dec) argunents = ["--ra", ra, "--dec", dec, "--radius", float(FoV)/2.] except KeyError: arguments = [] # User passed the numbers try: ra, dec = float(ra), float(dec) argunents = ["--ra", ra, "--dec", dec, "--radius", float(FoV)/2.] except ValueError: arguments = [] arguments = arguments + ["solve-field", "--no-plots", "--no-fits2fits", "--use-sextractor", "--code-tolerance", "0.01", "--overwrite", im_name] subprocess.call(arguments) # Sort things out, clean up... solved = utilities.replace_extension(im_name, "solved") output_name = utilities.replace_extension(im_name, "new") assert os.path.exists(output_name) shutil.move(output_name, im_name) # Update old WCS system PC matrices and so on to avoid confusion utilities.update_WCS(im_name, im_name) # Build a catalogue with the coordinates of the stars found in # X and Y, RA and DEC and the flux of the stars corr_file = utilities.replace_extension(im_name, "corr") table = fits.open(corr_file)[1] cat_radec = utilities.replace_extension(im_name, "radec") f = open(cat_radec, "w") for line in table.data: f.write(str(line[2]) + " " + str(line[3]) + "\n") f.close()
def apply_psf(args, phot_file, pst_file): with tempfile.NamedTemporaryFile(suffix=".psf.1.fits") as fd0: psffile_table = fd0.name with tempfile.NamedTemporaryFile(suffix=".psf") as fd1: psf_name = fd1.name with tempfile.NamedTemporaryFile(suffix=".psg.1") as fd2: psg_name = fd2.name with tempfile.NamedTemporaryFile(suffix=".pst.2") as fd3: pst2_name = fd3.name hdr = args.image.header # for short seeing, sigma = utils.get_from_header(args.image.im_name, hdr.seeingk, hdr.sigmak) iraf.psf( args.image.im_name, photfile=phot_file, pstfile=pst_file, groupfile=psg_name, opstfile=pst2_name, psfimage=psffile_table, fwhm=seeing, sigma=sigma, ccdread=hdr.ccdronk, gain=hdr.gaink, exposure=hdr.exptimek, function="auto", nclean=1, psfrad=6 * seeing, fitrad=5 * seeing, interactive="no", varorder=-1, verbose="no", verify="no", ) # Use seepsf to make an image of the PSF iraf.seepsf(psffile_table, psf_name) print "\n PSF file: ", psf_name return psf_name
def combine(args): # Create the folders that do not already exist for the output file outdir, outfile = os.path.split(os.path.abspath(args.output)) if outdir == "": outdir = "." utils.if_dir_not_exists_create(outdir) # Build a list of the filter of each image #filter_list, images_filters = build_filter_list(args) images_filters = utils.collect_from_images(args.input, args.filterk) # If user wants all images to be combined together, regardless of filter: if args.all_together: images_filters = ["AllFilters"] * len(images_filters) # Create a default dictionary for the resulting images result = collections.defaultdict(str) # For each of the filters present combine the images (and write) for filt in set(images_filters): # list of objects with current filter (exception: allfilters is true) list1 = [args.input[p] for p,f in enumerate(images_filters) if f == filt ] # Check that all images have same dimension. If not, exit program if not utils.check_dimensions(list1): sys.exit("Dimensions of images to combine are different!") # Calculate scale of images scales = compute_scales(list1, args.scale, args.mask_key) # Get the sizes of the images lx, ly = utils.get_from_header(list1[0], "NAXIS2", "NAXIS1") # Now, in order to avoid loading many images in memory, we need to slice the images in pieces and combine a slice # of all the images at a time n_slices = 32 # divide the slow axis in this many pieces # Define the whole image and set all elements of mask to False whole_image = numpy.ma.zeros([lx,ly]) whole_image.mask = numpy.zeros_like(whole_image.data) for xmin in range(0, lx, lx/n_slices): xmax = min(xmin + lx/n_slices, lx) # Now we can build and sort a section of the cube with all the images cube = cube_images(list1, args.mask_key, scales, limits=[xmin, 0, xmax, ly]) cube.sort(axis=0) # Finally, average! Remember that the cube is sorted so that # cube[0,ii,jj] < cube[1,ii,jj] and that the highest values of all # are the masked elements. We will take advantage of it if the median # is selected, because nowadays the masked median is absurdly slow: # https://github.com/numpy/numpy/issues/1811 map_cube = numpy.ma.count(cube, axis=0) # number non-masked values per pixel if args.average == "mean": image = numpy.ma.mean(cube, axis=0) non_masked_equivalent = numpy.mean(cube.data, axis=0) elif args.average == "median": image = home_made_median(map_cube, cube) non_masked_equivalent = numpy.median(cube.data, axis=0) # Image is a masked array, we need to fill in masked values with the # args.fill_val if user provided it. Also, values with less than # args.nmin valid values should be masked out. If user did not provide # a fill_val argument, we will substitute masked values with the # unmasked equivalent operation. image.mask[map_cube < args.nmin] = 1 mask = image.mask if args.fill_val != '': image = image.filled(args.fill_val) else: image.data[mask == True] = non_masked_equivalent[mask == True] image = image.data whole_image.data[xmin:xmax, 0:ly] = image[:,:] whole_image.mask[xmin:xmax, 0:ly] = mask[:,:] # And save images. If all_together is activated, use the file name given by user. If not, we need # to separate by filter, so compose a new name with the one given by the user adding the filter if args.all_together: newfile = args.output else: newfile = os.path.join(outdir, utils.add_suffix_prefix(outfile, suffix="_" + filt) ) if args.out_mask != "": name_mask = args.out_mask else: name_mask = newfile + ".msk" if os.path.isfile(newfile): os.remove(newfile) if os.path.isfile(name_mask): os.remove(name_mask) fits.writeto(newfile, whole_image.data) fits.writeto(name_mask, whole_image.mask.astype(numpy.int)) result[filt] = newfile # Add comments to the headers string1 = " - Image built from the combination of the images: "+\ ", ".join(list1) string2 = " combine = " + args.average + ", scale = " + args.scale utils.add_history_line(newfile, string1 + string2 ) utils.add_history_line(name_mask, " - Mask of image: " + newfile) if args.mask_key != "": utils.header_update_keyword(newfile, args.mask_key, name_mask, "Mask for this image") # To normalize calculate median and call arith_images to divide by it. if args.norm == True: median = compute_scales([newfile], args.scale, args.mask_key)[0] msg = "- NORMALIZED USING MEDIAN VALUE:" arith_images.main(arguments=["--message", msg, "--output", newfile, "--mask_key", args.mask_key, "--fill_val", args.fill_val, newfile, "/", str(median)]) return result
list_images = utilities.locate_images2(dir, in_pattern) return list_images if os.path.exists( os.path.join(directory, 'cig') ): list_images = search_images(directory) else: print "Rename files" list_images = rename.main(arguments=["--copy", "--objectk", objectk,\ "--filterk", filterk, "--datek", datek,\ "--overwrite", "--exptime", exptimek,\ directory]) print "Include homogeneous filter names into the filter keyword" for im in list_images["filename"]: imfilt = utilities.get_from_header(im, filterk) imfilt2 = utilities.homogeneous_filter_name(imfilt) utilities.header_update_keyword(im, filterk+"_OLD", imfilt, "Original filter name") utilities.header_update_keyword(im, filterk, imfilt2, "Revised filter name") print "Ignore images as selected by user, if any." try: for im in remove_images: index = [i for i,v in enumerate(list_images["filename"]) if str(im) in v] for key in list_images.keys(): # remove that item from all the lists list_images[key] = np.delete(list_images[key], index) except NameError: # variable remove_images not defined pass
obj_images = list(list_images["filename"][np.where(list_images["objname"] == obj)]) stars_images = [utils.replace_extension(ii, "radec") for ii in obj_images] output_images = match_psfs.main(["--input_stars"] + stars_images + ["--suffix", " -p", "--sigma_key", sky_stdk, "--gain_key", gaink, "--ron_key", read_noisek, "--expt_key", exptimek, "--airm_key", airmassk, "--FWHM_k", seeingk] + obj_images) list_images["filename"][np.where(list_images["objname"] == obj)] = output_images print "Normalize using exposure time. " for ii, im_name in enumerate(list_images["filename"]): if list_images["type"][ii] in ["cig", "clusters"]: tt = float(utils.get_from_header(im_name, exptimek)) newname = utils.add_suffix_prefix(im_name, suffix="-t") mssg = "Normalized to exptime (divided by " + str(tt) + ")" arith_images.main(arguments=["--output", newname, "--message", mssg, "--mask_key", "MASK", im_name, "/", str(tt)]) mssg = "Before normalizing: " + str(tt) # Update values for the exptime, the sky, the sky std... utils.header_update_keyword(newname, exptimek, 1, mssg) ss = float(utils.get_from_header(im_name, skyk)) utils.header_update_keyword(newname, skyk, ss/tt) ss_std = float(utils.get_from_header(im_name, sky_stdk)) utils.header_update_keyword(newname, sky_stdk, ss_std/tt) list_images["filename"][ii] = newname print "Correct for atmospheric extinction." for ii, im_name in enumerate(list_images["filename"]):
# ### Remove images in list remove_images. #print "> Ignore images as selected by user, if any." #try: # for im in remove_images: # index = [i for i,v in enumerate(list_images["filename"]) if str(im) in v] # for key in list_images.keys(): # remove that item from all the lists # list_images[key] = np.delete(list_images[key], index) #except NameError: # variable remove_images not defined # pass # # ### Write down homogeneous filter names. print "> Include homogeneous filter names into the filter keyword" for im in list_images["filename"]: imfilt = utilities.get_from_header(im, filterk) imfilt2 = utilities.homogeneous_filter_name(imfilt) utilities.header_update_keyword(im, filterk+"_OLD", imfilt, "Original filter name") utilities.header_update_keyword(im, filterk, imfilt2, "Revised filter name") # ### Create masks for all images. Stars in blanks need to be removed (max_val small). print "> Create masks for images" for ii,im in enumerate(list_images["filename"]): # Arguments to be passed to create_masks args = ["--max_val", str(max_counts), "--min_val", "0", "--mask_key", "mask", "--outside_val", "2", im] if circular_FoV: # from the campaign file args = ["--circular"] + args create_masks.main(arguments=args )
obj_images = list(list_images["filename"][np.where(list_images["objname"] == obj)]) stars_images = [utils.replace_extension(ii, "radec") for ii in obj_images] output_images = match_psfs.main(["--input_stars"] + stars_images + ["--suffix", " -p", "--sigma_key", sky_stdk, "--gain_key", gaink, "--ron_key", read_noisek, "--expt_key", exptimek, "--airm_key", airmassk, "--FWHM_k", seeingk] + obj_images) list_images["filename"][np.where(list_images["objname"] == obj)] = output_images print "Normalize using exposure time. " for ii, im_name in enumerate(list_images["filename"]): if list_images["type"][ii] in ["cig", "clusters"]: tt = float(utils.get_from_header(im_name, exptimek)) newname = utils.add_suffix_prefix(im_name, suffix="-t") mssg = "Normalized to exptime (divided by " + str(tt) + ")" arith_images.main(arguments=["--output", newname, "--message", mssg, "--mask_key", "MASK", im_name, "/", str(tt)]) mssg = "Before normalizing: " + str(tt) # Update values for the exptime, the sky, the sky std... utils.header_update_keyword(newname, exptimek, 1, mssg) ss = float(utils.get_from_header(im_name, skyk)) utils.header_update_keyword(newname, skyk, ss/tt) ss_std = float(utils.get_from_header(im_name, sky_stdk)) utils.header_update_keyword(newname, skyk, ss_std/tt) list_images["filename"][ii] = newname print "Correct for atmospheric extinction." for ii, im_name in enumerate(list_images["filename"]):