152 match_tolerance=None):
153 """Match sources to position reference stars.
154
155 Parameters
156 ----------
157 refCat : `lsst.afw.table.SimpleCatalog`
158 Reference catalog to match.
159 sourceCat : `lsst.afw.table.SourceCatalog`
160 Catalog of sources found on an exposure. This should already be
161 down-selected to "good"/"usable" sources in the calling Task.
162 wcs : `lsst.afw.geom.SkyWcs`
163 Current WCS of the exposure containing the sources.
164 sourceFluxField : `str`
165 Field of the sourceCat to use for flux
166 refFluxField : `str`
167 Field of the refCat to use for flux
168 match_tolerance : `lsst.meas.astrom.MatchTolerance`
169 Object containing information from previous
170 `lsst.meas.astrom.AstrometryTask` match/fit cycles for use in
171 matching. If `None` is config defaults.
172
173 Returns
174 -------
175 matchResult : `lsst.pipe.base.Struct`
176 Result struct with components
177
178 - ``matches`` : List of matches with distance below the maximum match
179 distance (`list` of `lsst.afw.table.ReferenceMatch`).
180 - ``useableSourceCat`` : Catalog of sources matched and suited for
181 WCS fitting (`lsst.afw.table.SourceCatalog`).
182 - ``match_tolerance`` : MatchTolerance object updated from this
183 match iteration (`lsst.meas.astrom.MatchTolerance`).
184 """
185 import lsstDebug
187
188 preNumObj = len(refCat)
189 refCat = self.filterStars(refCat)
190 numRefObj = len(refCat)
191
192 if self.log:
193 self.log.info("filterStars purged %d reference stars, leaving %d stars",
194 preNumObj - numRefObj, numRefObj)
195
196 if match_tolerance is None:
197 match_tolerance = MatchTolerance()
198
199
200
201 usableSourceCat = sourceCat
202
203 numUsableSources = len(usableSourceCat)
204
205 if len(usableSourceCat) == 0:
206 raise pipeBase.TaskError("No sources are usable")
207
208 minMatchedPairs =
min(self.config.minMatchedPairs,
209 int(self.config.minFracMatchedPairs *
min([len(refCat), len(usableSourceCat)])))
210
211
212 usableMatches = self._doMatch(
213 refCat=refCat,
214 sourceCat=usableSourceCat,
215 wcs=wcs,
216 refFluxField=refFluxField,
217 numUsableSources=numUsableSources,
218 minMatchedPairs=minMatchedPairs,
219 maxMatchDist=match_tolerance.maxMatchDist,
220 sourceFluxField=sourceFluxField,
221 verbose=debug.verbose,
222 )
223
224
225 matches = []
226 self._getIsGoodKeys(usableSourceCat.schema)
227 for match in usableMatches:
228 if self._isGoodTest(match.second):
229
230 matches.append(match)
231
232 self.log.debug("Found %d usable matches, of which %d had good sources",
233 len(usableMatches), len(matches))
234
235 if len(matches) == 0:
236 raise RuntimeError("Unable to match sources")
237
238 self.log.info("Matched %d sources", len(matches))
239 if len(matches) < minMatchedPairs:
240 self.log.warning("Number of matches is smaller than request")
241
242 return pipeBase.Struct(
243 matches=matches,
244 usableSourceCat=usableSourceCat,
245 match_tolerance=match_tolerance,
246 )
247