def main(): path_gmadet = getpath() telescope_list = getTel() parser = argparse.ArgumentParser( usage="usage: %(prog)s [options] data", description="Create cutouts centered on the optical candidates.") parser.add_argument( "--training", dest="training", action="store_true", help="If set, enters training mode. (Default: normal mode)") parser.add_argument( "--false", dest="false", action="store_true", help="If set, put all unmatched objects to false folder " "in training mode. (Default: not applied)") parser.add_argument( "--size", dest="size", required=False, default=32, type=int, help="Size in pixels of the extracted images. (Default: 32)", ) parser.add_argument( "--radius", dest="radius", required=False, default=2, type=float, help="Radius for crossmatching detected sources with simulated events." " (Default: 2 arcseconds)", ) parser.add_argument( "--flag-notsub", dest="flag_notsub", required=False, action="store_true", help="Whether the candidates are not the results of an image " "substraction. (Default: False)", ) args, paths = parser.parse_known_args() for path in paths: subimage(path, args.training, size=args.size, radius=args.radius, flag_notsub=args.flag_notsub, false=args.false)
def main(): path_gmadet = getpath() telescope_list = getTel() parser = argparse.ArgumentParser( usage="usage: %(prog)s data [data2 ... dataN] [options]", description="Perform astrometric calibration of astronomical images.") parser.add_argument("--results", dest="path_results", required=False, type=str, default='gmadet_results', help="Base path to store the results. " "(Default: gmadet_results)") parser.add_argument("--keep-old", "--keep", dest="keep", required=False, action="store_true", help="Keep previous results") parser.add_argument("--skip-processed", "--skip", dest="skip", required=False, action="store_true", help="Skip already processed files") parser.add_argument( "--preprocess", dest="preprocess", required=False, type=str, default=None, help="Pre-process the image using external program before analysing. " "The program should accept two positional arguments - original " "filename and new one. (Default: just copy the image)") parser.add_argument( "--astrometry", dest="soft", required=False, choices=["scamp", "astrometry.net"], default="scamp", type=str, help="Software to use for performing astrometric solution." "Not working with astrometry.net. (Default: scamp)", ) parser.add_argument( "--accuracy", dest="accuracy", required=False, type=float, default=0.15, help="Astrometric accuracy to reach, in arcseconds. " "(Defautl: 0.15 arcseconds)", ) parser.add_argument( "--itermax", dest="itermax", required=False, type=float, default=5, help="Max number of iteration to reach the required accuracy. " "(Default: 5)", ) parser.add_argument( "--telescope", dest="telescope", choices=telescope_list, required=True, type=str, help="Alias for the available telescopes.", ) parser.add_argument( "--conv-filter", dest="convFilter", required=False, default="default", type=str, help="Corresponds to FILTER_NAME keyword for sextractor " "(without .conv)." "\nDifferent filter available listed here: %s" % path_gmadet + "/config/conv_kernels/" "\n(Default: default)", ) parser.add_argument( "--verbose", dest="verbose", required=False, default="NORMAL", choices=["QUIET", "NORMAL", "FULL", "LOG"], type=str, help="Level of verbose, according to astromatic software. " "(Default: NORMAL)", ) args, filenames = parser.parse_known_args() # Load config files for a given telescope config = load_config(args.telescope, args.convFilter) filenames, subdirs = list_files(filenames, exclude=args.path_results) for raw_filename, subdir in zip(filenames, subdirs): filename = make_results_dir(raw_filename, outputDir=os.path.join( args.path_results, subdir), keep=args.keep, skip=args.skip, copy=False if args.preprocess else True) if not filename: print("%s is already processed, skipping. \n" % raw_filename) continue if args.preprocess: # We need to call external code what will copy (processed) # image to results dir print("Pre-processing %s" % raw_filename) subprocess.call(args.preprocess.split() + [raw_filename, filename]) if not os.path.exists(filename): print("Pre-processing failed") continue print("Sanitise header and data of %s.\n" % filename) sanitise_fits(filename) astrometric_calib( filename, config, soft=args.soft, verbose=args.verbose, accuracy=args.accuracy, itermax=args.itermax, )
def main(): path_gmadet = getpath() telescope_list = getTel() parser = argparse.ArgumentParser( usage="usage: %(prog)s data [data2 ... dataN] [options]", description="Compute PSF of astronomical images.") parser.add_argument("--results", dest="path_results", required=False, type=str, default='gmadet_results', help="Base path to store the results. " "(Default: gmadet_results)") parser.add_argument("--keep-old", "--keep", dest="keep", required=False, action="store_true", help="Keep previous results") parser.add_argument("--skip-processed", "--skip", dest="skip", required=False, action="store_true", help="Skip already processed files") parser.add_argument( "--preprocess", dest="preprocess", required=False, type=str, default=None, help="Pre-process the image using external program before analysing. " "The program should accept two positional arguments - original " "filename and new one. (Default: just copy the image)") parser.add_argument( "--telescope", dest="telescope", choices=telescope_list, required=True, type=str, help="Alias for the available telescopes.", ) parser.add_argument( "--conv-filter", dest="convFilter", required=False, default="default", type=str, help="Corresponds to FILTER_NAME keyword for sextractor " "(without .conv)." "\nDifferent filter available listed here: %s" % path_gmadet + "/config/conv_kernels/" "\n(Default: default)", ) parser.add_argument( "--use-weight", dest="useweight", action="store_true", help="If set, use weight map. " "Must be same name as image with .weight.fits extension. " "(Default: False)", ) parser.add_argument( "--verbose", dest="verbose", required=False, default="NORMAL", choices=["QUIET", "NORMAL", "FULL", "LOG"], type=str, help="Level of verbose, according to astromatic software. " "(Default: NORMAL)", ) args, filenames = parser.parse_known_args() # Load config files for a given telescope config = load_config(args.telescope, args.convFilter) filenames, subdirs = list_files(filenames, exclude=args.path_results) for raw_filename, subdir in zip(filenames, subdirs): filename = make_results_dir(raw_filename, outputDir=os.path.join( args.path_results, subdir), keep=args.keep, skip=args.skip, copy=False if args.preprocess else True) if not filename: print("%s is already processed, skipping. \n" % raw_filename) continue if args.preprocess: # We need to call external code what will copy (processed) # image to results dir print("Pre-processing %s" % raw_filename) subprocess.call(args.preprocess.split() + [raw_filename, filename]) if not os.path.exists(filename): print("Pre-processing failed") continue psfex(filename, config, useweight=args.useweight, verbose=args.verbose, outLevel=2)
def main(): path_gmadet = getpath() telescope_list = getTel() parser = argparse.ArgumentParser( usage="usage: %(prog)s data [data2 ... dataN] [options]", description="Insert simulated point like sources in astronomical " "images using the estimated PSFs of each image." ) parser.add_argument( "--results", dest="path_results", required=False, type=str, default='gmadet_sim', help="Base path to store the results. " "(Default: gmadet_sim)" ) parser.add_argument( "--keep-old", "--keep", dest="keep", required=False, action="store_true", help="Keep previous results" ) parser.add_argument( "--skip-processed", "--skip", dest="skip", required=False, action="store_true", help="Skip already processed files" ) parser.add_argument( "--preprocess", dest="preprocess", required=False, type=str, default=None, help="Pre-process the image using external program before analysing. " "The program should accept two positional arguments - original " "filename and new one. (Default: just copy the image)" ) parser.add_argument( "--telescope", dest="telescope", choices=telescope_list, required=True, type=str, help="Alias for the available telescopes.", ) parser.add_argument( "--ntrans", "--num-trans", dest="Ntrans", required=False, type=int, default=100, help="Number of transients to insert in each image. " "(Defautl: 100)", ) parser.add_argument( "--size", dest="size", required=False, type=int, default=48, help="Size of the transient image to insert in each image. " "Assumed to be a square, in pixels. (Defautl: 48)", ) parser.add_argument( "--magrange", "--mag-range", dest="magrange", required=False, type=int, nargs='+', default=[14, 23], help="Magnitude range of simulated sources. (Default: 14 23)" ) parser.add_argument( "--zp", dest="ZP", required=False, type=int, default=30, help="Zeropoint used for the simulated sources. (Defautl: 30).", ) parser.add_argument( "--gain", dest="gain", required=False, type=float, default=None, help="Gain to use, in e-/ADU. If None, take value from header. " " (Defautl: None).", ) parser.add_argument( "--astrometry", dest="doAstrometry", required=False, default="scamp", choices=["no", "scamp"], type=str, help="Whether to perform astrometric calibration, with scamp. " "(Default: scamp)", ) parser.add_argument( "--accuracy", dest="accuracy", required=False, type=float, default=0.15, help="Astrometric accuracy to reach, in arcseconds. " "(Defautl: 0.15 arcseconds)", ) parser.add_argument( "--itermax", "--iter-max", dest="itermax", required=False, type=float, default=5, help="Max number of iteration to reach the required accuracy. " "(Default: 5)", ) parser.add_argument( "--conv-filter", dest="convFilter", required=False, default="default", type=str, help="Corresponds to FILTER_NAME keyword for sextractor " "(without .conv)." "\nDifferent filter available listed here: %s" % path_gmadet + "/config/conv_kernels/" "\n(Default: default)", ) parser.add_argument( "--verbose", dest="verbose", required=False, default="NORMAL", choices=["QUIET", "NORMAL", "FULL", "LOG"], type=str, help="Level of verbose, according to astromatic software. " "(Default: NORMAL)", ) args, filenames = parser.parse_known_args() # Load config files for a given telescope config = load_config(args.telescope, args.convFilter) filenames, subdirs = list_files(filenames, exclude=args.path_results) for raw_filename, subdir in zip(filenames, subdirs): filename = make_results_dir( raw_filename, outputDir=os.path.join(args.path_results, subdir), keep=args.keep, skip=args.skip, copy=False if args.preprocess else True ) if not filename: print("%s is already processed, skipping. \n" % raw_filename) continue if args.preprocess: # We need to call external code what will copy (processed) # image to results dir print("Pre-processing %s" % raw_filename) subprocess.call(args.preprocess.split() + [raw_filename, filename]) if not os.path.exists(filename): print("Pre-processing failed") continue if args.doAstrometry != "no": print("Sanitise header and data of %s.\n" % filename) sanitise_fits(filename) astrometric_calib( filename, config, soft=args.doAstrometry, verbose=args.verbose, accuracy=args.accuracy, itermax=args.itermax, ) # Estimate the PSF FWHM for each image/quadrants using psfex FWHM_list = psfex( filename, config, verbose=args.verbose, outLevel=2, ) datapath = os.path.dirname(filename) sim(datapath, filename, Ntrans=args.Ntrans, size=args.size, magrange=args.magrange, gain=args.gain, magzp=args.ZP )
def subimage(path, training, size=32, radius=1, flag_notsub=False, false=False): """ Extract a sub-image centered on the candidate position """ path_gmadet = getpath() # size of the extracted image cutsize = (size, size) print("Combine the detections from all simulated images.") candidates_list = getCandPos(path, flag_notsub=flag_notsub) if training: print("Crossmatch simulated events with detections") sim_list = crossmatch_detections(path, candidates_list, radius=radius) resdir = os.path.join(path, "candidates_training") mkdir_p(resdir) truedir = os.path.join(path, "candidates_training", "true") mkdir_p(truedir) falsedir = os.path.join(path, "candidates_training", "false") mkdir_p(falsedir) else: resdir = os.path.join(path, "candidates") mkdir_p(resdir) for i, cand in enumerate(candidates_list): print( "processing candidates %d/%d ..." % (i, len(candidates_list)), end="\r", flush=True, ) OT_coords = [cand["RA"], cand["Dec"]] if training: # Check if corresponds to a simulated event mask = sim_list["closest_candID"] == cand["ID"] # Check whether it is a simulated object # mask1 = sim_list['filename2'] == cand['OriginalIma'] # mask2 = (sim_list['RA'] - cand['RA'])**2 + \ # (sim_list['Dec'] - cand['Dec'])**2 < (radius/3600)**2 # mask = np.bitwise_and(mask1,mask2) # Consider only sources with a single match. # Some real sources close to a cosmic or another will not be # consider. But with a visual inspection they can be easily # classified as true transient. if len(sim_list[mask]) == 1: outdir = truedir else: if false: outdir = falsedir else: outdir = resdir inputname = cand["filename"] else: outdir = resdir inputname = cand["filename"] outname = os.path.join(outdir, "candidate_%d.fits" % i) # If the inputname can not be found for some reasons # Make sure the code is not crashing try: # Get initial image size hdr_input = fits.getheader(inputname) Naxis1 = hdr_input["NAXIS1"] Naxis2 = hdr_input["NAXIS2"] # Extract small image # Only one threads as we provide one image after another make_sub_image( inputname, outname, OT_coords, coords_type="world", sizes=[size, size], FoVs=-1, fmts="fits", nb_threads=1, ) # add information to header hdus = fits.open(outname, memmap=False) hdr = hdus[0].header hdr["MAG"] = cand["mag"] hdr["MAGERR"] = cand["magerr"] hdr["FWHM"] = cand["FWHM"] hdr["FWHMPSF"] = cand["FWHMPSF"] hdr["FILTER"] = cand["Band"] hdr["RA"] = cand["RA"] hdr["Dec"] = cand["Dec"] hdr["Xpos"] = cand["Xpos"] hdr["Ypos"] = cand["Ypos"] hdr["FILE"] = cand["filename"] hdr["CANDID"] = cand["ID"] # Whether it is close to the edge of the image # If yes the image will not be size x size in pixels """ if ( (cand["Xpos"] > Naxis1 - size) or (cand["Xpos"] < size) or (cand["Ypos"] > Naxis2 - size) or (cand["Ypos"] < size) ): hdr["edge"] = "True" print("Edge ", outname) else: hdr["edge"] = "False" """ # If source too close to the edge, the cutout has dimension # smaller than the reauired (size x size) # It will cause the CNN to crash so flag them. if hdus[0].data.shape != (size, size): hdr["edge"] = "True" else: hdr["edge"] = "False" hdus.writeto(outname, overwrite=True) except BaseException: print("Could not extract candidate in %s" % inputname)
def main(): path_gmadet = getpath() telescope_list = getTel() parser = argparse.ArgumentParser( usage="usage: %(prog)s data [data2 ... dataN] [options]", description="Finding unknown objects in astronomical images.") parser.add_argument("--results", dest="path_results", required=False, type=str, default='gmadet_results', help="Base path to store the results. " "(Default: gmadet_results)") parser.add_argument("--keep-old", "--keep", dest="keep", required=False, action="store_true", help="Keep previous results") parser.add_argument("--skip-processed", "--skip", dest="skip", required=False, action="store_true", help="Skip already processed files") parser.add_argument( "--preprocess", dest="preprocess", required=False, type=str, default=None, help="Pre-process the image using external program before analysing. " "The program should accept two positional arguments - original " "filename and new one. (Default: just copy the image)") parser.add_argument( "--fwhm", dest="FWHM", required=False, default='psfex', help="Typical telescope FWHM. " "(Default: use psfex to estimate FWHM)", ) parser.add_argument( "--radius-crossmatch", dest="radius_crossmatch", required=False, type=float, default=3.0, help="Radius to use for crossmatching, in pixels. " "(Default: 3.0 pixels)", ) parser.add_argument( "--threshold", dest="threshold", required=False, default=4.0, type=float, help="Consider only sources above this threshold. " "(Default: 4.0)", ) parser.add_argument( "--detect", dest="soft", required=False, choices=["sextractor"], default="sextractor", type=str, help="Software to use for detecting sources.\n (Default: sextractor)", ) parser.add_argument( "--conv-filter", dest="convFilter", required=False, default="default", type=str, help="Corresponds to FILTER_NAME keyword for sextractor " "(without .conv)." "\nDifferent filter available listed here: %s" % path_gmadet + "/config/conv_kernels/" "\n(Default: default)", ) parser.add_argument( "--telescope", dest="telescope", choices=telescope_list, required=True, type=str, help="Alias for the available telescopes.", ) parser.add_argument( "--quadrants", dest="quadrants", required=False, default=1, type=int, help="Number of quadrants the image is divided. " "(Default: 1)", ) parser.add_argument( "--astrometry", dest="doAstrometry", required=False, default="scamp", choices=["no", "scamp"], type=str, help="Whether to perform astrometric calibration, with scamp. " "(Default: scamp)", ) parser.add_argument( "--verbose", dest="verbose", required=False, default="NORMAL", choices=["QUIET", "NORMAL", "FULL", "LOG"], type=str, help="Level of verbose, according to astromatic software. " "(Default: NORMAL)", ) parser.add_argument( "--sub", dest="doSub", required=False, type=str, help="Whether to perform astrometric calibration, with ps1 images " 'or user provided reference image. Type "ps1" for PS1 reference ' 'image or provide the path to your reference image.', ) parser.add_argument( "--ps1-method", dest="ps1_method", required=False, default="individual", choices=["mosaic", "individual"], type=str, help="When substracting images using Pan-STARRS reference images, " "there 2 options, either create a mosaic of all PS1 image and " "substract or do the substraction individually for each PS1 " "image. In the latter case, your image is cut to match the " "PS1 image. (Default: mosaic)", ) parser.add_argument( "--mosaic", dest="doMosaic", action="store_true", help="Whether to combine the individual frames into a common mosaic " "when `ps1_method` is set to `individual`. (Default: not set)", ) parser.add_argument( "--remove-cosmics", dest="Remove_cosmics", action="store_true", help="Whether to remove cosmic rays using lacosmic. " " (Default: not set)", ) parser.add_argument( "--sub-bkg", dest="sub_bkg", action="store_true", help="Whether to substract background. (Default: not set)", ) parser.add_argument( "--output-data-level", dest="outLevel", required=False, type=int, default=2, choices=[0, 1, 2], help="Number of output files that are kept after the process. " "0: minimum, 2: maximum" "(Default: 2)", ) parser.add_argument( "--owncloud", dest="owncloud_path", required=False, type=str, help="Local path to the owncloud", ) parser.add_argument( "--voe", dest="VOE_path", required=False, type=str, help="Path/filename of the VOEvent containing the observation plan.", ) # args, filenames = parser.parse_known_args() args, filenames = parser.parse_known_args() Nb_cuts = (args.quadrants, args.quadrants) # Load config files for a given telescope config = load_config(args.telescope, args.convFilter) filenames, subdirs = list_files(filenames, exclude=args.path_results) for raw_filename, subdir in zip(filenames, subdirs): filename = make_results_dir(raw_filename, outputDir=os.path.join( args.path_results, subdir), keep=args.keep, skip=args.skip, copy=False if args.preprocess else True) if not filename: print("%s is already processed, skipping. \n" % raw_filename) continue if args.preprocess: # We need to call external code what will copy (processed) # image to results dir print("Pre-processing %s" % raw_filename) subprocess.call(args.preprocess.split() + [raw_filename, filename]) if not os.path.exists(filename): print("Pre-processing failed") continue # If there is simulated_objects.list file alongside the image, # let's copy it to the results dir if os.path.exists( os.path.join(os.path.dirname(raw_filename), 'simulated_objects.list')): cp_p( os.path.join(os.path.dirname(raw_filename), 'simulated_objects.list'), os.path.join(os.path.dirname(filename), 'simulated_objects.list')) # Rename the "filename" location in the copied # 'simulated_objects.list' fname = os.path.join(os.path.dirname(filename), 'simulated_objects.list') sim_obj = ascii.read(fname) newname_list = [] for i in range(len(sim_obj)): newname = os.path.join( os.path.dirname(filename), os.path.split(sim_obj[i]['filename'])[1]) newname_list.append(os.path.abspath(newname)) sim_obj['filename'] = newname_list sim_obj.write(fname, format='ascii.commented_header', overwrite=True) print("Sanitise header and data of %s.\n" % filename) sanitise_fits(filename) # Cut image into several quadrants if required # And create table with filename and quadrant ID image_table = cut_image(filename, config, Nb_cuts=Nb_cuts, doAstrometry=args.doAstrometry) if args.Remove_cosmics: print("Running lacosmic on %s to remove cosmic rays. \n" % filename) # Clean cosmic rays # Not using FWHM anymore FWHM_list = [None] * len(image_table) run_lacosmic(image_table["filenames"], FWHM_list, contrast=5.0, cr_threshold=5.0, neighbor_threshold=5.0, maxiter=4, outLevel=args.outLevel) if args.sub_bkg: # Substract background bkg_estimation( image_table["filenames"], box=(20, 20), filter_size=(3, 3), bkg_estimator='SExtractor', sigma=3., sigma_lower=None, sigma_upper=None, maxiters=10, outLevel=args.outLevel, ) if args.FWHM == "psfex": # Estimate the PSF FWHM for each image/quadrants using psfex FWHM_list = psfex( image_table["filenames"], config, verbose=args.verbose, outLevel=args.outLevel, ) else: FWHM_list = [args.FWHM] * len(image_table) if args.doAstrometry != "no": astrometric_calib(image_table["filenames"], config, soft=args.doAstrometry, verbose=args.verbose, accuracy=0.15, itermax=10) if args.doSub: substracted_files = substraction(image_table["filenames"], args.doSub, config, soft="hotpants", method=args.ps1_method, doMosaic=args.doMosaic, verbose=args.verbose, outLevel=args.outLevel, nb_threads=8) else: substracted_files = None if args.soft == "sextractor": run_sextractor(image_table["filenames"], FWHM_list, args.threshold, args.telescope, config, verbose=args.verbose, subFiles=substracted_files, outLevel=args.outLevel, nb_threads=8) filter_sources( image_table["filenames"], args.soft, sigma=1, subFiles=substracted_files, ) convert_xy_radec(image_table["filenames"], soft=args.soft, subFiles=substracted_files) total_sources = catalogs(image_table, args.radius_crossmatch, Nb_cuts=Nb_cuts, subFiles=substracted_files, nb_threads=4) # The raidus is used here to crossmatch our sources with # catalogs to derive the Zeropoint. Better keep 3 pixels. sources_calib, candidates = phot_calib(total_sources, args.telescope, radius=3, doPlot=True, subFiles=substracted_files, nb_threads=4) candidates = moving_objects(candidates) # Apply filter to candidates # Remove candidates on the edge # Remove candidate depending the FWHM ratio # Apply the CNN model candidates_filtered = filter_candidates(candidates) # If both arguments VOE_path and owncloud_path are provided # Send candidates to database # Set the tile_id corresponding to your tile by hand at the moment if args.VOE_path and args.owncloud_path: send_data2DB( filename, candidates_filtered, Nb_cuts, args.owncloud_path, args.VOE_path, "utilsDB/usrpwd.json", debug=True, subFiles=substracted_files, ) # clean output files clean_outputs(image_table["filenames"], args.outLevel)
def prepare_PS1_sub(ps1_cell_table, band, inputimage, config, verbose="QUIET", method="individual"): """Prepare the download and formatting of PS1 images to be used for image substraction""" path_gmadet = getpath() path, filenameInput = os.path.split(inputimage) if path: folder = path + "/" else: folder = "" # Get pixelscale from input science image # And add it to config dictionary header = fits.getheader(inputimage) pixScale = [ abs(float(header["CDELT1"])) * 3600, abs(float(header["CDELT2"])) * 3600 ] config['pixScale'] = pixScale ps1Dir = path_gmadet + "/ps1Dir/" if not os.path.isdir(ps1Dir): os.makedirs(ps1Dir) ps1RescaledDir = path_gmadet + "/ps1RescaledDir/" if not os.path.isdir(ps1RescaledDir): os.makedirs(ps1RescaledDir) # Download PS1 files if not present, and reformat them ps1files = download_ps1_cells(ps1_cell_table, band, config, ps1Dir, ps1RescaledDir, verbose=verbose) subfiles = [] if method == "mosaic": # Create mosaic file if it does not exist mosaicfile = folder + os.path.splitext( filenameInput)[0] + "_ps1_mosaic.fits" if os.path.isfile(mosaicfile): print( "PS1 mosaic image already exists in this location: %s. If you want to recompute it, delete it." % mosaicfile) else: fileref_names = create_ps1_mosaic(ps1files, inputimage, folder, config, band, verbose=verbose) subfiles.append([inputimage, fileref_names[0], fileref_names[1]]) elif method == "individual": for i in range(0, len(ps1files), 2): ref = ps1files[i] mask = ps1files[i + 1] subfiles.append([inputimage, ref, mask]) return subfiles
def ps1_grid(im_corner_coords): """ Return the ps1 cell IDs for a given image dimension Skycell images have names like skycell.nnnn.0yx where nnnn is the projection cell number (which ranges from 635 to 2643) and 0yx gives the skycell location in the image, with y and x ranging from 0 to 9 indicating the respective y and x section of the projection cell. The 000 skycell is in the bottom left corner of the projection cell, 010 is just above it, and 099 is in the upper right corner. RA = n *360 deg / M """ path_gmadet = getpath() # RA, dec min and max of input image ra_min = np.min(im_corner_coords[0], axis=0) ra_max = np.max(im_corner_coords[0], axis=0) dec_min = np.min(im_corner_coords[1], axis=0) dec_max = np.max(im_corner_coords[1], axis=0) ps1grid = Table.read(path_gmadet + "/ps1_survey/ps1grid.fits", hdu=1) # Get the min and max declination zones mask = ((ps1grid["DEC_MIN"] < dec_min) & (ps1grid["DEC_MAX"] > dec_min)) | ((ps1grid["DEC_MIN"] < dec_max) & (ps1grid["DEC_MAX"] > dec_max)) # Get all declinations zones all_zones_id = np.arange(ps1grid[mask]["ZONE"][0], ps1grid[mask]["ZONE"][-1] + 1) all_cells = [] # Loop over the different zones for zone in all_zones_id: mask = ps1grid["ZONE"] == zone idx_bkp = -1 projcell_idx_list = [] for ra in [ra_min, ra_max]: # Get the cells covering the input ra closet_projcell_idx = (float(ps1grid[mask]["PROJCELL"]) + ra * float(ps1grid[mask]["NBAND"]) / 360) projcell_idx = int(np.rint(closet_projcell_idx)) if projcell_idx != idx_bkp: projcell_idx_list.append(projcell_idx) idx_bkp = projcell_idx # Check the 0 - 360 transition # Assume that an image can not have a FoV larger than 60 degrees # Need to do it dependng on the image in the future if ra_max - ra_min < 300: total_proj_cell_idx = np.arange(projcell_idx_list[0], projcell_idx_list[-1] + 1) else: # Image overlapping the 0 - 360 region total_proj_cell_idx = np.arange(ps1grid[mask]["PROJCELL"], projcell_idx_list[0] + 1) list_proj_cell_end = np.arange( projcell_idx_list[-1], ps1grid[ps1grid["ZONE"] == zone + 1]["PROJCELL"]) total_proj_cell_idx = np.append(total_proj_cell_idx, list_proj_cell_end) for cell_id in total_proj_cell_idx: mask = ps1grid["ZONE"] == zone_PS1(ps1grid, cell_id) diff_projcell_idx = cell_id - float(ps1grid[mask]["PROJCELL"]) ra_center_projcell = diff_projcell_idx * \ 360 / float(ps1grid[mask]["NBAND"]) cell_query = ps1_cell_coord( im_corner_coords, cell_id, ps1grid[mask]["XCELL"], ps1grid[mask]["YCELL"], ra_center_projcell, ps1grid[mask]["DEC"], ps1grid[mask]["CRPIX1"], ps1grid[mask]["CRPIX2"], ) if len(cell_query) > 0: all_cells.append(cell_query) if len(all_cells) == 1: all_cells = all_cells[0] else: all_cells = vstack([tab for tab in all_cells]) return all_cells