LSSTApplications  18.1.0
LSSTDataManagementBasePackage
metrics.py
Go to the documentation of this file.
1 # This file is part of ip_diffim.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (http://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 <http://www.gnu.org/licenses/>.
21 #
22 
23 __all__ = [
24  "NumberSciSourcesMetricTask", "NumberSciSourcesMetricConfig",
25  "FractionDiaSourcesToSciSourcesMetricTask", "FractionDiaSourcesToSciSourcesMetricConfig",
26 ]
27 
28 
29 import astropy.units as u
30 
31 from lsst.pipe.base import Struct, InputDatasetField
32 from lsst.verify import Measurement
33 from lsst.verify.gen2tasks import MetricTask, register
34 from lsst.verify.tasks import MetricComputationError
35 
36 
37 class NumberSciSourcesMetricConfig(MetricTask.ConfigClass):
38  sources = InputDatasetField(
39  doc="The catalog of science sources.",
40  name="src",
41  storageClass="SourceCatalog",
42  dimensions={"Instrument", "Exposure", "Detector"},
43  )
44 
45 
46 @register("numSciSources")
47 class NumberSciSourcesMetricTask(MetricTask):
48  """Task that computes the number of cataloged science sources.
49  """
50  _DefaultName = "numSciSources"
51  ConfigClass = NumberSciSourcesMetricConfig
52 
53  def run(self, sources):
54  """Count the number of science sources.
55 
56  Parameters
57  ----------
58  sources : iterable of `lsst.afw.table.SourceCatalog`
59  A collection of science source catalogs, one for each unit of
60  processing to be incorporated into this metric. Its elements may
61  be `None` to represent missing data.
62 
63  Returns
64  -------
65  result : `lsst.pipe.base.Struct`
66  A `~lsst.pipe.base.Struct` containing the following component:
67 
68  ``measurement``
69  the total number of science sources (`lsst.verify.Measurement`
70  or `None`)
71  """
72  nSciSources = 0
73  inputData = False
74  for catalog in sources:
75  if catalog is not None:
76  nSciSources += len(catalog)
77  inputData = True
78 
79  if inputData:
80  meas = Measurement(self.getOutputMetricName(self.config), nSciSources * u.count)
81  else:
82  self.log.info("Nothing to do: no catalogs found.")
83  meas = None
84  return Struct(measurement=meas)
85 
86  @classmethod
87  def getOutputMetricName(cls, config):
88  return "ip_diffim.numSciSources"
89 
90 
91 class FractionDiaSourcesToSciSourcesMetricConfig(MetricTask.ConfigClass):
92  sciSources = InputDatasetField(
93  doc="The catalog of science sources.",
94  name="src",
95  storageClass="SourceCatalog",
96  dimensions={"Instrument", "Exposure", "Detector"},
97  )
98  diaSources = InputDatasetField(
99  doc="The catalog of DIASources.",
100  name="deepDiff_diaSrc",
101  nameTemplate="{coaddName}Diff_diaSrc",
102  storageClass="SourceCatalog",
103  dimensions={"Instrument", "Exposure", "Detector"},
104  )
105 
106 
107 @register("fracDiaSourcesToSciSources")
109  """Task that computes the ratio of difference image sources to science
110  sources in an image, visit, etc.
111  """
112  _DefaultName = "fracDiaSourcesToSciSources"
113  ConfigClass = FractionDiaSourcesToSciSourcesMetricConfig
114 
115  def run(self, sciSources, diaSources):
116  """Compute the ratio of DIASources to science sources.
117 
118  Parameters
119  ----------
120  sciSources : iterable of `lsst.afw.table.SourceCatalog`
121  A collection of science source catalogs, one for each unit of
122  processing to be incorporated into this metric. Its elements may
123  be `None` to represent missing data.
124  diaSources : iterable of `lsst.afw.table.SourceCatalog`
125  A collection of difference imaging catalogs similar to
126  ``sciSources``.
127 
128  Returns
129  -------
130  result : `lsst.pipe.base.Struct`
131  A `~lsst.pipe.base.Struct` containing the following component:
132 
133  ``measurement``
134  the ratio (`lsst.verify.Measurement` or `None`)
135  """
136  nSciSources = 0
137  nDiaSources = 0
138  inputData = False
139 
140  for sciCatalog, diaCatalog in zip(sciSources, diaSources):
141  if diaCatalog is not None and sciCatalog is not None:
142  nSciSources += len(sciCatalog)
143  nDiaSources += len(diaCatalog)
144  inputData = True
145 
146  if inputData:
147  metricName = self.getOutputMetricName(self.config)
148  if nSciSources <= 0.0:
149  raise MetricComputationError(
150  "No science sources found; ratio of DIASources to science sources ill-defined.")
151  meas = Measurement(metricName, 0.0 * u.dimensionless_unscaled)
152  else:
153  meas = Measurement(metricName, nDiaSources / nSciSources * u.dimensionless_unscaled)
154  else:
155  self.log.info("Nothing to do: no catalogs found.")
156  meas = None
157  return Struct(measurement=meas)
158 
159  @classmethod
160  def getOutputMetricName(cls, config):
161  return "ip_diffim.fracDiaSourcesToSciSources"