Coverage for python/lsst/faro/base/CatalogMeasurementBase.py: 29%
65 statements
« prev ^ index » next coverage.py v6.5.0, created at 2024-01-25 05:38 +0000
« prev ^ index » next coverage.py v6.5.0, created at 2024-01-25 05:38 +0000
1# This file is part of faro.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (https://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
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 GNU General Public License
20# along with this program. If not, see <https://www.gnu.org/licenses/>.
21from astropy.table import Table, hstack
22import astropy.units as u
24import lsst.pipe.base as pipeBase
25import lsst.pex.config as pexConfig
26from lsst.verify.tasks import MetricTask, MetricConfig, MetricConnections
27from lsst.pipe.tasks.loadReferenceCatalog import LoadReferenceCatalogTask
28import lsst.geom
29from .BaseSubTasks import NumSourcesTask
31__all__ = (
32 "CatalogMeasurementBaseConnections",
33 "CatalogMeasurementBaseConfig",
34 "CatalogMeasurementBaseTask",
35)
38class CatalogMeasurementBaseConnections(
39 MetricConnections, defaultTemplates={"refDataset": ""}
40):
42 refCat = pipeBase.connectionTypes.PrerequisiteInput(
43 doc="Reference catalog",
44 name="{refDataset}",
45 storageClass="SimpleCatalog",
46 dimensions=("skypix",),
47 deferLoad=True,
48 multiple=True,
49 )
51 def __init__(self, *, config=None):
52 super().__init__(config=config)
53 if config.connections.refDataset == "":
54 self.prerequisiteInputs.remove("refCat")
57class CatalogMeasurementBaseConfig(
58 MetricConfig, pipelineConnections=CatalogMeasurementBaseConnections
59):
60 """Configuration for CatalogMeasurementBaseTask."""
62 measure = pexConfig.ConfigurableField(
63 # This task is meant to make measurements of various types.
64 # The default task is, therefore, a bit of a place holder.
65 # It is expected that this will be overridden in the pipeline
66 # definition in most cases.
67 target=NumSourcesTask,
68 doc="Measure task",
69 )
71 referenceCatalogLoader = pexConfig.ConfigurableField(
72 target=LoadReferenceCatalogTask, doc="Reference catalog loader",
73 )
75 def setDefaults(self):
76 self.referenceCatalogLoader.refObjLoader.ref_dataset_name = ""
77 self.referenceCatalogLoader.doApplyColorTerms = False
79 def validate(self):
80 super().validate()
81 if (
82 self.connections.refDataset
83 != self.referenceCatalogLoader.refObjLoader.ref_dataset_name
84 ):
85 msg = "The reference datasets specified in connections and reference catalog loader must match."
86 raise pexConfig.FieldValidationError(
87 CatalogMeasurementBaseConfig.referenceCatalogLoader, self, msg
88 )
91class CatalogMeasurementBaseTask(MetricTask):
92 """Base class for science performance metrics measured from source/object catalogs."""
94 ConfigClass = CatalogMeasurementBaseConfig
95 _DefaultName = "catalogMeasurementBaseTask"
97 def __init__(self, config, *args, **kwargs):
98 super().__init__(*args, config=config, **kwargs)
99 self.makeSubtask("measure")
101 def run(self, **kwargs):
102 if 'shelveName' in self.measure.config.keys():
103 if self.measure.config.shelveName:
104 # Persist in-memory objects for development and testing
105 self._persistMeasurementInputs(self.measure.config, self.measure.config.shelveName, **kwargs)
106 return self.measure.run(self.config.connections.metric, **kwargs)
108 def _getTableColumnsSelectors(self, columns, currentBands=None):
109 """given a list of selectors return columns required to apply these
110 selectors.
111 Parameters
112 ----------
113 columns: `list` [`str`]
114 a list of columns required to calculate a metric. This list
115 is appended with any addditional columns required for the selectorActions.
117 currentBands: `list` [`str`]
118 The filter band(s) associated with the observations.
120 Returns
121 -------
122 columnNames: `list` [`str`] the set of columns required to compute a
123 metric with any addditional columns required for the selectorActions
124 appended to the set.
126 """
127 columnNames = set(columns)
128 for actionStruct in [self.config.measure.selectorActions]:
129 for action in actionStruct:
130 for col in action.columns(currentBands):
131 columnNames.add(col)
133 return columnNames
135 def _getReferenceCatalog(self, butlerQC, dataIds, refCats, filterList, epoch=None):
136 """Load reference catalog in sky region of interest and optionally applies proper
137 motion correction and color terms.
139 Loads the `lsst.afw.table.SimpleCatalog` reference catalog, computes ra and dec
140 (optionally) applying a proper motion correction. Also, color terms
141 are (optionally) applied to the reference magnitudes in order to transform
142 them to the data's photometric system.
144 returns a refCat with both the original loaded reference catalog and
145 the coorected coordinates (ra,dec) and transformed reference magnitudes
146 (refMag-/refMagErr-)
148 Parameters
149 ----------
150 butlerQC : `lsst.pipe.base.butlerQuantumContext.ButlerQuantumContext`
151 Butler quantum context for a Gen3 repository.
152 dataIds: interable of `lsst.daf.butler.dataId`
153 An iterable object of dataIds that point to reference catalogs
154 in a Gen3 repository.
155 refCats : iterable of `lsst.daf.butler.DeferredDatasetHandle`
156 An iterable object of dataset refs for reference catalogs in
157 a Gen3 repository.
158 filterList : `list` [`str`]
159 List of camera physicalFilter names to apply color terms.
160 epoch : `astropy.time.Time`, optional
161 Epoch to which to correct proper motion and parallax
162 (if available), or `None` to not apply such corrections.
164 Returns
165 -------
166 refCat: pandas.dataframe
167 a reference catalog with original columns and corrected
168 coordinates (ra,dec) and reference magnitudes (refMag-/refMagErr-)
169 """
170 center = lsst.geom.SpherePoint(
171 butlerQC.quantum.dataId.region.getBoundingCircle().getCenter()
172 )
173 radius = butlerQC.quantum.dataId.region.getBoundingCircle().getOpeningAngle()
175 loaderTask = LoadReferenceCatalogTask(
176 config=self.config.referenceCatalogLoader, dataIds=dataIds, refCats=refCats
177 )
179 # Get catalog with proper motion and color terms applied
180 refCatCorrected = loaderTask.getSkyCircleCatalog(
181 center, radius, filterList, epoch=epoch
182 )
184 # Get unformatted catalog w/ all columns
185 skyCircle = loaderTask.refObjLoader.loadSkyCircle(
186 center, radius, loaderTask._referenceFilter, epoch=epoch
187 )
188 refCat = skyCircle.refCat
190 refCatTable = Table()
191 refCatTable['ra'] = refCatCorrected['ra']*u.deg
192 refCatTable['dec'] = refCatCorrected['dec']*u.deg
193 for n, filterName in enumerate(filterList):
194 refCatTable['refMag-' + filterName] = refCatCorrected["refMag"][:, n]*u.ABmag
195 refCatTable['refMagErr-' + filterName] = refCatCorrected["refMagErr"][:, n]*u.ABmag
196 refCatFrame = hstack([refCatTable, refCat.asAstropy()]).to_pandas()
198 return refCatFrame
200 def _persistMeasurementInputs(self, config, shelveName, **kwargs):
201 """Persist in-memory objects sent as inputs to metric measurement run method.
203 This function is intended to be used for development and testing purposes
204 as a debug tool and is NOT to be used in routine operation.
206 Parameters
207 ----------
208 config : `lsst.pex.config.Config`
209 Config to be saved.
210 shelveName : `str`
211 Filename for output shelve.
212 """
214 import shelve
216 with shelve.open(shelveName, 'n') as shelf:
217 shelf['config'] = config
218 for key in kwargs.keys():
219 shelf[key] = kwargs[key]