24__all__ = [
"BaseSourceSelectorConfig",
"BaseSourceSelectorTask",
"sourceSelectorRegistry",
25 "ColorLimit",
"MagnitudeLimit",
"SignalToNoiseLimit",
"MagnitudeErrorLimit",
26 "RequireFlags",
"RequireUnresolved",
"RequireFiniteRaDec",
27 "ScienceSourceSelectorConfig",
"ScienceSourceSelectorTask",
28 "ReferenceSourceSelectorConfig",
"ReferenceSourceSelectorTask",
33import astropy.units
as u
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)
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()``.
64 ConfigClass = BaseSourceSelectorConfig
65 _DefaultName = "sourceSelector"
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.
78 sourceCat : Various table formats
79 Catalog of sources to select
from. Can be
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.
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.
90 The exposure the catalog was built
from; used
for debug display.
94 struct : `lsst.pipe.base.Struct`
95 The struct contains the following data:
98 The catalog of sources that were selected.
99 (may
not be memory-contiguous)
101 or `astropy.table.Table`)
103 Boolean array of sources that were selected, same length
as
105 (`numpy.ndarray` of `bool`)
110 Raised
if ``sourceCat``
is not contiguous.
112 if hasattr(sourceCat,
'isContiguous'):
114 if not sourceCat.isContiguous():
115 raise RuntimeError(
"Input catalogs for source selection must be contiguous.")
121 if sourceSelectedField
is not None:
122 if isinstance(sourceCat, (pandas.DataFrame, astropy.table.Table)):
123 sourceCat[sourceSelectedField] = result.selected
125 source_selected_key = \
126 sourceCat.getSchema()[sourceSelectedField].asKey()
128 for source, flag
in zip(sourceCat, result.selected):
129 source.set(source_selected_key, bool(flag))
130 return pipeBase.Struct(sourceCat=sourceCat[result.selected],
131 selected=result.selected)
135 """Return a selection of sources selected by some criteria.
139 sourceCat : Various table formats
140 Catalog of sources to select from. Supports
142 or `astropy.table.Table`
143 This catalog must be contiguous
in memory.
147 The exposure the catalog was built
from; used
for debug display.
151 struct : `lsst.pipe.base.Struct`
152 The struct contains the following data:
155 Boolean array of sources that were selected, same length
as
157 (`numpy.ndarray` of `bool`)
159 raise NotImplementedError(
"BaseSourceSelectorTask is abstract")
162sourceSelectorRegistry = pexConfig.makeRegistry(
163 doc=
"A registry of source selectors (subclasses of "
164 "BaseSourceSelectorTask)",
169 """Base class for selecting sources by applying a limit
172 the limit,
and then the `apply` method can be used to identify sources
173 in the catalog that match the configured limit.
175 This provides the `maximum`
and `minimum` fields
in the Config,
and
176 a method to apply the limits to an array of values calculated by the
179 minimum = pexConfig.Field(dtype=float, optional=True, doc=
"Select objects with value greater than this")
180 maximum = pexConfig.Field(dtype=float, optional=
True, doc=
"Select objects with value less than this")
183 """Apply the limits to an array of values
185 Subclasses should calculate the array of values and then
186 return the result of calling this method.
190 values : `numpy.ndarray`
191 Array of values to which to apply limits.
195 selected : `numpy.ndarray`
196 Boolean array indicating
for each source whether it
is selected
197 (
True means selected).
199 selected = np.ones(len(values), dtype=bool)
200 with np.errstate(invalid=
"ignore"):
202 selected &= values > self.
minimum
204 selected &= values < self.
maximum
209 """Select sources using a color limit
212 the limit,
and then the `apply` method can be used to identify sources
213 in the catalog that match the configured limit.
215 We refer to
'primary' and 'secondary' flux measurements; these are the
216 two components of the color, which
is:
218 instFluxToMag(cat[primary]) - instFluxToMag(cat[secondary])
220 primary = pexConfig.Field(dtype=str, doc="Name of column with primary flux measurement")
221 secondary = pexConfig.Field(dtype=str, doc=
"Name of column with secondary flux measurement")
224 """Apply the color limit to a catalog
228 catalog : Various table formats
229 Catalog of sources to which the limit will be applied.
231 or `astropy.table.Table`
235 selected : `numpy.ndarray`
236 Boolean array indicating
for each source whether it
is selected
237 (
True means selected).
239 primary = _getFieldFromCatalog(catalog, self.primary)
240 secondary = _getFieldFromCatalog(catalog, self.secondary)
242 primary = (primary*u.nJy).to_value(u.ABmag)
243 secondary = (secondary*u.nJy).to_value(u.ABmag)
244 color = primary - secondary
245 return BaseLimit.apply(self, color)
249 """Select sources using a flux limit
252 the limit,
and then the `apply` method can be used to identify sources
253 in the catalog that match the configured limit.
255 fluxField = pexConfig.Field(dtype=str, default="slot_CalibFlux_instFlux",
256 doc=
"Name of the source flux field to use.")
259 """Apply the flux limits to a catalog
264 Catalog of sources to which the limit will be applied.
268 selected : `numpy.ndarray`
269 Boolean array indicating for each source whether it
is selected
270 (
True means selected).
273 selected = np.logical_not(_getFieldFromCatalog(catalog, flagField, isFlag=
True))
274 flux = _getFieldFromCatalog(catalog, self.
fluxField)
276 selected &= BaseLimit.apply(self, flux)
281 """Select sources using a magnitude limit
283 Note that this assumes that a zero-point has already been applied and
284 the fluxes are
in AB fluxes
in Jansky. It
is therefore principally
285 intended
for reference catalogs rather than catalogs extracted
from
289 the limit,
and then the `apply` method can be used to identify sources
290 in the catalog that match the configured limit.
292 fluxField = pexConfig.Field(dtype=str, default="flux",
293 doc=
"Name of the source flux field to use.")
296 """Apply the magnitude limits to a catalog
301 Catalog of sources to which the limit will be applied.
305 selected : `numpy.ndarray`
306 Boolean array indicating for each source whether it
is selected
307 (
True means selected).
310 selected = np.logical_not(_getFieldFromCatalog(catalog, flagField, isFlag=
True))
311 flux = _getFieldFromCatalog(catalog, self.
fluxField)
313 magnitude = (flux*u.nJy).to_value(u.ABmag)
314 selected &= BaseLimit.apply(self, magnitude)
319 """Select sources using a flux signal-to-noise limit
322 the limit,
and then the `apply` method can be used to identify sources
323 in the catalog that match the configured limit.
325 fluxField = pexConfig.Field(dtype=str, default="flux",
326 doc=
"Name of the source flux field to use.")
327 errField = pexConfig.Field(dtype=str, default=
"flux_err",
328 doc=
"Name of the source flux error field to use.")
331 """Apply the signal-to-noise limits to a catalog
336 Catalog of sources to which the limit will be applied.
340 selected : `numpy.ndarray`
341 Boolean array indicating for each source whether it
is selected
342 (
True means selected).
345 selected = np.logical_not(_getFieldFromCatalog(catalog, flagField, isFlag=
True))
346 flux = _getFieldFromCatalog(catalog, self.
fluxField)
347 err = _getFieldFromCatalog(catalog, self.
errField)
349 signalToNoise = flux/err
350 selected &= BaseLimit.apply(self, signalToNoise)
355 """Select sources using a magnitude error limit
357 Because the magnitude error is the inverse of the signal-to-noise
358 ratio, this also works to select sources by signal-to-noise when
359 you only have a magnitude.
362 the limit,
and then the `apply` method can be used to identify sources
363 in the catalog that match the configured limit.
365 magErrField = pexConfig.Field(dtype=str, default="mag_err",
366 doc=
"Name of the source flux error field to use.")
369 """Apply the magnitude error limits to a catalog
374 Catalog of sources to which the limit will be applied.
378 selected : `numpy.ndarray`
379 Boolean array indicating for each source whether it
is selected
380 (
True means selected).
382 return BaseLimit.apply(self, catalog[self.
magErrField])
386 """Select sources using flags
389 the limit,
and then the `apply` method can be used to identify sources
390 in the catalog that match the configured limit.
392 good = pexConfig.ListField(dtype=str, default=[],
393 doc="List of source flag fields that must be set for a source to be used.")
394 bad = pexConfig.ListField(dtype=str, default=[],
395 doc=
"List of source flag fields that must NOT be set for a source to be used.")
398 """Apply the flag requirements to a catalog
400 Returns whether the source is selected.
405 Catalog of sources to which the requirements will be applied.
409 selected : `numpy.ndarray`
410 Boolean array indicating
for each source whether it
is selected
411 (
True means selected).
413 selected = np.ones(len(catalog), dtype=bool)
414 for flag
in self.
good:
415 selected &= catalog[flag]
416 for flag
in self.
bad:
417 selected &= ~catalog[flag]
422 """Select sources using star/galaxy separation
425 the limit,
and then the `apply` method can be used to identify sources
426 in the catalog that match the configured limit.
428 name = pexConfig.Field(dtype=str, default="base_ClassificationExtendedness_value",
429 doc=
"Name of column for star/galaxy separation")
434 ``base_ClassificationExtendedness_value < 0.5`` means unresolved.
439 """Apply the flag requirements to a catalog
441 Returns whether the source is selected.
446 Catalog of sources to which the requirements will be applied.
450 selected : `numpy.ndarray`
451 Boolean array indicating
for each source whether it
is selected
452 (
True means selected).
454 value = catalog[self.name]
455 return BaseLimit.apply(self, value)
459 """Select sources based on whether they are isolated
462 the column names to check
for "parent" and "nChild" keys.
464 Note that this should only be run on a catalog that has had the
465 deblender already run (
or else deblend_nChild does
not exist).
467 parentName = pexConfig.Field(dtype=str, default="parent",
468 doc=
"Name of column for parent")
469 nChildName = pexConfig.Field(dtype=str, default=
"deblend_nChild",
470 doc=
"Name of column for nChild")
473 """Apply the isolation requirements to a catalog
475 Returns whether the source is selected.
480 Catalog of sources to which the requirements will be applied.
484 selected : `numpy.ndarray`
485 Boolean array indicating
for each source whether it
is selected
486 (
True means selected).
494 """Select sources that have finite RA and Dec sky coordinate values
497 the column names to check
for "coore_ra" and "coord_dec" keys.
499 This will select against objects
for which either the RA
or Dec coordinate
500 entries are
not numpy.isfinite().
502 raColName = pexConfig.Field(dtype=str, default="coord_ra", doc=
"Name of column for RA coordinate")
503 decColName = pexConfig.Field(dtype=str, default=
"coord_dec", doc=
"Name of column for Dec coordiante")
506 """Apply the sky coordinate requirements to a catalog
508 Returns whether the source is selected.
513 or `astropy.table.Table`
514 Catalog of sources to which the requirements will be applied.
518 selected : `numpy.ndarray`
519 Boolean array indicating
for each source whether it
is selected
520 (
True means selected).
522 selected = (np.isfinite(_getFieldFromCatalog(catalog, self.raColName))
523 & np.isfinite(_getFieldFromCatalog(catalog, self.decColName)))
528 """Configuration for selecting science sources"""
529 doFluxLimit = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply flux limit?")
530 doFlags = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply flag limitation?")
531 doUnresolved = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply unresolved limitation?")
532 doSignalToNoise = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply signal-to-noise limit?")
533 doIsolated = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply isolated limitation?")
534 doRequireFiniteRaDec = pexConfig.Field(dtype=bool, default=
False,
535 doc=
"Apply finite sky coordinate check?")
536 fluxLimit = pexConfig.ConfigField(dtype=FluxLimit, doc=
"Flux limit to apply")
537 flags = pexConfig.ConfigField(dtype=RequireFlags, doc=
"Flags to require")
538 unresolved = pexConfig.ConfigField(dtype=RequireUnresolved, doc=
"Star/galaxy separation to apply")
539 signalToNoise = pexConfig.ConfigField(dtype=SignalToNoiseLimit, doc=
"Signal-to-noise limit to apply")
540 isolated = pexConfig.ConfigField(dtype=RequireIsolated, doc=
"Isolated criteria to apply")
541 requireFiniteRaDec = pexConfig.ConfigField(dtype=RequireFiniteRaDec,
542 doc=
"Finite sky coordinate criteria to apply")
545 pexConfig.Config.setDefaults(self)
546 self.
flags.bad = [
"base_PixelFlags_flag_edge",
"base_PixelFlags_flag_saturated",
"base_PsfFlux_flags"]
551@pexConfig.registerConfigurable("science", sourceSelectorRegistry)
553 """Science source selector
555 By "science" sources, we mean sources that are on images that we
556 are processing,
as opposed to sources
from reference catalogs.
558 This selects (science) sources by (optionally) applying each of a
559 magnitude limit, flag requirements
and star/galaxy separation.
561 ConfigClass = ScienceSourceSelectorConfig
564 """Return a selection of sources selected by specified criteria.
569 Catalog of sources to select from.
570 This catalog must be contiguous
in memory.
572 Ignored
in this SourceSelector.
574 The exposure the catalog was built
from; used
for debug display.
578 struct : `lsst.pipe.base.Struct`
579 The struct contains the following data:
582 Boolean array of sources that were selected, same length
as
584 (`numpy.ndarray` of `bool`)
586 selected = np.ones(len(sourceCat), dtype=bool)
587 if self.config.doFluxLimit:
588 selected &= self.config.fluxLimit.apply(sourceCat)
589 if self.config.doFlags:
590 selected &= self.config.flags.apply(sourceCat)
591 if self.config.doUnresolved:
592 selected &= self.config.unresolved.apply(sourceCat)
593 if self.config.doSignalToNoise:
594 selected &= self.config.signalToNoise.apply(sourceCat)
595 if self.config.doIsolated:
596 selected &= self.config.isolated.apply(sourceCat)
597 if self.config.doRequireFiniteRaDec:
598 selected &= self.config.requireFiniteRaDec.apply(sourceCat)
600 self.log.info(
"Selected %d/%d sources", selected.sum(), len(sourceCat))
602 return pipeBase.Struct(selected=selected)
606 doMagLimit = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply magnitude limit?")
607 doFlags = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply flag limitation?")
608 doUnresolved = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply unresolved limitation?")
609 doSignalToNoise = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply signal-to-noise limit?")
610 doMagError = pexConfig.Field(dtype=bool, default=
False, doc=
"Apply magnitude error limit?")
611 magLimit = pexConfig.ConfigField(dtype=MagnitudeLimit, doc=
"Magnitude limit to apply")
612 flags = pexConfig.ConfigField(dtype=RequireFlags, doc=
"Flags to require")
613 unresolved = pexConfig.ConfigField(dtype=RequireUnresolved, doc=
"Star/galaxy separation to apply")
614 signalToNoise = pexConfig.ConfigField(dtype=SignalToNoiseLimit, doc=
"Signal-to-noise limit to apply")
615 magError = pexConfig.ConfigField(dtype=MagnitudeErrorLimit, doc=
"Magnitude error limit to apply")
616 colorLimits = pexConfig.ConfigDictField(keytype=str, itemtype=ColorLimit, default={},
617 doc=
"Color limits to apply; key is used as a label only")
620@pexConfig.registerConfigurable("references", sourceSelectorRegistry)
622 """Reference source selector
624 This selects reference sources by (optionally) applying each of a
625 magnitude limit, flag requirements and color limits.
627 ConfigClass = ReferenceSourceSelectorConfig
630 """Return a selection of reference sources selected by some criteria.
635 Catalog of sources to select from.
636 This catalog must be contiguous
in memory.
638 Ignored
in this SourceSelector.
640 The exposure the catalog was built
from; used
for debug display.
644 struct : `lsst.pipe.base.Struct`
645 The struct contains the following data:
648 Boolean array of sources that were selected, same length
as
650 (`numpy.ndarray` of `bool`)
652 selected = np.ones(len(sourceCat), dtype=bool)
653 if self.config.doMagLimit:
654 selected &= self.config.magLimit.apply(sourceCat)
655 if self.config.doFlags:
656 selected &= self.config.flags.apply(sourceCat)
657 if self.config.doUnresolved:
658 selected &= self.config.unresolved.apply(sourceCat)
659 if self.config.doSignalToNoise:
660 selected &= self.config.signalToNoise.apply(sourceCat)
661 if self.config.doMagError:
662 selected &= self.config.magError.apply(sourceCat)
663 for limit
in self.config.colorLimits.values():
664 selected &= limit.apply(sourceCat)
666 self.log.info(
"Selected %d/%d references", selected.sum(), len(sourceCat))
668 return pipeBase.Struct(selected=selected)
671def _getFieldFromCatalog(catalog, field, isFlag=False):
674 `pandas.DataFrame`
or `astropy.table.Table` catalogs.
679 or `astropy.table.Table`
680 Catalog of sources to extract field array
683 isFlag : `bool`, optional
684 Is this a flag column? If it does
not exist,
return array
690 Array of field values
from the catalog.
693 if isinstance(catalog, (pandas.DataFrame, astropy.table.Table)):
694 if field
in catalog.columns:
697 arr = np.array(catalog[field])
699 if field
in catalog.schema:
703 if isFlag
and not found:
704 arr = np.zeros(len(catalog), dtype=bool)
706 raise KeyError(f
"Could not find field {field} in catalog.")
A class to contain the data, WCS, and other information needed to describe an image of the sky.
def selectSources(self, sourceCat, matches=None, exposure=None)
def __init__(self, **kwargs)
def selectSources(self, sourceCat, matches=None, exposure=None)
def selectSources(self, sourceCat, matches=None, exposure=None)
Lightweight representation of a geometric match between two records.