Coverage for tests/test_RBTransiNetTask.py: 97%
94 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-21 09:18 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-21 09:18 +0000
1# This file is part of meas_transiNet.
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 unittest
23import numpy as np
25import lsst.afw.table
26from lsst.geom import Extent2I, Point2I, Point2D, Box2I
27from lsst.images import Image
28import lsst.meas.base.tests
29import lsst.utils.tests
31from lsst.meas.transiNet import RBTransiNetTask
34class TestRBTransiNetTask(lsst.utils.tests.TestCase):
35 def create_sample_datasets(self):
36 bbox = Box2I(Point2I(0, 0), Point2I(400, 400))
37 dataset = lsst.meas.base.tests.TestDataset(bbox)
38 dataset.addSource(5000, Point2D(50, 50.))
39 # TODO: make one of these centered in a different corner of the pixel,
40 # to test that the cutout is properly centered.
41 dataset.addSource(10000, Point2D(100, 50.))
42 dataset.addSource(20000, Point2D(1, 1)) # close-to-border source
43 self.exposure, self.catalog = dataset.realize(10.0, dataset.makeMinimalSchema())
44 self.image = Image.from_legacy(self.exposure.image)
46 def setUp(self):
47 self.create_sample_datasets()
49 # Task configuration
50 self.config = RBTransiNetTask.ConfigClass()
51 self.config.modelPackageName = "dummy"
52 self.config.modelPackageStorageMode = "local"
53 self.config.cutoutSize = 256
55 def test_make_cutouts(self):
56 task = RBTransiNetTask(config=self.config)
57 for record in self.catalog:
58 result = task._make_cutouts(self.image, self.image, self.image, record)
59 self._check_cutout(result.science, task.config.cutoutSize)
60 self._check_cutout(result.template, task.config.cutoutSize)
61 self._check_cutout(result.difference, task.config.cutoutSize)
63 if record.getX() == 1 and record.getY() == 1: # This is the "border"-source
64 self._check_empty_cutout(result.science)
65 self._check_empty_cutout(result.template)
66 self._check_empty_cutout(result.difference)
68 def test_cutout_pixels(self):
69 """Test that a cutout holds the pixels of an afw cutout of the same
70 box.
71 """
72 self.config.cutoutSize = 51
73 task = RBTransiNetTask(config=self.config)
74 record = self.catalog[0]
75 box = Box2I.makeCenteredBox(record.getCentroid(), Extent2I(self.config.cutoutSize))
76 science = self.exposure.image
77 template = self.exposure.image.clone()
78 template *= 2.
79 difference = self.exposure.image.clone()
80 difference *= 3.
81 scienceCutout = self.exposure.image.Factory(science, box).array
82 templateCutout = self.exposure.image.Factory(template, box).array
83 differenceCutout = self.exposure.image.Factory(difference, box).array
84 result = task._make_cutouts(Image.from_legacy(template),
85 Image.from_legacy(science),
86 Image.from_legacy(difference),
87 record)
88 np.testing.assert_array_equal(result.science, scienceCutout)
89 np.testing.assert_array_equal(result.template, templateCutout)
90 np.testing.assert_array_equal(result.difference, differenceCutout)
92 def test_connections(self):
93 """Test that the image inputs read the image component as
94 ``ImageV2``.
95 """
96 config = RBTransiNetTask.ConfigClass()
97 connections = config.connections.ConnectionsClass(config=config)
98 self.assertEqual(connections.science.name, "calexp.image")
99 self.assertEqual(connections.template.name, "deepDiff_templateExp.image")
100 self.assertEqual(connections.difference.name, "deepDiff_differenceExp.image")
101 for name in ("science", "template", "difference"):
102 self.assertEqual(getattr(connections, name).storageClass, "ImageV2")
104 def _check_cutout(self, image, size):
105 """Test that the image cutout was made correctly.
107 Parameters
108 ----------
109 image : `np.ndarray` (N, 2)
110 Square cutout made from image.
111 size : `int`
112 Expected size of the cutout.
113 """
114 self.assertEqual(image.shape, (size, size))
115 return
117 # TODO: below test should be removed/fixed -- disabled for now.
118 # It only passes with very specific cutout dimensions and in
119 # very specific configurations.
120 # See https://jira.lsstcorp.org/browse/DM-35635 for more info.
122 max_index = np.unravel_index(image.argmax(), image.shape)
123 # TODO: I'm not comfortable with this particular test: the exact
124 # position of the max pixel depends on where in that pixel the
125 # centroid is. We can assume Box2I.makeCenteredBox works correctly...
126 self.assertEqual(max_index, ((size/2)-1, (size/2)-1))
128 def _check_empty_cutout(self, cutout):
129 """Test that the cutout is empty.
131 Parameters
132 ----------
133 cutout : `np.ndarray` (N, 2)
134 Square cutout made from image.
135 """
136 np.testing.assert_array_equal(cutout, np.zeros_like(cutout))
138 def test_run(self):
139 """Test that run passes an appropriate object to the interface.
140 """
141 task = RBTransiNetTask(config=self.config)
142 result = task.run(self.image, self.image, self.image, self.catalog)
143 self.assertIsInstance(result.classifications, lsst.afw.table.BaseCatalog)
144 np.testing.assert_array_equal(self.catalog["id"], result.classifications["id"])
145 np.testing.assert_equal("0.0", result.classifications[0]["version"])
147 def test_config_butlerblock(self):
148 config = RBTransiNetTask.ConfigClass()
149 config.modelPackageName = "dummy"
150 config.modelPackageStorageMode = "butler"
151 with self.assertRaises(ValueError):
152 config.validate()
154 def test_config_butlerpass_none(self):
155 config = RBTransiNetTask.ConfigClass()
156 config.modelPackageName = None
157 config.modelPackageStorageMode = "butler"
158 # Should not raise
159 config.validate()
161 def test_config_butlerblock_empty(self):
162 config = RBTransiNetTask.ConfigClass()
163 config.modelPackageName = "" # Want *only* None for butler packages
164 config.modelPackageStorageMode = "butler"
165 with self.assertRaises(ValueError):
166 config.validate()
169class MemoryTester(lsst.utils.tests.MemoryTestCase):
170 pass
173def setup_module(module):
174 lsst.utils.tests.init()
177if __name__ == "__main__": 177 ↛ 178line 177 didn't jump to line 178 because the condition on line 177 was never true
178 lsst.utils.tests.init()
179 unittest.main()