LSST Applications g0b6bd0c080+a72a5dd7e6,g1182afd7b4+2a019aa3bb,g17e5ecfddb+2b8207f7de,g1d67935e3f+06cf436103,g38293774b4+ac198e9f13,g396055baef+6a2097e274,g3b44f30a73+6611e0205b,g480783c3b1+98f8679e14,g48ccf36440+89c08d0516,g4b93dc025c+98f8679e14,g5c4744a4d9+a302e8c7f0,g613e996a0d+e1c447f2e0,g6c8d09e9e7+25247a063c,g7271f0639c+98f8679e14,g7a9cd813b8+124095ede6,g9d27549199+a302e8c7f0,ga1cf026fa3+ac198e9f13,ga32aa97882+7403ac30ac,ga786bb30fb+7a139211af,gaa63f70f4e+9994eb9896,gabf319e997+ade567573c,gba47b54d5d+94dc90c3ea,gbec6a3398f+06cf436103,gc6308e37c7+07dd123edb,gc655b1545f+ade567573c,gcc9029db3c+ab229f5caf,gd01420fc67+06cf436103,gd877ba84e5+06cf436103,gdb4cecd868+6f279b5b48,ge2d134c3d5+cc4dbb2e3f,ge448b5faa6+86d1ceac1d,gecc7e12556+98f8679e14,gf3ee170dca+25247a063c,gf4ac96e456+ade567573c,gf9f5ea5b4d+ac198e9f13,gff490e6085+8c2580be5c,w.2022.27
LSST Data Management Base Package
reserveSourcesTask.py
Go to the documentation of this file.
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#
23
24__all__ = ["ReserveSourcesConfig", "ReserveSourcesTask"]
25
26import numpy as np
27
28from lsst.pex.config import Config, Field
29from lsst.pipe.base import Task, Struct
30
31
33 """Configuration for reserving sources"""
34 fraction = Field(dtype=float, default=0.0,
35 doc="Fraction of candidates to reserve from fitting; none if <= 0")
36 seed = Field(dtype=int, default=1,
37 doc=("This number will be added to the exposure ID to set the random seed for "
38 "reserving candidates"))
39
40
42 """Reserve sources from analysis
43
44 We randomly select a fraction of sources that will be reserved
45 from analysis. This allows evaluation of the quality of model fits
46 using sources that were not involved in the fitting process.
47
48 Constructor parameters
49 ----------------------
50 columnName : `str`, required
51 Name of flag column to add; we will suffix this with "_reserved".
52 schema : `lsst.afw.table.Schema`, required
53 Catalog schema.
54 doc : `str`
55 Documentation for column to add.
56 config : `ReserveSourcesConfig`
57 Configuration.
58 """
59 ConfigClass = ReserveSourcesConfig
60 _DefaultName = "reserveSources"
61
62 def __init__(self, columnName=None, schema=None, doc=None, **kwargs):
63 Task.__init__(self, **kwargs)
64 assert columnName is not None, "columnName not provided"
65 assert schema is not None, "schema not provided"
66 self.columnNamecolumnName = columnName
67 self.keykey = schema.addField(self.columnNamecolumnName + "_reserved", type="Flag", doc=doc)
68
69 def run(self, sources, prior=None, expId=0):
70 """Select sources to be reserved
71
72 Reserved sources will be flagged in the catalog, and we will return
73 boolean arrays that identify the sources to be reserved from and
74 used in the analysis. Typically you'll want to use the sources
75 from the `use` array in your fitting, and use the sources from the
76 `reserved` array as an independent test of your fitting.
77
78 Parameters
79 ----------
80 sources : `lsst.afw.table.Catalog` or `list` of `lsst.afw.table.Record`
81 Sources from which to select some to be reserved.
82 prior : `numpy.ndarray` of type `bool`, optional
83 Prior selection of sources. Should have the same length as
84 `sources`. If set, we will only consider for reservation sources
85 that are flagged `True` in this array.
86 expId : `int`
87 Exposure identifier; used for seeding the random number generator.
88
89 Return struct contents
90 ----------------------
91 reserved : `numpy.ndarray` of type `bool`
92 Sources to be reserved are flagged `True` in this array.
93 use : `numpy.ndarray` of type `bool`
94 Sources the user should use in analysis are flagged `True`.
95 """
96 if prior is not None:
97 assert len(prior) == len(sources), "Length mismatch: %s vs %s" % (len(prior), len(sources))
98 numSources = prior.sum()
99 else:
100 numSources = len(sources)
101 selection = self.selectselect(numSources, expId)
102 if prior is not None:
103 selection = self.applySelectionPriorapplySelectionPrior(prior, selection)
104 self.markSourcesmarkSources(sources, selection)
105 self.log.info("Reserved %d/%d sources", selection.sum(), len(selection))
106 return Struct(reserved=selection,
107 use=prior & ~selection if prior is not None else np.logical_not(selection))
108
109 def select(self, numSources, expId=0):
110 """Randomly select some sources
111
112 We return a boolean array with a random selection. The fraction
113 of sources selected is specified by the config parameter `fraction`.
114
115 Parameters
116 ----------
117 numSources : `int`
118 Number of sources in catalog from which to select.
119 expId : `int`
120 Exposure identifier; used for seeding the random number generator.
121
122 Returns
123 -------
124 selection : `numpy.ndarray` of type `bool`
125 Selected sources are flagged `True` in this array.
126 """
127 selection = np.zeros(numSources, dtype=bool)
128 if self.config.fraction <= 0:
129 return selection
130 reserve = int(np.round(numSources*self.config.fraction))
131 selection[:reserve] = True
132 rng = np.random.RandomState((self.config.seed + expId) & 0xFFFFFFFF)
133 rng.shuffle(selection)
134 return selection
135
136 def applySelectionPrior(self, prior, selection):
137 """Apply selection to full catalog
138
139 The `select` method makes a random selection of sources. If those
140 sources don't represent the full population (because a sub-selection
141 has already been made), then we need to generate a selection covering
142 the entire population.
143
144 Parameters
145 ----------
146 prior : `numpy.ndarray` of type `bool`
147 Prior selection of sources, identifying the subset from which the
148 random selection has been made.
149 selection : `numpy.ndarray` of type `bool`
150 Selection of sources in subset identified by `prior`.
151
152 Returns
153 -------
154 full : `numpy.ndarray` of type `bool`
155 Selection applied to full population.
156 """
157 full = np.zeros(len(prior), dtype=bool)
158 full[prior] = selection
159 return full
160
161 def markSources(self, sources, selection):
162 """Mark sources in a list or catalog
163
164 This requires iterating through the list and setting the flag in
165 each source individually. Even if the `sources` is a `Catalog`
166 with contiguous records, it's not currently possible to set a boolean
167 column (DM-6981) so we need to iterate.
168
169 Parameters
170 ----------
171 catalog : `lsst.afw.table.Catalog` or `list` of `lsst.afw.table.Record`
172 Catalog in which to flag selected sources.
173 selection : `numpy.ndarray` of type `bool`
174 Selection of sources to mark.
175 """
176 for src, select in zip(sources, selection):
177 if select:
178 src.set(self.keykey, True)
Defines the fields and offsets for a table.
Definition: Schema.h:51
def __init__(self, columnName=None, schema=None, doc=None, **kwargs)