LSSTApplications  20.0.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 from deprecated.sphinx import deprecated
26 
27 import lsst.geom
28 from ..transformFactory import linearizeTransform, makeTransform
29 from ..skyWcs import makeModifiedWcs
30 from .wcsUtils import _getSipMatrixFromMetadata
31 
32 
33 def getSipMatrixFromMetadata(metadata, name):
34  """Extract a SIP matrix from FITS TAN-SIP WCS metadata.
35 
36  Omitted coefficients are set to 0 and all coefficients may be omitted.
37 
38  Parameters
39  ----------
40  metadata : `lsst.daf.base.PropertySet`
41  FITS metadata.
42  name : `str`
43  Name of TAN-SIP matrix (``"A"``, ``"B"``, ``"Ap"``, or ``"Bp"``).
44 
45  Returns
46  -------
47  `numpy.array`
48  The SIP matrix.
49 
50  Raises
51  ------
52  TypeError
53  If the order keyword ``<name>_ORDER`` (e.g. ``AP_ORDER``) is not found,
54  the value of the order keyword cannot be read as an integer,
55  the value of the order keyword is negative,
56  or if a matrix parameter (e.g. ``AP_5_0``) cannot be read as a float.
57  """
58  arr = _getSipMatrixFromMetadata(metadata, name)
59  if arr.shape == (): # order=0
60  arr.shape = (1, 1)
61  return arr
62 
63 
64 @deprecated(reason="Camera geometry-based SkyWcs are now set when reading raws. To be removed after v20.",
65  category=FutureWarning)
66 def makeDistortedTanWcs(tanWcs, pixelToFocalPlane, focalPlaneToFieldAngle):
67  """Compute a WCS that includes a model of optical distortion.
68 
69  This is useful in the common case that the initial WCS entirely ignores
70  the effect of optical distortion.
71 
72  Parameters
73  ----------
74  tanWcs : `lsst.afw.geom.SkyWcs`
75  A pure TAN WCS, such as is usually provided in raw data.
76  This should have no existing compensation for optical distortion
77  (though it may include an ``ACTUAL_PIXELS`` frame to model pixel-level
78  distortions).
79  pixelToFocalPlane : `lsst.afw.geom.TransformPoint2ToPoint2`
80  Transform parent pixel coordinates to focal plane coordinates.
81  This models the location of the CCD on the focal plane
82  and is almost always an affine transformation.
83  This can be obtained from the detector of an exposure.
84  focalPlaneToFieldAngle : `lsst.afw.geom.TransformPoint2ToPoint2`
85  Transform focal plane coordinates to field angle coordinates.
86  This is a model for optical distortion, and is often a radial
87  polynomial. This can be obtained from the camera geometry.
88 
89 
90  Returns
91  -------
92  lsst.afw.geom.SkyWcs
93  A copy of `tanWcs` that includes the effect of optical distortion.
94 
95  Raises
96  ------
97  RuntimeError
98  If the current frame of `wcs` is not a SkyFrame;
99  LookupError
100  If 2-dimensional Frames with Domain "PIXELS" and "IWC"
101  are not all found.
102  """
103  # The math is as follows:
104  #
105  # Our input TAN WCS is:
106  # tanWcs = PIXELS frame -> pixelToIwc -> IWC frame -> iwcToSky -> SkyFrame
107  # See lsst.afw.geom.SkyWcs for a description of these frames.
108  # tanWcs may also contain an ACTUAL_PIXELS frame before the PIXELS frame;
109  # if so it will be preserved, but it is irrelevant to the computation
110  # and so not discussed further.
111  #
112  # Our desired WCS must still contain the PIXELS and IWC frames.
113  # The distortion will be inserted just after the PIXELS frame,
114  # So the new WCS will be as follows:
115  # wcs = PIXELS frame -> pixelToDistortedPixel -> pixelToIwc -> IWC frame -> iwcToSky -> SkyFrame
116  #
117  # We compute pixelToDistortedPixel as follows...
118  #
119  # We will omit the frames from now on, for simplicity. Thus:
120  # tanWcs = pixelToIwc -> iwcToSksy
121  # and:
122  # wcs = pixelToDistortedPixel -> pixelToIwc -> iwcToSky
123  #
124  # We also know pixelToFocalPlane and focalPlaneToFieldAngle,
125  # and can use them as follows:
126  #
127  # The tan WCS can be expressed as:
128  # tanWcs = pixelToFocalPlane -> focalPlaneToTanFieldAngle -> fieldAngleToIwc -> iwcToSky
129  # where:
130  # - focalPlaneToTanFieldAngle is the linear approximation to
131  # focalPlaneToFieldAngle at the center of the focal plane
132  #
133  # The desired WCS can be expressed as:
134  # wcs = pixelToFocalPlane -> focalPlaneToFieldAngle -> fieldAngleToIwc -> iwcToSky
135  #
136  # By equating the two expressions for tanWcs, we get:
137  # pixelToIwc = pixelToFocalPlane -> focalPlaneToTanFieldAngle -> fieldAngleToIwc
138  # fieldAngleToIwc = tanFieldAngleToFocalPlane -> focalPlaneToPixel -> pixelToIwc
139  #
140  # By equating the two expressions for desired wcs we get:
141  # pixelToDistortedPixel -> pixelToIwc = pixelToFocalPlane -> focalPlaneToFieldAngle -> fieldAngleToIwc
142  #
143  # Substitute our expression for fieldAngleToIwc from tanWcs into the
144  # previous equation, we get:
145  # pixelToDistortedPixel -> pixelToIwc
146  # = pixelToFocalPlane -> focalPlaneToFieldAngle -> tanFieldAngleToFocalPlane -> focalPlaneToPixel
147  # -> pixelToIwc
148  #
149  # Thus:
150  # pixelToDistortedPixel
151  # = pixelToFocalPlane -> focalPlaneToFieldAngle -> tanFieldAngleToFocalPlane -> focalPlaneToPixel
152 
153  pixelToDistortedPixel = computePixelToDistortedPixel(pixelToFocalPlane, focalPlaneToFieldAngle)
154  return makeModifiedWcs(pixelTransform=pixelToDistortedPixel, wcs=tanWcs, modifyActualPixels=False)
155 
156 
157 def computePixelToDistortedPixel(pixelToFocalPlane, focalPlaneToFieldAngle):
158  """Compute the transform ``pixelToDistortedPixel``, which applies optical
159  distortion specified by ``focalPlaneToFieldAngle``.
160 
161  The resulting transform is designed to be used to convert a pure TAN WCS
162  to a WCS that includes a model for optical distortion. In detail,
163  the initial WCS will contain these frames and transforms::
164 
165  PIXELS frame -> pixelToIwc -> IWC frame -> gridToIwc -> SkyFrame
166 
167  To produce the WCS with distortion, replace ``pixelToIwc`` with::
168 
169  pixelToDistortedPixel -> pixelToIwc
170 
171  Parameters
172  ----------
173  pixelToFocalPlane : `lsst.afw.geom.TransformPoint2ToPoint2`
174  Transform parent pixel coordinates to focal plane coordinates
175  focalPlaneToFieldAngle : `lsst.afw.geom.TransformPoint2ToPoint2`
176  Transform focal plane coordinates to field angle coordinates
177 
178  Returns
179  -------
180  pixelToDistortedPixel : `lsst.afw.geom.TransformPoint2ToPoint2`
181  A transform that applies the effect of the optical distortion model.
182  """
183  # return pixelToFocalPlane -> focalPlaneToFieldAngle -> tanFieldAngleToocalPlane -> focalPlaneToPixel
184  focalPlaneToTanFieldAngle = makeTransform(linearizeTransform(focalPlaneToFieldAngle,
185  lsst.geom.Point2D(0, 0)))
186  return pixelToFocalPlane.then(focalPlaneToFieldAngle) \
187  .then(focalPlaneToTanFieldAngle.inverted()) \
188  .then(pixelToFocalPlane.inverted())
lsst::afw::geom.wcsUtils.wcsUtilsContinued.computePixelToDistortedPixel
def computePixelToDistortedPixel(pixelToFocalPlane, focalPlaneToFieldAngle)
Definition: wcsUtilsContinued.py:157
lsst::afw::geom.wcsUtils.wcsUtilsContinued.getSipMatrixFromMetadata
def getSipMatrixFromMetadata(metadata, name)
Definition: wcsUtilsContinued.py:33
lsst::afw::geom::linearizeTransform
lsst::geom::AffineTransform linearizeTransform(TransformPoint2ToPoint2 const &original, lsst::geom::Point2D const &inPoint)
Approximate a Transform by its local linearization.
Definition: transformFactory.cc:132
lsst::afw::geom::makeModifiedWcs
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:491
lsst::afw::geom.wcsUtils.wcsUtilsContinued.makeDistortedTanWcs
def makeDistortedTanWcs(tanWcs, pixelToFocalPlane, focalPlaneToFieldAngle)
Definition: wcsUtilsContinued.py:66
lsst::geom
Definition: geomOperators.dox:4
lsst::geom::Point< double, 2 >
lsst::afw::geom.python.transform.then
then
Definition: transform.py:113
lsst::afw::geom::makeTransform
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
Definition: transformFactory.cc:154