Coverage for tests/test_focalPlaneProjector.py: 23%
85 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-17 04:15 -0700
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-17 04:15 -0700
1# See COPYRIGHT file at the top of the source tree.
2#
3# This file is part of fgcmcal.
4#
5# Developed for the LSST Data Management System.
6# This product includes software developed by the LSST Project
7# (https://www.lsst.org).
8# See the COPYRIGHT file at the top-level directory of this distribution
9# for details of code ownership.
10#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation, either version 3 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program. If not, see <https://www.gnu.org/licenses/>.
23"""Test the fgcmcal FocalPlaneProjector code with testdata_jointcal/hsc.
24"""
25import unittest
26import os
27import tempfile
28import numpy as np
29import warnings
31import lsst.utils
32import lsst.daf.butler as dafButler
33import lsst.fgcmcal as fgcmcal
35import fgcmcalTestBase
38ROOT = os.path.abspath(os.path.dirname(__file__))
41class FgcmFocalPlaneProjectorTestHsc(fgcmcalTestBase.FgcmcalTestBase, lsst.utils.tests.TestCase):
42 @classmethod
43 def setUpClass(cls):
44 try:
45 cls.dataDir = lsst.utils.getPackageDir('testdata_jointcal')
46 except LookupError:
47 raise unittest.SkipTest('testdata_jointcal not setup.')
48 try:
49 lsst.utils.getPackageDir('obs_subaru')
50 except LookupError:
51 raise unittest.SkipTest("obs_subaru not setup")
53 cls.testDir = tempfile.mkdtemp(dir=ROOT, prefix="TestFgcm-")
55 cls._importRepository('lsst.obs.subaru.HyperSuprimeCam',
56 os.path.join(cls.dataDir, 'hsc/repo'),
57 os.path.join(cls.dataDir, 'hsc', 'exports.yaml'))
59 def test_focalPlaneProjector(self):
60 """
61 Test focal plane projector code for HSC.
62 """
63 butler = dafButler.Butler(os.path.join(self.testDir, 'testrepo'),
64 instrument='HSC',
65 collections=['HSC/calib/unbounded', 'HSC/testdata'])
66 camera = butler.get('camera', instrument='HSC')
68 visit = 36236
69 detector = 87
71 visitInfo = butler.get('calexp.visitInfo', visit=visit, detector=detector)
72 wcs = butler.get('calexp.wcs', visit=visit, detector=detector)
73 rotAngle = visitInfo.getBoresightRotAngle().asDegrees()
75 defaultRotation = 270.0
76 self.assertAlmostEqual(rotAngle, defaultRotation)
78 focalPlaneProjector = fgcmcal.FocalPlaneProjector(camera, defaultRotation)
79 self.assertAlmostEqual(focalPlaneProjector.defaultOrientation, defaultRotation)
81 focalPlaneProjector2 = fgcmcal.FocalPlaneProjector(camera, -90.0)
82 self.assertAlmostEqual(focalPlaneProjector2.defaultOrientation, defaultRotation)
84 # Load a delta mapper at the default angle
85 deltaMapper = focalPlaneProjector(int(defaultRotation))
87 # Spot check relative orientations of some of the ccds
88 # This is based on
89 # https://subarutelescope.org/Observing/Instruments/HSC/CCDPosition_20170212.png
90 # The goal here is to check that North is Up, South is Down,
91 # East is Left, and West is Right.
92 self.assertLess(deltaMapper['delta_ra_cent'][15], deltaMapper['delta_ra_cent'][10])
93 self.assertLess(deltaMapper['delta_ra_cent'][95], deltaMapper['delta_ra_cent'][90])
94 self.assertGreater(deltaMapper['delta_ra_cent'][46], 0.0)
96 # Check that loading at NaN gives the same default (with a warning)
97 self.assertWarns(UserWarning, focalPlaneProjector, np.nan)
98 with warnings.catch_warnings():
99 warnings.simplefilter('ignore')
100 deltaMapperDefault = focalPlaneProjector(np.nan)
102 np.testing.assert_array_almost_equal(deltaMapperDefault['delta_ra_cent'],
103 deltaMapper['delta_ra_cent'])
104 np.testing.assert_array_almost_equal(deltaMapperDefault['delta_dec_cent'],
105 deltaMapper['delta_dec_cent'])
107 # Compare the ra/dec to x/y mapping for the one detector from the wcs.
108 wcsRa, wcsDec = wcs.pixelToSkyArray(deltaMapper['x'][detector, :],
109 deltaMapper['y'][detector, :],
110 degrees=True)
111 boresightRa = visitInfo.getBoresightRaDec().getRa().asDegrees()
112 boresightDec = visitInfo.getBoresightRaDec().getDec().asDegrees()
114 wcsDeltaRa = (wcsRa - boresightRa)*np.cos(np.deg2rad(boresightDec))
115 wcsDeltaDec = wcsDec - boresightDec
117 meanDeltaRa = np.mean(wcsDeltaRa - deltaMapper['delta_ra'][detector, :])
118 meanDeltaDec = np.mean(wcsDeltaDec - deltaMapper['delta_dec'][detector, :])
120 # Check that these offsets are reasonable (they will not be zero
121 # because the boresight is not updated after the WCS is fit...)
122 self.assertLess(np.abs(meanDeltaRa), 0.002)
123 self.assertLess(np.abs(meanDeltaDec), 0.002)
125 self.assertLess(np.abs(wcsDeltaRa - deltaMapper['delta_ra'][detector, :] - meanDeltaRa).max(),
126 0.0005)
127 self.assertLess(np.abs(wcsDeltaDec - deltaMapper['delta_dec'][detector, :] - meanDeltaDec).max(),
128 0.0005)
130 # Check the sizes
131 # The projected size of the ccds varies with radius over the large
132 # HSC field-of-view. Empirically, the x size is between 0.07 and 0.10 deg
133 # and the y size is between 0.17 and 0.20 deg for the non-rotated CCDs.
134 # This test checks that the orientations of the CCDs are as expected for
135 # rotated/non-rotated CCDs (relative size of RA/DEC), and that the size
136 # is roughly correct.
138 rotatedDetectors = [100, 101, 102, 103]
140 for i, detectorId in enumerate(deltaMapper['id']):
141 ra_size = np.max(deltaMapper['delta_ra'][i, :]) - np.min(deltaMapper['delta_ra'][i, :])
142 dec_size = np.max(deltaMapper['delta_dec'][i, :]) - np.min(deltaMapper['delta_dec'][i, :])
143 if detectorId in rotatedDetectors:
144 self.assertLess(ra_size, dec_size)
145 self.assertGreater(dec_size, 0.17)
146 self.assertLess(dec_size, 0.20)
147 self.assertGreater(ra_size, 0.07)
148 self.assertLess(ra_size, 0.10)
149 else:
150 self.assertGreater(ra_size, dec_size)
151 self.assertGreater(ra_size, 0.17)
152 self.assertLess(ra_size, 0.20)
153 self.assertGreater(dec_size, 0.07)
154 self.assertLess(dec_size, 0.10)
156 # And spin it around, testing the reverse of the test above.
157 deltaMapperRot = focalPlaneProjector(defaultRotation + 180.0)
158 self.assertGreater(deltaMapperRot['delta_ra_cent'][15], deltaMapperRot['delta_ra_cent'][10])
159 self.assertGreater(deltaMapperRot['delta_ra_cent'][95], deltaMapperRot['delta_ra_cent'][90])
160 self.assertLess(deltaMapperRot['delta_ra_cent'][46], 0.0)
163class TestMemory(lsst.utils.tests.MemoryTestCase):
164 pass
167def setup_module(module):
168 lsst.utils.tests.init()
171if __name__ == "__main__": 171 ↛ 172line 171 didn't jump to line 172, because the condition on line 171 was never true
172 lsst.utils.tests.init()
173 unittest.main()