Coverage for python/lsst/faro/measurement/DetectorMeasurement.py: 30%
63 statements
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-17 11:43 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-02-17 11:43 +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/>.
22import lsst.pipe.base as pipeBase
23import lsst.pex.config as pexConfig
25from lsst.faro.base.CatalogMeasurementBase import (
26 CatalogMeasurementBaseConnections,
27 CatalogMeasurementBaseConfig,
28 CatalogMeasurementBaseTask,
29)
31__all__ = ("DetectorMeasurementConfig", "DetectorMeasurementTask")
34class DetectorMeasurementConnections(
35 CatalogMeasurementBaseConnections,
36 dimensions=("instrument", "visit", "detector", "band"),
37 # TODO: remove deprecated templates on DM-39854.
38 defaultTemplates={
39 "photoCalibName": "calexp.photoCalib",
40 "externalPhotoCalibName": "fgcm",
41 "wcsName": "calexp.wcs",
42 "externalWcsName": "gbdesAstrometricFit",
43 },
44 deprecatedTemplates={
45 "photoCalibName": "Deprecated in favor of visitSummary; will be removed after v26.",
46 "externalPhotoCalibName": "Deprecated in favor of visitSummary; will be removed after v26.",
47 "wcsName": "Deprecated in favor of visitSummary; will be removed after v26.",
48 "externalWcsName": "Deprecated in favor of visitSummary; will be removed after v26.",
49 },
50):
52 catalog = pipeBase.connectionTypes.Input(
53 doc="Source catalog.",
54 dimensions=("instrument", "visit", "detector", "band"),
55 storageClass="SourceCatalog",
56 name="src",
57 )
58 visitSummary = pipeBase.connectionTypes.Input(
59 doc="Exposure catalog with WCS and PhotoCalib this detector+visit combination.",
60 dimensions=("instrument", "visit"),
61 storageClass="ExposureCatalog",
62 name="finalVisitSummary",
63 )
64 skyWcs = pipeBase.connectionTypes.Input(
65 doc="WCS for the catalog.",
66 dimensions=("instrument", "visit", "detector", "band"),
67 storageClass="Wcs",
68 name="{wcsName}",
69 # TODO: remove on DM-39854.
70 deprecated="Deprecated in favor of visitSummary and already ignored; will be removed after v26."
71 )
72 photoCalib = pipeBase.connectionTypes.Input(
73 doc="Photometric calibration object.",
74 dimensions=("instrument", "visit", "detector", "band"),
75 storageClass="PhotoCalib",
76 name="{photoCalibName}",
77 # TODO: remove on DM-39854.
78 deprecated="Deprecated in favor of visitSummary and already ignored; will be removed after v26."
79 )
80 externalSkyWcsTractCatalog = pipeBase.connectionTypes.Input(
81 doc=(
82 "Per-tract, per-visit wcs calibrations. These catalogs use the detector "
83 "id for the catalog id, sorted on id for fast lookup."
84 ),
85 name="{externalWcsName}SkyWcsCatalog",
86 storageClass="ExposureCatalog",
87 dimensions=("instrument", "visit", "tract"),
88 # TODO: remove on DM-39854.
89 deprecated="Deprecated in favor of visitSummary; will be removed after v26."
90 )
91 externalSkyWcsGlobalCatalog = pipeBase.connectionTypes.Input(
92 doc=(
93 "Per-visit wcs calibrations computed globally (with no tract information). "
94 "These catalogs use the detector id for the catalog id, sorted on id for "
95 "fast lookup."
96 ),
97 name="{externalWcsName}SkyWcsCatalog",
98 storageClass="ExposureCatalog",
99 dimensions=("instrument", "visit"),
100 # TODO: remove on DM-39854.
101 deprecated="Deprecated in favor of visitSummary; will be removed after v26."
102 )
103 externalPhotoCalibTractCatalog = pipeBase.connectionTypes.Input(
104 doc=(
105 "Per-tract, per-visit photometric calibrations. These catalogs use the "
106 "detector id for the catalog id, sorted on id for fast lookup."
107 ),
108 name="{externalPhotoCalibName}PhotoCalibCatalog",
109 storageClass="ExposureCatalog",
110 dimensions=("instrument", "visit", "tract"),
111 # TODO: remove on DM-39854.
112 deprecated="Deprecated in favor of visitSummary; will be removed after v26."
113 )
114 externalPhotoCalibGlobalCatalog = pipeBase.connectionTypes.Input(
115 doc=(
116 "Per-visit photometric calibrations computed globally (with no tract "
117 "information). These catalogs use the detector id for the catalog id, "
118 "sorted on id for fast lookup."
119 ),
120 name="{externalPhotoCalibName}PhotoCalibCatalog",
121 storageClass="ExposureCatalog",
122 dimensions=("instrument", "visit"),
123 # TODO: remove on DM-39854.
124 deprecated="Deprecated in favor of visitSummary; will be removed after v26."
125 )
126 measurement = pipeBase.connectionTypes.Output(
127 doc="Per-detector measurement.",
128 dimensions=("instrument", "visit", "detector", "band"),
129 storageClass="MetricValue",
130 name="metricvalue_{package}_{metric}",
131 )
133 def __init__(self, *, config=None):
134 super().__init__(config=config)
135 # TODO: remove references to deprecates things after DM-39854 (may
136 # allow the __init__ override to go away entirely).
137 if config.doApplyExternalSkyWcs:
138 if config.useGlobalExternalSkyWcs:
139 self.inputs.remove("externalSkyWcsTractCatalog")
140 else:
141 self.inputs.remove("externalSkyWcsGlobalCatalog")
142 else:
143 self.inputs.remove("externalSkyWcsTractCatalog")
144 self.inputs.remove("externalSkyWcsGlobalCatalog")
145 if config.doApplyExternalPhotoCalib:
146 if config.useGlobalExternalPhotoCalib:
147 self.inputs.remove("externalPhotoCalibTractCatalog")
148 else:
149 self.inputs.remove("externalPhotoCalibGlobalCatalog")
150 else:
151 self.inputs.remove("externalPhotoCalibTractCatalog")
152 self.inputs.remove("externalPhotoCalibGlobalCatalog")
153 del self.skyWcs
154 del self.photoCalib
157class DetectorMeasurementConfig(
158 CatalogMeasurementBaseConfig, pipelineConnections=DetectorMeasurementConnections
159):
160 doApplyExternalSkyWcs = pexConfig.Field(
161 doc="Whether or not to use the external wcs.", dtype=bool, default=False,
162 # TODO: remove on DM-39854.
163 deprecated="Deprecated in favor of the visitSummary connection; will be removed after v26."
164 )
165 useGlobalExternalSkyWcs = pexConfig.Field(
166 doc="Whether or not to use the global external wcs.", dtype=bool, default=False,
167 # TODO: remove on DM-39854.
168 deprecated="Deprecated in favor of the visitSummary connection; will be removed after v26."
169 )
170 doApplyExternalPhotoCalib = pexConfig.Field(
171 doc="Whether or not to use the external photoCalib.", dtype=bool, default=False,
172 # TODO: remove on DM-39854.
173 deprecated="Deprecated in favor of the visitSummary connection; will be removed after v26."
174 )
175 useGlobalExternalPhotoCalib = pexConfig.Field(
176 doc="Whether or not to use the global external photoCalib.",
177 dtype=bool,
178 default=False,
179 # TODO: remove on DM-39854.
180 deprecated="Deprecated in favor of the visitSummary connection; will be removed after v26."
181 )
184class DetectorMeasurementTask(CatalogMeasurementBaseTask):
185 ConfigClass = DetectorMeasurementConfig
186 _DefaultName = "detectorMeasurementTask"
188 def runQuantum(self, butlerQC, inputRefs, outputRefs):
189 inputs = butlerQC.get(inputRefs)
190 visitSummary = inputs.pop("visitSummary")
191 detector = inputRefs.catalog.dataId["detector"]
192 row = visitSummary.find(detector)
193 inputs["photoCalib"] = row.getPhotoCalib()
194 inputs["skyWcs"] = row.getSkyWcs()
195 # TODO: significant simplification should be possible here on DM-39854.
196 if self.config.doApplyExternalPhotoCalib:
197 if self.config.useGlobalExternalPhotoCalib:
198 externalPhotoCalibCatalog = inputs.pop(
199 "externalPhotoCalibGlobalCatalog"
200 )
201 else:
202 externalPhotoCalibCatalog = inputs.pop("externalPhotoCalibTractCatalog")
203 row = externalPhotoCalibCatalog.find(detector)
204 externalPhotoCalib = None if row is None else row.getPhotoCalib()
205 inputs["photoCalib"] = externalPhotoCalib
206 if self.config.doApplyExternalSkyWcs:
207 if self.config.useGlobalExternalSkyWcs:
208 externalSkyWcsCatalog = inputs.pop("externalSkyWcsGlobalCatalog")
209 else:
210 externalSkyWcsCatalog = inputs.pop("externalSkyWcsTractCatalog")
211 row = externalSkyWcsCatalog.find(detector)
212 externalSkyWcs = None if row is None else row.getWcs()
213 inputs["skyWcs"] = externalSkyWcs
215 outputs = self.run(**inputs)
216 if outputs.measurement is not None:
217 butlerQC.put(outputs, outputRefs)
218 else:
219 self.log.debug(
220 "Skipping measurement of {!r} on {} " "as not applicable.",
221 self,
222 inputRefs,
223 )