def test_roundtrip_sky_rotaion(inp): lon, lat, lon_pole = 42 * u.deg, (43 * u.deg).to( u.arcsec), (44 * u.deg).to(u.rad) n2c = models.RotateNative2Celestial(lon, lat, lon_pole) c2n = models.RotateCelestial2Native(lon, lat, lon_pole) assert_quantity_allclose(n2c.inverse(*n2c(*inp)), inp, atol=1e-13 * u.deg) assert_quantity_allclose(c2n.inverse(*c2n(*inp)), inp, atol=1e-13 * u.deg)
def test_against_wcslib(inp): w = wcs.WCS() crval = [202.4823228, 47.17511893] w.wcs.crval = crval w.wcs.ctype = ['RA---TAN', 'DEC--TAN'] lonpole = 180 tan = models.Pix2Sky_TAN() n2c = models.RotateNative2Celestial(crval[0], crval[1], lonpole) c2n = models.RotateCelestial2Native(crval[0], crval[1], lonpole) m = tan | n2c minv = c2n | tan.inverse radec = w.wcs_pix2world(inp[0], inp[1], 1) xy = w.wcs_world2pix(radec[0], radec[1], 1) assert_allclose(m(*inp), radec, atol=1e-12) assert_allclose(minv(*radec), xy, atol=1e-12)
test_models = [ astmodels.Identity(2), astmodels.Polynomial1D(2, c0=1, c1=2, c2=3), astmodels.Polynomial2D(1, c0_0=1, c0_1=2, c1_0=3), astmodels.Shift(2.), astmodels.Hermite1D(2, c0=2, c1=3, c2=0.5), astmodels.Legendre1D(2, c0=2, c1=3, c2=0.5), astmodels.Chebyshev1D(2, c0=2, c1=3, c2=0.5), astmodels.Chebyshev2D(1, 1, c0_0=1, c0_1=2, c1_0=3), astmodels.Legendre2D(1, 1, c0_0=1, c0_1=2, c1_0=3), astmodels.Hermite2D(1, 1, c0_0=1, c0_1=2, c1_0=3), astmodels.Scale(3.4), astmodels.RotateNative2Celestial(5.63, -72.5, 180), astmodels.Multiply(3), astmodels.Multiply(10 * u.m), astmodels.RotateCelestial2Native(5.63, -72.5, 180), astmodels.EulerAngleRotation(23, 14, 2.3, axes_order='xzx'), astmodels.Mapping((0, 1), n_inputs=3), astmodels.Shift(2. * u.deg), astmodels.Scale(3.4 * u.deg), astmodels.RotateNative2Celestial(5.63 * u.deg, -72.5 * u.deg, 180 * u.deg), astmodels.RotateCelestial2Native(5.63 * u.deg, -72.5 * u.deg, 180 * u.deg), astmodels.RotationSequence3D([1.2, 2.3, 3.4, .3], 'xyzx'), astmodels.SphericalRotationSequence([1.2, 2.3, 3.4, .3], 'xyzy'), custom_and_analytical_inverse(), ] math_models = [] for kl in astmodels.math.__all__: klass = getattr(astmodels.math, kl)
def wcs_from_points(xy, world_coordinates, fiducial, projection=projections.Sky2Pix_TAN(), degree=4, polynomial_type="polynomial"): """ Given two matching sets of coordinates on detector and sky, compute the WCS. Notes ----- This function implements the following algorithm: ``world_coordinates`` are transformed to a projection plane using the specified projection. A polynomial fits ``xy`` and the projected coordinates. The fitted polynomials and the projection transforms are combined into a tranform from detector to sky. The input coordinate frame is set to ``detector``. The output coordinate frame is initialized based on the frame in the fiducial. Parameters ---------- xy : tuple of 2 ndarrays Points in the input cooridnate frame - x, y inputs. world_coordinates : tuple of 2 ndarrays Points in the output coordinate frame. The order matches the order of ``xy``. fiducial_point : `~astropy.coordinates.SkyCoord` A fiducial point in the output coordinate frame. projection : `~astropy.modeling.projections.Projection` A projection type. One of the projections in `~astropy.modeling.projections.projcode`. degree : int Degree of Polynpomial model to be fit to data. polynomial_type : str one of "polynomial", "chebyshev", "legendre" Returns ------- wcsobj : `~gwcs.wcs.WCS` a WCS object for this observation. """ supported_poly_types = { "polynomial": models.Polynomial2D, "chebyshev": models.Chebyshev2D, "legendre": models.Legendre2D } x, y = xy lon, lat = world_coordinates if not isinstance(projection, projections.Projection): raise UnsupportedProjectionError( "Unsupported projection code {0}".format(projection)) if polynomial_type not in supported_poly_types.keys(): raise ValueError("Unsupported polynomial_type: {}. " "Only one of {} is supported.".format( polynomial_type, supported_poly_types.keys())) skyrot = models.RotateCelestial2Native(fiducial.data.lon, fiducial.data.lat, 180 * u.deg) trans = (skyrot | projection) projection_x, projection_y = trans(lon, lat) poly = supported_poly_types[polynomial_type](degree) fitter = fitting.LevMarLSQFitter() with warnings.catch_warnings(): warnings.simplefilter("ignore") poly_x = fitter(poly, x, y, projection_x) poly_y = fitter(poly, x, y, projection_y) transform = models.Mapping( (0, 1, 0, 1)) | poly_x & poly_y | projection.inverse | skyrot.inverse skyframe = CelestialFrame(reference_frame=fiducial.frame) detector = Frame2D(name="detector") pipeline = [(detector, transform), (skyframe, None)] return WCS(pipeline)
try: import astropy except ImportError: HAS_ASTROPY = False test_models = [] else: HAS_ASTROPY = True from astropy.utils import minversion ASTROPY_13 = minversion(astropy, "1.3.dev16506") from astropy.modeling import models as astmodels test_models = [astmodels.Identity(2), astmodels.Polynomial1D(2, c0=1, c1=2, c2=3), astmodels.Polynomial2D(1, c0_0=1, c0_1=2, c1_0=3), astmodels.Shift(2.), astmodels.Scale(3.4), astmodels.RotateNative2Celestial(5.63, -72.5, 180), astmodels.RotateCelestial2Native(5.63, -72.5, 180), astmodels.EulerAngleRotation(23, 14, 2.3, axes_order='xzx'), astmodels.Mapping((0, 1), n_inputs=3)] import pytest from ....tests import helpers from .... import util from ..basic import DomainType @pytest.mark.skipif('not HAS_ASTROPY') def test_transforms_compound(tmpdir): tree = { 'compound':
def test_roundtrip_sky_rotation(inp): lon, lat, lon_pole = 42, 43, 44 n2c = models.RotateNative2Celestial(lon, lat, lon_pole) c2n = models.RotateCelestial2Native(lon, lat, lon_pole) assert_allclose(n2c.inverse(*n2c(*inp)), inp, atol=1e-13) assert_allclose(c2n.inverse(*c2n(*inp)), inp, atol=1e-13)
def wcs_from_points(xy, world_coords, proj_point='center', projection=projections.Sky2Pix_TAN(), poly_degree=4, polynomial_type='polynomial'): """ Given two matching sets of coordinates on detector and sky, compute the WCS. Notes ----- This function implements the following algorithm: ``world_coords`` are transformed to a projection plane using the specified projection. A polynomial fits ``xy`` and the projected coordinates. The fitted polynomials and the projection transforms are combined into a tranform from detector to sky. The input coordinate frame is set to ``detector``. The output coordinate frame is initialized based on the frame in the fiducial. Parameters ---------- xy : tuple of 2 ndarrays Points in the input cooridnate frame - x, y inputs. world_coords : `~astropy.coordinates.SkyCoord` Points in the output coordinate frame. The order matches the order of ``xy``. proj_point : `~astropy.coordinates.SkyCoord` A fiducial point in the output coordinate frame. If set to 'center' (default), the geometric center of input world coordinates will be used as the projection point. To specify an exact point for the projection, a Skycoord object with a coordinate pair can be passed in. projection : `~astropy.modeling.projections.Projection` A projection type. One of the projections in `~astropy.modeling.projections.projcode`. Defaults to TAN projection (`projections.Sky2Pix_TAN()`). poly_degree : int Degree of polynomial model to be fit to data. Defaults to 4. polynomial_type : str one of "polynomial", "chebyshev", "legendre". Defaults to "polynomial". Returns ------- wcsobj : `~gwcs.wcs.WCS` a WCS object for this observation. """ from .wcs import WCS supported_poly_types = { "polynomial": models.Polynomial2D, "chebyshev": models.Chebyshev2D, "legendre": models.Legendre2D } x, y = xy if not isinstance(world_coords, coord.SkyCoord): raise TypeError( '`world_coords` must be an `~astropy.coordinates.SkyCoord`') try: lon, lat = world_coords.data.lon.deg, world_coords.data.lat.deg except AttributeError: unit_sph = world_coords.unit_spherical lon, lat = unit_sph.lon.deg, unit_sph.lat.deg if isinstance(proj_point, coord.SkyCoord): assert proj_point.size == 1 proj_point.transform_to(world_coords) crval = (proj_point.data.lon, proj_point.data.lat) frame = proj_point.frame elif proj_point == 'center': # use center of input points sc1 = SkyCoord(lon.min() * u.deg, lat.max() * u.deg) sc2 = SkyCoord(lon.max() * u.deg, lat.min() * u.deg) pa = sc1.position_angle(sc2) sep = sc1.separation(sc2) midpoint_sc = sc1.directional_offset_by(pa, sep / 2) crval = (midpoint_sc.data.lon, midpoint_sc.data.lat) frame = sc1.frame else: raise ValueError("`proj_point` must be set to 'center', or an" + "`~astropy.coordinates.SkyCoord` object with " + "a pair of points.") if not isinstance(projection, projections.Projection): raise UnsupportedProjectionError( "Unsupported projection code {0}".format(projection)) if polynomial_type not in supported_poly_types.keys(): raise ValueError("Unsupported polynomial_type: {}. " "Only one of {} is supported.".format( polynomial_type, supported_poly_types.keys())) skyrot = models.RotateCelestial2Native(crval[0], crval[1], 180 * u.deg) trans = (skyrot | projection) projection_x, projection_y = trans(lon, lat) poly = supported_poly_types[polynomial_type](poly_degree) fitter = fitting.LevMarLSQFitter() with warnings.catch_warnings(): warnings.simplefilter("ignore") poly_x = fitter(poly, x, y, projection_x) poly_y = fitter(poly, x, y, projection_y) distortion = models.Mapping((0, 1, 0, 1)) | poly_x & poly_y poly_x_inverse = fitter(poly, projection_x, projection_y, x) poly_y_inverse = fitter(poly, projection_x, projection_y, y) distortion.inverse = models.Mapping( (0, 1, 0, 1)) | poly_x_inverse & poly_y_inverse transform = distortion | projection.inverse | skyrot.inverse skyframe = CelestialFrame(reference_frame=frame) detector = Frame2D(name="detector") pipeline = [(detector, transform), (skyframe, None)] return WCS(pipeline)