LSST Applications g04e9c324dd+8c5ae1fdc5,g134cb467dc+1b3060144d,g18429d2f64+f642bf4753,g199a45376c+0ba108daf9,g1fd858c14a+2dcf163641,g262e1987ae+7b8c96d2ca,g29ae962dfc+3bd6ecb08a,g2cef7863aa+aef1011c0b,g35bb328faa+8c5ae1fdc5,g3fd5ace14f+53e1a9e7c5,g4595892280+fef73a337f,g47891489e3+2efcf17695,g4d44eb3520+642b70b07e,g53246c7159+8c5ae1fdc5,g67b6fd64d1+2efcf17695,g67fd3c3899+b70e05ef52,g74acd417e5+317eb4c7d4,g786e29fd12+668abc6043,g87389fa792+8856018cbb,g89139ef638+2efcf17695,g8d7436a09f+3be3c13596,g8ea07a8fe4+9f5ccc88ac,g90f42f885a+a4e7b16d9b,g97be763408+ad77d7208f,g9dd6db0277+b70e05ef52,ga681d05dcb+a3f46e7fff,gabf8522325+735880ea63,gac2eed3f23+2efcf17695,gb89ab40317+2efcf17695,gbf99507273+8c5ae1fdc5,gd8ff7fe66e+b70e05ef52,gdab6d2f7ff+317eb4c7d4,gdc713202bf+b70e05ef52,gdfd2d52018+b10e285e0f,ge365c994fd+310e8507c4,ge410e46f29+2efcf17695,geaed405ab2+562b3308c0,gffca2db377+8c5ae1fdc5,w.2025.35
LSST Data Management Base Package
Loading...
Searching...
No Matches
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"
35#include "lsst/afw/fits.h"
36
37using namespace std::string_literals;
38
39namespace {
40LOG_LOGGER _log = LOG_GET("lsst.afw.image.ExposureInfo");
41
43} // namespace
44
45namespace lsst {
46namespace afw {
47namespace image {
48
49// Important: do *not* change the keys' strings; doing so will break compatibility with old FITS files
50
51typehandling::Key<std::string, std::shared_ptr<geom::SkyWcs const>> const ExposureInfo::KEY_WCS =
53
54bool ExposureInfo::hasWcs() const { return hasComponent(KEY_WCS); }
57
60
61bool ExposureInfo::hasPsf() const { return hasComponent(KEY_PSF); }
64
67
75
78
86
90
98
101
109
112
118
122
130
131bool ExposureInfo::hasId() const noexcept { return _exposureId.has_value(); }
132
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
141void ExposureInfo::setId(table::RecordId id) { _exposureId = id; }
142
143void ExposureInfo::clearId() noexcept { _exposureId.reset(); }
144
150
152 // Version history:
153 // unversioned and 0: photometric calibration via Calib, WCS via SkyWcs using AST.
154 // 1: photometric calibration via PhotoCalib, generic components
155 // 2: remove Filter, replaced with (generic) FilterLabel
156 static int const version = 2;
157 return version;
158}
159
161 static std::string const versionName("EXPINFO_V");
162 return versionName;
163}
164
165// Clone various components; defined here so that we don't have to expose their insides in Exposure.h
166
167std::shared_ptr<ApCorrMap> ExposureInfo::_cloneApCorrMap(std::shared_ptr<ApCorrMap const> apCorrMap) {
168 if (apCorrMap) {
169 return std::make_shared<ApCorrMap>(*apCorrMap);
170 }
172}
173
176 std::shared_ptr<PhotoCalib const> const& photoCalib,
180 std::shared_ptr<CoaddInputs> const& coaddInputs,
181 std::shared_ptr<ApCorrMap> const& apCorrMap,
183 std::shared_ptr<TransmissionCurve const> const& transmissionCurve)
184 : _exposureId(),
185 _metadata(metadata ? metadata
186 : std::shared_ptr<daf::base::PropertySet>(new daf::base::PropertyList())),
187 _visitInfo(visitInfo),
188 _components(std::make_unique<MapClass>()) {
189 setWcs(wcs);
190 setPsf(psf);
191 setPhotoCalib(photoCalib);
192 setDetector(detector);
193 setValidPolygon(polygon);
194 setCoaddInputs(coaddInputs);
195 setApCorrMap(_cloneApCorrMap(apCorrMap));
196 setTransmissionCurve(transmissionCurve);
197}
198
200
201// Delegate to copy-constructor for backwards compatibility
203
204ExposureInfo::ExposureInfo(ExposureInfo const& other, bool copyMetadata)
205 : _exposureId(other._exposureId),
206 _metadata(other._metadata),
207 _visitInfo(other._visitInfo),
208 // ExposureInfos can (historically) share objects, but should each have their own pointers to them
209 _components(std::make_unique<MapClass>(*(other._components))) {
210 if (copyMetadata) _metadata = _metadata->deepCopy();
211}
212
214 if (&other != this) {
215 _exposureId = other._exposureId;
216 _metadata = other._metadata;
217 _visitInfo = other._visitInfo;
218 // ExposureInfos can (historically) share objects, but should each have their own pointers to them
219 _components = std::make_unique<MapClass>(*(other._components));
220 }
221 return *this;
222}
223// Delegate to copy-assignment for backwards compatibility
224ExposureInfo& ExposureInfo::operator=(ExposureInfo&& other) { return *this = other; }
225
227
228int ExposureInfo::_addToArchive(FitsWriteData& data, table::io::Persistable const& object, std::string key,
229 std::string comment) {
230 int componentId = data.archive.put(object);
231 data.metadata->set(key, componentId, comment);
232 return componentId;
233}
234
235int ExposureInfo::_addToArchive(FitsWriteData& data,
237 std::string comment) {
238 // Don't delegate to Persistable const& version because OutputArchive::put
239 // has special handling of shared_ptr
240 int componentId = data.archive.put(object);
241 data.metadata->set(key, componentId, comment);
242 return componentId;
243}
244
245// Standardized strings for _startWriteFits
246namespace {
247std::string _getOldHeaderKey(std::string mapKey) { return mapKey + "_ID"; }
248std::string _getNewHeaderKey(std::string mapKey) { return "ARCHIVE_ID_" + mapKey; }
249
250std::string _getHeaderComment(std::string mapKey) {
251 return "archive ID for generic component '" + mapKey + "'";
252}
253} // namespace
254
255ExposureInfo::FitsWriteData ExposureInfo::_startWriteFits(lsst::geom::Point2I const& xy0) const {
256 FitsWriteData data;
257
258 data.metadata.reset(new daf::base::PropertyList());
259 data.imageMetadata.reset(new daf::base::PropertyList());
260 data.maskMetadata = data.imageMetadata;
261 data.varianceMetadata = data.imageMetadata;
262
263 data.metadata->combine(*getMetadata());
264
266
267 // In the future, we might not have exactly three image HDUs, but we always do right now,
268 // so 0=primary, 1=image, 2=mask, 3=variance, 4+=archive
269 //
270 // Historically the AR_HDU keyword was 1-indexed (see RFC-304), and to maintain file compatibility
271 // this is still the case so we're setting AR_HDU to 5 == 4 + 1
272 //
273 data.metadata->set("AR_HDU", 5, "HDU (1-indexed) containing the archive used to store ancillary objects");
274 for (auto const& keyValue : *_components) {
275 std::string const& key = keyValue.first.getId();
276 std::shared_ptr<typehandling::Storable const> const& object = keyValue.second;
277
278 if (object && object->isPersistable()) {
279 std::string comment = _getHeaderComment(key);
280 // Store archive ID in two header keys:
281 // - old-style key for backwards compatibility,
282 // - and new-style key because it's much safer to parse
283 int id = _addToArchive(data, object, _getOldHeaderKey(key), comment);
284 data.metadata->set(_getNewHeaderKey(key), id, comment);
285 }
286 }
287
288 // LSST convention is that Wcs is in pixel coordinates (i.e relative to bottom left
289 // corner of parent image, if any). The Wcs/Fits convention is that the Wcs is in
290 // image coordinates. When saving an image we convert from pixel to index coordinates.
291 // In the case where this image is a parent image, the reference pixels are unchanged
292 // by this transformation
293 if (hasWcs()) {
294 auto wcs = getWcs();
295 if (wcs->hasFitsApproximation()) {
296 wcs = wcs->getFitsApproximation();
297 }
298 // Try to save the WCS as FITS-WCS metadata; if an exact representation
299 // is not possible then skip it
300 auto shift = lsst::geom::Extent2D(lsst::geom::Point2I(0, 0) - xy0);
301 auto newWcs = wcs->copyAtShiftedPixelOrigin(shift);
302 try {
303 data.imageMetadata->combine(*newWcs->getFitsMetadata(true));
304 } catch (pex::exceptions::RuntimeError const&) {
305 // cannot represent this WCS as FITS-WCS; don't write its metadata
306 }
307 }
308
309 // For the sake of ds9, store _x0 and _y0 as -LTV1, -LTV2.
310 // This is in addition to saving _x0 and _y0 as WCS A, which is done elsewhere
311 // and is what LSST uses to read _x0 and _y0.
312 // LTV is a convention used by STScI (see \S2.6.2 of HST Data Handbook for STIS, version 5.0
313 // http://www.stsci.edu/hst/stis/documents/handbooks/currentDHB/ch2_stis_data7.html#429287)
314 // and recognized by ds9.
315 data.imageMetadata->set("LTV1", static_cast<double>(-xy0.getX()));
316 data.imageMetadata->set("LTV2", static_cast<double>(-xy0.getY()));
317
318 if (hasDetector()) {
319 data.metadata->set("DETNAME", getDetector()->getName());
320 data.metadata->set("DETSER", getDetector()->getSerial());
321 }
322
323 auto visitInfoPtr = getVisitInfo();
324 if (visitInfoPtr) {
325 detail::setVisitInfoMetadata(*(data.metadata), *visitInfoPtr);
326 }
327
328 if (hasId()) {
329 data.metadata->set("EXPID", getId());
330 }
331
332 // FITS BUNIT header has to end up in the IMAGE or VARIANCE HDU and cannot
333 // be in the primary HDU. We have to make separate variance and mask
334 // headers at this point (so far the content has been identical).
335 auto varIsIdentical = true;
336 if (data.metadata->exists("BUNIT")) {
337 // Do not set anything if undefined value and remove from primary
338 // header to avoid confusion.
339 if (!data.metadata->isUndefined("BUNIT")) {
340 // Need to have distinct versions for mask and variance but seeded
341 // from image metadata.
342 varIsIdentical = false;
343 data.varianceMetadata.reset(new daf::base::PropertyList());
344 data.maskMetadata.reset(new daf::base::PropertyList());
345 data.varianceMetadata->combine(*data.imageMetadata);
346 data.maskMetadata->combine(*data.imageMetadata);
347
348 auto units = data.metadata->getAsString("BUNIT");
349 data.imageMetadata->set("BUNIT", units, "Image Data units");
350 data.varianceMetadata->set("BUNIT", units + "**2", "Variance Data units");
351 data.maskMetadata->set("BUNIT", nullptr, "Mask Data units");
352 }
353 data.metadata->remove("BUNIT");
354 }
355 if (varIsIdentical) {
356 data.maskMetadata = data.imageMetadata;
357 data.varianceMetadata = data.imageMetadata;
358 }
359
360 return data;
361}
362
363void ExposureInfo::_finishWriteFits(fits::Fits& fitsfile, FitsWriteData const& data) const {
364 data.archive.writeFits(fitsfile);
365}
366
367} // namespace image
368} // namespace afw
369} // namespace lsst
#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.
bool hasWcs() const
Does this exposure have a Wcs?
static int getFitsSerializationVersion()
Get the version of FITS serialization that this ExposureInfo understands.
bool hasCoaddInputs() const
Does this exposure have coadd provenance catalogs?
static typehandling::Key< std::string, std::shared_ptr< geom::SkyWcs const > > const KEY_WCS
Standard key for looking up the Wcs.
ExposureInfo & operator=(ExposureInfo const &other)
Assignment; shares all components.
static typehandling::Key< std::string, std::shared_ptr< cameraGeom::Detector const > > const KEY_DETECTOR
Standard key for looking up the detector information.
bool hasTransmissionCurve() const
Does this exposure have a transmission curve?
bool hasPsf() const
Does this exposure have a Psf?
void setValidPolygon(std::shared_ptr< geom::polygon::Polygon const > polygon)
Set the exposure's valid Polygon.
bool hasPhotoCalib() const
Does this exposure have a photometric calibration?
bool hasApCorrMap() const
Return true if the exposure has an aperture correction map.
void setWcs(std::shared_ptr< geom::SkyWcs const > wcs)
Set the WCS of the exposure.
std::shared_ptr< PhotoCalib const > getPhotoCalib() const
Return the exposure's photometric calibration.
bool hasComponent(typehandling::Key< std::string, T > const &key) const
Test whether a generic component is defined.
std::shared_ptr< ApCorrMap const > getApCorrMap() const
Return the exposure's aperture correction map (null pointer if !hasApCorrMap())
void setApCorrMap(std::shared_ptr< ApCorrMap const > apCorrMap)
Set the exposure's aperture correction map (null pointer if !hasApCorrMap())
void setPhotoCalib(std::shared_ptr< PhotoCalib const > photoCalib)
Set the Exposure's PhotoCalib object.
static typehandling::Key< std::string, std::shared_ptr< geom::polygon::Polygon const > > const KEY_VALID_POLYGON
Standard key for looking up the valid polygon.
void setComponent(typehandling::Key< std::string, std::shared_ptr< T > > const &key, std::shared_ptr< T > const &object)
Add a generic component to the ExposureInfo.
bool hasValidPolygon() const
Does this exposure have a valid Polygon.
std::shared_ptr< geom::SkyWcs const > getWcs() const
Return the WCS of the exposure.
std::shared_ptr< T > getComponent(typehandling::Key< std::string, std::shared_ptr< T > > const &key) const
Retrieve a generic component from the ExposureInfo.
std::shared_ptr< FilterLabel const > getFilter() const
Return the exposure's filter information.
static typehandling::Key< std::string, std::shared_ptr< PhotoCalib const > > const KEY_PHOTO_CALIB
Standard key for looking up the photometric calibration.
void setCoaddInputs(std::shared_ptr< CoaddInputs const > coaddInputs)
Set the exposure's coadd provenance catalogs.
std::shared_ptr< cameraGeom::Detector const > getDetector() const
Return the exposure's Detector information.
void clearId() noexcept
Unset the exposure ID, if any.
void setDetector(std::shared_ptr< cameraGeom::Detector const > detector)
Set the exposure's Detector information.
void setFilter(std::shared_ptr< FilterLabel const > filter)
Set the exposure's filter information.
void setPsf(std::shared_ptr< detection::Psf const > psf)
Set the exposure's point-spread function.
static typehandling::Key< std::string, std::shared_ptr< TransmissionCurve const > > const KEY_TRANSMISSION_CURVE
Standard key for looking up the transmission curve.
static typehandling::Key< std::string, std::shared_ptr< CoaddInputs const > > const KEY_COADD_INPUTS
Standard key for looking up coadd provenance catalogs.
static typehandling::Key< std::string, std::shared_ptr< detection::Psf const > > const KEY_PSF
Standard key for looking up the point-spread function.
std::shared_ptr< CoaddInputs const > getCoaddInputs() const
Return a pair of catalogs that record the inputs, if this Exposure is a coadd (otherwise null).
bool hasFilter() const
Does this exposure have filter information?
table::RecordId getId() const
Return the exposure ID.
std::shared_ptr< geom::polygon::Polygon const > getValidPolygon() const
Return the valid Polygon.
std::shared_ptr< daf::base::PropertySet > getMetadata() const
Return flexible metadata.
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 >(), 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.
bool hasDetector() const
Does this exposure have Detector information?
static typehandling::Key< std::string, std::shared_ptr< ApCorrMap const > > const KEY_AP_CORR_MAP
Standard key for looking up the aperture correction map.
static std::string const & getFitsSerializationVersionName()
Get the version of FITS serialization version info name.
std::shared_ptr< image::VisitInfo const > getVisitInfo() const
Return the exposure's visit info.
static typehandling::Key< std::string, std::shared_ptr< FilterLabel const > > const KEY_FILTER
Standard key for looking up filter information.
void setId(table::RecordId id)
Set the exposure ID.
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.
std::shared_ptr< detection::Psf const > getPsf() const
Return the exposure's point-spread function.
std::shared_ptr< TransmissionCurve const > getTransmissionCurve() const
Return the exposure's transmission curve.
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
T make_shared(T... args)
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
Definition VisitInfo.cc:408
std::int64_t RecordId
Type used for unique IDs for records.
Definition misc.h:21
constexpr Key< K, V > makeKey(K const &id)
Factory function for Key, to enable type parameter inference.
Definition Key.h:173
Extent< double, 2 > Extent2D
Definition Extent.h:400
Point< int, 2 > Point2I
Definition Point.h:321
STL namespace.
data(channels)
Definition test_model.py:17