def retrieve_calibration_table(self, force=False): if self.name in self.qc1_retrievable: if self.calibration_table_last_updated != date.today() or force: down_path = os.path.join(self.data_path, "fors2_qc.tbl") fil = self.name if fil == "R_SPECIAL": fil = "R_SPEC" save_fors2_calib( output=down_path, fil=fil, ) self.calibration_table = table.QTable.read(down_path, format="ascii") self.calibration_table["zeropoint"] *= units.mag self.calibration_table["zeropoint_err"] *= units.mag self.calibration_table["colour_term"] *= units.mag self.calibration_table["colour_term_err"] *= units.mag self.calibration_table["extinction"] *= units.mag self.calibration_table["extinction_err"] *= units.mag self.write_calibration_table() self.calibration_table_last_updated = date.today() else: u.debug_print(1, "Filter calibrations already updated today; skipping.") else: u.debug_print(1, f"Cannot retrieve calibration table for {self.name}.") self.update_output_file() return self.calibration_table
def from_params(cls, instrument_name: str): if instrument_name in active_instruments: return active_instruments[instrument_name] path = cls._build_param_path(instrument_name=instrument_name) u.debug_print(1, "Instrument.from_params(): instrument_name ==", instrument_name) u.debug_print(1, "Instrument.from_params(): path ==", path) return cls.from_file(param_file=path)
def _build_param_dir(cls, instrument_name: str): path = os.path.join(p.param_dir, "instruments") u.mkdir_check(path) u.debug_print(2, "Instrument._build_param_dir(): instrument_name ==", instrument_name) path = os.path.join(path, instrument_name) u.mkdir_check(path) return path
def match_catalogs(cat_1: table.Table, cat_2: table.Table, ra_col_1: str = "RA", dec_col_1: str = "DEC", ra_col_2: str = "ra", dec_col_2: str = "dec", tolerance: units.Quantity = 1 * units.arcsec): # Clean out any invalid declinations u.debug_print(2, "match_catalogs(): type(cat_1) ==", type(cat_1), "type(cat_2) ==", type(cat_2)) cat_1 = cat_1[cat_1[dec_col_1] <= 90 * units.deg] cat_1 = cat_1[cat_1[dec_col_1] >= -90 * units.deg] cat_2 = cat_2[cat_2[dec_col_2] <= 90 * units.deg] cat_2 = cat_2[cat_2[dec_col_2] >= -90 * units.deg] coords_1 = SkyCoord(cat_1[ra_col_1], cat_1[dec_col_1]) coords_2 = SkyCoord(cat_2[ra_col_2], cat_2[dec_col_2]) idx, distance, _ = coords_2.match_to_catalog_sky(coords_1) keep = distance < tolerance idx = idx[keep] matches_2 = cat_2[keep] distance = distance[keep] matches_1 = cat_1[idx] return matches_1, matches_2, distance
def save_params(file: str, dictionary: dict): file = u.sanitise_file_ext(filename=file, ext=".yaml") u.debug_print(1, 'Saving parameter file to ' + str(file)) u.debug_print(2, "params.save_params: dictionary ==", dictionary) with open(file, 'w') as f: yaml.dump(dictionary, f)
def gather_filters(self): filter_dir = self.guess_filter_dir() for file in filter(lambda f: f.endswith(".yaml"), os.listdir(filter_dir)): u.debug_print(1, "Instrument.gather_filters(): file == ", file) fil = Filter.from_params(filter_name=file[:-5], instrument_name=self.name) fil.instrument = self self.filters[fil.name] = fil if fil.votable_path is None: fil.retrieve_from_svo()
def solve_field( image_files: Union[str, list], base_filename: str = "astrometry", overwrite: bool = True, tweak: bool = True, search_radius: units.Quantity = 1 * units.degree, centre: SkyCoord = None, guess_scale: bool = True, time_limit: units.Quantity = None, verify: bool = True, odds_to_tune_up: float = 1e6, odds_to_solve: float = 1e9, *flags, **params): """ Returns True if successful (by checking whether the corrected file is generated); False if not. :param image_files: :param base_filename: :param overwrite: :param flags: :param params: :return: """ params["o"] = base_filename params["odds-to-tune-up"] = odds_to_tune_up params["odds-to-solve"] = odds_to_solve if time_limit is not None: params["l"] = check_quantity(time_limit, units.second).value if search_radius is not None: params["radius"] = search_radius.to(units.deg).value if centre is not None: params["ra"] = centre.ra.to(units.deg).value params["dec"] = centre.dec.to(units.deg).value debug_print(1, "solve_field(): tweak ==", tweak) flags = list(flags) if overwrite: flags.append("O") if guess_scale: flags.append("g") if not tweak: flags.append("T") if not verify: flags.append("y") system_command("solve-field", image_files, False, True, False, *flags, **params) if isinstance(image_files, list): image_path = image_files[0] else: image_path = image_files check_dir = os.path.split(image_path)[0] check_path = os.path.join(check_dir, f"{base_filename}.new") print(f"Checking for result file at {check_path}...") return os.path.isfile(check_path)
def check_data_path(self): if self.field is not None: u.debug_print(2, "", self.name) # print(self.field.data_path, self.name_filesys) self.data_path = os.path.join(self.field.data_path, "objects", self.name_filesys) u.mkdir_check(self.data_path) self.output_file = os.path.join(self.data_path, f"{self.name_filesys}_outputs.yaml") return True else: return False
def write_calibration_table(self): if self.calibration_table is None: u.debug_print(1, "calibration_table not yet loaded.") else: if self.calibration_table_path is None: self.calibration_table_path = os.path.join( self.data_path, f"{self.instrument.name}_{self.name}_calibration_table.ecsv") u.debug_print(1, "Writing calibration table to", self.calibration_table_path) self.calibration_table.write(self.calibration_table_path, format="ascii.ecsv", overwrite=True)
def plot_gal_params( hdu: fits.HDUList, ras: Union[list, np.ndarray, float], decs: Union[list, np.ndarray, float], a: Union[list, np.ndarray, float], b: Union[list, np.ndarray, float], theta: Union[list, np.ndarray, float], colour: str = 'white', show_centre: bool = False, label: str = None, world: bool = True, world_axes: bool = True, **kwargs): """ :param hdu: :param ras: In degrees. :param decs: In degrees. :param a: In degrees. :param b: In degrees. :param theta: In degrees, apparently. :param colour: :param offset: :param show_centre: :return: """ # TODO: Rename parameters to reflect acceptance of pixel coordinates. _, pix_scale = ff.get_pixel_scale(hdu) n_y, n_x = hdu[0].data.shape header = hdu[0].header wcs_image = wcs.WCS(header=header) if world: xs, ys = wcs_image.all_world2pix(ras, decs, 0) else: xs = np.array(ras) ys = np.array(decs) theta = np.array(theta) # Convert to photutils angle format theta = u.world_angle_se_to_pu(theta, rot_angle=ff.get_rotation_angle(header)) a = u.dequantify(a) b = u.dequantify(b) for i, x in enumerate(xs): u.debug_print(2, "plotting.plot_gal_params(): x, ys[i] ==", x, ys[i]) if a[i] != 0 and b[i] != 0: if world_axes: ellipse = photutils.EllipticalAperture((x, ys[i]), a=a[i] / pix_scale, b=b[i] / pix_scale, theta=theta[i]) else: ellipse = photutils.EllipticalAperture((x, ys[i]), a=a[i], b=b[i], theta=theta[i]) ellipse.plot(**kwargs) line_label = None else: line_label = label if show_centre: plt.plot((0.0, n_x), (ys[i], ys[i]), c=colour, label=line_label) plt.plot((x, x), (0.0, n_y), c=colour)
def load_params(file: str): file = u.sanitise_file_ext(file, '.yaml') u.debug_print(2, 'Loading parameter file from ' + str(file)) if os.path.isfile(file): with open(file) as f: p = yaml.load(f) else: p = None u.debug_print(1, 'No parameter file found at', str(file) + ', returning None.') return p
def sof(frames: Dict[str, list], output_path: str): output_lines = [] for frame_type in frames: u.debug_print(0, output_lines) for frame in frames[frame_type]: output_lines.append(f"{frame} {frame_type}\n") u.mkdir_check_nested(output_path) print(f"Writing SOF file to {output_path}") with open(output_path, "w") as file: file.writelines(output_lines) return output_lines
def update_output_file(obj): if obj.output_file is not None: param_dict = load_params(obj.output_file) if param_dict is None: param_dict = {} # For each of these, check if None first. u.debug_print(2, "params.update_output_file(): obj, type(obj) ==", obj, type(obj)) u.debug_print(2, "params.update_output_file(): obj._output_dict() ==", obj._output_dict()) param_dict.update(obj._output_dict()) save_params(dictionary=param_dict, file=obj.output_file) else: raise ValueError( "Output could not be saved to file due to lack of valid output path." )
def select_photometry_sep( self, fil: str, instrument: str, local_output: bool = True ): fil_photom = self.photometry_tbl[self.photometry_tbl["band"] == fil] fil_photom = fil_photom[fil_photom["instrument"] == instrument] mean = { "mag": np.mean(fil_photom["mag_sep"]), "mag_err": np.std(fil_photom["mag_sep"]), "mag_psf": np.mean(fil_photom["mag_psf"]), "mag_psf_err": np.std(fil_photom["mag_psf"]) } u.debug_print(2, f"Object.select_photometry_sep(): {self.name=}, {fil=}, {instrument=}") print(fil_photom) return fil_photom[np.argmax(fil_photom["snr_sep"])], mean
def check_subimage_edges(data: np.ndarray, bottom, top, left, right): u.debug_print( 1, "fits_files.check_subimage_edges(): bottom, top, left, right == ", bottom, top, left, right) if (bottom < 0 and top < 0) or (bottom > data.shape[0] and top > data.shape[0]): raise ValueError( f"Both y-axis edges ({bottom}, {top}) are outside the image.") if (left < 0 and right < 0) or (left > data.shape[1] and right > data.shape[1]): raise ValueError( f"Both x-axis edges ({left}, {right}) are outside the image.") bottom = max(int(bottom), 0) top = min(int(top), data.shape[0]) left = max(int(left), 0) right = min(int(right), data.shape[1]) return bottom, top, left, right
def detect_edges_area(file: Union['fits.HDUList', 'str']): if type(file) is str: print("Area file:", file) file = fits.open(file) data = file[0].data # We round to the 13th decimal place keep_val = u.bucket_mode(data, 13) height = data.shape[0] mid_y = int(height / 2) # Take a horizontal slice right across the middle of the image. slice_hor = np.round(data[mid_y], 13) slice_hor_keep = np.nonzero(slice_hor == keep_val)[0] # This is here just in case mid_y finds a row that does not have maximum coverage. while len(slice_hor_keep) == 0: mid_y = int(mid_y / 2) if mid_y == 0: raise ValueError("mid_y got stuck.") u.debug_print(2, "detect_edges_area(): mid_y==", mid_y) # Take a horizontal slice right across the middle of the image. slice_hor = np.round(data[mid_y], 13) slice_hor_keep = np.nonzero(slice_hor > 0.75 * keep_val)[0] u.debug_print(2, "detect_edges_area(): slice_hor.max()", slice_hor.max()) left = slice_hor_keep[0] right = slice_hor_keep[-1] width = data.shape[1] mid_x = int(width / 2) slice_vert = np.round(data[:, mid_x], 13) slice_vert_keep = np.nonzero(slice_vert == keep_val)[0] while len(slice_hor_keep) == 0: mid_x = int(mid_x / 2) # Take a horizontal slice right across the middle of the image. slice_hor = np.round(data[mid_x], 13) slice_hor_keep = np.nonzero(slice_hor == keep_val)[0] bottom = slice_vert_keep[0] top = slice_vert_keep[-1] if type(file) is str: file.close() return left, right, bottom, top
def correct_gaia_to_epoch(gaia_cat: Union[str, table.QTable], new_epoch: time.Time): gaia_cat = load_catalogue(cat_name="gaia", cat=gaia_cat) epochs = list(map(lambda y: f"J{y}", gaia_cat['ref_epoch'])) gaia_coords = SkyCoord(ra=gaia_cat["ra"], dec=gaia_cat["dec"], pm_ra_cosdec=gaia_cat["pmra"], pm_dec=gaia_cat["pmdec"], obstime=epochs) u.debug_print(2, "astrometry.correct_gaia_to_epoch(): new_epoch ==", new_epoch) gaia_coords_corrected = gaia_coords.apply_space_motion( new_obstime=new_epoch) gaia_cat_corrected = copy.deepcopy(gaia_cat) gaia_cat_corrected["ra"] = gaia_coords_corrected.ra gaia_cat_corrected["dec"] = gaia_coords_corrected.dec new_epoch.format = "jyear" gaia_cat_corrected["ref_epoch"] = new_epoch.value return gaia_cat_corrected
def yaml_to_json(yaml_file: str, output: str = None): yaml_file = u.sanitise_file_ext(yaml_file, '.yaml') if output is not None: output = u.sanitise_file_ext(output, '.json') elif output is None: output = yaml_file.replace('.yaml', '.json') p = load_params(file=yaml_file) u.debug_print(1, 'Saving parameter file to ' + output) for param in p: if type(p[param]) is date: p[param] = str(p[param]) with open(output, 'w') as fj: json.dump(p, fj) return p
def from_file(cls, param_file: Union[str, dict]): u.debug_print(1, "Instrument.from_file(): param_file ==", param_file) name, param_file, param_dict = p.params_init(param_file) u.debug_print(1, "Instrument.from_file(): name ==", name) u.debug_print(1, "Instrument.from_file(): param_dict ==", param_dict) if param_dict is None: raise FileNotFoundError("Param file missing!") return cls(**param_dict)
def from_params(cls, survey_name: str): path = cls._build_param_path(survey_name=survey_name) u.debug_print(1, "Survey.from_params(): path ==", path) return cls.from_file(param_file=path)
def main( field_name: str, epoch_name: str, imaging: bool, spectroscopy: bool, instrument: str, furby_path: str, do: str, do_not_reuse_masters: bool, overwrite_download: bool, distance_tolerance: float, snr_min: float, class_star_tolerance: float, debug_level: int, ): u.debug_level = debug_level new_field = False directory = fld.load_epoch_directory() if epoch_name is not None: print(f"Looking for {epoch_name} in directory...") if epoch_name in directory: epoch_dict = directory[epoch_name] field_name = epoch_dict["field_name"] instrument = epoch_dict["instrument"] mode = epoch_dict["mode"] if mode == "imaging": imaging = True elif mode == "spectroscopy": spectroscopy = True else: print(f"{epoch_name} not found.") # Do automated FURBY process. if furby_path is not None: new_field = True furby = True imaging = True healpix_path = furby_path.replace(".json", "_hp.fits") if not os.path.isfile(healpix_path): healpix_path = None params = fld.FRBField.param_from_furby_json( json_path=furby_path, healpix_path=healpix_path, ) field_name = params["name"] field = fld.Field.from_params(name=field_name) instrument = "vlt-fors2" epoch_name = f"{field_name}_FORS2_1" fld.FORS2ImagingEpoch.new_yaml( name=epoch_name, path=fld.FORS2ImagingEpoch.build_param_path( instrument_name=instrument, field_name=field_name, epoch_name=epoch_name), field=field.name, instrument=instrument, data_path=os.path.join(field_name, "imaging", instrument, epoch_name, "")) # epoch = fld.FORS2ImagingEpoch.from_params( # name=epoch_name, # instrument=instrument, # field=field, # old_format=False, # ) else: if field_name is None: fields = ["New field"] fields += fld.list_fields() old_fields = fld.list_fields_old() for old_field in old_fields: if old_field not in fields and f"FRB20{old_field[3:]}" not in fields: fields.append(old_field) opt, field_name = u.select_option( "No field specified. Please select one:", options=fields, sort=False) if opt == 0: new_field = True field_name = input("Please enter the name of the new field:\n") # Check for field param file if not new_field: field = fld.Field.from_params(name=field_name) else: field = None # If this field has no parameter file, ask to create one. if field is None: param_path = os.path.join(p.param_dir, "fields", "") # Check for old format param file, and ask to convert if found. old_field_name = f"FRB{field_name[-8:]}" old_params = p.object_params_frb(obj=old_field_name) print() field_param_path = os.path.join(param_path, field_name) u.mkdir_check(field_param_path) field_param_path_yaml = os.path.join(field_param_path, f"{field_name}.yaml") if old_params is None: if not new_field: print(f"{field_name} not found in the param directory.") if u.select_yn( f"Create a new param file at '{field_param_path_yaml}'?" ): fld.Field.new_params_from_input( field_name=field_name, field_param_path=field_param_path) else: print("Exiting.") exit(0) else: print("Old format param file detected.") if u.select_yn("Convert to new format?"): fld.FRBField.convert_old_param(frb=old_field_name) else: print("Exiting...") exit(0) field = fld.Field.from_params(name=field_name) if spectroscopy: mode = "Spectroscopy" elif imaging: mode = "Imaging" else: _, mode = u.select_option(message="Please select a mode.", options=["Imaging", "Spectroscopy"]) if mode == "Spectroscopy": if epoch_name is None: # Build a list of imaging epochs from that field. field.gather_epochs_spectroscopy() # Let the user select an epoch. epoch = field.select_epoch_spectroscopy() else: if instrument is None: instrument = fld.select_instrument(mode="spectroscopy") epoch = fld.SpectroscopyEpoch.from_params(epoch_name, instrument=instrument, field=field) else: # if mode == "Imaging" if epoch_name is None: # Build a list of imaging epochs from that field. if type(field) is fld.FRBField: field.gather_epochs_old() field.gather_epochs_imaging() # Let the user select an epoch. epoch = field.select_epoch_imaging() else: if instrument is None: instrument = fld.select_instrument(mode="imaging") epoch = fld.ImagingEpoch.from_params(epoch_name, instrument=instrument, field=field) epoch.field = field u.debug_print(2, "pipeline.py: type(epoch) ==", type(epoch)) epoch.do = do epoch.pipeline(do_not_reuse_masters=do_not_reuse_masters, overwrite_download=overwrite_download, distance_tolerance=distance_tolerance, snr_min=snr_min, class_star_tolerance=class_star_tolerance)
def standard_script( input_directory: str, output_directory: str, output_file_name: str = None, ignore_differences: bool = False, coadd_types: Union[List[str], str] = 'median', # unit="electron / second", do_inject_header: bool = True, **kwargs): """ Does a standard median coaddition of fits files in input_directory. Adapted from an example bash script found at http://montage.ipac.caltech.edu/docs/first_mosaic_tutorial.html :param input_directory: path to directory containing input images. :param output_directory: path to directory to write data products to; will be created if it doesn't exist. :param output_file_name: Name of final coadded image file. :param ignore_differences: If False, checks if input images have compatible exposure times, filter, etc. and raises ValueError if not. :return: """ u.mkdir_check(output_directory) old_dir = os.getcwd() proj_dir = os.path.join(output_directory, "projdir") diff_dir = os.path.join(output_directory, "diffdir") corr_dir = os.path.join(output_directory, "corrdir") u.mkdir_check(proj_dir, diff_dir, corr_dir) os.chdir(output_directory) print("Creating directories to hold processed images.") proj_dir = "projdir" diff_dir = "diffdir" corr_dir = "corrdir" if not ignore_differences: print("Checking input images...") check_input_images(input_directory=input_directory, **kwargs) print("Creating metadata tables of the input images.") table_path = "images.tbl" image_table(input_directory=input_directory, output_path=table_path) print("Creating FITS headers describing the footprint of the mosaic.") header_path = "template.hdr" make_header(table_path=table_path, output_path=header_path) print("Reprojecting input images.") stats_table_path = "stats.tbl" project_execute(input_directory=input_directory, table_path=table_path, header_path=header_path, proj_dir=proj_dir, stats_table_path=stats_table_path) print("Creating metadata table of the reprojected images.") reprojected_table_path = "proj.tbl" image_table(input_directory=proj_dir, output_path=reprojected_table_path) print("Analyzing the overlaps between images.") difference_table_path = "diffs.tbl" fit_table_path = "fits.tbl" overlaps(table_path=reprojected_table_path, difference_table_path=difference_table_path) difference_execute(input_directory=proj_dir, difference_table_path=difference_table_path, header_path=header_path, diff_dir=diff_dir) fit_execute(difference_table_path=difference_table_path, fit_table_path=fit_table_path, diff_dir=diff_dir) print( "Performing background modeling and compute corrections for each image." ) corrections_table_path = "corrections.tbl" background_model(table_path=reprojected_table_path, fit_table_path=fit_table_path, correction_table_path=corrections_table_path) print("Applying corrections to each image") background_execute(input_directory=proj_dir, table_path=reprojected_table_path, correction_table_path=corrections_table_path, corr_dir=corr_dir) if isinstance(coadd_types, str): coadd_types = [coadd_types] file_paths = [] for i, coadd_type in enumerate(coadd_types): print(f"Coadding the images with {coadd_type}.") if output_file_name is None: output_file_name = "coadded.fits" output_file_name_coadd = output_file_name.replace( ".fits", f"_{coadd_type}.fits") add(input_directory=corr_dir, coadd_type=coadd_type, table_path=reprojected_table_path, header_path=header_path, output_path=output_file_name_coadd) if do_inject_header: inject_header(file_path=output_file_name_coadd, input_directory=input_directory, coadd_type=coadd_type) file_paths.append( os.path.join(output_directory, output_file_name_coadd)) os.chdir(old_dir) u.debug_print(1, "montage.standard_script():", file_paths) return file_paths
def load_extinction_table(self, force: bool = False): if force or self.irsa_extinction is None: if self.irsa_extinction_path is not None: u.debug_print(1, "Loading irsa_extinction from", self.irsa_extinction_path) self.irsa_extinction = table.QTable.read(self.irsa_extinction_path, format="ascii.ecsv")
def plot_subimage( fig: plt.Figure, hdu: Union[str, fits.HDUList], ra: float, dec: float, frame: Union[int, float], world_frame: bool = False, title: str = None, n: int = 1, n_x: int = 1, n_y: int = 1, cmap: str = 'viridis', show_cbar: bool = False, stretch: str = 'sqrt', vmin: float = None, vmax: float = None, show_grid: bool = False, ticks: int = None, interval: str = 'minmax', show_coords: bool = True, ylabel: str = None, font_size: int = 12, reverse_y=False, **kwargs): """ :param fig: :param hdu: :param ra: :param dec: :param frame: in pixels, or in degrees (?) if world_frame is True. :param world_frame: :param title: :param n: :param n_x: :param n_y: :param cmap: :param show_cbar: :param stretch: :param vmin: :param vmax: :param show_grid: :param ticks: :param interval: :param show_coords: :param ylabel: :param font_size: :param reverse_y: :return: """ u.debug_print(1, "plotting.plot_subimage(): hdu ==", hdu) hdu, path = ff.path_or_hdu(hdu=hdu) u.debug_print(1, "plotting.plot_subimage(): hdu[0].data.shape ==", hdu[0].data.shape) hdu_cut = ff.trim_frame_point(hdu=hdu, ra=ra, dec=dec, frame=frame, world_frame=world_frame) wcs_cut = wcs.WCS(header=hdu_cut[0].header) u.debug_print(1, "plotting.plot_subimage(): n_y, n_x, n ==", n_y, n_x, n) if show_coords: plot = fig.add_subplot(n_y, n_x, n, projection=wcs_cut) if ticks is not None: lat = plot.coords[0] lat.set_ticks(number=ticks) else: plot = fig.add_subplot(n_y, n_x, n) frame1 = plt.gca() frame1.axes.get_xaxis().set_visible(False) frame1.axes.set_yticks([]) frame1.axes.invert_yaxis() # frame1.axes.get_yaxis().set_visible(False) if show_grid: plt.grid(color='black', ls='dashed') if type(vmin) is str: if vmin == 'median_full': vmin = np.nanmedian(hdu[0].data) elif vmin == 'median_cut': vmin = np.nanmedian(hdu_cut[0].data) else: raise ValueError('Unrecognised vmin string argument.') if interval == 'minmax': interval = MinMaxInterval() elif interval == 'zscale': interval = ZScaleInterval() else: raise ValueError('Interval not recognised.') u.debug_print(1, "plotting.plot_subimage(): hdu_cut[0].data.shape ==", hdu_cut[0].data.shape) if stretch == 'log': norm = ImageNormalize(hdu_cut[0].data, interval=interval, stretch=LogStretch(), vmin=vmin, vmax=vmax) elif stretch == 'sqrt': norm = ImageNormalize(hdu_cut[0].data, interval=interval, stretch=SqrtStretch(), vmin=vmin, vmax=vmax) else: raise ValueError('Stretch not recognised.') plot.title.set_text(title) plot.title.set_size(font_size) u.debug_print(1, "plotting.plot_subimage(): ylabel ==", ylabel) if ylabel is not None: plot.set_ylabel(ylabel, size=12) im = plt.imshow(hdu_cut[0].data, norm=norm, cmap=cmap, **kwargs, origin='lower') if reverse_y: plot.invert_yaxis() c_ticks = np.linspace(norm.vmin, norm.vmax, 5, endpoint=True) if show_cbar: cbar = plt.colorbar(im) # ticks=c_ticks) return plot, hdu_cut
def push_to_table(self, select: bool = False, local_output: bool = True): if select: tbl = obs.load_master_objects_table() else: tbl = obs.load_master_all_objects_table() jname = self.jname() for instrument in self.photometry: for fil in self.photometry[instrument]: band_str = f"{instrument}_{fil.replace('_', '-')}" obs.add_columns_to_master_objects(band_str) if select: row, index = obs.get_row(tbl=obs.master_objects_table, colname="object_name", colval=self.name) else: row, index = obs.get_row(tbl=obs.master_objects_all_table, colname="object_name", colval=self.name) print() if row is None: row = {} self.estimate_galactic_extinction() if select: self.get_good_photometry() self.photometry_to_table() deepest = self.select_deepest_sep(local_output=local_output) else: deepest = self.select_deepest(local_output=local_output) # best_position = self.select_best_position(local_output=local_output) best_psf = self.select_psf_photometry(local_output=local_output) row["jname"] = jname row["field_name"] = self.field.name row["object_name"] = self.name row["ra"] = deepest["ra"] row["ra_err"] = deepest["ra_err"] row["dec"] = deepest["dec"] row["dec_err"] = deepest["dec_err"] row["epoch_position"] = deepest["epoch_name"] row["epoch_position_date"] = deepest["epoch_date"] row["a"] = deepest["a"] row["a_err"] = deepest["a_err"] row["b"] = deepest["b"] row["b_err"] = deepest["b_err"] row["theta"] = deepest["theta"] row["kron_radius"] = deepest["kron_radius"] row["epoch_ellipse"] = deepest["epoch_name"] row["epoch_ellipse_date"] = deepest["epoch_date"] row["theta_err"] = deepest["theta_err"] row[f"e_b-v"] = self.ebv_sandf row[f"class_star"] = best_psf["class_star"] for instrument in self.photometry: for fil in self.photometry[instrument]: band_str = f"{instrument}_{fil.replace('_', '-')}" obs.add_columns_to_master_objects(band_str) if select: best_photom, mean_photom = self.select_photometry_sep(fil, instrument, local_output=local_output) row[f"mag_best_{band_str}"] = best_photom["mag_sep"] row[f"mag_best_{band_str}_err"] = best_photom["mag_sep_err"] row[f"snr_best_{band_str}"] = best_photom["snr_sep"] else: best_photom, mean_photom = self.select_photometry(fil, instrument, local_output=local_output) row[f"mag_best_{band_str}"] = best_photom["mag"] row[f"mag_best_{band_str}_err"] = best_photom["mag_err"] row[f"snr_best_{band_str}"] = best_photom["snr"] row[f"mag_mean_{band_str}"] = mean_photom["mag"] row[f"mag_mean_{band_str}_err"] = mean_photom["mag_err"] row[f"ext_gal_{band_str}"] = best_photom["ext_gal"] # else: # row[f"ext_gal_{band_str}"] = best_photom["ext_gal_sandf"] row[f"epoch_best_{band_str}"] = best_photom[f"epoch_name"] row[f"epoch_best_date_{band_str}"] = best_photom[f"epoch_date"] row[f"mag_psf_best_{band_str}"] = best_photom[f"mag_psf"] row[f"mag_psf_best_{band_str}_err"] = best_photom[f"mag_psf_err"] row[f"snr_psf_best_{band_str}"] = best_photom["snr_psf"] row[f"mag_psf_mean_{band_str}"] = mean_photom[f"mag_psf"] row[f"mag_psf_mean_{band_str}_err"] = mean_photom[f"mag_psf_err"] for colname in tbl.colnames: if colname not in row: if "epoch" in colname: row[colname] = "N/A" else: row[colname] = tbl[0][colname] u.debug_print(2, "Object.push_to_table(): select ==", select) print(f"INDEX: {index}") if select: if index is None: obs.master_objects_table.add_row(row) else: obs.master_objects_table[index] = row obs.write_master_objects_table() else: if index is None: obs.master_objects_all_table.add_row(row) else: obs.master_objects_all_table[index] = row obs.write_master_all_objects_table()
def __init__( self, uncertainty: Union[float, units.Quantity, dict, tuple] = None, position: SkyCoord = None, ra_err_sys: Union[float, units.Quantity] = None, ra_err_stat: Union[float, units.Quantity] = None, dec_err_sys: Union[float, units.Quantity] = None, dec_err_stat: Union[float, units.Quantity] = None, a_stat: Union[float, units.Quantity] = None, a_sys: Union[float, units.Quantity] = None, b_stat: Union[float, units.Quantity] = None, b_sys: Union[float, units.Quantity] = None, theta: Union[float, units.Quantity] = None, sigma: float = None ): """ If a single value is provided for uncertainty, the uncertainty ellipse will be assumed to be circular. Values in dictionary, if provided, override values given as arguments. Position values provided without units are assumed to be in degrees. On the other hand, uncertainty values provided without units are assumed to be in arcseconds; except for uncertainties in RA, which are assumed in RA seconds. :param uncertainty: :param position: :param ra_err_sys: :param ra_err_stat: :param dec_err_sys: :param dec_err_stat: :param a_stat: :param a_sys: :param b_stat: :param b_sys: :param theta: :param sigma: The confidence interval (expressed in multiples of sigma) of the uncertainty ellipse. """ self.sigma = sigma # Assign values from dictionary, if provided. if type(uncertainty) is dict: if "ra" in uncertainty and uncertainty["ra"] is not None: if "sys" in uncertainty["ra"] and uncertainty["ra"]["sys"] is not None: ra_err_sys = uncertainty["ra"]["sys"] if "stat" in uncertainty["ra"] and uncertainty["ra"]["stat"] is not None: ra_err_stat = uncertainty["ra"]["stat"] if "dec" in uncertainty and uncertainty["dec"] is not None: if "sys" in uncertainty["dec"] and uncertainty["dec"]["sys"] is not None: dec_err_sys = uncertainty["dec"]["sys"] if "stat" in uncertainty["dec"] and uncertainty["dec"]["stat"] is not None: dec_err_stat = uncertainty["dec"]["stat"] if "a" in uncertainty and uncertainty["a"] is not None: if "sys" in uncertainty["a"] and uncertainty["a"]["sys"] is not None: a_sys = uncertainty["a"]["sys"] if "stat" in uncertainty["a"] and uncertainty["a"]["stat"] is not None: a_stat = uncertainty["a"]["stat"] if "b" in uncertainty and uncertainty["b"] is not None: if "sys" in uncertainty["b"] and uncertainty["b"]["sys"] is not None: b_sys = uncertainty["b"]["sys"] if "stat" in uncertainty["b"] and uncertainty["a"]["stat"] is not None: b_stat = uncertainty["b"]["stat"] if "theta" in uncertainty and uncertainty["theta"] is not None: theta = uncertainty["theta"] # If uncertainty is a single value, assume a circular uncertainty region without distinction between systematic # and statistical. elif uncertainty is not None: a_stat = uncertainty a_sys = 0.0 b_stat = uncertainty b_sys = 0.0 theta = 0.0 # Check whether we're specifying uncertainty using equatorial coordinates or ellipse parameters. u.debug_print(2, "PositionUncertainty.__init__(): a_stat, a_sys, b_stat, b_sys, theta, position ==", a_stat, a_sys, b_stat, b_sys, theta, position) u.debug_print(2, "PositionUncertainty.__init__(): ra_err_sys, ra_err_stat, dec_err_sys, dec_err_stat ==", ra_err_sys, ra_err_stat, dec_err_sys, dec_err_stat) if a_stat is not None and a_sys is not None and b_stat is not None and b_sys is not None and theta is not None and position is not None: ellipse = True elif ra_err_sys is not None and ra_err_stat is not None and dec_err_sys is not None and dec_err_stat is not None: ellipse = False else: raise ValueError( "Either all ellipse values (a, b, theta) or all equatorial values (ra, dec, position) must be provided.") ra_err_sys = u.check_quantity(number=ra_err_sys, unit=units.hourangle / 3600) ra_err_stat = u.check_quantity(number=ra_err_stat, unit=units.hourangle / 3600) dec_err_sys = u.check_quantity(number=dec_err_sys, unit=units.arcsec) dec_err_stat = u.check_quantity(number=dec_err_stat, unit=units.arcsec) # Convert equatorial uncertainty to ellipse with theta=0 if not ellipse: ra = position.ra dec = position.dec a_sys = SkyCoord(0.0 * units.degree, dec).separation(SkyCoord(ra_err_sys, dec)) a_stat = SkyCoord(0.0 * units.degree, dec).separation(SkyCoord(ra_err_stat, dec)) b_sys = SkyCoord(ra, dec).separation(SkyCoord(ra, dec + dec_err_sys)) b_stat = SkyCoord(ra, dec).separation(SkyCoord(ra, dec + dec_err_stat)) a_sys, b_sys = max(a_sys, b_sys), min(a_sys, b_sys) a_stat, b_stat = max(a_stat, b_stat), min(a_stat, b_stat) theta = 0.0 * units.degree # Or use ellipse parameters as given. else: a_sys = u.check_quantity(number=a_sys, unit=units.arcsec) a_stat = u.check_quantity(number=a_stat, unit=units.arcsec) b_sys = u.check_quantity(number=b_sys, unit=units.arcsec) b_stat = u.check_quantity(number=b_stat, unit=units.arcsec) theta = u.check_quantity(number=theta, unit=units.arcsec) self.a_sys = a_sys self.a_stat = a_stat self.b_sys = b_sys self.b_stat = b_stat self.theta = theta self.ra_sys = ra_err_sys self.dec_sys = dec_err_sys self.ra_stat = ra_err_stat self.dec_stat = dec_err_stat