LSST Applications g0265f82a02+0e5473021a,g02d81e74bb+0dd8ce4237,g1470d8bcf6+3ea6592b6f,g2079a07aa2+86d27d4dc4,g2305ad1205+5ca4c0b359,g295015adf3+d10818ec9d,g2a9a014e59+6f9be1b9cd,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g3ddfee87b4+703ba97ebf,g487adcacf7+4fa16da234,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+ffa42b374e,g5a732f18d5+53520f316c,g64a986408d+0dd8ce4237,g858d7b2824+0dd8ce4237,g8a8a8dda67+585e252eca,g99cad8db69+d39438377f,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+f1d96605c8,gb0e22166c9+60f28cb32d,gb6a65358fc+0e5473021a,gba4ed39666+c2a2e4ac27,gbb8dafda3b+e5339d463f,gc120e1dc64+da31e9920e,gc28159a63d+0e5473021a,gcf0d15dbbd+703ba97ebf,gdaeeff99f8+f9a426f77a,ge6526c86ff+889fc9d533,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gf18bd8381d+7268b93478,gff1a9f87cc+0dd8ce4237,w.2024.16
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Static Public Attributes | Protected Member Functions | Static Protected Attributes | List of all members
lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask Class Reference
Inheritance diagram for lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask:

Public Member Functions

 fitWcs (self, matches, initWcs, bbox=None, refCat=None, sourceCat=None, exposure=None)
 
 initialWcs (self, matches, wcs)
 
 rejectMatches (self, matches, wcs, rejected)
 
 plotFit (self, matches, wcs, rejected)
 

Static Public Attributes

 ConfigClass = FitTanSipWcsConfig
 

Protected Member Functions

 _fitWcs (self, matches, wcs)
 

Static Protected Attributes

str _DefaultName = "fitTanSipWcs"
 

Detailed Description

Fit a TAN-SIP WCS given a list of reference object/source matches.

Definition at line 75 of file fitTanSipWcs.py.

Member Function Documentation

◆ _fitWcs()

lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask._fitWcs ( self,
matches,
wcs )
protected
Fit a Wcs based on the matches and a guess Wcs.

Parameters
----------
matches : `list` of `lsst.afw.table.ReferenceMatch`
    List of sources matched to references.
wcs : `lsst.afw.geom.SkyWcs`
    Current WCS.

Returns
-------
sipObject : `lsst.meas.astrom.sip.CreateWcsWithSip`
    Fitted SIP object.

Definition at line 216 of file fitTanSipWcs.py.

216 def _fitWcs(self, matches, wcs):
217 """Fit a Wcs based on the matches and a guess Wcs.
218
219 Parameters
220 ----------
221 matches : `list` of `lsst.afw.table.ReferenceMatch`
222 List of sources matched to references.
223 wcs : `lsst.afw.geom.SkyWcs`
224 Current WCS.
225
226 Returns
227 -------
228 sipObject : `lsst.meas.astrom.sip.CreateWcsWithSip`
229 Fitted SIP object.
230 """
231 for i in range(self.config.numIter):
232 sipObject = makeCreateWcsWithSip(matches, wcs, self.config.order)
233 wcs = sipObject.getNewWcs()
234 return sipObject
235

◆ fitWcs()

lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask.fitWcs ( self,
matches,
initWcs,
bbox = None,
refCat = None,
sourceCat = None,
exposure = None )
Fit a TAN-SIP WCS from a list of reference object/source matches

Parameters
----------
matches : `list` of `lsst.afw.table.ReferenceMatch`
    The following fields are read:

    - match.first (reference object) coord
    - match.second (source) centroid

    The following fields are written:

    - match.first (reference object) centroid,
    - match.second (source) centroid
    - match.distance (on sky separation, in radians)

initWcs : `lsst.afw.geom.SkyWcs`
    initial WCS
bbox : `lsst.geom.Box2I`
    the region over which the WCS will be valid (an lsst:afw::geom::Box2I);
    if None or an empty box then computed from matches
refCat : `lsst.afw.table.SimpleCatalog`
    reference object catalog, or None.
    If provided then all centroids are updated with the new WCS,
    otherwise only the centroids for ref objects in matches are updated.
    Required fields are "centroid_x", "centroid_y", "coord_ra", and "coord_dec".
sourceCat : `lsst.afw.table.SourceCatalog`
    source catalog, or None.
    If provided then coords are updated with the new WCS;
    otherwise only the coords for sources in matches are updated.
    Required fields are "slot_Centroid_x", "slot_Centroid_y", and "coord_ra", and "coord_dec".
exposure : `lsst.afw.image.Exposure`
    Ignored; present for consistency with FitSipDistortionTask.

Returns
-------
result : `lsst.pipe.base.Struct`
    with the following fields:

    - ``wcs`` :  the fit WCS (`lsst.afw.geom.SkyWcs`)
    - ``scatterOnSky`` :  median on-sky separation between reference
      objects and sources in "matches" (`lsst.afw.geom.Angle`)

Definition at line 82 of file fitTanSipWcs.py.

82 def fitWcs(self, matches, initWcs, bbox=None, refCat=None, sourceCat=None, exposure=None):
83 """Fit a TAN-SIP WCS from a list of reference object/source matches
84
85 Parameters
86 ----------
87 matches : `list` of `lsst.afw.table.ReferenceMatch`
88 The following fields are read:
89
90 - match.first (reference object) coord
91 - match.second (source) centroid
92
93 The following fields are written:
94
95 - match.first (reference object) centroid,
96 - match.second (source) centroid
97 - match.distance (on sky separation, in radians)
98
99 initWcs : `lsst.afw.geom.SkyWcs`
100 initial WCS
101 bbox : `lsst.geom.Box2I`
102 the region over which the WCS will be valid (an lsst:afw::geom::Box2I);
103 if None or an empty box then computed from matches
104 refCat : `lsst.afw.table.SimpleCatalog`
105 reference object catalog, or None.
106 If provided then all centroids are updated with the new WCS,
107 otherwise only the centroids for ref objects in matches are updated.
108 Required fields are "centroid_x", "centroid_y", "coord_ra", and "coord_dec".
109 sourceCat : `lsst.afw.table.SourceCatalog`
110 source catalog, or None.
111 If provided then coords are updated with the new WCS;
112 otherwise only the coords for sources in matches are updated.
113 Required fields are "slot_Centroid_x", "slot_Centroid_y", and "coord_ra", and "coord_dec".
114 exposure : `lsst.afw.image.Exposure`
115 Ignored; present for consistency with FitSipDistortionTask.
116
117 Returns
118 -------
119 result : `lsst.pipe.base.Struct`
120 with the following fields:
121
122 - ``wcs`` : the fit WCS (`lsst.afw.geom.SkyWcs`)
123 - ``scatterOnSky`` : median on-sky separation between reference
124 objects and sources in "matches" (`lsst.afw.geom.Angle`)
125 """
126 if bbox is None:
127 bbox = lsst.geom.Box2I()
128
129 import lsstDebug
130 debug = lsstDebug.Info(__name__)
131
132 wcs = self.initialWcs(matches, initWcs)
133 rejected = np.zeros(len(matches), dtype=bool)
134 for rej in range(self.config.numRejIter):
135 sipObject = self._fitWcs([mm for i, mm in enumerate(matches) if not rejected[i]], wcs)
136 wcs = sipObject.getNewWcs()
137 rejected = self.rejectMatches(matches, wcs, rejected)
138 if rejected.sum() == len(rejected):
139 raise exceptions.AstrometryFitFailure(f"All matches rejected in fitter iteration {rej+1}")
140 self.log.debug(
141 "Iteration %d of astrometry fitting: rejected %d outliers, out of %d total matches.",
142 rej, rejected.sum(), len(rejected)
143 )
144 if debug.plot:
145 print("Plotting fit after rejection iteration %d/%d" % (rej + 1, self.config.numRejIter))
146 self.plotFit(matches, wcs, rejected)
147 # Final fit after rejection
148 sipObject = self._fitWcs([mm for i, mm in enumerate(matches) if not rejected[i]], wcs)
149 wcs = sipObject.getNewWcs()
150 if debug.plot:
151 print("Plotting final fit")
152 self.plotFit(matches, wcs, rejected)
153
154 if refCat is not None:
155 self.log.debug("Updating centroids in refCat")
156 afwTable.updateRefCentroids(wcs, refList=refCat)
157 else:
158 self.log.warning("Updating reference object centroids in match list; refCat is None")
159 afwTable.updateRefCentroids(wcs, refList=[match.first for match in matches])
160
161 if sourceCat is not None:
162 self.log.debug("Updating coords in sourceCat")
163 afwTable.updateSourceCoords(wcs, sourceList=sourceCat)
164 else:
165 self.log.warning("Updating source coords in match list; sourceCat is None")
166 afwTable.updateSourceCoords(wcs, sourceList=[match.second for match in matches])
167
168 self.log.debug("Updating distance in match list")
169 setMatchDistance(matches)
170
171 scatterOnSky = sipObject.getScatterOnSky()
172
173 if scatterOnSky.asArcseconds() > self.config.maxScatterArcsec:
174 raise exceptions.AstrometryFitFailure(
175 "Fit failed: median scatter on sky = %0.3f arcsec > %0.3f config.maxScatterArcsec" %
176 (scatterOnSky.asArcseconds(), self.config.maxScatterArcsec))
177
178 return pipeBase.Struct(
179 wcs=wcs,
180 scatterOnSky=scatterOnSky,
181 )
182
An integer coordinate rectangle.
Definition Box.h:55
void updateRefCentroids(geom::SkyWcs const &wcs, ReferenceCollection &refList)
Update centroids in a collection of reference objects.
Definition wcsUtils.cc:73
void updateSourceCoords(geom::SkyWcs const &wcs, SourceCollection &sourceList, bool include_covariance=true)
Update sky coordinates in a collection of source objects.
Definition wcsUtils.cc:125

◆ initialWcs()

lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask.initialWcs ( self,
matches,
wcs )
Generate a guess Wcs from the astrometric matches

We create a Wcs anchored at the center of the matches, with the scale
of the input Wcs.  This is necessary because matching returns only
matches with no estimated Wcs, and the input Wcs is a wild guess.
We're using the best of each: positions from the matches, and scale
from the input Wcs.

Parameters
----------
matches : `list` of `lsst.afw.table.ReferenceMatch`
    List of sources matched to references.
wcs : `lsst.afw.geom.SkyWcs`
    Current WCS.

Returns
-------
newWcs : `lsst.afw.geom.SkyWcs`
    Initial WCS guess from estimated crpix and crval.

Definition at line 183 of file fitTanSipWcs.py.

183 def initialWcs(self, matches, wcs):
184 """Generate a guess Wcs from the astrometric matches
185
186 We create a Wcs anchored at the center of the matches, with the scale
187 of the input Wcs. This is necessary because matching returns only
188 matches with no estimated Wcs, and the input Wcs is a wild guess.
189 We're using the best of each: positions from the matches, and scale
190 from the input Wcs.
191
192 Parameters
193 ----------
194 matches : `list` of `lsst.afw.table.ReferenceMatch`
195 List of sources matched to references.
196 wcs : `lsst.afw.geom.SkyWcs`
197 Current WCS.
198
199 Returns
200 -------
201 newWcs : `lsst.afw.geom.SkyWcs`
202 Initial WCS guess from estimated crpix and crval.
203 """
204 crpix = lsst.geom.Extent2D(0, 0)
205 crval = lsst.sphgeom.Vector3d(0, 0, 0)
206 for mm in matches:
207 crpix += lsst.geom.Extent2D(mm.second.getCentroid())
208 crval += mm.first.getCoord().getVector()
209 crpix /= len(matches)
210 crval /= len(matches)
211 newWcs = afwGeom.makeSkyWcs(crpix=lsst.geom.Point2D(crpix),
212 crval=lsst.geom.SpherePoint(crval),
213 cdMatrix=wcs.getCdMatrix())
214 return newWcs
215
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57
Vector3d is a vector in ℝ³ with components stored in double precision.
Definition Vector3d.h:51
std::shared_ptr< SkyWcs > makeSkyWcs(daf::base::PropertySet &metadata, bool strip=false)
Construct a SkyWcs from FITS keywords.
Definition SkyWcs.cc:521

◆ plotFit()

lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask.plotFit ( self,
matches,
wcs,
rejected )
Plot the fit

We create four plots, for all combinations of (dx, dy) against
(x, y).  Good points are black, while rejected points are red.

Parameters
----------
matches : `list` of `lsst.afw.table.ReferenceMatch`
    List of sources matched to references.
wcs : `lsst.afw.geom.SkyWcs`
    Fitted WCS.
rejected : array-like of `bool`
    Array of matches rejected from the fit.

Definition at line 263 of file fitTanSipWcs.py.

263 def plotFit(self, matches, wcs, rejected):
264 """Plot the fit
265
266 We create four plots, for all combinations of (dx, dy) against
267 (x, y). Good points are black, while rejected points are red.
268
269 Parameters
270 ----------
271 matches : `list` of `lsst.afw.table.ReferenceMatch`
272 List of sources matched to references.
273 wcs : `lsst.afw.geom.SkyWcs`
274 Fitted WCS.
275 rejected : array-like of `bool`
276 Array of matches rejected from the fit.
277 """
278 try:
279 import matplotlib.pyplot as plt
280 except ImportError as e:
281 self.log.warning("Unable to import matplotlib: %s", e)
282 return
283
284 fit = [wcs.skyToPixel(m.first.getCoord()) for m in matches]
285 x1 = np.array([ff.getX() for ff in fit])
286 y1 = np.array([ff.getY() for ff in fit])
287 x2 = np.array([m.second.getCentroid().getX() for m in matches])
288 y2 = np.array([m.second.getCentroid().getY() for m in matches])
289
290 dx = x1 - x2
291 dy = y1 - y2
292
293 good = np.logical_not(rejected)
294
295 figure = plt.figure()
296 axes = figure.add_subplot(2, 2, 1)
297 axes.plot(x2[good], dx[good], 'ko')
298 axes.plot(x2[rejected], dx[rejected], 'ro')
299 axes.set_xlabel("x")
300 axes.set_ylabel("dx")
301
302 axes = figure.add_subplot(2, 2, 2)
303 axes.plot(x2[good], dy[good], 'ko')
304 axes.plot(x2[rejected], dy[rejected], 'ro')
305 axes.set_xlabel("x")
306 axes.set_ylabel("dy")
307
308 axes = figure.add_subplot(2, 2, 3)
309 axes.plot(y2[good], dx[good], 'ko')
310 axes.plot(y2[rejected], dx[rejected], 'ro')
311 axes.set_xlabel("y")
312 axes.set_ylabel("dx")
313
314 axes = figure.add_subplot(2, 2, 4)
315 axes.plot(y2[good], dy[good], 'ko')
316 axes.plot(y2[rejected], dy[rejected], 'ro')
317 axes.set_xlabel("y")
318 axes.set_ylabel("dy")
319
320 plt.show()

◆ rejectMatches()

lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask.rejectMatches ( self,
matches,
wcs,
rejected )
Flag deviant matches

We return a boolean numpy array indicating whether the corresponding
match should be rejected.  The previous list of rejections is used
so we can calculate uncontaminated statistics.

Parameters
----------
matches : `list` of `lsst.afw.table.ReferenceMatch`
    List of sources matched to references.
wcs : `lsst.afw.geom.SkyWcs`
    Fitted WCS.
rejected : array-like of `bool`
    Array of matches rejected from the fit. Unused.

Returns
-------
rejectedMatches : `ndarray` of type `bool`
    Matched objects found to be outside of tolerance.

Definition at line 236 of file fitTanSipWcs.py.

236 def rejectMatches(self, matches, wcs, rejected):
237 """Flag deviant matches
238
239 We return a boolean numpy array indicating whether the corresponding
240 match should be rejected. The previous list of rejections is used
241 so we can calculate uncontaminated statistics.
242
243 Parameters
244 ----------
245 matches : `list` of `lsst.afw.table.ReferenceMatch`
246 List of sources matched to references.
247 wcs : `lsst.afw.geom.SkyWcs`
248 Fitted WCS.
249 rejected : array-like of `bool`
250 Array of matches rejected from the fit. Unused.
251
252 Returns
253 -------
254 rejectedMatches : `ndarray` of type `bool`
255 Matched objects found to be outside of tolerance.
256 """
257 fit = [wcs.skyToPixel(m.first.getCoord()) for m in matches]
258 dx = np.array([ff.getX() - mm.second.getCentroid().getX() for ff, mm in zip(fit, matches)])
259 dy = np.array([ff.getY() - mm.second.getCentroid().getY() for ff, mm in zip(fit, matches)])
260 good = np.logical_not(rejected)
261 return (dx > self.config.rejSigma*dx[good].std()) | (dy > self.config.rejSigma*dy[good].std())
262
STL namespace.

Member Data Documentation

◆ _DefaultName

str lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask._DefaultName = "fitTanSipWcs"
staticprotected

Definition at line 79 of file fitTanSipWcs.py.

◆ ConfigClass

lsst.meas.astrom.fitTanSipWcs.FitTanSipWcsTask.ConfigClass = FitTanSipWcsConfig
static

Definition at line 78 of file fitTanSipWcs.py.


The documentation for this class was generated from the following file: