Coverage for python/lsst/meas/algorithms/sourceSelector.py: 39%
201 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-23 10:17 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-23 10:17 +0000
1#
2# LSST Data Management System
3#
4# Copyright 2008-2017 AURA/LSST.
5#
6# This product includes software developed by the
7# LSST Project (http://www.lsst.org/).
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the LSST License Statement and
20# the GNU General Public License along with this program. If not,
21# see <https://www.lsstcorp.org/LegalNotices/>.
22#
24__all__ = ["BaseSourceSelectorConfig", "BaseSourceSelectorTask", "sourceSelectorRegistry",
25 "ColorLimit", "MagnitudeLimit", "SignalToNoiseLimit", "MagnitudeErrorLimit",
26 "RequireFlags", "RequireUnresolved", "RequireFiniteRaDec", "RequirePrimary",
27 "ScienceSourceSelectorConfig", "ScienceSourceSelectorTask",
28 "ReferenceSourceSelectorConfig", "ReferenceSourceSelectorTask",
29 ]
31import abc
32import numpy as np
33import astropy.units as u
34import pandas
35import astropy.table
37import lsst.pex.config as pexConfig
38import lsst.pipe.base as pipeBase
41class BaseSourceSelectorConfig(pexConfig.Config):
42 pass
45class BaseSourceSelectorTask(pipeBase.Task, metaclass=abc.ABCMeta):
46 """Base class for source selectors
48 Source selectors are classes that perform a selection on a catalog
49 object given a set of criteria or cuts. They return the selected catalog
50 and can optionally set a specified Flag field in the input catalog to
51 identify if the source was selected.
53 Register all source selectors with the sourceSelectorRegistry using:
54 sourceSelectorRegistry.register(name, class)
56 Attributes
57 ----------
58 usesMatches : `bool`
59 A boolean variable specify if the inherited source selector uses
60 matches to an external catalog, and thus requires the ``matches``
61 argument to ``run()``.
62 """
64 ConfigClass = BaseSourceSelectorConfig
65 _DefaultName = "sourceSelector"
66 usesMatches = False
68 def __init__(self, **kwargs):
69 pipeBase.Task.__init__(self, **kwargs)
71 def run(self, sourceCat, sourceSelectedField=None, matches=None, exposure=None):
72 """Select sources and return them.
74 The input catalog must be contiguous in memory.
76 Parameters
77 ----------
78 sourceCat : Various table formats
79 Catalog of sources to select from. Can be
80 `lsst.afw.table.SourceCatalog` or `pandas.DataFrame` or
81 `astropy.table.Table`,
82 sourceSelectedField : `str` or None
83 Name of flag field in sourceCat to set for selected sources.
84 If set, will modify sourceCat in-place.
85 matches : `list` of `lsst.afw.table.ReferenceMatch` or None
86 List of matches to use for source selection.
87 If usesMatches is set in source selector this field is required.
88 If not, it is ignored.
89 exposure : `lsst.afw.image.Exposure` or None
90 The exposure the catalog was built from; used for debug display.
92 Returns
93 -------
94 struct : `lsst.pipe.base.Struct`
95 The struct contains the following data:
97 ``sourceCat``
98 The catalog of sources that were selected.
99 (may not be memory-contiguous)
100 (`lsst.afw.table.SourceCatalog` or `pandas.DataFrame`
101 or `astropy.table.Table`)
102 ``selected``
103 Boolean array of sources that were selected, same length as
104 sourceCat.
105 (`numpy.ndarray` of `bool`)
107 Raises
108 ------
109 RuntimeError
110 Raised if ``sourceCat`` is not contiguous.
111 """
112 if hasattr(sourceCat, 'isContiguous'):
113 # Check for continuity on afwTable catalogs
114 if not sourceCat.isContiguous():
115 raise RuntimeError("Input catalogs for source selection must be contiguous.")
117 result = self.selectSources(sourceCat=sourceCat,
118 exposure=exposure,
119 matches=matches)
121 if sourceSelectedField is not None:
122 sourceCat[sourceSelectedField] = result.selected
124 return pipeBase.Struct(sourceCat=sourceCat[result.selected],
125 selected=result.selected)
127 @abc.abstractmethod
128 def selectSources(self, sourceCat, matches=None, exposure=None):
129 """Return a selection of sources selected by some criteria.
131 Parameters
132 ----------
133 sourceCat : Various table formats
134 Catalog of sources to select from. Supports
135 `lsst.afw.table.SourceCatalog` or `pandas.DataFrame`
136 or `astropy.table.Table`
137 This catalog must be contiguous in memory.
138 matches : `list` of `lsst.afw.table.ReferenceMatch` or None
139 A list of lsst.afw.table.ReferenceMatch objects
140 exposure : `lsst.afw.image.Exposure` or None
141 The exposure the catalog was built from; used for debug display.
143 Returns
144 -------
145 struct : `lsst.pipe.base.Struct`
146 The struct contains the following data:
148 ``selected``
149 Boolean array of sources that were selected, same length as
150 sourceCat.
151 (`numpy.ndarray` of `bool`)
152 """
153 raise NotImplementedError("BaseSourceSelectorTask is abstract")
156sourceSelectorRegistry = pexConfig.makeRegistry(
157 doc="A registry of source selectors (subclasses of "
158 "BaseSourceSelectorTask)",
159)
162class BaseLimit(pexConfig.Config):
163 """Base class for selecting sources by applying a limit
165 This object can be used as a `lsst.pex.config.Config` for configuring
166 the limit, and then the `apply` method can be used to identify sources
167 in the catalog that match the configured limit.
169 This provides the `maximum` and `minimum` fields in the Config, and
170 a method to apply the limits to an array of values calculated by the
171 subclass.
172 """
173 minimum = pexConfig.Field(dtype=float, optional=True, doc="Select objects with value greater than this")
174 maximum = pexConfig.Field(dtype=float, optional=True, doc="Select objects with value less than this")
176 def apply(self, values):
177 """Apply the limits to an array of values
179 Subclasses should calculate the array of values and then
180 return the result of calling this method.
182 Parameters
183 ----------
184 values : `numpy.ndarray`
185 Array of values to which to apply limits.
187 Returns
188 -------
189 selected : `numpy.ndarray`
190 Boolean array indicating for each source whether it is selected
191 (True means selected).
192 """
193 selected = np.ones(len(values), dtype=bool)
194 with np.errstate(invalid="ignore"): # suppress NAN warnings
195 if self.minimum is not None:
196 selected &= values > self.minimum
197 if self.maximum is not None:
198 selected &= values < self.maximum
199 return selected
202class ColorLimit(BaseLimit):
203 """Select sources using a color limit
205 This object can be used as a `lsst.pex.config.Config` for configuring
206 the limit, and then the `apply` method can be used to identify sources
207 in the catalog that match the configured limit.
209 We refer to 'primary' and 'secondary' flux measurements; these are the
210 two components of the color, which is:
212 instFluxToMag(cat[primary]) - instFluxToMag(cat[secondary])
213 """
214 primary = pexConfig.Field(dtype=str, doc="Name of column with primary flux measurement")
215 secondary = pexConfig.Field(dtype=str, doc="Name of column with secondary flux measurement")
217 def apply(self, catalog):
218 """Apply the color limit to a catalog
220 Parameters
221 ----------
222 catalog : Various table formats
223 Catalog of sources to which the limit will be applied.
224 Supports `lsst.afw.table.SourceCatalog` or `pandas.DataFrame`
225 or `astropy.table.Table`
227 Returns
228 -------
229 selected : `numpy.ndarray`
230 Boolean array indicating for each source whether it is selected
231 (True means selected).
232 """
233 primary = _getFieldFromCatalog(catalog, self.primary)
234 secondary = _getFieldFromCatalog(catalog, self.secondary)
236 primary = (primary*u.nJy).to_value(u.ABmag)
237 secondary = (secondary*u.nJy).to_value(u.ABmag)
238 color = primary - secondary
239 return BaseLimit.apply(self, color)
242class FluxLimit(BaseLimit):
243 """Select sources using a flux limit
245 This object can be used as a `lsst.pex.config.Config` for configuring
246 the limit, and then the `apply` method can be used to identify sources
247 in the catalog that match the configured limit.
248 """
249 fluxField = pexConfig.Field(dtype=str, default="slot_CalibFlux_instFlux",
250 doc="Name of the source flux field to use.")
252 def apply(self, catalog):
253 """Apply the flux limits to a catalog
255 Parameters
256 ----------
257 catalog : `lsst.afw.table.SourceCatalog`
258 Catalog of sources to which the limit will be applied.
260 Returns
261 -------
262 selected : `numpy.ndarray`
263 Boolean array indicating for each source whether it is selected
264 (True means selected).
265 """
266 flagField = self.fluxField + "_flag"
267 selected = np.logical_not(_getFieldFromCatalog(catalog, flagField, isFlag=True))
268 flux = _getFieldFromCatalog(catalog, self.fluxField)
270 selected &= BaseLimit.apply(self, flux)
271 return selected
274class MagnitudeLimit(BaseLimit):
275 """Select sources using a magnitude limit
277 Note that this assumes that a zero-point has already been applied and
278 the fluxes are in AB fluxes in Jansky. It is therefore principally
279 intended for reference catalogs rather than catalogs extracted from
280 science images.
282 This object can be used as a `lsst.pex.config.Config` for configuring
283 the limit, and then the `apply` method can be used to identify sources
284 in the catalog that match the configured limit.
285 """
286 fluxField = pexConfig.Field(dtype=str, default="flux",
287 doc="Name of the source flux field to use.")
289 def apply(self, catalog):
290 """Apply the magnitude limits to a catalog
292 Parameters
293 ----------
294 catalog : `lsst.afw.table.SourceCatalog`
295 Catalog of sources to which the limit will be applied.
297 Returns
298 -------
299 selected : `numpy.ndarray`
300 Boolean array indicating for each source whether it is selected
301 (True means selected).
302 """
303 flagField = self.fluxField + "_flag"
304 selected = np.logical_not(_getFieldFromCatalog(catalog, flagField, isFlag=True))
305 flux = _getFieldFromCatalog(catalog, self.fluxField)
307 magnitude = (flux*u.nJy).to_value(u.ABmag)
308 selected &= BaseLimit.apply(self, magnitude)
309 return selected
312class SignalToNoiseLimit(BaseLimit):
313 """Select sources using a flux signal-to-noise limit
315 This object can be used as a `lsst.pex.config.Config` for configuring
316 the limit, and then the `apply` method can be used to identify sources
317 in the catalog that match the configured limit.
318 """
319 fluxField = pexConfig.Field(dtype=str, default="flux",
320 doc="Name of the source flux field to use.")
321 errField = pexConfig.Field(dtype=str, default="flux_err",
322 doc="Name of the source flux error field to use.")
324 def apply(self, catalog):
325 """Apply the signal-to-noise limits to a catalog
327 Parameters
328 ----------
329 catalog : `lsst.afw.table.SourceCatalog`
330 Catalog of sources to which the limit will be applied.
332 Returns
333 -------
334 selected : `numpy.ndarray`
335 Boolean array indicating for each source whether it is selected
336 (True means selected).
337 """
338 flagField = self.fluxField + "_flag"
339 selected = np.logical_not(_getFieldFromCatalog(catalog, flagField, isFlag=True))
340 flux = _getFieldFromCatalog(catalog, self.fluxField)
341 err = _getFieldFromCatalog(catalog, self.errField)
343 signalToNoise = flux/err
344 selected &= BaseLimit.apply(self, signalToNoise)
345 return selected
348class MagnitudeErrorLimit(BaseLimit):
349 """Select sources using a magnitude error limit
351 Because the magnitude error is the inverse of the signal-to-noise
352 ratio, this also works to select sources by signal-to-noise when
353 you only have a magnitude.
355 This object can be used as a `lsst.pex.config.Config` for configuring
356 the limit, and then the `apply` method can be used to identify sources
357 in the catalog that match the configured limit.
358 """
359 magErrField = pexConfig.Field(dtype=str, default="mag_err",
360 doc="Name of the source flux error field to use.")
362 def apply(self, catalog):
363 """Apply the magnitude error limits to a catalog
365 Parameters
366 ----------
367 catalog : `lsst.afw.table.SourceCatalog`
368 Catalog of sources to which the limit will be applied.
370 Returns
371 -------
372 selected : `numpy.ndarray`
373 Boolean array indicating for each source whether it is selected
374 (True means selected).
375 """
376 return BaseLimit.apply(self, catalog[self.magErrField])
379class RequireFlags(pexConfig.Config):
380 """Select sources using flags
382 This object can be used as a `lsst.pex.config.Config` for configuring
383 the limit, and then the `apply` method can be used to identify sources
384 in the catalog that match the configured limit.
385 """
386 good = pexConfig.ListField(dtype=str, default=[],
387 doc="List of source flag fields that must be set for a source to be used.")
388 bad = pexConfig.ListField(dtype=str, default=[],
389 doc="List of source flag fields that must NOT be set for a source to be used.")
391 def apply(self, catalog):
392 """Apply the flag requirements to a catalog
394 Returns whether the source is selected.
396 Parameters
397 ----------
398 catalog : `lsst.afw.table.SourceCatalog`
399 Catalog of sources to which the requirements will be applied.
401 Returns
402 -------
403 selected : `numpy.ndarray`
404 Boolean array indicating for each source whether it is selected
405 (True means selected).
406 """
407 selected = np.ones(len(catalog), dtype=bool)
408 for flag in self.good:
409 selected &= catalog[flag]
410 for flag in self.bad:
411 selected &= ~catalog[flag]
412 return selected
415class RequireUnresolved(BaseLimit):
416 """Select sources using star/galaxy separation
418 This object can be used as a `lsst.pex.config.Config` for configuring
419 the limit, and then the `apply` method can be used to identify sources
420 in the catalog that match the configured limit.
421 """
422 name = pexConfig.Field(dtype=str, default="base_ClassificationExtendedness_value",
423 doc="Name of column for star/galaxy separation")
425 def setDefaults(self):
426 """Set default
428 ``base_ClassificationExtendedness_value < 0.5`` means unresolved.
429 """
430 self.maximum = 0.5
432 def apply(self, catalog):
433 """Apply the flag requirements to a catalog
435 Returns whether the source is selected.
437 Parameters
438 ----------
439 catalog : `lsst.afw.table.SourceCatalog`
440 Catalog of sources to which the requirements will be applied.
442 Returns
443 -------
444 selected : `numpy.ndarray`
445 Boolean array indicating for each source whether it is selected
446 (True means selected).
447 """
448 value = catalog[self.name]
449 return BaseLimit.apply(self, value)
452class RequireIsolated(pexConfig.Config):
453 """Select sources based on whether they are isolated
455 This object can be used as a `lsst.pex.config.Config` for configuring
456 the column names to check for "parent" and "nChild" keys.
458 Note that this should only be run on a catalog that has had the
459 deblender already run (or else deblend_nChild does not exist).
460 """
461 parentName = pexConfig.Field(dtype=str, default="parent",
462 doc="Name of column for parent")
463 nChildName = pexConfig.Field(dtype=str, default="deblend_nChild",
464 doc="Name of column for nChild")
466 def apply(self, catalog):
467 """Apply the isolation requirements to a catalog
469 Returns whether the source is selected.
471 Parameters
472 ----------
473 catalog : `lsst.afw.table.SourceCatalog`
474 Catalog of sources to which the requirements will be applied.
476 Returns
477 -------
478 selected : `numpy.ndarray`
479 Boolean array indicating for each source whether it is selected
480 (True means selected).
481 """
482 selected = ((catalog[self.parentName] == 0)
483 & (catalog[self.nChildName] == 0))
484 return selected
487class RequireFiniteRaDec(pexConfig.Config):
488 """Select sources that have finite RA and Dec sky coordinate values
490 This object can be used as a `lsst.pex.config.Config` for configuring
491 the column names to check for "coord_ra" and "coord_dec" keys.
493 This will select against objects for which either the RA or Dec coordinate
494 entries are not numpy.isfinite().
495 """
496 raColName = pexConfig.Field(dtype=str, default="coord_ra", doc="Name of column for RA coordinate")
497 decColName = pexConfig.Field(dtype=str, default="coord_dec", doc="Name of column for Dec coordinate")
499 def apply(self, catalog):
500 """Apply the sky coordinate requirements to a catalog
502 Returns whether the sources were selected.
504 Parameters
505 ----------
506 catalog : `lsst.afw.table.SourceCatalog` or `pandas.DataFrame`
507 or `astropy.table.Table`
508 Catalog of sources to which the requirements will be applied.
510 Returns
511 -------
512 selected : `numpy.ndarray`
513 Boolean array indicating for each source whether it is selected
514 (True means selected).
515 """
516 selected = (np.isfinite(_getFieldFromCatalog(catalog, self.raColName))
517 & np.isfinite(_getFieldFromCatalog(catalog, self.decColName)))
518 return selected
521class RequirePrimary(pexConfig.Config):
522 """Select sources that have the detect_isPrimary flag set.
524 This object can be used as a `lsst.pex.config.Config` for configuring
525 the column names to check for "detect_isPrimary". For single frame
526 catalogs this will be True when the source is not a sky object, and is
527 either an isolated parent that is un-modeled or deblended from a parent
528 with multiple children. For meas_deblender, this is equivalent to
529 deblend_nChild=0. For coadd catalogs there is an additional constraint
530 that the source is located on the interior of a patch and tract.
531 """
532 primaryColName = pexConfig.Field(
533 dtype=str,
534 default="detect_isPrimary",
535 doc="Name of primary flag column",
536 )
538 def apply(self, catalog):
539 """Apply the primary requirements to a catalog.
541 Returns whether the sources were selected.
543 Parameters
544 ----------
545 catalog : lsst.afw.table.SourceCatalog` or `pandas.DataFrame`
546 or `astropy.table.Table`
547 Catalog of sources to which the requirement will be applied.
549 Returns
550 -------
551 selected : `numpy.ndarray`
552 Boolean array indicating for each source whether it is selected
553 (True means selected).
554 """
555 selected = (_getFieldFromCatalog(catalog, self.primaryColName)).astype(bool)
557 return selected
560class ScienceSourceSelectorConfig(pexConfig.Config):
561 """Configuration for selecting science sources"""
562 doFluxLimit = pexConfig.Field(dtype=bool, default=False, doc="Apply flux limit?")
563 doFlags = pexConfig.Field(dtype=bool, default=False, doc="Apply flag limitation?")
564 doUnresolved = pexConfig.Field(dtype=bool, default=False, doc="Apply unresolved limitation?")
565 doSignalToNoise = pexConfig.Field(dtype=bool, default=False, doc="Apply signal-to-noise limit?")
566 doIsolated = pexConfig.Field(dtype=bool, default=False, doc="Apply isolated limitation?")
567 doRequireFiniteRaDec = pexConfig.Field(dtype=bool, default=False,
568 doc="Apply finite sky coordinate check?")
569 doRequirePrimary = pexConfig.Field(dtype=bool, default=False,
570 doc="Apply source is primary check?")
571 fluxLimit = pexConfig.ConfigField(dtype=FluxLimit, doc="Flux limit to apply")
572 flags = pexConfig.ConfigField(dtype=RequireFlags, doc="Flags to require")
573 unresolved = pexConfig.ConfigField(dtype=RequireUnresolved, doc="Star/galaxy separation to apply")
574 signalToNoise = pexConfig.ConfigField(dtype=SignalToNoiseLimit, doc="Signal-to-noise limit to apply")
575 isolated = pexConfig.ConfigField(dtype=RequireIsolated, doc="Isolated criteria to apply")
576 requireFiniteRaDec = pexConfig.ConfigField(dtype=RequireFiniteRaDec,
577 doc="Finite sky coordinate criteria to apply")
578 requirePrimary = pexConfig.ConfigField(dtype=RequirePrimary,
579 doc="Primary source criteria to apply")
581 def setDefaults(self):
582 pexConfig.Config.setDefaults(self)
583 self.flags.bad = ["base_PixelFlags_flag_edge", "base_PixelFlags_flag_saturated", "base_PsfFlux_flags"]
584 self.signalToNoise.fluxField = "base_PsfFlux_instFlux"
585 self.signalToNoise.errField = "base_PsfFlux_instFluxErr"
588@pexConfig.registerConfigurable("science", sourceSelectorRegistry)
589class ScienceSourceSelectorTask(BaseSourceSelectorTask):
590 """Science source selector
592 By "science" sources, we mean sources that are on images that we
593 are processing, as opposed to sources from reference catalogs.
595 This selects (science) sources by (optionally) applying each of a
596 magnitude limit, flag requirements and star/galaxy separation.
597 """
598 ConfigClass = ScienceSourceSelectorConfig
600 def selectSources(self, sourceCat, matches=None, exposure=None):
601 """Return a selection of sources selected by specified criteria.
603 Parameters
604 ----------
605 sourceCat : `lsst.afw.table.SourceCatalog`
606 Catalog of sources to select from.
607 This catalog must be contiguous in memory.
608 matches : `list` of `lsst.afw.table.ReferenceMatch` or None
609 Ignored in this SourceSelector.
610 exposure : `lsst.afw.image.Exposure` or None
611 The exposure the catalog was built from; used for debug display.
613 Returns
614 -------
615 struct : `lsst.pipe.base.Struct`
616 The struct contains the following data:
618 ``selected``
619 Boolean array of sources that were selected, same length as
620 sourceCat.
621 (`numpy.ndarray` of `bool`)
622 """
623 selected = np.ones(len(sourceCat), dtype=bool)
624 if self.config.doFluxLimit:
625 selected &= self.config.fluxLimit.apply(sourceCat)
626 if self.config.doFlags:
627 selected &= self.config.flags.apply(sourceCat)
628 if self.config.doUnresolved:
629 selected &= self.config.unresolved.apply(sourceCat)
630 if self.config.doSignalToNoise:
631 selected &= self.config.signalToNoise.apply(sourceCat)
632 if self.config.doIsolated:
633 selected &= self.config.isolated.apply(sourceCat)
634 if self.config.doRequireFiniteRaDec:
635 selected &= self.config.requireFiniteRaDec.apply(sourceCat)
636 if self.config.doRequirePrimary:
637 selected &= self.config.requirePrimary.apply(sourceCat)
639 self.log.info("Selected %d/%d sources", selected.sum(), len(sourceCat))
641 return pipeBase.Struct(selected=selected)
644class ReferenceSourceSelectorConfig(pexConfig.Config):
645 doMagLimit = pexConfig.Field(dtype=bool, default=False, doc="Apply magnitude limit?")
646 doFlags = pexConfig.Field(dtype=bool, default=False, doc="Apply flag limitation?")
647 doUnresolved = pexConfig.Field(dtype=bool, default=False, doc="Apply unresolved limitation?")
648 doSignalToNoise = pexConfig.Field(dtype=bool, default=False, doc="Apply signal-to-noise limit?")
649 doMagError = pexConfig.Field(dtype=bool, default=False, doc="Apply magnitude error limit?")
650 magLimit = pexConfig.ConfigField(dtype=MagnitudeLimit, doc="Magnitude limit to apply")
651 flags = pexConfig.ConfigField(dtype=RequireFlags, doc="Flags to require")
652 unresolved = pexConfig.ConfigField(dtype=RequireUnresolved, doc="Star/galaxy separation to apply")
653 signalToNoise = pexConfig.ConfigField(dtype=SignalToNoiseLimit, doc="Signal-to-noise limit to apply")
654 magError = pexConfig.ConfigField(dtype=MagnitudeErrorLimit, doc="Magnitude error limit to apply")
655 colorLimits = pexConfig.ConfigDictField(keytype=str, itemtype=ColorLimit, default={},
656 doc="Color limits to apply; key is used as a label only")
659@pexConfig.registerConfigurable("references", sourceSelectorRegistry)
660class ReferenceSourceSelectorTask(BaseSourceSelectorTask):
661 """Reference source selector
663 This selects reference sources by (optionally) applying each of a
664 magnitude limit, flag requirements and color limits.
665 """
666 ConfigClass = ReferenceSourceSelectorConfig
668 def selectSources(self, sourceCat, matches=None, exposure=None):
669 """Return a selection of reference sources selected by some criteria.
671 Parameters
672 ----------
673 sourceCat : `lsst.afw.table.SourceCatalog`
674 Catalog of sources to select from.
675 This catalog must be contiguous in memory.
676 matches : `list` of `lsst.afw.table.ReferenceMatch` or None
677 Ignored in this SourceSelector.
678 exposure : `lsst.afw.image.Exposure` or None
679 The exposure the catalog was built from; used for debug display.
681 Returns
682 -------
683 struct : `lsst.pipe.base.Struct`
684 The struct contains the following data:
686 ``selected``
687 Boolean array of sources that were selected, same length as
688 sourceCat.
689 (`numpy.ndarray` of `bool`)
690 """
691 selected = np.ones(len(sourceCat), dtype=bool)
692 if self.config.doMagLimit:
693 selected &= self.config.magLimit.apply(sourceCat)
694 if self.config.doFlags:
695 selected &= self.config.flags.apply(sourceCat)
696 if self.config.doUnresolved:
697 selected &= self.config.unresolved.apply(sourceCat)
698 if self.config.doSignalToNoise:
699 selected &= self.config.signalToNoise.apply(sourceCat)
700 if self.config.doMagError:
701 selected &= self.config.magError.apply(sourceCat)
702 for limit in self.config.colorLimits.values():
703 selected &= limit.apply(sourceCat)
705 self.log.info("Selected %d/%d references", selected.sum(), len(sourceCat))
707 return pipeBase.Struct(selected=selected)
710def _getFieldFromCatalog(catalog, field, isFlag=False):
711 """
712 Get a field from a catalog, for `lsst.afw.table` catalogs or
713 `pandas.DataFrame` or `astropy.table.Table` catalogs.
715 Parameters
716 ----------
717 catalog : `lsst.afw.table.SourceCatalog` or `pandas.DataFrame`
718 or `astropy.table.Table`
719 Catalog of sources to extract field array
720 field : `str`
721 Name of field
722 isFlag : `bool`, optional
723 Is this a flag column? If it does not exist, return array
724 of False.
726 Returns
727 -------
728 array : `np.ndarray`
729 Array of field values from the catalog.
730 """
731 found = False
732 if isinstance(catalog, (pandas.DataFrame, astropy.table.Table)):
733 if field in catalog.columns:
734 found = True
735 # Sequences must be converted to numpy arrays
736 arr = np.array(catalog[field])
737 else:
738 if field in catalog.schema:
739 found = True
740 arr = catalog[field]
742 if isFlag and not found:
743 arr = np.zeros(len(catalog), dtype=bool)
744 elif not found:
745 raise KeyError(f"Could not find field {field} in catalog.")
747 return arr