LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
ExposureInfo.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*- // fixed format comment for emacs
2 /*
3  * This file is part of afw.
4  *
5  * Developed for the LSST Data Management System.
6  * This product includes software developed by the LSST Project
7  * (https://www.lsst.org).
8  * See the COPYRIGHT file at the top-level directory of this distribution
9  * for details of code ownership.
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program. If not, see <https://www.gnu.org/licenses/>.
23  */
24 
25 #include "lsst/pex/exceptions.h"
26 #include "lsst/log/Log.h"
30 #include "lsst/afw/geom/SkyWcs.h"
32 #include "lsst/afw/detection/Psf.h"
35 #include "lsst/afw/fits.h"
36 
37 using namespace std::string_literals;
38 
39 namespace {
40 LOG_LOGGER _log = LOG_GET("lsst.afw.image.ExposureInfo");
41 
43 } // namespace
44 
45 namespace lsst {
46 namespace afw {
47 namespace image {
48 
49 // Important: do *not* change the keys' strings; doing so will break compatibility with old FITS files
50 
51 typehandling::Key<std::string, std::shared_ptr<geom::SkyWcs const>> const ExposureInfo::KEY_WCS =
52  typehandling::makeKey<std::shared_ptr<geom::SkyWcs const>>("SKYWCS"s);
53 
54 bool ExposureInfo::hasWcs() const { return hasComponent(KEY_WCS); }
55 std::shared_ptr<geom::SkyWcs const> ExposureInfo::getWcs() const { return getComponent(KEY_WCS); }
56 void ExposureInfo::setWcs(std::shared_ptr<geom::SkyWcs const> wcs) { setComponent(KEY_WCS, wcs); }
57 
59  typehandling::makeKey<std::shared_ptr<detection::Psf const>>("PSF"s);
60 
61 bool ExposureInfo::hasPsf() const { return hasComponent(KEY_PSF); }
62 std::shared_ptr<detection::Psf const> ExposureInfo::getPsf() const { return getComponent(KEY_PSF); }
63 void ExposureInfo::setPsf(std::shared_ptr<detection::Psf const> psf) { setComponent(KEY_PSF, psf); }
64 
65 typehandling::Key<std::string, std::shared_ptr<PhotoCalib const>> const ExposureInfo::KEY_PHOTO_CALIB =
66  typehandling::makeKey<std::shared_ptr<PhotoCalib const>>("PHOTOCALIB"s);
67 
68 bool ExposureInfo::hasPhotoCalib() const { return hasComponent(KEY_PHOTO_CALIB); }
69 std::shared_ptr<PhotoCalib const> ExposureInfo::getPhotoCalib() const {
70  return getComponent(KEY_PHOTO_CALIB);
71 }
72 void ExposureInfo::setPhotoCalib(std::shared_ptr<PhotoCalib const> photoCalib) {
73  setComponent(KEY_PHOTO_CALIB, photoCalib);
74 }
75 
77  typehandling::makeKey<std::shared_ptr<cameraGeom::Detector const>>("DETECTOR"s);
78 
79 bool ExposureInfo::hasDetector() const { return hasComponent(KEY_DETECTOR); }
80 std::shared_ptr<cameraGeom::Detector const> ExposureInfo::getDetector() const {
81  return getComponent(KEY_DETECTOR);
82 }
83 void ExposureInfo::setDetector(std::shared_ptr<cameraGeom::Detector const> detector) {
84  setComponent(KEY_DETECTOR, detector);
85 }
86 
88  ExposureInfo::KEY_VALID_POLYGON =
89  typehandling::makeKey<std::shared_ptr<geom::polygon::Polygon const>>("VALID_POLYGON"s);
90 
91 bool ExposureInfo::hasValidPolygon() const { return hasComponent(KEY_VALID_POLYGON); }
92 std::shared_ptr<geom::polygon::Polygon const> ExposureInfo::getValidPolygon() const {
93  return getComponent(KEY_VALID_POLYGON);
94 }
95 void ExposureInfo::setValidPolygon(std::shared_ptr<geom::polygon::Polygon const> polygon) {
96  setComponent(KEY_VALID_POLYGON, polygon);
97 }
98 
99 typehandling::Key<std::string, std::shared_ptr<CoaddInputs const>> const ExposureInfo::KEY_COADD_INPUTS =
100  typehandling::makeKey<std::shared_ptr<CoaddInputs const>>("COADD_INPUTS"s);
101 
102 bool ExposureInfo::hasCoaddInputs() const { return hasComponent(KEY_COADD_INPUTS); }
103 void ExposureInfo::setCoaddInputs(std::shared_ptr<CoaddInputs const> coaddInputs) {
104  setComponent(KEY_COADD_INPUTS, coaddInputs);
105 }
106 std::shared_ptr<CoaddInputs const> ExposureInfo::getCoaddInputs() const {
107  return getComponent(KEY_COADD_INPUTS);
108 }
109 
110 typehandling::Key<std::string, std::shared_ptr<ApCorrMap const>> const ExposureInfo::KEY_AP_CORR_MAP =
111  typehandling::makeKey<std::shared_ptr<ApCorrMap const>>("AP_CORR_MAP"s);
112 
113 bool ExposureInfo::hasApCorrMap() const { return hasComponent(KEY_AP_CORR_MAP); }
114 std::shared_ptr<ApCorrMap const> ExposureInfo::getApCorrMap() const { return getComponent(KEY_AP_CORR_MAP); }
115 void ExposureInfo::setApCorrMap(std::shared_ptr<ApCorrMap const> apCorrMap) {
116  setComponent(KEY_AP_CORR_MAP, apCorrMap);
117 }
118 
120  ExposureInfo::KEY_TRANSMISSION_CURVE =
121  typehandling::makeKey<std::shared_ptr<TransmissionCurve const>>("TRANSMISSION_CURVE"s);
122 
123 bool ExposureInfo::hasTransmissionCurve() const { return hasComponent(KEY_TRANSMISSION_CURVE); }
124 std::shared_ptr<TransmissionCurve const> ExposureInfo::getTransmissionCurve() const {
125  return getComponent(KEY_TRANSMISSION_CURVE);
126 }
127 void ExposureInfo::setTransmissionCurve(std::shared_ptr<TransmissionCurve const> tc) {
128  setComponent(KEY_TRANSMISSION_CURVE, tc);
129 }
130 
131 bool ExposureInfo::hasId() const noexcept { return _exposureId.has_value(); }
132 
133 table::RecordId ExposureInfo::getId() const {
134  if (_exposureId) {
135  return *_exposureId;
136  } else {
137  throw LSST_EXCEPT(lsst::pex::exceptions::NotFoundError, "Exposure does not have an ID.");
138  }
139 }
140 
141 void ExposureInfo::setId(table::RecordId id) {
142  _exposureId = id;
143  // Ensure consistency with VisitInfo::getExposureId() until the latter is removed in DM-32138.
144  std::shared_ptr<VisitInfo const> oldVisitInfo = getVisitInfo();
145  if (oldVisitInfo) {
146  auto newVisitInfo = std::make_shared<VisitInfo>(
147  *_exposureId, oldVisitInfo->getExposureTime(), oldVisitInfo->getDarkTime(),
148  oldVisitInfo->getDate(), oldVisitInfo->getUt1(), oldVisitInfo->getEra(),
149  oldVisitInfo->getBoresightRaDec(), oldVisitInfo->getBoresightAzAlt(),
150  oldVisitInfo->getBoresightAirmass(), oldVisitInfo->getBoresightRotAngle(),
151  oldVisitInfo->getRotType(), oldVisitInfo->getObservatory(), oldVisitInfo->getWeather(),
152  oldVisitInfo->getInstrumentLabel(), oldVisitInfo->getId());
153  // Do not call setVisitInfo, to avoid recursion
154  _visitInfo = newVisitInfo;
155  }
156 }
157 
158 void ExposureInfo::clearId() noexcept { _exposureId.reset(); }
159 
160 // Compatibility code defined inside ExposureFitsReader.cc, to be removed in DM-27177
162 Filter makeFilter(FilterLabel const& label);
163 
165  std::shared_ptr<FilterLabel const> label = getFilterLabel();
166  if (label) {
167  return makeFilter(*label);
168  } else {
169  // Old exposures always had a Filter, even if only the default
170  return Filter();
171  }
172 }
173 
174 void ExposureInfo::setFilter(Filter const& filter) { setFilterLabel(makeFilterLabel(filter)); }
175 
177  typehandling::makeKey<std::shared_ptr<FilterLabel const>>("FILTER"s);
178 bool ExposureInfo::hasFilterLabel() const { return hasComponent(KEY_FILTER); }
179 std::shared_ptr<FilterLabel const> ExposureInfo::getFilterLabel() const { return getComponent(KEY_FILTER); }
180 void ExposureInfo::setFilterLabel(std::shared_ptr<FilterLabel const> label) {
181  setComponent(KEY_FILTER, label);
182 }
183 
184 int ExposureInfo::getFitsSerializationVersion() {
185  // Version history:
186  // unversioned and 0: photometric calibration via Calib, WCS via SkyWcs using AST.
187  // 1: photometric calibration via PhotoCalib, generic components
188  // 2: remove Filter, replaced with (generic) FilterLabel
189  static int const version = 2;
190  return version;
191 }
192 
193 std::string const& ExposureInfo::getFitsSerializationVersionName() {
194  static std::string const versionName("EXPINFO_V");
195  return versionName;
196 }
197 
198 // Clone various components; defined here so that we don't have to expose their insides in Exposure.h
199 
201  if (apCorrMap) {
202  return std::make_shared<ApCorrMap>(*apCorrMap);
203  }
205 }
206 
207 ExposureInfo::ExposureInfo(std::shared_ptr<geom::SkyWcs const> const& wcs,
213  std::shared_ptr<CoaddInputs> const& coaddInputs,
217  : _exposureId(),
218  _metadata(metadata ? metadata
219  : std::shared_ptr<daf::base::PropertySet>(new daf::base::PropertyList())),
220  _visitInfo(visitInfo),
221  _components(std::make_unique<MapClass>()) {
222  // setFilter guards against default filters
223  setFilter(filter);
224  setWcs(wcs);
225  setPsf(psf);
228  setValidPolygon(polygon);
229  setCoaddInputs(coaddInputs);
230  setApCorrMap(_cloneApCorrMap(apCorrMap));
232 }
233 
234 ExposureInfo::ExposureInfo(ExposureInfo const& other) : ExposureInfo(other, false) {}
235 
236 // Delegate to copy-constructor for backwards compatibility
238 
239 ExposureInfo::ExposureInfo(ExposureInfo const& other, bool copyMetadata)
240  : _exposureId(other._exposureId),
241  _metadata(other._metadata),
242  _visitInfo(other._visitInfo),
243  // ExposureInfos can (historically) share objects, but should each have their own pointers to them
244  _components(std::make_unique<MapClass>(*(other._components))) {
245  if (copyMetadata) _metadata = _metadata->deepCopy();
246 }
247 
249  if (&other != this) {
250  _exposureId = other._exposureId;
251  _metadata = other._metadata;
252  _visitInfo = other._visitInfo;
253  // ExposureInfos can (historically) share objects, but should each have their own pointers to them
254  _components = std::make_unique<MapClass>(*(other._components));
255  }
256  return *this;
257 }
258 // Delegate to copy-assignment for backwards compatibility
259 ExposureInfo& ExposureInfo::operator=(ExposureInfo&& other) { return *this = other; }
260 
261 void ExposureInfo::initApCorrMap() { setApCorrMap(std::make_shared<ApCorrMap>()); }
262 
263 ExposureInfo::~ExposureInfo() = default;
264 
265 int ExposureInfo::_addToArchive(FitsWriteData& data, table::io::Persistable const& object, std::string key,
266  std::string comment) {
267  int componentId = data.archive.put(object);
268  data.metadata->set(key, componentId, comment);
269  return componentId;
270 }
271 
272 int ExposureInfo::_addToArchive(FitsWriteData& data,
274  std::string comment) {
275  // Don't delegate to Persistable const& version because OutputArchive::put
276  // has special handling of shared_ptr
277  int componentId = data.archive.put(object);
278  data.metadata->set(key, componentId, comment);
279  return componentId;
280 }
281 
282 // Standardized strings for _startWriteFits
283 namespace {
284 std::string _getOldHeaderKey(std::string mapKey) { return mapKey + "_ID"; }
285 std::string _getNewHeaderKey(std::string mapKey) { return "ARCHIVE_ID_" + mapKey; }
286 
287 std::string _getHeaderComment(std::string mapKey) {
288  return "archive ID for generic component '" + mapKey + "'";
289 }
290 } // namespace
291 
292 ExposureInfo::FitsWriteData ExposureInfo::_startWriteFits(lsst::geom::Point2I const& xy0) const {
293  FitsWriteData data;
294 
295  data.metadata.reset(new daf::base::PropertyList());
296  data.imageMetadata.reset(new daf::base::PropertyList());
297  data.maskMetadata = data.imageMetadata;
298  data.varianceMetadata = data.imageMetadata;
299 
300  data.metadata->combine(getMetadata());
301 
303 
304  // In the future, we might not have exactly three image HDUs, but we always do right now,
305  // so 0=primary, 1=image, 2=mask, 3=variance, 4+=archive
306  //
307  // Historically the AR_HDU keyword was 1-indexed (see RFC-304), and to maintain file compatibility
308  // this is still the case so we're setting AR_HDU to 5 == 4 + 1
309  //
310  data.metadata->set("AR_HDU", 5, "HDU (1-indexed) containing the archive used to store ancillary objects");
311  for (auto const& keyValue : *_components) {
312  std::string const& key = keyValue.first.getId();
313  std::shared_ptr<typehandling::Storable const> const& object = keyValue.second;
314 
315  if (object && object->isPersistable()) {
316  std::string comment = _getHeaderComment(key);
317  // Store archive ID in two header keys:
318  // - old-style key for backwards compatibility,
319  // - and new-style key because it's much safer to parse
320  int id = _addToArchive(data, object, _getOldHeaderKey(key), comment);
321  data.metadata->set(_getNewHeaderKey(key), id, comment);
322  }
323  }
324 
325  // LSST convention is that Wcs is in pixel coordinates (i.e relative to bottom left
326  // corner of parent image, if any). The Wcs/Fits convention is that the Wcs is in
327  // image coordinates. When saving an image we convert from pixel to index coordinates.
328  // In the case where this image is a parent image, the reference pixels are unchanged
329  // by this transformation
330  if (hasWcs() && getWcs()->isFits()) {
331  // Try to save the WCS as FITS-WCS metadata; if an exact representation
332  // is not possible then skip it
333  auto shift = lsst::geom::Extent2D(lsst::geom::Point2I(0, 0) - xy0);
334  auto newWcs = getWcs()->copyAtShiftedPixelOrigin(shift);
336  try {
337  wcsMetadata = newWcs->getFitsMetadata(true);
338  } catch (pex::exceptions::RuntimeError const&) {
339  // cannot represent this WCS as FITS-WCS; don't write its metadata
340  }
341  if (wcsMetadata) {
342  data.imageMetadata->combine(newWcs->getFitsMetadata(true));
343  }
344  }
345 
346  // For the sake of ds9, store _x0 and _y0 as -LTV1, -LTV2.
347  // This is in addition to saving _x0 and _y0 as WCS A, which is done elsewhere
348  // and is what LSST uses to read _x0 and _y0.
349  // LTV is a convention used by STScI (see \S2.6.2 of HST Data Handbook for STIS, version 5.0
350  // http://www.stsci.edu/hst/stis/documents/handbooks/currentDHB/ch2_stis_data7.html#429287)
351  // and recognized by ds9.
352  data.imageMetadata->set("LTV1", static_cast<double>(-xy0.getX()));
353  data.imageMetadata->set("LTV2", static_cast<double>(-xy0.getY()));
354 
355  if (hasDetector()) {
356  data.metadata->set("DETNAME", getDetector()->getName());
357  data.metadata->set("DETSER", getDetector()->getSerial());
358  }
359 
360  auto visitInfoPtr = getVisitInfo();
361  if (visitInfoPtr) {
362  detail::setVisitInfoMetadata(*(data.metadata), *visitInfoPtr);
363  }
364 
365  // So long as VisitInfo also writes exposureId (until DM-32138), let ours take precedence.
366  if (hasId()) {
367  data.metadata->set("EXPID", getId());
368  }
369 
370  return data;
371 }
372 
373 void ExposureInfo::_finishWriteFits(fits::Fits& fitsfile, FitsWriteData const& data) const {
374  data.archive.writeFits(fitsfile);
375 }
376 
377 } // namespace image
378 } // namespace afw
379 } // namespace lsst
char * data
Definition: BaseRecord.cc:61
table::Key< int > id
Definition: Detector.cc:162
table::Key< int > detector
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
LSST DM logging module built on log4cxx.
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
#define LOG_LOGGER
Definition: Log.h:714
Implementation of the Photometric Calibration class.
table::Key< table::Array< std::uint8_t > > wcs
Definition: SkyWcs.cc:66
A collection of all the things that make an Exposure different from a MaskedImage.
Definition: ExposureInfo.h:89
bool hasWcs() const
Does this exposure have a Wcs?
Definition: ExposureInfo.cc:54
static int getFitsSerializationVersion()
Get the version of FITS serialization that this ExposureInfo understands.
std::shared_ptr< daf::base::PropertySet > getMetadata() const
Return flexible metadata.
Definition: ExposureInfo.h:201
ExposureInfo & operator=(ExposureInfo const &other)
Assignment; shares all components.
void setFilter(Filter const &filter)
Set the exposure's filter.
ExposureInfo(std::shared_ptr< geom::SkyWcs const > const &wcs=std::shared_ptr< geom::SkyWcs const >(), std::shared_ptr< detection::Psf const > const &psf=std::shared_ptr< detection::Psf const >(), std::shared_ptr< PhotoCalib const > const &photoCalib=std::shared_ptr< PhotoCalib const >(), std::shared_ptr< cameraGeom::Detector const > const &detector=std::shared_ptr< cameraGeom::Detector const >(), std::shared_ptr< geom::polygon::Polygon const > const &polygon=std::shared_ptr< geom::polygon::Polygon const >(), Filter const &filter=Filter(), std::shared_ptr< daf::base::PropertySet > const &metadata=std::shared_ptr< daf::base::PropertySet >(), std::shared_ptr< CoaddInputs > const &coaddInputs=std::shared_ptr< CoaddInputs >(), std::shared_ptr< ApCorrMap > const &apCorrMap=std::shared_ptr< ApCorrMap >(), std::shared_ptr< image::VisitInfo const > const &visitInfo=std::shared_ptr< image::VisitInfo const >(), std::shared_ptr< TransmissionCurve const > const &transmissionCurve=std::shared_ptr< TransmissionCurve >())
Construct an ExposureInfo from its various components.
void setValidPolygon(std::shared_ptr< geom::polygon::Polygon const > polygon)
Set the exposure's valid Polygon.
Definition: ExposureInfo.cc:95
void setWcs(std::shared_ptr< geom::SkyWcs const > wcs)
Set the WCS of the exposure.
Definition: ExposureInfo.cc:56
std::shared_ptr< image::VisitInfo const > getVisitInfo() const
Return the exposure's visit info.
Definition: ExposureInfo.h:251
void setApCorrMap(std::shared_ptr< ApCorrMap const > apCorrMap)
Set the exposure's aperture correction map (null pointer if !hasApCorrMap())
std::shared_ptr< cameraGeom::Detector const > getDetector() const
Return the exposure's Detector information.
Definition: ExposureInfo.cc:80
void setPhotoCalib(std::shared_ptr< PhotoCalib const > photoCalib)
Set the Exposure's PhotoCalib object.
Definition: ExposureInfo.cc:72
void setCoaddInputs(std::shared_ptr< CoaddInputs const > coaddInputs)
Set the exposure's coadd provenance catalogs.
void setDetector(std::shared_ptr< cameraGeom::Detector const > detector)
Set the exposure's Detector information.
Definition: ExposureInfo.cc:83
void setPsf(std::shared_ptr< detection::Psf const > psf)
Set the exposure's point-spread function.
Definition: ExposureInfo.cc:63
void initApCorrMap()
Set the exposure's aperture correction map to a new, empty map.
table::RecordId getId() const
Return the exposure ID.
std::shared_ptr< geom::SkyWcs const > getWcs() const
Return the WCS of the exposure.
Definition: ExposureInfo.cc:55
bool hasDetector() const
Does this exposure have Detector information?
Definition: ExposureInfo.cc:79
static std::string const & getFitsSerializationVersionName()
Get the version of FITS serialization version info name.
bool hasId() const noexcept
Does this Exposure have an exposure id?
void setTransmissionCurve(std::shared_ptr< TransmissionCurve const > tc)
Set the exposure's transmission curve.
A group of labels for a filter in an exposure or coadd.
Definition: FilterLabel.h:58
A map of Storable supporting strongly-typed access.
Definition: StorableMap.h:59
A base class for objects that can be persisted via afw::table::io Archive classes.
Definition: Persistable.h:74
Key for type-safe lookup in a GenericMap.
Definition: Key.h:52
Reports attempts to access elements using an invalid key.
Definition: Runtime.h:151
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
Definition: VisitInfo.cc:363
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Filter makeFilter(FilterLabel const &label)
Convert a FilterLabel back to an old-style Filter.
std::shared_ptr< FilterLabel > makeFilterLabel(Filter const &filter)
Convert an old-style Filter to a FilterLabel.
std::string const & getName() const noexcept
Return a filter's name.
Definition: Filter.h:78
Extent< double, 2 > Extent2D
Definition: Extent.h:400
A base class for image defects.
STL namespace.
Key< int > psf
Definition: Exposure.cc:65
Key< int > visitInfo
Definition: Exposure.cc:70
Key< int > photoCalib
Definition: Exposure.cc:67
Key< int > transmissionCurve
Definition: Exposure.cc:71
Key< int > apCorrMap
Definition: Exposure.cc:68