Coverage for tests / test_assemble.py: 31%
82 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-21 10:45 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-21 10:45 +0000
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 numpy
23import os
24import sys
25import unittest
27import lsst.utils.tests
28from lsst.daf.butler import Butler
29from lsst.afw.cameraGeom import Detector
30from lsst.afw.image import ImageFitsReader
31import lsst.obs.base.yamlCamera as yamlCamera
32from lsst.ip.isr import AssembleCcdTask
33from lsst.resources import ResourcePath
35from lsst.obs.lsst.utils import readRawFile
37TESTDIR = os.path.dirname(__file__)
38LATISS_DATA_ROOT = os.path.join(TESTDIR, 'data', 'input', 'latiss')
39BOT_DATA_ROOT = os.path.join(TESTDIR, 'data', 'input', 'bot')
40E2V_DATA_ID = {'raft': 'R22', 'name_in_raft': 'S11', 'exposure': 3019103101985, 'instrument': 'LSSTCam'}
41ITL_DATA_ID = {'raft': 'R02', 'name_in_raft': 'S02', 'exposure': 3019110102212, 'instrument': 'LSSTCam'}
42TESTDATA_ROOT = os.path.join(TESTDIR, "data")
45class RawAssemblyTestCase(lsst.utils.tests.TestCase):
46 """Test assembly of each of data from each of the two
47 manufacturers. Data come from BOT spot data runs.
48 """
50 def setUp(self):
51 # E2V and ITL detecotrs and expected assembled images
52 self.e2v = {'detector': Detector.readFits(os.path.join(TESTDATA_ROOT, 'e2v_detector.fits')),
53 'expected': ImageFitsReader(os.path.join(TESTDATA_ROOT,
54 'e2v_expected_assembled.fits.gz'))}
55 self.itl = {'detector': Detector.readFits(os.path.join(TESTDATA_ROOT, 'itl_detector.fits')),
56 'expected': ImageFitsReader(os.path.join(TESTDATA_ROOT,
57 'itl_expected_assembled.fits.gz'))}
58 self.roots = [BOT_DATA_ROOT, BOT_DATA_ROOT]
59 self.ids = [E2V_DATA_ID, ITL_DATA_ID]
60 self.expecteds = [self.e2v, self.itl]
62 def assertAmpRawBBoxesEqual(self, amp1, amp2):
63 """Check that Raw bounding boxes match between amps.
65 Parameters
66 ----------
67 amp1 : `~lsst.afw.cameraGeom.Amplifier`
68 First amplifier.
69 amp2 : `~lsst.afw.cameraGeom.Amplifier`
70 Second amplifier.
71 """
72 self.assertEqual(amp1.getRawBBox(), amp2.getRawBBox())
73 self.assertEqual(amp1.getRawHorizontalOverscanBBox(), amp2.getRawHorizontalOverscanBBox())
74 self.assertEqual(amp1.getRawVerticalOverscanBBox(), amp2.getRawVerticalOverscanBBox())
76 def assertAmpRawBBoxesFlippablyEqual(self, amp1, amp2):
77 """Check that amp1 can be self-consistently transformed to match amp2.
79 This method compares amplifier bounding boxes by confirming
80 that they represent the same segment of the detector image.
81 If the offsets or amplifier flips differ between the
82 amplifiers, this method will pass even if the raw bounding
83 boxes returned by the amplifier accessors are not equal.
85 Parameters
86 ----------
87 amp1 : `~lsst.afw.cameraGeom.Amplifier`
88 Amplifier to transform.
89 amp2 : `~lsst.afw.cameraGeom.Amplifier`
90 Reference amplifier.
92 """
93 xFlip = amp1.getRawFlipX() ^ amp2.getRawFlipX()
94 yFlip = amp1.getRawFlipY() ^ amp2.getRawFlipY()
95 XYOffset = amp1.getRawXYOffset() - amp2.getRawXYOffset()
97 testRawBox = amp1.getRawBBox()
98 testHOSBox = amp1.getRawHorizontalOverscanBBox()
99 testVOSBox = amp1.getRawVerticalOverscanBBox()
101 if xFlip:
102 size = amp1.getRawBBox().getWidth()
103 testRawBox.flipLR(size)
104 testHOSBox.flipLR(size)
105 testVOSBox.flipLR(size)
106 if yFlip:
107 size = amp1.getRawBBox().getHeight()
108 testRawBox.flipTB(size)
109 testHOSBox.flipTB(size)
110 testVOSBox.flipTB(size)
112 testRawBox.shift(XYOffset)
113 testHOSBox.shift(XYOffset)
114 testVOSBox.shift(XYOffset)
116 self.assertEqual(testRawBox, amp2.getRawBBox())
117 self.assertEqual(testHOSBox, amp2.getRawHorizontalOverscanBBox())
118 self.assertEqual(testVOSBox, amp2.getRawVerticalOverscanBBox())
120 def testDetectors(self):
121 """Test that the detector returned by the butler is the same
122 as the expected one.
123 """
124 for root, did, expected in zip(self.roots, self.ids, self.expecteds):
125 with Butler.from_config(root) as butler:
126 raw = butler.get("raw", dataId=did, collections="LSSTCam/raw/all")
127 for amp1, amp2 in zip(expected['detector'], raw.getDetector()):
128 with self.subTest(amp=amp1.getName()):
129 self.assertEqual(amp1.getName(), amp2.getName())
130 self.assertAmpRawBBoxesEqual(amp1, amp2)
132 def testAssemble(self):
133 """Test the assembly of E2V and ITL sensors
134 """
135 task = AssembleCcdTask()
136 # exclude LATISS for this test since we don't have an expected output
137 for root, did, expected in zip(self.roots, self.ids, self.expecteds):
138 with Butler.from_config(root) as butler:
139 raw = butler.get("raw", dataId=did, collections="LSSTCam/raw/all")
140 assembled = task.assembleCcd(raw)
141 count = numpy.sum(expected['expected'].read().array - assembled.getImage().array)
142 self.assertEqual(count, 0)
145class ReadRawFileTestCase(lsst.utils.tests.TestCase):
146 def testReadRawLatissFile(self):
147 fileName = os.path.join(LATISS_DATA_ROOT, "raw/2018-09-20/3018092000065-det000.fits")
148 with ResourcePath(
149 "resource://lsst.obs.lsst/resources/policy/latiss.yaml", forceDirectory=False
150 ).as_local() as policy_file:
151 camera = yamlCamera.makeCamera(policy_file.ospath)
152 exposure = readRawFile(fileName, camera[0], dataId={"file": fileName})
153 self.assertIsInstance(exposure, lsst.afw.image.Exposure)
154 md = exposure.getMetadata()
155 self.assertIn("INSTRUME", md)
158def setup_module(module):
159 lsst.utils.tests.init()
162if __name__ == "__main__": 162 ↛ 163line 162 didn't jump to line 163 because the condition on line 162 was never true
163 setup_module(sys.modules[__name__])
164 unittest.main()