def is_field_in_fov(fov_header, table_or_imagehdu, wcs_suffix=""): s = wcs_suffix pixel_scale = utils.quantify(fov_header["CDELT1" + s], u.deg) if isinstance(table_or_imagehdu, Table): ext_hdr = imp_utils._make_bounding_header_for_tables( [table_or_imagehdu], pixel_scale) elif isinstance(table_or_imagehdu, fits.ImageHDU): ext_hdr = imp_utils._make_bounding_header_from_imagehdus( [table_or_imagehdu], pixel_scale) else: warnings.warn("Input was neither Table nor ImageHDU: {}" "".format(table_or_imagehdu)) return False ext_xsky, ext_ysky = imp_utils.calc_footprint(ext_hdr, wcs_suffix) fov_xsky, fov_ysky = imp_utils.calc_footprint(fov_header, wcs_suffix) is_inside_fov = min(ext_xsky) < max(fov_xsky) and \ max(ext_xsky) > min(fov_xsky) and \ min(ext_ysky) < max(fov_ysky) and \ max(ext_ysky) > min(fov_ysky) return is_inside_fov
def extract_range_from_spectrum(spectrum, waverange): if not isinstance(spectrum, SourceSpectrum): raise ValueError(f"spectrum must be of type synphot.SourceSpectrum: " f"{type(spectrum)}") wave_min, wave_max = utils.quantify(waverange, u.um).to(u.AA).value spec_waveset = spectrum.waveset.to(u.AA).value mask = (spec_waveset > wave_min) * (spec_waveset < wave_max) if sum(mask) == 0: logging.warning(f"Waverange does not overlap with Spectrum waveset: " f"{[wave_min, wave_max]} <> {spec_waveset} " f"for spectrum {spectrum}") if wave_min < min(spec_waveset) or wave_max > max(spec_waveset): logging.warning(f"Waverange only partially overlaps with Spectrum waveset: " f"{[wave_min, wave_max]} <> {spec_waveset} " f"for spectrum {spectrum}") wave = np.r_[wave_min, spec_waveset[mask], wave_max] flux = spectrum(wave) new_spectrum = SourceSpectrum(Empirical1D, points=wave, lookup_table=flux) new_spectrum.meta.update(spectrum.meta) return new_spectrum
def is_field_in_fov(fov_header, field, wcs_suffix=""): """ Returns True if Source.field footprint is inside the FieldOfView footprint Parameters ---------- fov_header : fits.Header Header from a FieldOfView object field : [astropy.Table, astropy.ImageHDU] Field object from a Source object wcs_suffix : str ["S", "D"] Coordinate system: Sky or Detector Returns ------- is_inside_fov : bool """ if isinstance(field, fits.ImageHDU) and \ field.header.get("BG_SRC") is not None: is_inside_fov = True else: if isinstance(field, Table): x = list(utils.quantity_from_table("x", field, u.arcsec).to(u.deg).value) y = list(utils.quantity_from_table("y", field, u.arcsec).to(u.deg).value) s = wcs_suffix cdelt = utils.quantify(fov_header["CDELT1" + s], u.deg).value field_header = imp_utils.header_from_list_of_xy(x, y, cdelt, s) elif isinstance(field, (fits.ImageHDU, fits.PrimaryHDU)): field_header = field.header else: logging.warning("Input was neither Table nor ImageHDU: {}" "".format(field)) return False ext_xsky, ext_ysky = imp_utils.calc_footprint(field_header, wcs_suffix) fov_xsky, fov_ysky = imp_utils.calc_footprint(fov_header, wcs_suffix) is_inside_fov = min(ext_xsky) < max(fov_xsky) and \ max(ext_xsky) > min(fov_xsky) and \ min(ext_ysky) < max(fov_ysky) and \ max(ext_ysky) > min(fov_ysky) return is_inside_fov
def test_return_quantity_for_valid_data(self, item, unit, expected): assert utils.quantify(item, unit) == expected
def extract_area_from_imagehdu(imagehdu, fov_volume): """ Extracts the part of a ImageHDU that fits inside the fov_volume Parameters ---------- imagehdu : fits.ImageHDU The field ImageHDU, either an image of a wavelength [um] cube fov_volume : dict Contains {"xs": [xmin, xmax], "ys": [ymin, ymax], "waves": [wave_min, wave_max], "xy_unit": "deg" or "mm", "wave_unit": "um"} Returns ------- new_imagehdu : fits.ImageHDU """ hdr = imagehdu.header new_hdr = {} x_hdu, y_hdu = imp_utils.calc_footprint(imagehdu) # field edges in "deg" x_fov, y_fov = fov_volume["xs"], fov_volume["ys"] x0s, x1s = max(min(x_hdu), min(x_fov)), min(max(x_hdu), max(x_fov)) y0s, y1s = max(min(y_hdu), min(y_fov)), min(max(y_hdu), max(y_fov)) xp, yp = imp_utils.val2pix(hdr, np.array([x0s, x1s]), np.array([y0s, y1s])) (x0p, x1p), (y0p, y1p) = np.round(xp).astype(int), np.round(yp).astype(int) if x0p == x1p: x1p += 1 if y0p == y1p: y1p += 1 new_hdr = imp_utils.header_from_list_of_xy([x0s, x1s], [y0s, y1s], pixel_scale=hdr["CDELT1"]) if hdr["NAXIS"] == 3: # Look 0.5*wdel past the fov edges in each direction to catch any # slices where the middle wavelength value doesn't fall inside the # fov waverange, but up to 50% of the slice is actually inside the # fov waverange: # E.g. FOV: [1.92, 2.095], HDU bin centres: [1.9, 2.0, 2.1] # CDELT3 = 0.1, and HDU bin edges: [1.85, 1.95, 2.05, 2.15] # So 1.9 slice needs to be multiplied by 0.3, and 2.1 slice should be # multipled by 0.45 to reach the scaled contribution of the edge slices # This scaling factor is: # f = ((hdu_bin_centre - fov_edge [+/-] 0.5 * cdelt3) % cdelt3) / cdelt3 hdu_waves = get_cube_waveset(hdr) wdel = hdr["CDELT3"] wunit = u.Unit(hdr.get("CUNIT3", "AA")) fov_waves = utils.quantify(fov_volume["waves"], u.um).to(wunit).value mask = ((hdu_waves > fov_waves[0] - 0.5 * wdel) * (hdu_waves <= fov_waves[1] + 0.5 * wdel)) # need to go [+/-] half a bin # OC [2021-12-14] if fov range is not covered by the source return nothing if not np.any(mask): print("FOV {} um - {} um: not covered by Source".format(fov_waves[0], fov_waves[1])) return None i0p, i1p = np.where(mask)[0][0], np.where(mask)[0][-1] f0 = (abs(hdu_waves[i0p] - fov_waves[0] + 0.5 * wdel) % wdel) / wdel # blue edge f1 = (abs(hdu_waves[i1p] - fov_waves[1] - 0.5 * wdel) % wdel) / wdel # red edge data = imagehdu.data[i0p:i1p+1, y0p:y1p, x0p:x1p] data[0, :, :] *= f0 if i1p > i0p: data[-1, :, :] *= f1 # w0, w1 : the closest cube wavelengths outside the fov edge wavelengths # fov_waves : the fov edge wavelengths # f0, f1 : the scaling factors for the blue and red edge cube slices # # w0, w1 = hdu_waves[i0p], hdu_waves[i1p] # print(f"\nw0: {w0}, f0: {f0}, {fov_waves}, f1: {f1}, w1: {w1}") new_hdr.update({"NAXIS": 3, "NAXIS3": data.shape[0], "CRVAL3": hdu_waves[i0p], "CRPIX3": 0, "CDELT3": hdr["CDELT3"], "CUNIT3": hdr["CUNIT3"], "CTYPE3": hdr["CTYPE3"], "BUNIT": hdr["BUNIT"]}) else: data = imagehdu.data[y0p:y1p, x0p:x1p] new_hdr["SPEC_REF"] = hdr.get("SPEC_REF") new_imagehdu = fits.ImageHDU(data=data) new_imagehdu.header.update(new_hdr) return new_imagehdu