FITS Equivalent WCS ExampleΒΆ
The following example shows how to construct a GWCS object equivalent to a FITS imaging WCS without distortion, defined in this FITS imaging header:
WCSAXES = 2 / Number of coordinate axes
WCSNAME = '47 Tuc ' / Coordinate system title
CRPIX1 = 2048.0 / Pixel coordinate of reference point
CRPIX2 = 1024.0 / Pixel coordinate of reference point
PC1_1 = 1.290551569736E-05 / Coordinate transformation matrix element
PC1_2 = 5.9525007864732E-06 / Coordinate transformation matrix element
PC2_1 = 5.0226382102765E-06 / Coordinate transformation matrix element
PC2_2 = -1.2644844123757E-05 / 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' / TAN (gnomonic) projection + SIP distortions
CTYPE2 = 'DEC--TAN' / TAN (gnomonic) projection + SIP distortions
CRVAL1 = 5.63056810618 / [deg] Coordinate value at reference point
CRVAL2 = -72.05457184279 / [deg] Coordinate value at reference point
LONPOLE = 180.0 / [deg] Native longitude of celestial pole
LATPOLE = -72.05457184279 / [deg] Native latitude of celestial pole
RADESYS = 'ICRS' / Equatorial coordinate system
For this example the following imports are needed:
>>> import numpy as np
>>> from astropy.modeling import models
>>> from astropy import coordinates as coord
>>> from astropy import units as u
>>> from gwcs import wcs
>>> from gwcs import coordinate_frames as cf
The forward_transform
is constructed as a combined model using astropy.modeling
.
The frames
are subclasses of CoordinateFrame
. Although strings are
acceptable as coordinate_frames
it is recommended this is used only in testing/debugging.
Using the modeling
package create a combined model to transform
detector coordinates to ICRS following the FITS WCS standard convention.
First, create a transform which shifts the input x
and y
coordinates by CRPIX
. We subtract 1 from the CRPIX values because the first pixel is considered pixel 1
in FITS WCS:
>>> shift_by_crpix = models.Shift(-(2048 - 1)*u.pix) & models.Shift(-(1024 - 1)*u.pix)
Create a transform which rotates the inputs using the PC matrix
.
>>> matrix = np.array([[1.290551569736E-05, 5.9525007864732E-06],
... [5.0226382102765E-06 , -1.2644844123757E-05]])
>>> rotation = models.AffineTransformation2D(matrix * u.deg,
... translation=[0, 0] * u.deg)
>>> rotation.input_units_equivalencies = {"x": u.pixel_scale(1*u.deg/u.pix),
... "y": u.pixel_scale(1*u.deg/u.pix)}
>>> rotation.inverse = models.AffineTransformation2D(np.linalg.inv(matrix) * u.pix,
... translation=[0, 0] * u.pix)
>>> rotation.inverse.input_units_equivalencies = {"x": u.pixel_scale(1*u.pix/u.deg),
... "y": u.pixel_scale(1*u.pix/u.deg)}
Create a tangent projection and a rotation on the sky using CRVAL
.
>>> tan = models.Pix2Sky_TAN()
>>> celestial_rotation = models.RotateNative2Celestial(5.63056810618*u.deg, -72.05457184279*u.deg, 180*u.deg)
>>> det2sky = shift_by_crpix | rotation | tan | celestial_rotation
>>> det2sky.name = "linear_transform"
Create a detector
coordinate frame and a celestial
ICRS frame.
>>> detector_frame = cf.Frame2D(name="detector", axes_names=("x", "y"),
... unit=(u.pix, u.pix))
>>> sky_frame = cf.CelestialFrame(reference_frame=coord.ICRS(), name='icrs',
... unit=(u.deg, u.deg))
This WCS pipeline has only one step - from detector
to sky
:
>>> pipeline = [(detector_frame, det2sky),
... (sky_frame, None)
... ]
>>> wcsobj = wcs.WCS(pipeline)
>>> print(wcsobj)
From Transform
-------- ----------------
detector linear_transform
icrs None
Now we have a complete WCS object. The next example will use it to convert pixel coordinates(1, 2) to sky coordinates:
>>> sky = wcsobj(1*u.pix, 2*u.pix, with_units=True)
>>> print(sky)
<SkyCoord (ICRS): (ra, dec) in deg
(5.52515954, -72.05190935)>
The invert()
method evaluates the backward_transform()
to provide a mapping from sky coordinates to pixel coordinates
if available, otherwise it applies an iterative method to calculate the pixel coordinates.
>>> wcsobj.invert(sky)
(<Quantity 1. pix>, <Quantity 2. pix>)