Coverage for python/lsst/obs/base/tests.py: 29%
40 statements
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-29 02:33 -0700
« prev ^ index » next coverage.py v6.4.2, created at 2022-07-29 02:33 -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 = {'raw': {'visit': 1, 'filter': 'g'},
83 'bias': {'visit': 1},
84 'flat': {'visit': 1},
85 'dark': unittest.SkipTest
86 }
87 """
88 self.butler = butler
89 self.dataIds = dataIds
90 self.log = logging.getLogger(__name__)
92 def tearDown(self):
93 del self.butler
94 super(ObsTests, self).tearDown()
97def make_ramp_array(bbox, pedestal):
98 """Make a 2-d ramp array.
100 Parameters
101 ----------
102 bbox : `lsst.geom.Box2I`
103 Bounding box for the array.
104 pedestal : `int`
105 Minimum value for the ramp.
107 Returns
108 -------
109 ramp : `np.ndarray`
110 A 2-d array with shape ``(bbox.getHeight(), bbox.getWidth())``.
111 end : `int`
112 One past the maximum value in the ramp (for use as the
113 pedestal for another box).
114 """
115 end = pedestal + bbox.getArea()
116 return np.arange(pedestal, end).reshape(bbox.getHeight(), bbox.getWidth()), end
119def make_ramp_exposure_untrimmed(detector, dtype=None):
120 """Create an untrimmed, assembled exposure with different ramps for
121 each sub-amplifier region.
123 Parameters
124 ----------
125 detector : `lsst.afw.cameraGeom.Detector`
126 Detector object that the new exposure should match. Must have all amp
127 flips and offsets set to False/zero (i.e. represent an already-
128 assembled image).
129 dtype : `np.dtype`, optional
130 Type of the new exposure. Defaults to ``int32``.
132 Returns
133 -------
134 exposure : `lsst.afw.image.Exposure`
135 New exposure with the given detector attached.
136 """
137 if dtype is None:
138 dtype = np.dtype(np.int32)
139 ramp_exposure = Exposure(calcRawCcdBBox(detector), dtype=np.dtype(dtype))
140 ramp_exposure.setDetector(detector)
141 pedestal = 0
142 for amp in detector:
143 for name in ("HorizontalOverscan", "VerticalOverscan", "Prescan", "Data"):
144 bbox = getattr(amp, f"getRaw{name}BBox")()
145 ramp, pedestal = make_ramp_array(bbox, pedestal)
146 ramp_exposure.image[bbox].array[:, :] = ramp
147 return ramp_exposure
150def make_ramp_exposure_trimmed(detector, dtype=None):
151 """Create a trimmed, assembled exposure with different ramps for
152 each amplifier region.
154 Parameters
155 ----------
156 detector : `lsst.afw.cameraGeom.Detector`
157 Detector object that the new exposure should match.
158 dtype : `np.dtype`, optional
159 Type of the new exposure. Defaults to ``int32``.
161 Returns
162 -------
163 exposure : `lsst.afw.image.Exposure`
164 New exposure with the given detector attached.
165 """
166 if dtype is None:
167 dtype = np.dtype(np.int32)
168 ramp_exposure = Exposure(detector.getBBox(), dtype=np.dtype(dtype))
169 ramp_exposure.setDetector(detector)
170 pedestal = 0
171 for amp in detector:
172 ramp, pedestal = make_ramp_array(amp.getBBox(), pedestal)
173 ramp_exposure.image[amp.getBBox()].array[:, :] = ramp
174 return ramp_exposure