Coverage for tests/test_assemble.py : 29%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of obs_lsst.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://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 <http://www.gnu.org/licenses/>.
22import os
23import sys
24import unittest
26import lsst.utils.tests
27from lsst.utils import getPackageDir
28from lsst.daf.persistence import Butler
29from lsst.afw.cameraGeom import Camera, Detector
30from lsst.afw.image import ImageFitsReader
31import lsst.obs.base.yamlCamera as yamlCamera
33from lsst.obs.lsst.assembly import fixAmpGeometry
34from lsst.obs.lsst.utils import readRawFile
36PACKAGE_DIR = getPackageDir("obs_lsst")
37TESTDIR = os.path.dirname(__file__)
38LATISS_DATA_ROOT = os.path.join(PACKAGE_DIR, "data", "input", "latiss")
39BAD_OVERSCAN_GEN2_DATA_ID = {'dayObs': '2018-09-20', 'seqNum': 65, 'detector': 0}
40BAD_OVERSCAN_FILENAME = "raw/2018-09-20/3018092000065-det000.fits"
41LOCAL_DATA_ROOT = os.path.join(TESTDIR, "data")
44class RawAssemblyTestCase(lsst.utils.tests.TestCase):
46 def setUp(self):
47 # A snapshot of LATISS that has incorrect overscan regions for this
48 # data ID
49 self.cameraBroken = Camera.readFits(os.path.join(LOCAL_DATA_ROOT, "camera-bad-overscan.fits"))
50 # A snapshot of the Detector for this file after we've read it in with
51 # code that fixes the overscans.
52 self.detectorFixed = Detector.readFits(os.path.join(LOCAL_DATA_ROOT, "detector-fixed-assembled.fits"))
53 self.assertEqual(self.cameraBroken[0].getName(), self.detectorFixed.getName())
55 def assertAmpRawBBoxesEqual(self, amp1, amp2):
56 """Check that Raw bounding boxes match between amps.
58 Parameters
59 ----------
60 amp1 : `~lsst.afw.cameraGeom.Amplifier`
61 First amplifier.
62 amp2 : `~lsst.afw.cameraGeom.Amplifier`
63 Second amplifier.
64 """
65 self.assertEqual(amp1.getRawBBox(), amp2.getRawBBox())
66 self.assertEqual(amp1.getRawHorizontalOverscanBBox(), amp2.getRawHorizontalOverscanBBox())
67 self.assertEqual(amp1.getRawVerticalOverscanBBox(), amp2.getRawVerticalOverscanBBox())
69 def assertAmpRawBBoxesFlippablyEqual(self, amp1, amp2):
70 """Check that amp1 can be self-consistently transformed to match amp2.
72 This method compares amplifier bounding boxes by confirming
73 that they represent the same segment of the detector image.
74 If the offsets or amplifier flips differ between the
75 amplifiers, this method will pass even if the raw bounding
76 boxes returned by the amplifier accessors are not equal.
78 Parameters
79 ----------
80 amp1 : `~lsst.afw.cameraGeom.Amplifier`
81 Amplifier to transform.
82 amp2 : `~lsst.afw.cameraGeom.Amplifier`
83 Reference amplifier.
85 """
86 xFlip = amp1.getRawFlipX() ^ amp2.getRawFlipX()
87 yFlip = amp1.getRawFlipY() ^ amp2.getRawFlipY()
88 XYOffset = amp1.getRawXYOffset() - amp2.getRawXYOffset()
90 testRawBox = amp1.getRawBBox()
91 testHOSBox = amp1.getRawHorizontalOverscanBBox()
92 testVOSBox = amp1.getRawVerticalOverscanBBox()
94 if xFlip:
95 size = amp1.getRawBBox().getWidth()
96 testRawBox.flipLR(size)
97 testHOSBox.flipLR(size)
98 testVOSBox.flipLR(size)
99 if yFlip:
100 size = amp1.getRawBBox().getHeight()
101 testRawBox.flipTB(size)
102 testHOSBox.flipTB(size)
103 testVOSBox.flipTB(size)
105 testRawBox.shift(XYOffset)
106 testHOSBox.shift(XYOffset)
107 testVOSBox.shift(XYOffset)
109 self.assertEqual(testRawBox, amp2.getRawBBox())
110 self.assertEqual(testHOSBox, amp2.getRawHorizontalOverscanBBox())
111 self.assertEqual(testVOSBox, amp2.getRawVerticalOverscanBBox())
113 def testGen2GetBadOverscan(self):
114 """Test that we can use the Gen2 Butler to read a file with overscan
115 regions that disagree with cameraGeom, and that the detector attached
116 to it has its overscan regions corrected.
118 This is essentially just a regression test, and an incomplete one at
119 that: the fixed Detector snapshot that we're comparing to was generated
120 by the same code we're calling here. And because the LATISS
121 associated by the Butler we use in this test may in the future be
122 corrected to have the right overscan regions, we may end up just
123 testing a simpler case than we intended. We'll use a snapshot of
124 the incorrect Camera in other tests to get coverage of that case.
125 """
126 butler = Butler(LATISS_DATA_ROOT)
127 raw = butler.get("raw", dataId=BAD_OVERSCAN_GEN2_DATA_ID)
128 for amp1, amp2 in zip(self.detectorFixed, raw.getDetector()):
129 with self.subTest(amp=amp1.getName()):
130 self.assertEqual(amp1.getName(), amp2.getName())
131 self.assertAmpRawBBoxesEqual(amp1, amp2)
133 def testFixBadOverscans(self):
134 """Test the low-level code for repairing cameraGeom overscan regions
135 that disagree with raw files.
136 """
137 testFile = os.path.join(LATISS_DATA_ROOT, BAD_OVERSCAN_FILENAME)
139 for i, (ampBad, ampGood) in enumerate(zip(self.cameraBroken[0], self.detectorFixed)):
140 with self.subTest(amp=ampBad.getName()):
141 self.assertEqual(ampBad.getName(), ampGood.getName())
142 hdu = i + 1
143 reader = ImageFitsReader(testFile, hdu=hdu)
144 metadata = reader.readMetadata()
145 image = reader.read()
146 self.assertEqual(ampGood.getRawBBox().getDimensions(), image.getBBox().getDimensions())
147 self.assertNotEqual(ampBad.getRawBBox().getDimensions(), image.getBBox().getDimensions())
148 newAmp, modified = fixAmpGeometry(ampBad, image.getBBox(), metadata)
149 self.assertTrue(modified)
150 self.assertNotEqual(newAmp.getRawBBox().getDimensions(), ampBad.getRawBBox().getDimensions())
151 self.assertAmpRawBBoxesFlippablyEqual(newAmp, ampGood)
154class ReadRawFileTestCase(lsst.utils.tests.TestCase):
155 def testReadRawLatissFile(self):
156 fileName = os.path.join(LATISS_DATA_ROOT, BAD_OVERSCAN_FILENAME)
157 policy = os.path.join(PACKAGE_DIR, "policy", "latiss.yaml")
158 camera = yamlCamera.makeCamera(policy)
159 exposure = readRawFile(fileName, camera[0], dataId={"file": fileName})
160 self.assertIsInstance(exposure, lsst.afw.image.Exposure)
161 md = exposure.getMetadata()
162 self.assertIn("INSTRUME", md)
165def setup_module(module):
166 lsst.utils.tests.init()
169if __name__ == "__main__": 169 ↛ 170line 169 didn't jump to line 170, because the condition on line 169 was never true
170 setup_module(sys.modules[__name__])
171 unittest.main()