def test_all_two_mm_imagehdus_are_inside_header_wcs( self, image_hdu_square_mm, image_hdu_rect_mm): image_hdu_rect_mm.header["CRVAL1D"] -= 40 image_hdu_square_mm.header["CRVAL2D"] += 80 hdr = imp_utils._make_bounding_header_from_imagehdus( [image_hdu_square_mm, image_hdu_rect_mm], pixel_scale=1 * u.mm) for imhdr in [image_hdu_square_mm.header, image_hdu_rect_mm.header]: x, y = imp_utils.calc_footprint(imhdr, "D") x, y = imp_utils.val2pix(hdr, x, y, "D") for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] if PLOTS: for imhdr in [ image_hdu_square_mm.header, image_hdu_rect_mm.header, hdr ]: x, y = imp_utils.calc_footprint(imhdr, "D") xp, yp = imp_utils.val2pix(imhdr, x, y, "D") plt.plot(x, y, "r-") plt.plot(0, 0, "ro") plt.gca().set_aspect(1) plt.show()
def test_returns_the_desired_number_of_fovs(self, mvs_effects_list, mvs_usr_cmds): rc.__currsys__ = UserCommands(yamls=mvs_usr_cmds) rc.__currsys__["!SIM.computing.max_segment_size"] = 2**20 fov_man = FOVManager(mvs_effects_list) fovs = fov_man.generate_fovs_list() implane_size = mvs_effects_list[-2].image_plane_header["NAXIS1"] chunk_size = sim.rc.__currsys__["!SIM.computing.chunk_size"] wave_layers = 1 assert len(fovs) == np.round( implane_size / chunk_size)**2 * wave_layers # ..todo:: go searching for the white line if PLOTS: plt.subplot(121) for fov in fovs: from scopesim.optics.image_plane_utils import calc_footprint x, y = calc_footprint(fov.hdu.header) plt.fill(x * 3600, y * 3600) plt.subplot(122) for fov in fovs: from scopesim.optics.image_plane_utils import calc_footprint x, y = calc_footprint(fov.hdu.header, "D") plt.plot(x, y) plt.show()
def test_returns_set_of_headers_from_detector_list_effect(self): # det = eo._full_detector_list() det = eo._detector_list() kwargs = { "pixel_scale": 0.004, "plate_scale": 0.26666666666, "max_segment_size": 2048**2, "chunk_size": 1024 } hdrs = fm_utils.get_imaging_headers([det], **kwargs) area_sum = np.sum([hdr["NAXIS1"] * hdr["NAXIS2"] for hdr in hdrs]) assert area_sum == 4096**2 if PLOTS: plt.subplot(121) for hdr in hdrs: from scopesim.optics.image_plane_utils import calc_footprint x, y = calc_footprint(hdr) plt.plot(x * 3600, y * 3600) plt.title("Sky plane") plt.xlabel("[arcsec]") plt.subplot(122) for hdr in hdrs: from scopesim.optics.image_plane_utils import calc_footprint x, y = calc_footprint(hdr, "D") plt.plot(x, y) plt.title("Detector focal plane") plt.xlabel("[mm]") plt.show()
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 test_all_5_objects_are_inside_header_wcs(self, image_hdu_square, image_hdu_rect, input_table): tbl1 = deepcopy(input_table) tbl2 = deepcopy(input_table) tbl3 = deepcopy(input_table) tbl2["x"] -= 150 tbl3["y"] -= 100 image_hdu_rect.header["CRVAL1"] += 100 * u.arcsec.to(u.deg) image_hdu_square.header["CRVAL1"] += 0 * u.arcsec.to(u.deg) image_hdu_square.header["CRVAL2"] += 100 * u.arcsec.to(u.deg) hdr = imp_utils.get_canvas_header( [image_hdu_square, tbl1, tbl2, tbl3, image_hdu_rect], pixel_scale=1 * u.arcsec) for im in [image_hdu_square.header, image_hdu_rect.header]: x, y = imp_utils.calc_footprint(im) x, y = imp_utils.val2pix(hdr, x, y) for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] as2deg = u.arcsec.to(u.deg) for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x"] * as2deg, tbl["y"] * as2deg) for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] if PLOTS: x, y = imp_utils.calc_footprint(hdr) x, y = imp_utils.val2pix(hdr, x, y) plt.plot(x, y, "b") x0, y0 = imp_utils.val2pix(hdr, 0, 0) plt.plot(x0, y0, "ro") for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x"] * as2deg, tbl["y"] * as2deg) plt.plot(x, y, "k.") for im in [image_hdu_square.header, image_hdu_rect.header]: x, y = imp_utils.calc_footprint(im) x, y = imp_utils.val2pix(hdr, x, y) plt.plot(x, y, "r-") plt.gca().set_aspect(1) plt.show()
def test_all_5_objects_are_inside_mm_header_wcs(self, image_hdu_square_mm, image_hdu_rect_mm, input_table_mm): tbl1 = deepcopy(input_table_mm) tbl2 = deepcopy(input_table_mm) tbl3 = deepcopy(input_table_mm) tbl2["x_mm"] -= 150 tbl3["y_mm"] -= 100 image_hdu_rect_mm.header["CRVAL1D"] += 100 image_hdu_square_mm.header["CRVAL1D"] += 0 image_hdu_square_mm.header["CRVAL2D"] += 100 hdr = imp_utils.get_canvas_header( [image_hdu_square_mm, tbl1, tbl2, tbl3, image_hdu_rect_mm], pixel_scale=1 * u.mm) for im in [image_hdu_square_mm.header, image_hdu_rect_mm.header]: x, y = imp_utils.calc_footprint(im, "D") x, y = imp_utils.val2pix(hdr, x, y, "D") for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x_mm"], tbl["y_mm"], "D") for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] if PLOTS: x, y = imp_utils.calc_footprint(hdr, "D") x, y = imp_utils.val2pix(hdr, x, y, "D") plt.plot(x, y, "b") x0, y0 = imp_utils.val2pix(hdr, 0, 0, "D") plt.plot(x0, y0, "ro") for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x_mm"], tbl["y_mm"], "D") plt.plot(x, y, "k.") for im in [image_hdu_square_mm.header, image_hdu_rect_mm.header]: x, y = imp_utils.calc_footprint(im, "D") x, y = imp_utils.val2pix(hdr, x, y, "D") plt.plot(x, y, "r-") plt.gca().set_aspect(1) plt.show()
def test_image_is_added_to_small_canvas(self, image_hdu_rect, image_hdu_square): im_hdu = image_hdu_rect im_hdu.header["CRVAL1"] -= 150 * u.arcsec.to(u.deg) im_hdu.header["CRVAL2"] += 40 * u.arcsec.to(u.deg) hdr = imp_utils.get_canvas_header([im_hdu, image_hdu_square]) im = np.zeros((hdr["NAXIS2"], hdr["NAXIS1"])) canvas_hdu = fits.ImageHDU(header=hdr, data=im) canvas_hdu = imp_utils.add_imagehdu_to_imagehdu(im_hdu, canvas_hdu) canvas_hdu = imp_utils.add_imagehdu_to_imagehdu( image_hdu_square, canvas_hdu) flux = np.sum(im_hdu.data) + np.sum(image_hdu_square.data) assert np.sum(canvas_hdu.data) == approx(flux, rel=1e-2) if PLOTS: for im in [im_hdu, image_hdu_square]: x, y = imp_utils.calc_footprint(im.header) x, y = imp_utils.val2pix(canvas_hdu.header, x, y) plt.plot(x, y, "r-") x0, y0 = imp_utils.val2pix(canvas_hdu.header, 0, 0) plt.plot(x0, y0, "ro") plt.gca().set_aspect(1) plt.imshow(canvas_hdu.data, origin="lower") plt.show()
def test_mm_image_is_added_to_small_canvas(self, image_hdu_rect_mm, image_hdu_square_mm): im_hdu = image_hdu_rect_mm im_hdu.header["CRVAL1D"] -= 150 im_hdu.header["CRVAL2D"] += 40 hdr = imp_utils.get_canvas_header([im_hdu, image_hdu_square_mm], pixel_scale=1 * u.mm) im = np.zeros((hdr["NAXIS2"], hdr["NAXIS1"])) canvas_hdu = fits.ImageHDU(header=hdr, data=im) canvas_hdu = imp_utils.add_imagehdu_to_imagehdu(im_hdu, canvas_hdu, wcs_suffix="D") assert np.sum(canvas_hdu.data) == approx(np.sum(im_hdu.data)) if PLOTS: for im in [im_hdu, image_hdu_square_mm]: x, y = imp_utils.calc_footprint(im.header, "D") x, y = imp_utils.val2pix(canvas_hdu.header, x, y, "D") plt.plot(x, y, "r-") x0, y0 = imp_utils.val2pix(canvas_hdu.header, 0, 0, "D") plt.plot(x0, y0, "ro") plt.gca().set_aspect(1) plt.imshow(canvas_hdu.data, origin="lower") plt.show()
def test_all_three_tables_are_inside_header_wcs(self, input_table): tbl1 = deepcopy(input_table) tbl2 = deepcopy(input_table) tbl3 = deepcopy(input_table) tbl2["x"] -= 25 tbl3["y"] -= 60 hdr = imp_utils._make_bounding_header_for_tables([tbl1, tbl2, tbl3]) as2deg = u.arcsec.to(u.deg) for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x"] * as2deg, tbl["y"] * as2deg) for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] if PLOTS: x, y = imp_utils.calc_footprint(hdr) x, y = imp_utils.val2pix(hdr, x, y) x0, y0 = imp_utils.val2pix(hdr, 0, 0) plt.plot(x, y, "b") plt.plot(x0, y0, "ro") for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x"] / 3600., tbl["y"] / 3600.) plt.plot(x, y, "k.") plt.show()
def test_all_three_mm_tables_are_inside_header_wcs(self, input_table_mm): tbl1 = deepcopy(input_table_mm) tbl2 = deepcopy(input_table_mm) tbl3 = deepcopy(input_table_mm) tbl2["x_mm"] += 50 tbl3["y_mm"] += 25 hdr = imp_utils._make_bounding_header_for_tables([tbl1, tbl2, tbl3], 100 * u.um) for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x_mm"], tbl["y_mm"], "D") for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] if PLOTS: x, y = imp_utils.calc_footprint(hdr, "D") x, y = imp_utils.val2pix(hdr, x, y, "D") x0, y0 = imp_utils.val2pix(hdr, 0, 0, "D") plt.plot(x, y, "b") plt.plot(x0, y0, "ro") for tbl in [tbl1, tbl2, tbl3]: x, y = imp_utils.val2pix(hdr, tbl["x_mm"], tbl["y_mm"], "D") plt.plot(x, y, "k.") plt.show()
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_add_many_mm_tables_and_imagehdus(self, input_table_mm, image_hdu_rect_mm, image_hdu_square_mm): image_hdu_rect = image_hdu_rect_mm image_hdu_square = image_hdu_square_mm tbl1 = deepcopy(input_table_mm) tbl2 = deepcopy(input_table_mm) tbl1["y_mm"] -= 50 tbl2["x_mm"] += 50 tbl2["y_mm"] += 50 im_hdu = image_hdu_rect im_hdu.header["CRVAL1D"] -= 150 # mm im_hdu.header["CRVAL2D"] += 20 fields = [im_hdu, tbl1, tbl2, image_hdu_square] hdr = imp_utils.get_canvas_header(fields, pixel_scale=1 * u.mm) implane = opt_imp.ImagePlane(hdr) implane.add(fields, wcs_suffix="D") total_flux = np.sum(tbl1["flux"]) + np.sum(tbl2["flux"]) + \ np.sum(im_hdu.data) + np.sum(image_hdu_square.data) assert np.sum(implane.data) == approx(total_flux) if PLOTS: for im in [im_hdu, image_hdu_square]: x, y = imp_utils.calc_footprint(im.header, "D") x, y = imp_utils.val2pix(implane.header, x, y, "D") plt.plot(x, y, "r-") for tbl in [tbl1, tbl2]: hdr = imp_utils._make_bounding_header_for_tables( [tbl], pixel_scale=1 * u.mm) x, y = imp_utils.calc_footprint(hdr, "D") x, y = imp_utils.val2pix(implane.header, x, y, "D") plt.plot(x, y, "r-") x0, y0 = imp_utils.val2pix(implane.header, 0, 0, "D") plt.plot(x0, y0, "ro") plt.gca().set_aspect(1) plt.imshow(implane.data, origin="lower", norm=LogNorm()) plt.show()
def test_returns_wavelength_cut_cube_for_thin_fov(self, cube_source, basic_fov_header): fov = FieldOfView(basic_fov_header, [1.3, 1.7]) field = cube_source.fields[0] new_field = fov_utils.extract_area_from_imagehdu(field, fov.volume()) if PLOTS: x, y = imp_utils.calc_footprint(basic_fov_header) plt.fill(x, y, c="r") x, y = imp_utils.calc_footprint(field.header) plt.fill(x, y, c="y") x, y = imp_utils.calc_footprint(new_field.header) plt.fill(x, y, c="g") plt.show() assert new_field.header["NAXIS1"] == field.header["NAXIS1"] assert new_field.header["NAXIS2"] == field.header["NAXIS2"] assert new_field.header["NAXIS3"] == 21
def test_returns_fov_objects_for_basic_input(self): apm = eo._img_aperture_mask(array_dict={ "x": [-1.0, 1.0, 1.0, -1.0], "y": [-1.0, -1.0, 1.0, 1.0] }) kwargs = { "pixel_scale": 0.01, "plate_scale": 1, "max_segment_size": 100**2, "chunk_size": 100 } hdrs = fm_utils.get_imaging_headers([apm], **kwargs) waveset = np.linspace(1, 2, 6) shifts = { "wavelengths": np.array([1, 2]), "x_shifts": np.zeros(2), "y_shifts": np.array([0, 1]) / 3600 } # 0..1 arcsec shift fovs = fm_utils.get_imaging_fovs(headers=hdrs, waveset=waveset, shifts=shifts) assert len(fovs) == (len(waveset) - 1) * len(hdrs) if PLOTS: from scopesim.optics.image_plane_utils import calc_footprint plt.subplot(121) for fov in fovs: x, y = calc_footprint(fov.hdu.header) plt.fill(x * 3600, y * 3600, alpha=0.1, c="b") plt.title("Sky plane") plt.xlabel("[arcsec]") plt.subplot(122) for fov in fovs: x, y = calc_footprint(fov.hdu.header, "D") plt.fill(x, y) plt.title("Detector focal plane") plt.xlabel("[mm]") plt.show()
def test_returns_right_sky_coords_from_known_coords( self, image_hdu_square): xsky, ysky = imp_utils.calc_footprint(image_hdu_square.header) xsky = np.array(xsky) xsky[xsky > 180] -= 360 xsky = np.array(xsky) * u.deg.to(u.arcsec) ysky = np.array(ysky) * u.deg.to(u.arcsec) dx = max(xsky) - min(xsky) dy = max(ysky) - min(ysky) assert dx == approx(image_hdu_square.header["NAXIS1"]) assert dy == approx(image_hdu_square.header["NAXIS2"])
def test_add_many_tables_and_imagehdus(self, input_table, image_hdu_rect, image_hdu_square): tbl1 = deepcopy(input_table) tbl2 = deepcopy(input_table) tbl1["y"] -= 50 tbl2["x"] += 50 tbl2["y"] += 50 im_hdu = image_hdu_rect im_hdu.header["CRVAL1"] -= 150 * u.arcsec.to(u.deg) im_hdu.header["CRVAL2"] += 20 * u.arcsec.to(u.deg) fields = [im_hdu, tbl1, tbl2, image_hdu_square] hdr = imp_utils.get_canvas_header(fields, pixel_scale=1 * u.arcsec) implane = opt_imp.ImagePlane(hdr) implane.add(fields) total_flux = np.sum(tbl1["flux"]) + np.sum(tbl2["flux"]) + \ np.sum(im_hdu.data) + np.sum(image_hdu_square.data) assert np.sum(implane.data) == approx(total_flux) if PLOTS: for im in [im_hdu, image_hdu_square]: x, y = imp_utils.calc_footprint(im.header) x, y = imp_utils.val2pix(implane.header, x, y) plt.plot(x, y, "r-") for tbl in [tbl1, tbl2]: hdr = imp_utils._make_bounding_header_for_tables([tbl]) x, y = imp_utils.calc_footprint(hdr) x, y = imp_utils.val2pix(implane.header, x, y) plt.plot(x, y, "r-") x0, y0 = imp_utils.val2pix(implane.header, 0, 0) plt.plot(x0, y0, "ro") plt.gca().set_aspect(1) plt.imshow(implane.data, origin="lower", norm=LogNorm()) plt.show()
def test_mm_image_and_tables_on_large_canvas(self, input_table_mm, image_hdu_rect_mm, image_hdu_square_mm): image_hdu_rect = image_hdu_rect_mm image_hdu_square = image_hdu_square_mm tbl1 = deepcopy(input_table_mm) tbl2 = deepcopy(input_table_mm) tbl1["y_mm"] -= 100 tbl2["x_mm"] += 100 tbl2["y_mm"] += 100 im_hdu = image_hdu_rect im_hdu.header["CRVAL1D"] -= 150 im_hdu.header["CRVAL2D"] += 20 hdr = imp_utils.get_canvas_header( [im_hdu, image_hdu_square, tbl1, tbl2], pixel_scale=3 * u.mm) im = np.zeros((hdr["NAXIS2"], hdr["NAXIS1"])) canvas_hdu = fits.ImageHDU(header=hdr, data=im) canvas_hdu = imp_utils.add_table_to_imagehdu(tbl1, canvas_hdu, wcs_suffix="D") canvas_hdu = imp_utils.add_table_to_imagehdu(tbl2, canvas_hdu, wcs_suffix="D") canvas_hdu = imp_utils.add_imagehdu_to_imagehdu(im_hdu, canvas_hdu, wcs_suffix="D") canvas_hdu = imp_utils.add_imagehdu_to_imagehdu(image_hdu_square, canvas_hdu, wcs_suffix="D") total_flux = np.sum(tbl1["flux"]) + np.sum(tbl2["flux"]) + \ np.sum(im_hdu.data) + np.sum(image_hdu_square.data) assert np.sum(canvas_hdu.data) == approx(total_flux) if PLOTS: for im in [im_hdu, image_hdu_square]: x, y = imp_utils.calc_footprint(im, "D") x, y = imp_utils.val2pix(canvas_hdu, x, y, "D") plt.plot(x, y, "r-") x0, y0 = imp_utils.val2pix(canvas_hdu, 0, 0, "D") plt.plot(x0, y0, "ro") plt.gca().set_aspect(1) plt.imshow(canvas_hdu.data, origin="lower") plt.show()
def test_returns_eigth_cube_for_3d_offset_fov(self, cube_source, basic_fov_header): hdr = basic_fov_header hdr["CRVAL1"] += 75 * hdr["CDELT1"] hdr["CRVAL2"] += 75 * hdr["CDELT2"] fov = FieldOfView(hdr, [1.5, 2.5]) field = cube_source.fields[0] new_field = fov_utils.extract_area_from_imagehdu(field, fov.volume()) if PLOTS: x, y = imp_utils.calc_footprint(basic_fov_header) plt.fill(x, y, c="r") x, y = imp_utils.calc_footprint(field.header) plt.fill(x, y, c="y") x, y = imp_utils.calc_footprint(new_field.header) plt.fill(x, y, c="g") plt.show() assert new_field.header["NAXIS1"] == 26 assert new_field.header["NAXIS2"] == 26 assert new_field.header["NAXIS3"] == 51
def test_all_two_imagehdus_are_inside_header_wcs(self, image_hdu_square, image_hdu_rect): image_hdu_rect.header["CRVAL1"] -= 70 * u.arcsec.to(u.deg) image_hdu_square.header["CRVAL2"] += 70 * u.arcsec.to(u.deg) hdr = imp_utils._make_bounding_header_from_imagehdus( [image_hdu_square, image_hdu_rect]) for imhdr in [image_hdu_square.header, image_hdu_rect.header]: x, y = imp_utils.calc_footprint(imhdr) x, y = imp_utils.val2pix(hdr, x, y) for xi, yi in zip(x, y): assert 0 <= xi < hdr["NAXIS1"] assert 0 <= yi < hdr["NAXIS2"] if PLOTS: for imhdr in [image_hdu_square.header, image_hdu_rect.header, hdr]: x, y = imp_utils.calc_footprint(imhdr) xp, yp = imp_utils.val2pix(imhdr, x, y) plt.plot(x, y, "r-") plt.plot(0, 0, "ro") plt.gca().set_aspect(1) plt.show()
def combine_table_fields(fov_header, src, field_indexes): """ Combines a list of Table objects into a single one bounded by the Header WCS Parameters ---------- fov_header : fits.Header Header from a FieldOfView objects src : Source object field_indexes : list of int Returns ------- tbl : Table """ fov_xsky, fov_ysky = imp_utils.calc_footprint(fov_header) x, y, ref, weight = [], [], [], [] for ii in field_indexes: field = src.fields[ii] if isinstance(field, Table): xcol = utils.quantity_from_table("x", field, u.arcsec) ycol = utils.quantity_from_table("y", field, u.arcsec) x += list(xcol.to(u.deg).value) y += list(ycol.to(u.deg).value) ref += list(field["ref"]) weight += list(field["weight"]) x = np.array(x) y = np.array(y) mask = np.array(x < max(fov_xsky)) * np.array(x > min(fov_xsky)) * \ np.array(y < max(fov_ysky)) * np.array(y > min(fov_ysky)) x = x[mask] y = y[mask] ref = np.array(ref)[mask] weight = np.array(weight)[mask] tbl = Table(names=["x", "y", "ref", "weight"], data=[x, y, ref, weight]) tbl["x"].unit = u.deg tbl["y"].unit = u.deg return tbl
def test_works_seamlessly_for_hawki_package(self, capsys): cmd = scopesim.UserCommands(use_instrument="HAWKI") opt = scopesim.OpticalTrain(cmd) # test that the major values have been updated in rc.__currsys__ assert rc.__currsys__["!TEL.area"].value == approx(52.81, rel=1e-3) assert rc.__currsys__["!TEL.etendue"].value == approx(0.5934, rel=1e-3) assert rc.__currsys__["!INST.pixel_scale"] == approx(0.106, rel=1e-3) # test that OpticalTrain builds properly assert isinstance(opt, scopesim.OpticalTrain) # test that we have a system throughput wave = np.linspace(0.7, 2.5, 181) * u.um tc = opt.optics_manager.surfaces_table.throughput ec = opt.optics_manager.surfaces_table.emission # ..todo:: something super wierd is going on here when running pytest in the top directory assert 0.55 < np.max(tc(wave)) < 0.7 if PLOTS: plt.plot(wave, tc(wave)) plt.show() if PLOTS: plt.plot(wave, ec(wave)) plt.show() # test that we have the correct number of FOVs for Ks band assert len(opt.fov_manager.fovs) == 9 if PLOTS: fovs = opt.fov_manager.fovs from scopesim.optics.image_plane_utils import calc_footprint plt.subplot(121) for fov in fovs: x, y = calc_footprint(fov.hdu.header) plt.fill(x*3600, y*3600, alpha=0.1, c="b") plt.title("Sky plane") plt.xlabel("[arcsec]") plt.subplot(122) for fov in fovs: x, y = calc_footprint(fov.hdu.header, "D") plt.fill(x, y) plt.title("Detector focal plane") plt.xlabel("[mm]") plt.show() # test that the ImagePlane is large enough assert opt.image_planes[0].header["NAXIS1"] > 4200 assert opt.image_planes[0].header["NAXIS2"] > 4200 assert np.all(opt.image_planes[0].data == 0) # test assert there are 4 detectors, each 2048x2048 pixels hdu = opt.readout()[0] assert len(opt.detector_arrays[0].detectors) == 4 for detector in opt.detector_arrays[0].detectors: assert detector.hdu.header["NAXIS1"] == 2048 assert detector.hdu.header["NAXIS2"] == 2048 if PLOTS: for i in range(1, 5): plt.subplot(2, 2, i) plt.imshow(hdu[i].data) plt.show() dit = rc.__currsys__["!OBS.dit"] ndit = rc.__currsys__["!OBS.ndit"] assert np.average(hdu[1].data) == approx(ndit * dit * 0.1, abs=0.5)
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