Hide keyboard shortcuts

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_base. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://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/>. 

21from __future__ import annotations 

22 

23__all__ = ["CalibRepoConverter"] 

24 

25import os 

26import sqlite3 

27from datetime import datetime, timedelta 

28from typing import TYPE_CHECKING, Dict, Iterator, Tuple 

29 

30from lsst.daf.butler import Butler as Butler3 

31 

32from .repoConverter import RepoConverter 

33from .repoWalker import RepoWalker 

34from .translators import makeCalibrationLabel 

35 

36if TYPE_CHECKING: 36 ↛ 37line 36 didn't jump to line 37, because the condition on line 36 was never true

37 from lsst.daf.butler import StorageClass 

38 from ..cameraMapper import CameraMapper 

39 from ..mapping import Mapping as CameraMapperMapping # disambiguate from collections.abc.Mapping 

40 

41CURATED_CALIBRATION_DATASET_TYPES = ( 

42 "defects", 

43 "camera", 

44 "transmission_sensor", 

45 "transmission_filter", 

46 "transmission_optics", 

47 "transmission_atmosphere", 

48 "bfKernel" 

49) 

50 

51 

52class CalibRepoConverter(RepoConverter): 

53 """A specialization of `RepoConverter` for calibration repositories. 

54 

55 Parameters 

56 ---------- 

57 mapper : `CameraMapper` 

58 Gen2 mapper for the data repository. The root associated with the 

59 mapper is ignored and need not match the root of the repository. 

60 kwds 

61 Additional keyword arguments are forwarded to (and required by) 

62 `RepoConverter`. 

63 """ 

64 

65 def __init__(self, *, mapper: CameraMapper, **kwds): 

66 super().__init__(**kwds) 

67 self.mapper = mapper 

68 self._datasetTypes = [] 

69 

70 def isDatasetTypeSpecial(self, datasetTypeName: str) -> bool: 

71 # Docstring inherited from RepoConverter. 

72 return datasetTypeName in CURATED_CALIBRATION_DATASET_TYPES 

73 

74 def iterMappings(self) -> Iterator[Tuple[str, CameraMapperMapping]]: 

75 # Docstring inherited from RepoConverter. 

76 yield from self.mapper.calibrations.items() 

77 

78 def makeRepoWalkerTarget(self, datasetTypeName: str, template: str, keys: Dict[str, type], 

79 storageClass: StorageClass) -> RepoWalker.Target: 

80 # Docstring inherited from RepoConverter. 

81 target = RepoWalker.Target( 

82 datasetTypeName=datasetTypeName, 

83 storageClass=storageClass, 

84 template=template, 

85 keys=keys, 

86 instrument=self.task.instrument.getName(), 

87 universe=self.task.registry.dimensions, 

88 ) 

89 self._datasetTypes.append(target.datasetType) 

90 return target 

91 

92 def insertDimensionData(self): 

93 # Docstring inherited from RepoConverter. 

94 # This has only been tested on HSC, and it's not clear how general it 

95 # is. The catch is that it needs to generate calibration_label strings 

96 # consistent with those produced by the Translator system. 

97 db = sqlite3.connect(os.path.join(self.root, "calibRegistry.sqlite3")) 

98 db.row_factory = sqlite3.Row 

99 records = [] 

100 for datasetType in self._datasetTypes: 

101 if "calibration_label" not in datasetType.dimensions: 

102 continue 

103 fields = ["validStart", "validEnd", "calibDate"] 

104 if "detector" in datasetType.dimensions.names: 

105 fields.append(self.task.config.ccdKey) 

106 else: 

107 fields.append(f"NULL AS {self.task.config.ccdKey}") 

108 if "physical_filter" in datasetType.dimensions.names: 

109 fields.append("filter") 

110 else: 

111 fields.append("NULL AS filter") 

112 query = f"SELECT DISTINCT {', '.join(fields)} FROM {datasetType.name};" 

113 try: 

114 results = db.execute(query) 

115 except sqlite3.OperationalError: 

116 self.task.log.warn("Could not extract calibration ranges for %s in %s.", 

117 datasetType.name, self.root) 

118 continue 

119 for row in results: 

120 label = makeCalibrationLabel(datasetType.name, row["calibDate"], 

121 ccd=row[self.task.config.ccdKey], filter=row["filter"]) 

122 records.append({ 

123 "instrument": self.task.instrument.getName(), 

124 "name": label, 

125 "datetime_begin": datetime.strptime(row["validStart"], "%Y-%m-%d"), 

126 "datetime_end": datetime.strptime(row["validEnd"], "%Y-%m-%d") + timedelta(days=1), 

127 }) 

128 if records: 

129 self.task.registry.insertDimensionData("calibration_label", *records) 

130 

131 def ingest(self): 

132 # Docstring inherited from RepoConverter. 

133 if self.task.config.doWriteCuratedCalibrations: 

134 try: 

135 collections = self.getCollections(None) 

136 except LookupError as err: 

137 raise ValueError("Cannot ingest curated calibration into a calibration repo with no " 

138 "collections of its own; skipping.") from err 

139 # TODO: associate the curated calibrations with any other 

140 # collections and remove this assert; blocker is DM-23230. 

141 assert len(collections) == 1, \ 

142 "Multiple collections for curated calibrations is not yet supported." 

143 butler3 = Butler3(butler=self.task.butler3, run=collections[0]) 

144 self.task.instrument.writeCuratedCalibrations(butler3) 

145 super().ingest() 

146 

147 # Class attributes that will be shadowed by public instance attributes; 

148 # defined here only for documentation purposes. 

149 

150 mapper: CameraMapper 

151 """Gen2 mapper associated with this repository. 

152 """