Coverage for python/lsst/obs/base/tests.py: 26%
40 statements
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-27 03:06 -0700
« prev ^ index » next coverage.py v7.5.0, created at 2024-04-27 03:06 -0700
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
42class ObsTests(butler_tests.ButlerGetTests, 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_camera(...)
57 Notes
58 -----
59 The intention is for each obs package to have a single test class that
60 inherits from this collector class, thus "automatically" getting all new
61 tests. If those tests require setup that isn't defined in a given obs
62 package, that obs package will be broken until updated. This is
63 intentional, as a way to prevent obs packages from falling behind out of
64 neglect.
65 """
67 def setUp_tests(self, butler, dataIds):
68 """Set up the necessary shared variables used by multiple tests.
70 Parameters
71 ----------
72 butler: `lsst.daf.butler.Butler`
73 A butler object, instantiated on the testdata repository for the
74 obs package being tested.
75 dataIds: `dict`
76 dictionary of (exposure name): (dataId of that exposure in the
77 testdata repository), with unittest.SkipTest as the value for any
78 exposures you do not have/do not want to test. It must contain a
79 valid 'raw' dataId, in addition to 'bias','flat','dark', which may
80 be set to SkipTest. For example::
82 self.dataIds = {
83 "raw": {"visit": 1, "filter": "g"},
84 "bias": {"visit": 1},
85 "flat": {"visit": 1},
86 "dark": unittest.SkipTest,
87 }
88 """
89 self.butler = butler
90 self.dataIds = dataIds
91 self.log = logging.getLogger(__name__)
93 def tearDown(self):
94 del self.butler
95 super().tearDown()
98def make_ramp_array(bbox, pedestal):
99 """Make a 2-d ramp array.
101 Parameters
102 ----------
103 bbox : `lsst.geom.Box2I`
104 Bounding box for the array.
105 pedestal : `int`
106 Minimum value for the ramp.
108 Returns
109 -------
110 ramp : `numpy.ndarray`
111 A 2-d array with shape ``(bbox.getHeight(), bbox.getWidth())``.
112 end : `int`
113 One past the maximum value in the ramp (for use as the
114 pedestal for another box).
115 """
116 end = pedestal + bbox.getArea()
117 return np.arange(pedestal, end).reshape(bbox.getHeight(), bbox.getWidth()), end
120def make_ramp_exposure_untrimmed(detector, dtype=None):
121 """Create an untrimmed, assembled exposure with different ramps for
122 each sub-amplifier region.
124 Parameters
125 ----------
126 detector : `lsst.afw.cameraGeom.Detector`
127 Detector object that the new exposure should match. Must have all amp
128 flips and offsets set to False/zero (i.e. represent an already-
129 assembled image).
130 dtype : `numpy.dtype`, optional
131 Type of the new exposure. Defaults to ``int32``.
133 Returns
134 -------
135 exposure : `lsst.afw.image.Exposure`
136 New exposure with the given detector attached.
137 """
138 if dtype is None:
139 dtype = np.dtype(np.int32)
140 ramp_exposure = Exposure(calcRawCcdBBox(detector), dtype=np.dtype(dtype))
141 ramp_exposure.setDetector(detector)
142 pedestal = 0
143 for amp in detector:
144 for name in ("HorizontalOverscan", "VerticalOverscan", "Prescan", "Data"):
145 bbox = getattr(amp, f"getRaw{name}BBox")()
146 ramp, pedestal = make_ramp_array(bbox, pedestal)
147 ramp_exposure.image[bbox].array[:, :] = ramp
148 return ramp_exposure
151def make_ramp_exposure_trimmed(detector, dtype=None):
152 """Create a trimmed, assembled exposure with different ramps for
153 each amplifier region.
155 Parameters
156 ----------
157 detector : `lsst.afw.cameraGeom.Detector`
158 Detector object that the new exposure should match.
159 dtype : `numpy.dtype`, optional
160 Type of the new exposure. Defaults to ``int32``.
162 Returns
163 -------
164 exposure : `lsst.afw.image.Exposure`
165 New exposure with the given detector attached.
166 """
167 if dtype is None:
168 dtype = np.dtype(np.int32)
169 ramp_exposure = Exposure(detector.getBBox(), dtype=np.dtype(dtype))
170 ramp_exposure.setDetector(detector)
171 pedestal = 0
172 for amp in detector:
173 ramp, pedestal = make_ramp_array(amp.getBBox(), pedestal)
174 ramp_exposure.image[amp.getBBox()].array[:, :] = ramp
175 return ramp_exposure