Coverage for python/lsst/obs/base/tests.py: 28%
42 statements
« prev ^ index » next coverage.py v6.4.1, created at 2022-06-11 11:06 +0000
« prev ^ index » next coverage.py v6.4.1, created at 2022-06-11 11:06 +0000
1# This file is part of obs_base.
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/>.
22"""
23Test utilities for obs_base and concrete obs* packages.
24"""
26__all__ = (
27 "ObsTests",
28 "make_ramp_array",
29 "make_ramp_exposure_trimmed",
30 "make_ramp_exposure_untrimmed",
31)
33import logging
35import numpy as np
36from lsst.afw.cameraGeom.utils import calcRawCcdBBox
37from lsst.afw.image import Exposure
39from . import butler_tests, camera_tests, mapper_tests
42class ObsTests(butler_tests.ButlerGetTests, mapper_tests.MapperTests, camera_tests.CameraTests):
43 """Aggregator class for all of the obs_* test classes.
45 Inherit from this class, then lsst.utils.tests.TestCase, in that order.
47 Example subclass:
49 .. code-block:: python
51 class TestObs(lsst.obs.base.tests.ObsTests, lsst.utils.tests.TestCase):
52 def setUp(self):
53 self.setUp_tests(...)
54 self.setUp_butler_get(...)
55 self.setUp_mapper(...)
56 self.setUp_camera(...)
58 Notes
59 -----
60 The intention is for each obs package to have a single test class that
61 inherits from this collector class, thus "automatically" getting all new
62 tests. If those tests require setup that isn't defined in a given obs
63 package, that obs package will be broken until updated. This is
64 intentional, as a way to prevent obs packages from falling behind out of
65 neglect.
66 """
68 def setUp_tests(self, butler, mapper, dataIds):
69 """Set up the necessary shared variables used by multiple tests.
71 Parameters
72 ----------
73 butler: lsst.daf.persistence.Butler
74 A butler object, instantiated on the testdata repository for the
75 obs package being tested.
76 mapper: lsst.obs.CameraMapper
77 A CameraMapper object for your camera, instantiated on the testdata
78 repository the obs package being tested.
79 dataIds: dict
80 dictionary of (exposure name): (dataId of that exposure in the
81 testdata repository), with unittest.SkipTest as the value for any
82 exposures you do not have/do not want to test. It must contain a
83 valid 'raw' dataId, in addition to 'bias','flat','dark', which may
84 be set to SkipTest. For example::
86 self.dataIds = {'raw': {'visit': 1, 'filter': 'g'},
87 'bias': {'visit': 1},
88 'flat': {'visit': 1},
89 'dark': unittest.SkipTest
90 }
91 """
92 self.butler = butler
93 self.mapper = mapper
94 self.dataIds = dataIds
95 self.log = logging.getLogger(__name__)
97 def tearDown(self):
98 del self.butler
99 del self.mapper
100 super(ObsTests, self).tearDown()
103def make_ramp_array(bbox, pedestal):
104 """Make a 2-d ramp array.
106 Parameters
107 ----------
108 bbox : `lsst.geom.Box2I`
109 Bounding box for the array.
110 pedestal : `int`
111 Minimum value for the ramp.
113 Returns
114 -------
115 ramp : `np.ndarray`
116 A 2-d array with shape ``(bbox.getHeight(), bbox.getWidth())``.
117 end : `int`
118 One past the maximum value in the ramp (for use as the
119 pedestal for another box).
120 """
121 end = pedestal + bbox.getArea()
122 return np.arange(pedestal, end).reshape(bbox.getHeight(), bbox.getWidth()), end
125def make_ramp_exposure_untrimmed(detector, dtype=None):
126 """Create an untrimmed, assembled exposure with different ramps for
127 each sub-amplifier region.
129 Parameters
130 ----------
131 detector : `lsst.afw.cameraGeom.Detector`
132 Detector object that the new exposure should match. Must have all amp
133 flips and offsets set to False/zero (i.e. represent an already-
134 assembled image).
135 dtype : `np.dtype`, optional
136 Type of the new exposure. Defaults to ``int32``.
138 Returns
139 -------
140 exposure : `lsst.afw.image.Exposure`
141 New exposure with the given detector attached.
142 """
143 if dtype is None:
144 dtype = np.dtype(np.int32)
145 ramp_exposure = Exposure(calcRawCcdBBox(detector), dtype=np.dtype(dtype))
146 ramp_exposure.setDetector(detector)
147 pedestal = 0
148 for amp in detector:
149 for name in ("HorizontalOverscan", "VerticalOverscan", "Prescan", "Data"):
150 bbox = getattr(amp, f"getRaw{name}BBox")()
151 ramp, pedestal = make_ramp_array(bbox, pedestal)
152 ramp_exposure.image[bbox].array[:, :] = ramp
153 return ramp_exposure
156def make_ramp_exposure_trimmed(detector, dtype=None):
157 """Create a trimmed, assembled exposure with different ramps for
158 each amplifier region.
160 Parameters
161 ----------
162 detector : `lsst.afw.cameraGeom.Detector`
163 Detector object that the new exposure should match.
164 dtype : `np.dtype`, optional
165 Type of the new exposure. Defaults to ``int32``.
167 Returns
168 -------
169 exposure : `lsst.afw.image.Exposure`
170 New exposure with the given detector attached.
171 """
172 if dtype is None:
173 dtype = np.dtype(np.int32)
174 ramp_exposure = Exposure(detector.getBBox(), dtype=np.dtype(dtype))
175 ramp_exposure.setDetector(detector)
176 pedestal = 0
177 for amp in detector:
178 ramp, pedestal = make_ramp_array(amp.getBBox(), pedestal)
179 ramp_exposure.image[amp.getBBox()].array[:, :] = ramp
180 return ramp_exposure