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__ = ["StandardRepoConverter"] 

24 

25from dataclasses import dataclass 

26from typing import TYPE_CHECKING, Dict, Iterator, List, Mapping, Optional, Tuple 

27 

28from lsst.log import Log 

29from lsst.log.utils import temporaryLogLevel 

30from lsst.daf.persistence import Butler as Butler2 

31from lsst.daf.butler import DatasetType, DatasetRef, DataCoordinate, FileDataset 

32from lsst.skymap import BaseSkyMap 

33from .repoConverter import RepoConverter 

34from .repoWalker import RepoWalker 

35 

36SKYMAP_DATASET_TYPES = { 

37 coaddName: f"{coaddName}Coadd_skyMap" for coaddName in ("deep", "goodSeeing", "dcr") 

38} 

39 

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

41 from lsst.daf.butler import StorageClass, FormatterParameter 

42 from .cameraMapper import CameraMapper 

43 from .repoWalker.scanner import PathElementHandler 

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

45 

46 

47@dataclass 

48class FoundSkyMap: 

49 """Struct containing information about a SkyMap found in a Gen2 repository. 

50 """ 

51 

52 name: str 

53 """Name of the skymap used in Gen3 data IDs. 

54 """ 

55 

56 instance: BaseSkyMap 

57 """An instance of the actual skymap class. 

58 """ 

59 

60 coaddName: str 

61 """The coadd name used as a prefix for the dataset type this skymap was 

62 found in. 

63 """ 

64 

65 ref: DatasetRef 

66 """A `DatasetRef` that can be used to ingest the skymap dataset into a 

67 Gen3 repository. 

68 """ 

69 

70 filename: str 

71 """Name of the file containing the skymap dataset, relative to the 

72 repository root. 

73 """ 

74 

75 

76class StandardRepoConverter(RepoConverter): 

77 """A specialization of `RepoConverter` for non-calibration repositories. 

78 

79 Parameters 

80 ---------- 

81 kwds 

82 Keyword arguments are forwarded to (and required by) `RepoConverter`. 

83 """ 

84 

85 def __init__(self, **kwds): 

86 super().__init__(**kwds) 

87 # Shush noisy log messages from Gen2 Mapper classes. 

88 # These are currently lsst.log loggers. 

89 with temporaryLogLevel("CameraMapper", Log.ERROR): 

90 with temporaryLogLevel("HscMapper", Log.ERROR): 

91 self.butler2 = Butler2(self.root) 

92 self.mapper = self.butler2.getMapperClass(self.root)(root=self.root) 

93 self._foundSkyMapsByCoaddName = {} 

94 self._chain = [] 

95 

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

97 # Docstring inherited from RepoConverter. 

98 return datasetTypeName in SKYMAP_DATASET_TYPES.values() 

99 

100 def prep(self): 

101 # Docstring inherited from RepoConverter. 

102 self.task.log.info("Looking for skymaps in root %s", self.root) 

103 for coaddName, datasetTypeName in SKYMAP_DATASET_TYPES.items(): 

104 if not self.task.isDatasetTypeIncluded(datasetTypeName): 

105 continue 

106 try: 

107 exists = self.butler2.datasetExists(datasetTypeName) 

108 except AttributeError: 

109 # This mapper doesn't even define this dataset type. 

110 continue 

111 if not exists: 

112 continue 

113 instance = self.butler2.get(datasetTypeName) 

114 name = self.task.useSkyMap(instance, datasetTypeName) 

115 datasetType = DatasetType(datasetTypeName, dimensions=["skymap"], 

116 storageClass="SkyMap", universe=self.task.universe) 

117 dataId = DataCoordinate.standardize(skymap=name, universe=self.task.universe) 

118 struct = FoundSkyMap(name=name, instance=instance, coaddName=coaddName, 

119 ref=DatasetRef(datasetType, dataId), 

120 filename=self.butler2.getUri(datasetTypeName)) 

121 self._foundSkyMapsByCoaddName[coaddName] = struct 

122 self.task.log.info("Found skymap %s in %s in %s.", name, datasetTypeName, self.root) 

123 super().prep() 

124 

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

126 # Docstring inherited from RepoConverter. 

127 for datasetTypeName, mapping in self.mapper.mappings.items(): 

128 if datasetTypeName not in self.mapper.calibrations: 

129 yield datasetTypeName, mapping 

130 

131 def findMatchingSkyMap(self, datasetTypeName: str) -> Tuple[Optional[BaseSkyMap], Optional[str]]: 

132 """Return the appropriate SkyMap for the given dataset type. 

133 

134 Parameters 

135 ---------- 

136 datasetTypeName : `str` 

137 Name of the dataset type for which a skymap is sought. 

138 

139 Returns 

140 ------- 

141 skyMap : `BaseSkyMap` or `None` 

142 The `BaseSkyMap` instance, or `None` if there was no match. 

143 skyMapName : `str` or `None` 

144 The Gen3 name for the SkyMap, or `None` if there was no match. 

145 """ 

146 # Use deepCoadd_skyMap by default; there are some dataset types 

147 # that use it but don't have "deep" anywhere in their name. 

148 struct = self._foundSkyMapsByCoaddName.get("deep") 

149 for coaddName in SKYMAP_DATASET_TYPES.keys(): 

150 if coaddName in datasetTypeName: 

151 try: 

152 struct = self._foundSkyMapsByCoaddName[coaddName] 

153 break 

154 except KeyError: 

155 # Don't use the default, since we did find a specific 

156 # coaddName. 

157 struct = None 

158 self.task.log.debug( 

159 "Dataset %s looks like it might need a skymap, but no %sCoadd_skyMap " 

160 "found in repo %s.", 

161 datasetTypeName, coaddName, self.root 

162 ) 

163 if struct is not None: 

164 return struct.instance, struct.name 

165 else: 

166 return None, None 

167 

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

169 storageClass: StorageClass, 

170 formatter: FormatterParameter = None, 

171 targetHandler: Optional[PathElementHandler] = None, 

172 ) -> RepoWalker.Target: 

173 # Docstring inherited from RepoConverter. 

174 skyMap, skyMapName = self.findMatchingSkyMap(datasetTypeName) 

175 return RepoWalker.Target( 

176 datasetTypeName=datasetTypeName, 

177 storageClass=storageClass, 

178 template=template, 

179 keys=keys, 

180 universe=self.task.registry.dimensions, 

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

182 skyMap=skyMap, 

183 skyMapName=skyMapName, 

184 formatter=formatter, 

185 targetHandler=targetHandler, 

186 translatorFactory=self.task.translatorFactory, 

187 ) 

188 

189 def iterDatasets(self) -> Iterator[FileDataset]: 

190 # Docstring inherited from RepoConverter. 

191 yield from super().iterDatasets() 

192 

193 def getRun(self, datasetTypeName: str, calibDate: Optional[str] = None) -> str: 

194 # Docstring inherited from RepoConverter. 

195 run = self.task.config.runsForced.get(datasetTypeName) 

196 if run is None: 

197 if self._run is not None: 

198 run = self._run 

199 else: 

200 run = self.task.config.runs.get(datasetTypeName) 

201 if run is None: 

202 raise ValueError(f"No default run for repo at {self.root}, and no " 

203 f"override for dataset {datasetTypeName}.") 

204 if run not in self._chain: 

205 self._chain.append(run) 

206 return run 

207 

208 def getCollectionChain(self) -> List[str]: 

209 """Return run names that can be used to construct a chained collection 

210 that refers to the converted repository (`list` [ `str` ]). 

211 """ 

212 return self._chain 

213 

214 def _finish(self, datasets: Mapping[DatasetType, Mapping[Optional[str], List[FileDataset]]], 

215 count: int) -> None: 

216 # Docstring inherited from RepoConverter. 

217 super()._finish(datasets, count) 

218 if self._foundSkyMapsByCoaddName: 

219 self._chain.append(BaseSkyMap.SKYMAP_RUN_COLLECTION_NAME) 

220 

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

222 # defined here only for documentation purposes. 

223 

224 butler2: Butler2 

225 """Gen2 butler associated with this repository. 

226 """ 

227 

228 mapper: CameraMapper 

229 """Gen2 mapper associated with this repository. 

230 """