Coverage for tests/test_gen3.py: 37%
82 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-16 10:13 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-03-16 10:13 +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 os
23import unittest
24import shutil
25import tempfile
26from cProfile import Profile
27from pstats import Stats
29import numpy as np
31from astro_metadata_translator import ObservationInfo
32from lsst.obs.lsst import (LsstCam, LsstComCam, LsstCamImSim, LsstCamPhoSim,
33 LsstTS8, LsstTS3, LsstUCDCam, Latiss, LsstComCamSim,
34 readRawFitsHeader)
36from lsst.daf.butler import (
37 Butler,
38 DatasetType,
39 StorageClassFactory,
40)
42TESTDIR = os.path.abspath(os.path.dirname(__file__))
43DATAROOT = os.path.join(TESTDIR, os.path.pardir, "data", "input")
45# This test is unfortunately slow; leave a profiling option in in case we want
46# to improve it later. Initial version is about 60% YamlCamera construction
47# (!) and 40% SQLite operations inside Butler.
48PRINT_PROFILE = False
51class TestInstruments(unittest.TestCase):
53 def setUp(self):
54 self.root = tempfile.mkdtemp(dir=TESTDIR)
55 self.rng = np.random.RandomState(50) # arbitrary deterministic seed
57 @classmethod
58 def setUpClass(cls):
59 if PRINT_PROFILE:
60 cls.profile = Profile()
61 cls.profile.enable()
63 def tearDown(self):
64 if self.root is not None and os.path.exists(self.root):
65 shutil.rmtree(self.root, ignore_errors=True)
67 @classmethod
68 def tearDownClass(cls):
69 if PRINT_PROFILE:
70 stats = Stats(cls.profile)
71 stats.strip_dirs()
72 stats.sort_stats("cumtime")
73 stats.print_stats()
75 def checkInstrumentWithRegistry(self, cls, testRaw):
77 Butler.makeRepo(self.root)
78 butler = Butler(self.root, run="tests")
79 instrument = cls()
80 scFactory = StorageClassFactory()
82 # Check instrument class and metadata translator agree on
83 # instrument name, using readRawFitsHeader to read the metadata.
84 filename = os.path.join(DATAROOT, testRaw)
85 md = readRawFitsHeader(filename, translator_class=cls.translatorClass)
86 obsInfo = ObservationInfo(md, translator_class=cls.translatorClass, filename=filename)
87 self.assertEqual(instrument.getName(), obsInfo.instrument)
89 # Add Instrument, Detector, and PhysicalFilter entries to the
90 # Butler Registry.
91 instrument.register(butler.registry)
93 # Define a DatasetType for the cameraGeom.Camera, which can be
94 # accessed just by identifying its Instrument.
95 # A real-world Camera DatasetType should be identified by a
96 # validity range as well.
97 cameraDatasetType = DatasetType("camera", dimensions=["instrument"],
98 storageClass=scFactory.getStorageClass("Camera"),
99 universe=butler.dimensions)
100 butler.registry.registerDatasetType(cameraDatasetType)
102 # Define a DatasetType for cameraGeom.Detectors, which can be
103 # accessed by identifying its Instrument and (Butler) Detector.
104 # A real-world Detector DatasetType probably doesn't need to exist,
105 # as it would just duplicate information in the Camera, and
106 # reading a full Camera just to get a single Detector should be
107 # plenty efficient.
108 detectorDatasetType = DatasetType("detector", dimensions=["instrument", "detector"],
109 storageClass=scFactory.getStorageClass("Detector"),
110 universe=butler.dimensions)
111 butler.registry.registerDatasetType(detectorDatasetType)
113 # Put and get the Camera.
114 dataId = dict(instrument=instrument.instrument)
115 butler.put(instrument.getCamera(), "camera", dataId=dataId)
116 camera = butler.get("camera", dataId)
117 # Full camera comparisons are *slow*; just compare names.
118 self.assertEqual(instrument.getCamera().getName(), camera.getName())
120 # Put and get a random subset of the Detectors.
121 allDetectors = list(instrument.getCamera())
122 numDetectors = min(3, len(allDetectors))
123 someDetectors = [allDetectors[i] for i in self.rng.choice(len(allDetectors),
124 size=numDetectors, replace=False)]
125 for cameraGeomDetector in someDetectors:
126 # Right now we only support integer detector IDs in data IDs;
127 # support for detector names and groups (i.e. rafts) is
128 # definitely planned but not yet implemented.
129 dataId = dict(instrument=instrument.instrument, detector=cameraGeomDetector.getId())
130 butler.put(cameraGeomDetector, "detector", dataId=dataId)
131 cameraGeomDetector2 = butler.get("detector", dataId=dataId)
132 # Full detector comparisons are *slow*; just compare names and
133 # serials.
134 self.assertEqual(cameraGeomDetector.getName(), cameraGeomDetector2.getName())
135 self.assertEqual(cameraGeomDetector.getSerial(), cameraGeomDetector2.getSerial())
137 def testLsstCam(self):
138 testFpath = "lsstCam/raw/2019-03-22/3019032200002/3019032200002-R10-S22-det035.fits"
139 self.checkInstrumentWithRegistry(LsstCam, testFpath)
141 def testComCam(self):
142 testFpath = "comCam/raw/2019-05-30/3019053000001/3019053000001-R22-S00-det000.fits"
143 self.checkInstrumentWithRegistry(LsstComCam, testFpath)
145 def testComCamSim(self):
146 testFpath = "comCamSim/raw/2024-03-21/7024032100720/7024032100720-R22-S11-det004.fits.fz"
147 self.checkInstrumentWithRegistry(LsstComCamSim, testFpath)
149 def testImSim(self):
150 self.checkInstrumentWithRegistry(LsstCamImSim,
151 "imsim/raw/204595/R11/00204595-R11-S20-det042.fits")
153 def testPhoSim(self):
154 self.checkInstrumentWithRegistry(LsstCamPhoSim,
155 "phosim/raw/204595/R11/00204595-R11-S20-det042.fits")
157 def testTs8(self):
158 self.checkInstrumentWithRegistry(LsstTS8,
159 "ts8/raw/6006D/201807241028453-RTM-010-S11-det067.fits")
161 def testTs3(self):
162 self.checkInstrumentWithRegistry(LsstTS3,
163 "ts3/raw/2016-07-22/201607220607067-R071-S00-det071.fits")
165 def testUcdCam(self):
166 self.checkInstrumentWithRegistry(LsstUCDCam,
167 "ucd/raw/2023-10-31/2023103100227-R21-S01-det010.fits")
169 def testLatiss(self):
170 self.checkInstrumentWithRegistry(Latiss,
171 "latiss/raw/2018-09-20/3018092000065-det000.fits")
174if __name__ == "__main__": 174 ↛ 175line 174 didn't jump to line 175, because the condition on line 174 was never true
175 unittest.main()