Coverage for tests/test_finalizeCharacterization.py: 18%
104 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-03 02:24 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-03 02:24 -0700
1# This file is part of pipe_tasks.
2#
3# LSST Data Management System
4# This product includes software developed by the
5# LSST Project (http://www.lsst.org/).
6# See COPYRIGHT file at the top of the source tree.
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the LSST License Statement and
19# the GNU General Public License along with this program. If not,
20# see <https://www.lsstcorp.org/LegalNotices/>.
21#
22"""Test FinalizeCharacterizationTask.
23"""
24import logging
25import unittest
26import numpy as np
27import pandas as pd
29import lsst.utils.tests
30import lsst.afw.table as afwTable
31import lsst.pipe.base as pipeBase
33from lsst.pipe.tasks.finalizeCharacterization import (FinalizeCharacterizationConfig,
34 FinalizeCharacterizationTask)
37class TestFinalizeCharacterizationTask(FinalizeCharacterizationTask):
38 """A derived class which skips the initialization routines.
39 """
40 __test__ = False # Stop Pytest from trying to parse as a TestCase
42 def __init__(self, **kwargs):
43 pipeBase.PipelineTask.__init__(self, **kwargs)
45 self.makeSubtask('reserve_selection')
46 self.makeSubtask('source_selector')
49class FinalizeCharacterizationTestCase(lsst.utils.tests.TestCase):
50 """Tests of some functionality of FinalizeCharacterizationTask.
52 Full testing comes from integration tests such as ci_hsc and ci_imsim.
54 These tests bypass the middleware used for accessing data and
55 managing Task execution.
56 """
57 def setUp(self):
58 config = FinalizeCharacterizationConfig()
60 self.finalizeCharacterizationTask = TestFinalizeCharacterizationTask(
61 config=config,
62 )
64 self.isolated_star_cat_dict, self.isolated_star_source_dict = self._make_isocats()
66 def _make_isocats(self):
67 """Make test isolated star catalogs.
69 Returns
70 -------
71 isolated_star_cat_dict : `dict`
72 Per-"tract" dict of isolated star catalogs.
73 isolate_star_source_dict : `dict`
74 Per-"tract" dict of isolated source catalogs.
75 """
76 dtype_cat = [('isolated_star_id', 'i8'),
77 ('ra', 'f8'),
78 ('dec', 'f8'),
79 ('primary_band', 'U2'),
80 ('source_cat_index', 'i4'),
81 ('nsource', 'i4'),
82 ('source_cat_index_i', 'i4'),
83 ('nsource_i', 'i4'),
84 ('source_cat_index_r', 'i4'),
85 ('nsource_r', 'i4'),
86 ('source_cat_index_z', 'i4'),
87 ('nsource_z', 'i4')]
89 dtype_source = [('sourceId', 'i8'),
90 ('obj_index', 'i4')]
92 isolated_star_cat_dict = {}
93 isolated_star_source_dict = {}
95 np.random.seed(12345)
97 # There are 90 stars in both r, i. 10 individually in each.
98 nstar = 110
99 nsource_per_band_per_star = 2
100 self.nstar_total = nstar
101 self.nstar_per_band = nstar - 10
103 # This is a brute-force assembly of a star catalog and matched sources.
104 for tract in [0, 1, 2]:
105 ra = np.random.uniform(low=tract, high=tract + 1.0, size=nstar)
106 dec = np.random.uniform(low=0.0, high=1.0, size=nstar)
108 cat = np.zeros(nstar, dtype=dtype_cat)
109 cat['isolated_star_id'] = tract*nstar + np.arange(nstar)
110 cat['ra'] = ra
111 cat['dec'] = dec
112 if tract < 2:
113 cat['primary_band'][0: 100] = 'i'
114 cat['primary_band'][100:] = 'r'
115 else:
116 # Tract 2 only has z band.
117 cat['primary_band'][:] = 'z'
119 source_cats = []
120 counter = 0
121 for i in range(cat.size):
122 cat['source_cat_index'][i] = counter
123 if tract < 2:
124 if i < 90:
125 cat['nsource'][i] = 2*nsource_per_band_per_star
126 bands = ['r', 'i']
127 else:
128 cat['nsource'][i] = nsource_per_band_per_star
129 if i < 100:
130 bands = ['i']
131 else:
132 bands = ['r']
133 else:
134 cat['nsource'][i] = nsource_per_band_per_star
135 bands = ['z']
137 for band in bands:
138 cat[f'source_cat_index_{band}'][i] = counter
139 cat[f'nsource_{band}'][i] = nsource_per_band_per_star
140 source_cat = np.zeros(nsource_per_band_per_star, dtype=dtype_source)
141 source_cat['sourceId'] = np.arange(
142 tract*nstar + counter,
143 tract*nstar + counter + nsource_per_band_per_star
144 )
145 source_cat['obj_index'] = i
147 source_cats.append(source_cat)
149 counter += nsource_per_band_per_star
151 source_cat = np.concatenate(source_cats)
153 isolated_star_cat_dict[tract] = pipeBase.InMemoryDatasetHandle(pd.DataFrame(cat),
154 storageClass="DataFrame")
155 isolated_star_source_dict[tract] = pipeBase.InMemoryDatasetHandle(pd.DataFrame(source_cat),
156 storageClass="DataFrame")
158 return isolated_star_cat_dict, isolated_star_source_dict
160 def test_concat_isolated_star_cats(self):
161 """Test concatenation and reservation of the isolated star catalogs.
162 """
164 for band in ['r', 'i']:
165 iso, iso_src = self.finalizeCharacterizationTask.concat_isolated_star_cats(
166 band,
167 self.isolated_star_cat_dict,
168 self.isolated_star_source_dict
169 )
171 # There are two tracts, so double everything.
172 self.assertEqual(len(iso), 2*self.nstar_per_band)
174 reserve_fraction = self.finalizeCharacterizationTask.config.reserve_selection.reserve_fraction
175 self.assertEqual(np.sum(iso['reserved']),
176 int(reserve_fraction*len(iso)))
178 # 2 tracts, 4 observations per tract per star, minus 2*10 not in the given band.
179 self.assertEqual(len(iso_src), 2*(4*len(iso)//2 - 20))
181 # Check that every star is properly matched to the sources.
182 for i in range(len(iso)):
183 np.testing.assert_array_equal(
184 iso_src['obj_index'][iso[f'source_cat_index_{band}'][i]:
185 iso[f'source_cat_index_{band}'][i] + iso[f'nsource_{band}'][i]],
186 i
187 )
189 # Check that every reserved star is marked as a reserved source.
190 res_star, = np.where(iso['reserved'])
191 for i in res_star:
192 np.testing.assert_array_equal(
193 iso_src['reserved'][iso[f'source_cat_index_{band}'][i]:
194 iso[f'source_cat_index_{band}'][i] + iso[f'nsource_{band}'][i]],
195 True
196 )
198 # Check that every reserved source is marked as a reserved star.
199 res_src, = np.where(iso_src['reserved'])
200 np.testing.assert_array_equal(
201 iso['reserved'][iso_src['obj_index'][res_src]],
202 True
203 )
205 def test_concat_isolate_star_cats_no_sources(self):
206 """Test concatenation when there are no sources in a tract."""
207 iso, iso_src = self.finalizeCharacterizationTask.concat_isolated_star_cats(
208 'z',
209 self.isolated_star_cat_dict,
210 self.isolated_star_source_dict
211 )
213 self.assertGreater(len(iso), 0)
215 def test_compute_psf_and_ap_corr_map_no_sources(self):
216 """Test log message when there are no good sources after selection."""
217 # Create an empty source catalog.
218 src_schema = afwTable.SourceTable.makeMinimalSchema()
219 src_schema.addField('base_GaussianFlux_instFlux', type='F', doc='Flux field')
220 src_schema.addField('base_GaussianFlux_instFluxErr', type='F', doc='Flux field')
221 src = afwTable.SourceCatalog(src_schema)
223 # Set defaults and placeholders for required positional arguments.
224 self.finalizeCharacterizationTask.config.source_selector['science'].flags.bad = []
225 visit = 0
226 detector = 0
227 exposure = None
228 isolated_source_table = None
229 with self.assertLogs(level=logging.WARNING) as cm:
230 psf, ap_corr_map, measured_src = self.finalizeCharacterizationTask.compute_psf_and_ap_corr_map(
231 visit,
232 detector,
233 exposure,
234 src,
235 isolated_source_table
236 )
237 self.assertIn(
238 "No good sources remain after cuts for visit {}, detector {}".format(visit, detector),
239 cm.output[0]
240 )
243class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
244 pass
247def setup_module(module):
248 lsst.utils.tests.init()
251if __name__ == "__main__": 251 ↛ 252line 251 didn't jump to line 252, because the condition on line 251 was never true
252 lsst.utils.tests.init()
253 unittest.main()