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