LSSTApplications  18.1.0
LSSTDataManagementBasePackage
wcsUtilsContinued.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2017 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 __all__ = ["getSipMatrixFromMetadata", "makeDistortedTanWcs", "computePixelToDistortedPixel"]
24 
25 import lsst.geom
26 from ..transformFactory import linearizeTransform, makeTransform
27 from ..skyWcs import makeModifiedWcs
28 from .wcsUtils import _getSipMatrixFromMetadata
29 
30 
31 def getSipMatrixFromMetadata(metadata, name):
32  """Extract a SIP matrix from FITS TAN-SIP WCS metadata.
33 
34  Omitted coefficients are set to 0 and all coefficients may be omitted.
35 
36  Parameters
37  ----------
38  metadata : `lsst.daf.base.PropertySet`
39  FITS metadata.
40  name : `str`
41  Name of TAN-SIP matrix (``"A"``, ``"B"``, ``"Ap"``, or ``"Bp"``).
42 
43  Returns
44  -------
45  `numpy.array`
46  The SIP matrix.
47 
48  Raises
49  ------
50  TypeError
51  If the order keyword ``<name>_ORDER`` (e.g. ``AP_ORDER``) is not found,
52  the value of the order keyword cannot be read as an integer,
53  the value of the order keyword is negative,
54  or if a matrix parameter (e.g. ``AP_5_0``) cannot be read as a float.
55  """
56  arr = _getSipMatrixFromMetadata(metadata, name)
57  if arr.shape == (): # order=0
58  arr.shape = (1, 1)
59  return arr
60 
61 
62 def makeDistortedTanWcs(tanWcs, pixelToFocalPlane, focalPlaneToFieldAngle):
63  """Compute a WCS that includes a model of optical distortion.
64 
65  This is useful in the common case that the initial WCS entirely ignores
66  the effect of optical distortion.
67 
68  Parameters
69  ----------
70  tanWcs : `lsst.afw.geom.SkyWcs`
71  A pure TAN WCS, such as is usually provided in raw data.
72  This should have no existing compensation for optical distortion
73  (though it may include an ``ACTUAL_PIXELS`` frame to model pixel-level
74  distortions).
75  pixelToFocalPlane : `lsst.afw.geom.TransformPoint2ToPoint2`
76  Transform parent pixel coordinates to focal plane coordinates.
77  This models the location of the CCD on the focal plane
78  and is almost always an affine transformation.
79  This can be obtained from the detector of an exposure.
80  focalPlaneToFieldAngle : `lsst.afw.geom.TransformPoint2ToPoint2`
81  Transform focal plane coordinates to field angle coordinates.
82  This is a model for optical distortion, and is often a radial
83  polynomial. This can be obtained from the camera geometry.
84 
85 
86  Returns
87  -------
88  lsst.afw.geom.SkyWcs
89  A copy of `tanWcs` that includes the effect of optical distortion.
90 
91  Raises
92  ------
93  RuntimeError
94  If the current frame of `wcs` is not a SkyFrame;
95  LookupError
96  If 2-dimensional Frames with Domain "PIXELS" and "IWC"
97  are not all found.
98  """
99  # The math is as follows:
100  #
101  # Our input TAN WCS is:
102  # tanWcs = PIXELS frame -> pixelToIwc -> IWC frame -> iwcToSky -> SkyFrame
103  # See lsst.afw.geom.SkyWcs for a description of these frames.
104  # tanWcs may also contain an ACTUAL_PIXELS frame before the PIXELS frame;
105  # if so it will be preserved, but it is irrelevant to the computation
106  # and so not discussed further.
107  #
108  # Our desired WCS must still contain the PIXELS and IWC frames.
109  # The distortion will be inserted just after the PIXELS frame,
110  # So the new WCS will be as follows:
111  # wcs = PIXELS frame -> pixelToDistortedPixel -> pixelToIwc -> IWC frame -> iwcToSky -> SkyFrame
112  #
113  # We compute pixelToDistortedPixel as follows...
114  #
115  # We will omit the frames from now on, for simplicity. Thus:
116  # tanWcs = pixelToIwc -> iwcToSksy
117  # and:
118  # wcs = pixelToDistortedPixel -> pixelToIwc -> iwcToSky
119  #
120  # We also know pixelToFocalPlane and focalPlaneToFieldAngle,
121  # and can use them as follows:
122  #
123  # The tan WCS can be expressed as:
124  # tanWcs = pixelToFocalPlane -> focalPlaneToTanFieldAngle -> fieldAngleToIwc -> iwcToSky
125  # where:
126  # - focalPlaneToTanFieldAngle is the linear approximation to
127  # focalPlaneToFieldAngle at the center of the focal plane
128  #
129  # The desired WCS can be expressed as:
130  # wcs = pixelToFocalPlane -> focalPlaneToFieldAngle -> fieldAngleToIwc -> iwcToSky
131  #
132  # By equating the two expressions for tanWcs, we get:
133  # pixelToIwc = pixelToFocalPlane -> focalPlaneToTanFieldAngle -> fieldAngleToIwc
134  # fieldAngleToIwc = tanFieldAngleToFocalPlane -> focalPlaneToPixel -> pixelToIwc
135  #
136  # By equating the two expressions for desired wcs we get:
137  # pixelToDistortedPixel -> pixelToIwc = pixelToFocalPlane -> focalPlaneToFieldAngle -> fieldAngleToIwc
138  #
139  # Substitute our expression for fieldAngleToIwc from tanWcs into the
140  # previous equation, we get:
141  # pixelToDistortedPixel -> pixelToIwc
142  # = pixelToFocalPlane -> focalPlaneToFieldAngle -> tanFieldAngleToFocalPlane -> focalPlaneToPixel
143  # -> pixelToIwc
144  #
145  # Thus:
146  # pixelToDistortedPixel
147  # = pixelToFocalPlane -> focalPlaneToFieldAngle -> tanFieldAngleToFocalPlane -> focalPlaneToPixel
148 
149  pixelToDistortedPixel = computePixelToDistortedPixel(pixelToFocalPlane, focalPlaneToFieldAngle)
150  return makeModifiedWcs(pixelTransform=pixelToDistortedPixel, wcs=tanWcs, modifyActualPixels=False)
151 
152 
153 def computePixelToDistortedPixel(pixelToFocalPlane, focalPlaneToFieldAngle):
154  """Compute the transform ``pixelToDistortedPixel``, which applies optical
155  distortion specified by ``focalPlaneToFieldAngle``.
156 
157  The resulting transform is designed to be used to convert a pure TAN WCS
158  to a WCS that includes a model for optical distortion. In detail,
159  the initial WCS will contain these frames and transforms::
160 
161  PIXELS frame -> pixelToIwc -> IWC frame -> gridToIwc -> SkyFrame
162 
163  To produce the WCS with distortion, replace ``pixelToIwc`` with::
164 
165  pixelToDistortedPixel -> pixelToIwc
166 
167  Parameters
168  ----------
169  pixelToFocalPlane : `lsst.afw.geom.TransformPoint2ToPoint2`
170  Transform parent pixel coordinates to focal plane coordinates
171  focalPlaneToFieldAngle : `lsst.afw.geom.TransformPoint2ToPoint2`
172  Transform focal plane coordinates to field angle coordinates
173 
174  Returns
175  -------
176  pixelToDistortedPixel : `lsst.afw.geom.TransformPoint2ToPoint2`
177  A transform that applies the effect of the optical distortion model.
178  """
179  # return pixelToFocalPlane -> focalPlaneToFieldAngle -> tanFieldAngleToocalPlane -> focalPlaneToPixel
180  focalPlaneToTanFieldAngle = makeTransform(linearizeTransform(focalPlaneToFieldAngle,
181  lsst.geom.Point2D(0, 0)))
182  return pixelToFocalPlane.then(focalPlaneToFieldAngle) \
183  .then(focalPlaneToTanFieldAngle.inverted()) \
184  .then(pixelToFocalPlane.inverted())
lsst::geom::AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, lsst::geom::Point2D const &inPoint)
Approximate a Transform by its local linearization.
std::shared_ptr< SkyWcs > makeModifiedWcs(TransformPoint2ToPoint2 const &pixelTransform, SkyWcs const &wcs, bool modifyActualPixels)
Create a new SkyWcs whose pixels are transformed by pixelTransform, as described below.
Definition: SkyWcs.cc:451
def makeDistortedTanWcs(tanWcs, pixelToFocalPlane, focalPlaneToFieldAngle)
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
def computePixelToDistortedPixel(pixelToFocalPlane, focalPlaneToFieldAngle)