def test_chart_with_wcs(): """test cartographer.chart""" helpers.setup(with_data=True) out_dir = helpers.TEST_PATH title = "test" map_layer_names = "test_layer" marker_file_names = "test_marker" wcs = WCS(os.path.join(out_dir, "test_image.fits")) columns = "a,b,c" with open(os.path.join(out_dir, f"{marker_file_names}.columns"), "w") as f: f.write(columns) list( map( lambda r: os.makedirs( os.path.join(out_dir, map_layer_names, str(r))), range(2), )) os.mkdir(os.path.join(out_dir, "js")) os.mkdir(os.path.join(out_dir, "css")) c.chart( out_dir, title, [map_layer_names], [marker_file_names], wcs, float("inf"), [100, 100], ) # inject current version in to test_index.html version = helpers.get_version() raw_path = os.path.join(out_dir, "test_index_wcs.html") with open(raw_path, "r") as f: converted = list( map(lambda l: l.replace("VERSION", version), f.readlines())) with open(raw_path, "w") as f: f.writelines(converted) actual_html = os.path.join(out_dir, "index.html") expected_html = os.path.join(out_dir, "test_index_wcs.html") files_match = filecmp.cmp(expected_html, actual_html) helpers.tear_down() assert files_match
def test_time_1d_location_geocenter(header_time_1d_no_obs): header_time_1d_no_obs['TREFPOS'] = 'GEOCENTER' wcs = WCS(header_time_1d_no_obs) time = wcs.pixel_to_world(10) x, y, z = time.location.to_geocentric() assert_allclose(x.to_value(u.m), 0) assert_allclose(y.to_value(u.m), 0) assert_allclose(z.to_value(u.m), 0)
def spatial_wcs_2d_small_angle(): """ This WCS has an almost linear correlation between the pixel and world axes close to the reference pixel. """ wcs = WCS(naxis=2) wcs.wcs.ctype = ['HPLN-TAN', 'HPLT-TAN'] wcs.wcs.crpix = [3.0] * 2 wcs.wcs.cdelt = [0.002] * 2 wcs.wcs.crval = [0] * 2 wcs.wcs.set() return wcs
def test_pixel_to_world_correlation_matrix_spectral_cube_correlated(): wcs = WCS(naxis=3) wcs.wcs.ctype = 'RA---TAN', 'FREQ', 'DEC--TAN' wcs.wcs.cd = np.ones((3, 3)) wcs.wcs.set() assert_equal(wcs.axis_correlation_matrix, [[1, 1, 1], [1, 1, 1], [1, 1, 1]]) matrix, classes = _pixel_to_world_correlation_matrix(wcs) assert_equal(matrix, [[1, 1, 1], [1, 1, 1]]) assert classes == [SkyCoord, Quantity]
def getCenterRADec(header): """ Returns RA,Dec for the image center. :param header: must also contain IMAGEW and IMAGEH :rtype: tuple (ra,dec) in degrees, ra is [0,360], dec is [-90,90] """ w = header['IMAGEW'] h = header['IMAGEH'] del header[ 'NAXIS'] # emits a warning in WCS constructor if present (as it's 0 for .wcs files) return WCS(header).all_pix2world(w / 2, h / 2, 0, ra_dec_order=True)
def test_time_1d_location_unsupported(header_time_1d_no_obs): # Check what happens when TREFPOS is unsupported header_time_1d_no_obs['TREFPOS'] = 'BARYCENTER' wcs = WCS(header_time_1d_no_obs) with pytest.warns(UserWarning, match="Observation location 'barycenter' is not " "supported, setting location in Time to None"): time = wcs.pixel_to_world(10) assert time.location is None
def test_time_1d_location_incomplete(header_time_1d_noobs): # Check what happens when location information is incomplete header_time_1d_noobs['OBSGEO-L'] = 10. wcs = WCS(header_time_1d_noobs) with pytest.warns(UserWarning, match='Missing or incomplete observer location ' 'information, setting location in Time to None'): time = wcs.pixel_to_world(10) assert time.location is None
def test_time_1d_unsupported_ctype(header_time_1d_no_obs): # For cases that we don't support yet, e.g. UT(...), use Time and drop sub-scale # Case where the MJDREF is split into two for high precision header_time_1d_no_obs['CTYPE1'] = 'UT(WWV)' wcs = WCS(header_time_1d_no_obs) with pytest.warns(UserWarning, match="Dropping unsupported sub-scale WWV from scale UT"): time = wcs.pixel_to_world(10) assert isinstance(time, Time)
def test_wcs_swapping(): wcs = WCS(naxis=4) wcs.wcs.pc = np.zeros([4, 4]) np.fill_diagonal(wcs.wcs.pc, np.arange(1, 5)) pc = wcs.wcs.pc # for later use below swapped = wcs.swapaxes(0, 1) assert np.all(swapped.wcs.get_pc().diagonal() == np.array([2, 1, 3, 4])) swapped = wcs.swapaxes(0, 3) assert np.all(swapped.wcs.get_pc().diagonal() == np.array([4, 2, 3, 1])) swapped = wcs.swapaxes(2, 3) assert np.all(swapped.wcs.get_pc().diagonal() == np.array([1, 2, 4, 3])) wcs = WCS(naxis=4) wcs.wcs.cd = pc swapped = wcs.swapaxes(0, 1) assert np.all(swapped.wcs.get_pc().diagonal() == np.array([2, 1, 3, 4])) swapped = wcs.swapaxes(0, 3) assert np.all(swapped.wcs.get_pc().diagonal() == np.array([4, 2, 3, 1])) swapped = wcs.swapaxes(2, 3) assert np.all(swapped.wcs.get_pc().diagonal() == np.array([1, 2, 4, 3]))
def test_time_1d_location_geodetic(header_time_1d): # Make sure that the location is correctly returned (geodetic case) wcs = WCS(header_time_1d) time = wcs.pixel_to_world(10) lon, lat, alt = time.location.to_geodetic() # FIXME: alt won't work for now because ERFA doesn't implement the IAU 1976 # ellipsoid (https://github.com/astropy/astropy/issues/9420) assert_allclose(lon.degree, -20) assert_allclose(lat.degree, -70)
def test_fit_wcs_from_points_CRPIX_bounds(): # Test CRPIX bounds requirement wcs_str = """ WCSAXES = 2 / Number of coordinate axes CRPIX1 = 1045.0 / Pixel coordinate of reference point CRPIX2 = 1001.0 / Pixel coordinate of reference point PC1_1 = 0.00056205870415378 / Coordinate transformation matrix element PC1_2 = -0.00569181083243 / Coordinate transformation matrix element PC2_1 = 0.0056776810932466 / Coordinate transformation matrix element PC2_2 = 0.0004208048403273 / Coordinate transformation matrix element CDELT1 = 1.0 / [deg] Coordinate increment at reference point CDELT2 = 1.0 / [deg] Coordinate increment at reference point CUNIT1 = 'deg' / Units of coordinate increment and value CUNIT2 = 'deg' / Units of coordinate increment and value CTYPE1 = 'RA---TAN' / Right ascension, gnomonic projection CTYPE2 = 'DEC--TAN' / Declination, gnomonic projection CRVAL1 = 104.57797893504 / [deg] Coordinate value at reference point CRVAL2 = -74.195502593322 / [deg] Coordinate value at reference point LONPOLE = 180.0 / [deg] Native longitude of celestial pole LATPOLE = -74.195502593322 / [deg] Native latitude of celestial pole TIMESYS = 'TDB' / Time scale TIMEUNIT= 'd' / Time units DATEREF = '1858-11-17' / ISO-8601 fiducial time MJDREFI = 0.0 / [d] MJD of fiducial time, integer part MJDREFF = 0.0 / [d] MJD of fiducial time, fractional part DATE-OBS= '2019-03-27T03:30:13.832Z' / ISO-8601 time of observation MJD-OBS = 58569.145993426 / [d] MJD of observation MJD-OBS = 58569.145993426 / [d] MJD at start of observation TSTART = 1569.6467941661 / [d] Time elapsed since fiducial time at start DATE-END= '2019-03-27T04:00:13.831Z' / ISO-8601 time at end of observation MJD-END = 58569.166826748 / [d] MJD at end of observation TSTOP = 1569.6676274905 / [d] Time elapsed since fiducial time at end TELAPSE = 0.02083332443 / [d] Elapsed time (start to stop) TIMEDEL = 0.020833333333333 / [d] Time resolution TIMEPIXR= 0.5 / Reference position of timestamp in binned data RADESYS = 'ICRS' / Equatorial coordinate system """ wcs_header = fits.Header.fromstring(wcs_str, sep='\n') ffi_wcs = WCS(wcs_header) yi, xi = (1000, 1000) y, x = (10, 200) center_coord = SkyCoord(ffi_wcs.all_pix2world([[xi+x//2, yi+y//2]], 0), unit='deg')[0] ypix, xpix = [arr.flatten() for arr in np.mgrid[xi : xi + x, yi : yi + y]] world_pix = SkyCoord(*ffi_wcs.all_pix2world(xpix, ypix, 0), unit='deg') fit_wcs = fit_wcs_from_points((ypix, xpix), world_pix, proj_point='center') assert (fit_wcs.wcs.crpix.astype(int) == [1100, 1005]).all() assert fit_wcs.pixel_shape == (1199, 1009)
def test_pixel_to_pixel_correlation_matrix_mismatch(): wcs_in = WCS(naxis=2) wcs_in.wcs.ctype = 'RA---TAN', 'DEC--TAN' wcs_in.wcs.set() wcs_out = WCS(naxis=3) wcs_out.wcs.ctype = 'DEC--TAN', 'FREQ', 'RA---TAN' wcs_out.wcs.set() with pytest.raises(ValueError) as exc: _pixel_to_pixel_correlation_matrix(wcs_in, wcs_out) assert exc.value.args[ 0] == "The two WCS return a different number of world coordinates" wcs3 = WCS(naxis=2) wcs3.wcs.ctype = 'FREQ', 'PIXEL' wcs3.wcs.set() with pytest.raises(ValueError) as exc: _pixel_to_pixel_correlation_matrix(wcs_out, wcs3) assert exc.value.args[ 0] == "The world coordinate types of the two WCS do not match" wcs4 = WCS(naxis=4) wcs4.wcs.ctype = 'RA---TAN', 'DEC--TAN', 'Q1', 'Q2' wcs4.wcs.cunit = ['deg', 'deg', 'm/s', 'm/s'] wcs4.wcs.set() wcs5 = WCS(naxis=4) wcs5.wcs.ctype = 'Q1', 'RA---TAN', 'DEC--TAN', 'Q2' wcs5.wcs.cunit = ['m/s', 'deg', 'deg', 'm/s'] wcs5.wcs.set() with pytest.raises(ValueError, match="World coordinate order doesn't match " "and automatic matching is ambiguous"): _pixel_to_pixel_correlation_matrix(wcs4, wcs5)
def test_invalid_slice(): mywcs = WCS(naxis=2) with pytest.raises(ValueError) as exc: mywcs[0] assert exc.value.args[0] == ("Cannot downsample a WCS with indexing. Use " "wcs.sub or wcs.dropaxis if you want to remove " "axes.") with pytest.raises(ValueError) as exc: mywcs[0, ::2] assert exc.value.args[0] == ("Cannot downsample a WCS with indexing. Use " "wcs.sub or wcs.dropaxis if you want to remove " "axes.")
def test_time_1d_high_precision(header_time_1d): # Case where the MJDREF is split into two for high precision del header_time_1d['MJDREF'] header_time_1d['MJDREFI'] = 52000. header_time_1d['MJDREFF'] = 1e-11 wcs = WCS(header_time_1d) time = wcs.pixel_to_world(10) # Here we have to use a very small rtol to really test that MJDREFF is # taken into account assert_allclose(time.jd1, 2452001.0, rtol=1e-12) assert_allclose(time.jd2, -0.5 + 25 / 3600 / 24 + 1e-11, rtol=1e-13)
def test_wcs_to_celestial_frame_correlated(): # Regression test for a bug that caused wcs_to_celestial_frame to fail when # the celestial axes were correlated with other axes. # Import astropy.coordinates here to avoid circular imports from astropy.coordinates.builtin_frames import ICRS mywcs = WCS(naxis=3) mywcs.wcs.ctype = 'RA---TAN', 'DEC--TAN', 'FREQ' mywcs.wcs.cd = np.ones((3, 3)) mywcs.wcs.set() frame = wcs_to_celestial_frame(mywcs) assert isinstance(frame, ICRS)
def test_noncelestial_scale(cdelt, pc, cd): mywcs = WCS(naxis=2) if cd is not None: mywcs.wcs.cd = cd if pc is not None: mywcs.wcs.pc = pc mywcs.wcs.cdelt = cdelt mywcs.wcs.ctype = ['RA---TAN', 'FREQ'] ps = non_celestial_pixel_scales(mywcs) assert_almost_equal(ps.to_value(u.deg), np.array([0.1, 0.2]))
def test_pixel_to_world_itrs(x_in, y_in): """Regression test for https://github.com/astropy/astropy/pull/9609""" wcs = WCS({'NAXIS': 2, 'CTYPE1': 'TLON-CAR', 'CTYPE2': 'TLAT-CAR', 'RADESYS': 'ITRS ', 'DATE-OBS': '2017-08-17T12:41:04.444'}) # This shouldn't raise an exception. coord = wcs.pixel_to_world(x_in, y_in) # Check round trip transformation. x, y = wcs.world_to_pixel(coord) np.testing.assert_almost_equal(x, x_in) np.testing.assert_almost_equal(y, y_in)
def test_time_1d_location_incomplete(header_time_1d_no_obs): # Check what happens when location information is incomplete header_time_1d_no_obs['OBSGEO-L'] = 10. with warnings.catch_warnings(): warnings.simplefilter('ignore', FITSFixedWarning) wcs = WCS(header_time_1d_no_obs) with pytest.warns(UserWarning, match='Missing or incomplete observer location ' 'information, setting location in Time to None'): time = wcs.pixel_to_world(10) assert time.location is None
def test_slice_fitsorder(): mywcs = WCS(naxis=2) mywcs.wcs.crval = [1, 1] mywcs.wcs.cdelt = [0.1, 0.1] mywcs.wcs.crpix = [1, 1] slice_wcs = mywcs.slice([slice(1, None), slice(0, None)], numpy_order=False) assert np.all(slice_wcs.wcs.crpix == np.array([0, 1])) slice_wcs = mywcs.slice([slice(1, None, 2), slice(0, None, 4)], numpy_order=False) assert np.all(slice_wcs.wcs.crpix == np.array([0.25, 0.625])) assert np.all(slice_wcs.wcs.cdelt == np.array([0.2, 0.4])) slice_wcs = mywcs.slice([slice(1, None, 2)], numpy_order=False) assert np.all(slice_wcs.wcs.crpix == np.array([0.25, 1])) assert np.all(slice_wcs.wcs.cdelt == np.array([0.2, 0.1]))
def test_noncelestial_scale(cdelt, pc, cd): mywcs = WCS(naxis=2) if cd is not None: mywcs.wcs.cd = cd if pc is not None: mywcs.wcs.pc = pc # TODO: Some inputs emit RuntimeWarning from here onwards. # Fix the test data. See @nden's comment in PR 9010. mywcs.wcs.cdelt = cdelt mywcs.wcs.ctype = ['RA---TAN', 'FREQ'] ps = non_celestial_pixel_scales(mywcs) assert_almost_equal(ps.to_value(u.deg), np.array([0.1, 0.2]))
def test_obsgeo_spherical(dkist_location): obstime = Time("2021-05-21T03:00:00") dkist_location = dkist_location.get_itrs(obstime) loc_sph = dkist_location.spherical wcs = WCS(naxis=2) wcs.wcs.obsgeo = [0, 0, 0] + [ loc_sph.lon.value, loc_sph.lat.value, loc_sph.distance.value ] wcs.wcs.dateobs = obstime.isot frame = obsgeo_to_frame(wcs.wcs.obsgeo, obstime) assert isinstance(frame, ITRS) assert u.allclose(frame.x, dkist_location.x) assert u.allclose(frame.y, dkist_location.y) assert u.allclose(frame.z, dkist_location.z)
def test_skycoord_to_pixel_distortions(mode): # Import astropy.coordinates here to avoid circular imports from astropy.coordinates import SkyCoord header = get_pkg_data_filename('data/sip.fits') wcs = WCS(header) ref = SkyCoord(202.50 * u.deg, 47.19 * u.deg, frame='icrs') xp, yp = skycoord_to_pixel(ref, wcs, mode=mode) # WCS is in FK5 so we need to transform back to ICRS new = pixel_to_skycoord(xp, yp, wcs, mode=mode).transform_to('icrs') assert_allclose(new.ra.degree, ref.ra.degree) assert_allclose(new.dec.degree, ref.dec.degree)
def test_time_1d_location_geocentric(header_time_1d_noobs): # Make sure that the location is correctly returned (geocentric case) header = header_time_1d_noobs header['OBSGEO-X'] = 10 header['OBSGEO-Y'] = -20 header['OBSGEO-Z'] = 30 wcs = WCS(header) time = wcs.pixel_to_world(10) x, y, z = time.location.to_geocentric() assert_allclose(x.to_value(u.m), 10) assert_allclose(y.to_value(u.m), -20) assert_allclose(z.to_value(u.m), 30)
def test_slice_getitem(): mywcs = WCS(naxis=2) mywcs.wcs.crval = [1, 1] mywcs.wcs.cdelt = [0.1, 0.1] mywcs.wcs.crpix = [1, 1] slice_wcs = mywcs[1::2, 0::4] assert np.all(slice_wcs.wcs.crpix == np.array([0.625, 0.25])) assert np.all(slice_wcs.wcs.cdelt == np.array([0.4, 0.2])) mywcs.wcs.crpix = [2, 2] slice_wcs = mywcs[1::2, 0::4] assert np.all(slice_wcs.wcs.crpix == np.array([0.875, 0.75])) assert np.all(slice_wcs.wcs.cdelt == np.array([0.4, 0.2])) # Default: numpy order slice_wcs = mywcs[1::2] assert np.all(slice_wcs.wcs.crpix == np.array([2, 0.75])) assert np.all(slice_wcs.wcs.cdelt == np.array([0.1, 0.2]))
def test_time_1d_roundtrip(header_time_1d, scale): # Check that coordinates round-trip pixel_in = np.arange(3, 10) header_time_1d['CTYPE1'] = scale.upper() wcs = WCS(header_time_1d) # Simple test time = wcs.pixel_to_world(pixel_in) pixel_out = wcs.world_to_pixel(time) assert_allclose(pixel_in, pixel_out) # Test with an intermediate change to a different scale/format time = wcs.pixel_to_world(pixel_in).tdb time.format = 'isot' pixel_out = wcs.world_to_pixel(time) assert_allclose(pixel_in, pixel_out)
def test_time_1d_location_geocentric(header_time_1d_no_obs): # Make sure that the location is correctly returned (geocentric case) header = header_time_1d_no_obs header['OBSGEO-X'] = 10 header['OBSGEO-Y'] = -20 header['OBSGEO-Z'] = 30 with warnings.catch_warnings(): warnings.simplefilter('ignore', FITSFixedWarning) wcs = WCS(header) time = wcs.pixel_to_world(10) x, y, z = time.location.to_geocentric() assert_allclose(x.to_value(u.m), 10) assert_allclose(y.to_value(u.m), -20) assert_allclose(z.to_value(u.m), 30)
def test_noncelestial_scale(cdelt, pc, cd): mywcs = WCS(naxis=2) if cd is not None: mywcs.wcs.cd = cd if pc is not None: mywcs.wcs.pc = pc # TODO: Some inputs emit RuntimeWarning from here onwards. # Fix the test data. See @nden's comment in PR 9010. with pytest.warns(None) as warning_lines: mywcs.wcs.cdelt = cdelt for w in warning_lines: assert issubclass(w.category, RuntimeWarning) assert 'cdelt will be ignored since cd is present' in str(w.message) mywcs.wcs.ctype = ['RA---TAN', 'FREQ'] ps = non_celestial_pixel_scales(mywcs) assert_almost_equal(ps.to_value(u.deg), np.array([0.1, 0.2]))
def test_fit_wcs_from_points(header_str, crval, sip_degree, user_proj_point, exp_max_dist, exp_std_dist): header = fits.Header.fromstring(header_str, sep='\n') header["CRVAL1"] = crval true_wcs = WCS(header, relax=True) # Getting the pixel coordinates x, y = np.meshgrid(list(range(10)), list(range(10))) x = x.flatten() y = y.flatten() # Calculating the true sky positions world_pix = true_wcs.pixel_to_world(x, y) # which projection point to use if user_proj_point: proj_point = world_pix[0] projlon = proj_point.data.lon.deg projlat = proj_point.data.lat.deg else: proj_point = 'center' # Fitting the wcs fit_wcs = fit_wcs_from_points((x, y), world_pix, proj_point=proj_point, sip_degree=sip_degree) # Validate that the true sky coordinates # match sky coordinates calculated from the wcs fit world_pix_new = fit_wcs.pixel_to_world(x, y) dists = world_pix.separation(world_pix_new) assert dists.max() < exp_max_dist assert np.std(dists) < exp_std_dist if user_proj_point: assert (fit_wcs.wcs.crval == [projlon, projlat]).all()
def wcsTest(): wcsPath = getResourcePath('ISS030-E-102170_dc.wcs') header = readHeader(wcsPath) # the pixel coordinates of which we want the world coordinates x, y = np.meshgrid(np.arange(0,4000), np.arange(0,2000)) x = x.ravel() y = y.ravel() # first, calculate using astropy as reference wcs = WCS(header) t0 = time.time() ra_astropy, dec_astropy = wcs.wcs_pix2world(x, y, 0) print('astropy wcs:', time.time()-t0, 's') # now, check against our own implementation #tan_pix2world(header, x, y, 0) # warmup t0 = time.time() ra, dec = tan_pix2world(header, x, y, 0) print('own wcs:', time.time()-t0, 's') assert_almost_equal([ra, dec], [ra_astropy, dec_astropy])
def test_wcs_to_celestial_frame_extend(): mywcs = WCS(naxis=2) mywcs.wcs.ctype = ['XOFFSET', 'YOFFSET'] mywcs.wcs.set() with pytest.raises(ValueError): wcs_to_celestial_frame(mywcs) class OffsetFrame: pass def identify_offset(wcs): if wcs.wcs.ctype[0].endswith('OFFSET') and wcs.wcs.ctype[1].endswith('OFFSET'): return OffsetFrame() with custom_wcs_to_frame_mappings(identify_offset): frame = wcs_to_celestial_frame(mywcs) assert isinstance(frame, OffsetFrame) # Check that things are back to normal after the context manager with pytest.raises(ValueError): wcs_to_celestial_frame(mywcs)