LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
LSSTDataManagementBasePackage
calibRepoConverter.py
Go to the documentation of this file.
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/>.
21 from __future__ import annotations
22 
23 __all__ = ["CalibRepoConverter"]
24 
25 import os
26 import sqlite3
27 from datetime import datetime, timedelta
28 from typing import TYPE_CHECKING, Iterator, Tuple
29 
30 from .repoConverter import RepoConverter
31 from .dataIdExtractor import DataIdExtractor
32 from .translators import makeCalibrationLabel
33 
34 if TYPE_CHECKING:
35  from lsst.daf.butler import StorageClass
36  from ..cameraMapper import CameraMapper
37  from ..mapping import Mapping as CameraMapperMapping # disambiguate from collections.abc.Mapping
38  from .filePathParser import FilePathParser
39 
40 CURATED_CALIBRATION_DATASET_TYPES = (
41  "defects",
42  "camera",
43  "transmission_sensor",
44  "transmission_filter",
45  "transmission_optics",
46  "transmission_atmosphere",
47  "bfKernel"
48 )
49 
50 
52  """A specialization of `RepoConverter` for calibration repositories.
53 
54  Parameters
55  ----------
56  mapper : `CameraMapper`
57  Gen2 mapper for the data repository. The root associated with the
58  mapper is ignored and need not match the root of the repository.
59  kwds
60  Additional keyword arguments are forwarded to (and required by)
61  `RepoConverter`.
62  """
63 
64  def __init__(self, *, mapper: CameraMapper, **kwds):
65  super().__init__(**kwds)
66  self.mapper = mapper
67  self._datasetTypes = []
68 
69  def isDatasetTypeSpecial(self, datasetTypeName: str) -> bool:
70  # Docstring inherited from RepoConverter.
71  return datasetTypeName in CURATED_CALIBRATION_DATASET_TYPES
72 
73  def isDirectorySpecial(self, subdirectory: str) -> bool:
74  # Docstring inherited from RepoConverter.
75  return False
76 
77  def iterMappings(self) -> Iterator[Tuple[str, CameraMapperMapping]]:
78  # Docstring inherited from RepoConverter.
79  yield from self.mapper.calibrations.items()
80 
81  def makeDataIdExtractor(self, datasetTypeName: str, parser: FilePathParser,
82  storageClass: StorageClass) -> DataIdExtractor:
83  # Docstring inherited from RepoConverter.
84  extractor = DataIdExtractor(
85  datasetTypeName,
86  storageClass,
87  filePathParser=parser,
88  universe=self.task.universe,
89  instrument=self.task.instrument.getName(),
90  )
91  self._datasetTypes.append(extractor.datasetType)
92  return extractor
93 
95  # Docstring inherited from RepoConverter.
96  # This has only been tested on HSC, and it's not clear how general it
97  # is. The catch is that it needs to generate calibration_label strings
98  # consistent with those produced by the Translator system.
99  db = sqlite3.connect(os.path.join(self.root, "calibRegistry.sqlite3"))
100  db.row_factory = sqlite3.Row
101  records = []
102  for datasetType in self._datasetTypes:
103  if "calibration_label" not in datasetType.dimensions:
104  continue
105  fields = ["validStart", "validEnd", "calibDate"]
106  if "detector" in datasetType.dimensions.names:
107  fields.append(self.task.config.ccdKey)
108  else:
109  fields.append(f"NULL AS {self.task.config.ccdKey}")
110  if "physical_filter" in datasetType.dimensions.names:
111  fields.append("filter")
112  else:
113  fields.append("NULL AS filter")
114  query = f"SELECT DISTINCT {', '.join(fields)} FROM {datasetType.name};"
115  try:
116  results = db.execute(query)
117  except sqlite3.OperationalError:
118  self.task.log.warn("Could not extract calibration ranges for %s in %s.",
119  datasetType.name, self.root)
120  continue
121  for row in results:
122  label = makeCalibrationLabel(datasetType.name, row["calibDate"],
123  ccd=row[self.task.config.ccdKey], filter=row["filter"])
124  records.append({
125  "instrument": self.task.instrument.getName(),
126  "name": label,
127  "datetime_begin": datetime.strptime(row["validStart"], "%Y-%m-%d"),
128  "datetime_end": datetime.strptime(row["validEnd"], "%Y-%m-%d") + timedelta(days=1),
129  })
130  if records:
131  self.task.registry.insertDimensionData("calibration_label", *records)
132 
133  def ingest(self):
134  # Docstring inherited from RepoConverter.
135  if self.task.config.doWriteCuratedCalibrations:
136  for datasetTypeName in CURATED_CALIBRATION_DATASET_TYPES:
137  if not self.task.isDatasetTypeIncluded(datasetTypeName):
138  raise ValueError(f"doWriteCuratedCalibrations is True but "
139  f"{datasetTypeName} is configured to be ignored.")
140  try:
141  butler3, collections = self.getButler(None)
142  except LookupError as err:
143  raise ValueError("Cannot ingest curated calibration into a calibration repo with no "
144  "collections of its own; skipping.") from err
145  # TODO: associate the curated calibrations with any other
146  # collections and remove this assert.
147  assert not collections, "Multiple collections for curated calibrations is not yet supported."
148  self.task.instrument.writeCuratedCalibrations(butler3)
149  super().ingest()
150 
151  # Class attributes that will be shadowed by public instance attributes;
152  # defined here only for documentation purposes.
153 
154  mapper: CameraMapper
155  """Gen2 mapper associated with this repository.
156  """
std::shared_ptr< FrameSet > append(FrameSet const &first, FrameSet const &second)
Construct a FrameSet that performs two transformations in series.
Definition: functional.cc:33