LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
LSSTDataManagementBasePackage
ExposureInfo.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*- // fixed format comment for emacs
2 /*
3  * LSST Data Management System
4  * Copyright 2008, 2009, 2010 LSST Corporation.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
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 LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 
24 #include "lsst/pex/exceptions.h"
25 #include "lsst/log/Log.h"
27 #include "lsst/afw/image/Calib.h"
28 #include "lsst/afw/image/Wcs.h"
31 #include "lsst/afw/detection/Psf.h"
33 #include "lsst/afw/fits.h"
34 
35 namespace {
36 LOG_LOGGER _log = LOG_GET("afw.image.ExposureInfo");
37 }
38 
39 namespace lsst { namespace afw { namespace image {
40 
41 namespace {
42 
43 // Return an int value from a PropertySet if it exists and remove it, or return 0.
44 int popInt(daf::base::PropertySet & metadata, std::string const & name) {
45  int r = 0;
46  if (metadata.exists(name)) {
47  r = metadata.get<int>(name);
48  metadata.remove(name);
49  }
50  return r;
51 }
52 
53 } // anonymous
54 
55 
56 // Clone various components; defined here so that we don't have to expose their insides in Exposure.h
57 
58 PTR(Calib) ExposureInfo::_cloneCalib(CONST_PTR(Calib) calib) {
59  if (calib)
60  return PTR(Calib)(new Calib(*calib));
61  return PTR(Calib)();
62 }
63 
65  if (wcs)
66  return wcs->clone();
67  return PTR(Wcs)();
68 }
69 
70 PTR(ApCorrMap) ExposureInfo::_cloneApCorrMap(PTR(ApCorrMap const) apCorrMap) {
71  if (apCorrMap) {
72  return std::make_shared<ApCorrMap>(*apCorrMap);
73  }
74  return PTR(ApCorrMap)();
75 }
76 
78  CONST_PTR(Wcs) const & wcs,
79  CONST_PTR(detection::Psf) const & psf,
80  CONST_PTR(Calib) const & calib,
81  CONST_PTR(cameraGeom::Detector) const & detector,
82  CONST_PTR(geom::polygon::Polygon) const & polygon,
83  Filter const & filter,
84  PTR(daf::base::PropertySet) const & metadata,
85  PTR(CoaddInputs) const & coaddInputs,
86  PTR(ApCorrMap) const & apCorrMap,
87  CONST_PTR(image::VisitInfo) const & visitInfo
88 ) : _wcs(_cloneWcs(wcs)),
89  _psf(std::const_pointer_cast<detection::Psf>(psf)),
90  _calib(calib ? _cloneCalib(calib) : PTR(Calib)(new Calib())),
91  _detector(detector),
92  _validPolygon(polygon),
93  _filter(filter),
94  _metadata(metadata ? metadata : PTR(daf::base::PropertySet)(new daf::base::PropertyList())),
95  _coaddInputs(coaddInputs),
96  _apCorrMap(_cloneApCorrMap(apCorrMap)),
97  _visitInfo(visitInfo)
98 {}
99 
101  _wcs(_cloneWcs(other._wcs)),
102  _psf(other._psf),
103  _calib(_cloneCalib(other._calib)),
104  _detector(other._detector),
105  _validPolygon(other._validPolygon),
106  _filter(other._filter),
107  _metadata(other._metadata),
108  _coaddInputs(other._coaddInputs),
109  _apCorrMap(_cloneApCorrMap(other._apCorrMap)),
110  _visitInfo(other._visitInfo)
111 {}
112 
113 ExposureInfo::ExposureInfo(ExposureInfo const & other, bool copyMetadata) :
114  _wcs(_cloneWcs(other._wcs)),
115  _psf(other._psf),
116  _calib(_cloneCalib(other._calib)),
117  _detector(other._detector),
118  _validPolygon(other._validPolygon),
119  _filter(other._filter),
120  _metadata(other._metadata),
121  _coaddInputs(other._coaddInputs),
122  _apCorrMap(_cloneApCorrMap(other._apCorrMap)),
123  _visitInfo(other._visitInfo)
124 {
125  if (copyMetadata) _metadata = _metadata->deepCopy();
126 }
127 
129  if (&other != this) {
130  _wcs = _cloneWcs(other._wcs);
131  _psf = other._psf;
132  _calib = _cloneCalib(other._calib);
133  _detector = other._detector;
135  _filter = other._filter;
136  _metadata = other._metadata;
137  _coaddInputs = other._coaddInputs;
139  _visitInfo = other._visitInfo;
140  }
141  return *this;
142 }
143 
145  _apCorrMap = std::make_shared<ApCorrMap>();
146 }
147 
149 
152 
153  FitsWriteData data;
154 
155  data.metadata.reset(new daf::base::PropertyList());
156  data.imageMetadata.reset(new daf::base::PropertyList());
157  data.maskMetadata = data.imageMetadata;
158  data.varianceMetadata = data.imageMetadata;
159 
160  data.metadata->combine(getMetadata());
161 
162  // In the future, we might not have exactly three image HDUs, but we always do right now,
163  // so 1=primary, 2=image, 3=mask, 4=variance, 5+=archive
164  data.metadata->set("AR_HDU", 5, "HDU containing the archive used to store ancillary objects");
165  if (hasCoaddInputs()) {
166  int coaddInputsId = data.archive.put(getCoaddInputs());
167  data.metadata->set("COADD_INPUTS_ID", coaddInputsId, "archive ID for coadd inputs catalogs");
168  }
169  if (hasApCorrMap()) {
170  int apCorrMapId = data.archive.put(getApCorrMap());
171  data.metadata->set("AP_CORR_MAP_ID", apCorrMapId, "archive ID for aperture correction map");
172  }
173  if (hasPsf() && getPsf()->isPersistable()) {
174  int psfId = data.archive.put(getPsf());
175  data.metadata->set("PSF_ID", psfId, "archive ID for the Exposure's main Psf");
176  }
177  if (hasWcs() && getWcs()->isPersistable()) {
178  int wcsId = data.archive.put(getWcs());
179  data.metadata->set("WCS_ID", wcsId, "archive ID for the Exposure's main Wcs");
180  }
181  if (hasValidPolygon() && getValidPolygon()->isPersistable()) {
182  int polygonId = data.archive.put(getValidPolygon());
183  data.metadata->set("VALID_POLYGON_ID", polygonId, "archive ID for the Exposure's valid polygon");
184  }
185 
186  //LSST convention is that Wcs is in pixel coordinates (i.e relative to bottom left
187  //corner of parent image, if any). The Wcs/Fits convention is that the Wcs is in
188  //image coordinates. When saving an image we convert from pixel to index coordinates.
189  //In the case where this image is a parent image, the reference pixels are unchanged
190  //by this transformation
191  if (hasWcs()) {
192  PTR(Wcs) newWcs = getWcs()->clone(); //Create a copy
193  newWcs->shiftReferencePixel(-xy0.getX(), -xy0.getY() );
194 
195  // We want the WCS to appear in all HDUs
196  data.imageMetadata->combine(newWcs->getFitsMetadata());
197  }
198 
199  //Store _x0 and _y0. If this exposure is a portion of a larger image, _x0 and _y0
200  //indicate the origin (the position of the bottom left corner) of the sub-image with
201  //respect to the origin of the parent image.
202  //This is stored in the fits header using the LTV convention used by STScI
203  //(see \S2.6.2 of HST Data Handbook for STIS, version 5.0
204  // http://www.stsci.edu/hst/stis/documents/handbooks/currentDHB/ch2_stis_data7.html#429287).
205  //This is not a fits standard keyword, but is recognised by ds9
206  //LTV keywords use the opposite convention to the LSST, in that they represent
207  //the position of the origin of the parent image relative to the origin of the sub-image.
208  // _x0, _y0 >= 0, while LTV1 and LTV2 <= 0
209 
210  data.imageMetadata->set("LTV1", static_cast<double>(-xy0.getX()));
211  data.imageMetadata->set("LTV2", static_cast<double>(-xy0.getY()));
212 
213  data.metadata->set("FILTER", getFilter().getName());
214  if (hasDetector()) {
215  data.metadata->set("DETNAME", getDetector()->getName());
216  data.metadata->set("DETSER", getDetector()->getSerial());
217  }
218 
219  auto visitInfoPtr = getVisitInfo();
220  if (visitInfoPtr) {
221  detail::setVisitInfoMetadata(*(data.metadata), *visitInfoPtr);
222  }
223 
227  data.metadata->set("FLUXMAG0", getCalib()->getFluxMag0().first);
228  data.metadata->set("FLUXMAG0ERR", getCalib()->getFluxMag0().second);
229 
230  return data;
231 }
232 
233 void ExposureInfo::_finishWriteFits(fits::Fits & fitsfile, FitsWriteData const & data) const {
234  data.archive.writeFits(fitsfile);
235 }
236 
238  fits::Fits & fitsfile,
239  PTR(daf::base::PropertySet) metadata,
240  PTR(daf::base::PropertySet) imageMetadata
241 ) {
242  // true: strip keywords that are related to the created WCS from the input metadata
243  _wcs = makeWcs(imageMetadata, true);
244 
245  if (!imageMetadata->exists("INHERIT")) {
246  // New-style exposures put everything but the Wcs in the primary HDU, use
247  // INHERIT keyword in the others. For backwards compatibility, if we don't
248  // find the INHERIT keyword, we ignore the primary HDU metadata and expect
249  // everything to be in the image HDU metadata. Note that we can't merge them,
250  // because they're probably duplicates.
251  metadata = imageMetadata;
252  }
253 
254  _filter = Filter(metadata, true);
255  detail::stripFilterKeywords(metadata);
256 
257  _visitInfo = CONST_PTR(VisitInfo)(new VisitInfo(*metadata));
259 
260  PTR(Calib) newCalib(new Calib(metadata));
261  setCalib(newCalib);
262  detail::stripCalibKeywords(metadata);
263 
264  int archiveHdu = popInt(*metadata, "AR_HDU");
265 
266  if (archiveHdu) {
267  fitsfile.setHdu(archiveHdu);
269  // Load the Psf and Wcs from the archive; id=0 results in a null pointer.
270  // Note that the binary table Wcs, if present, clobbers the FITS header one,
271  // because the former might be an approximation to something we can't represent
272  // using the FITS WCS standard but can represent with binary tables.
273  int psfId = popInt(*metadata, "PSF_ID");
274  try {
275  _psf = archive.get<detection::Psf>(psfId);
276  } catch (pex::exceptions::NotFoundError & err) {
277  LOGLS_WARN(_log, "Could not read PSF; setting to null: " << err.what());
278  }
279  int wcsId = popInt(*metadata, "WCS_ID");
280  try {
281  auto archiveWcs = archive.get<Wcs>(wcsId);
282  if (archiveWcs) {
283  _wcs = archiveWcs;
284  } else {
285  LOGLS_INFO(_log, "Empty WCS extension, using FITS header");
286  }
287  } catch (pex::exceptions::NotFoundError & err) {
288  auto msg = str(boost::format("Could not read WCS extension; setting to null: %s") % err.what());
289  if (_wcs) {
290  msg += " ; using WCS from FITS header";
291  }
292  LOGLS_WARN(_log, msg);
293  }
294  int coaddInputsId = popInt(*metadata, "COADD_INPUTS_ID");
295  try {
296  _coaddInputs = archive.get<CoaddInputs>(coaddInputsId);
297  } catch (pex::exceptions::NotFoundError & err) {
298  LOGLS_WARN(_log, "Could not read CoaddInputs; setting to null: " << err.what());
299  }
300  int apCorrMapId = popInt(*metadata, "AP_CORR_MAP_ID");
301  try {
302  _apCorrMap = archive.get<ApCorrMap>(apCorrMapId);
303  } catch (pex::exceptions::NotFoundError & err) {
304  LOGLS_WARN(_log, "Could not read ApCorrMap; setting to null: " << err.what());
305  }
306  int validPolygonId = popInt(*metadata, "VALID_POLYGON_ID");
307  try {
308  _validPolygon = archive.get<geom::polygon::Polygon>(validPolygonId);
309  } catch (pex::exceptions::NotFoundError & err) {
310  LOGLS_WARN(_log, "Could not read ValidPolygon; setting to null: " << err.what());
311  }
312  }
313 
314  _metadata = metadata;
315 }
316 
317 }}} // namespace lsst::afw::image
#define LOGLS_WARN(logger, message)
Log a warn-level message using an iostream-based interface.
Definition: Log.h:657
boost::shared_ptr< ApCorrMap > _apCorrMap
Definition: ExposureInfo.h:298
boost::shared_ptr< Persistable > get(int id) const
Load the Persistable with the given ID and return it.
boost::shared_ptr< detection::Psf > getPsf() const
Return the exposure&#39;s point-spread function.
Definition: ExposureInfo.h:135
static InputArchive readFits(fits::Fits &fitsfile)
Read an object from an already open FITS object.
#define LOG_LOGGER
Definition: Log.h:712
table::Key< std::string > name
Definition: ApCorrMap.cc:71
void _finishWriteFits(fits::Fits &fitsfile, FitsWriteData const &data) const
Write any additional non-image HDUs to a FITS file.
boost::shared_ptr< daf::base::PropertyList > imageMetadata
Definition: ExposureInfo.h:242
boost::shared_ptr< image::VisitInfo const > getVisitInfo() const
Return the exposure&#39;s visit info.
Definition: ExposureInfo.h:183
boost::shared_ptr< image::VisitInfo const > _visitInfo
Definition: ExposureInfo.h:299
Class for storing ordered metadata with comments.
Definition: PropertyList.h:82
A thin wrapper around std::map to allow aperture corrections to be attached to Exposures.
Definition: ApCorrMap.h:42
Include files required for standard LSST Exception handling.
static boost::shared_ptr< Wcs > _cloneWcs(boost::shared_ptr< Wcs const > wcs)
Definition: ExposureInfo.cc:64
Information about a single exposure of an imaging camera.
Definition: VisitInfo.h:63
int put(Persistable const *obj, bool permissive=false)
Save an object to the archive and return a unique ID that can be used to retrieve it from an InputArc...
tbl::Key< int > wcs
bool hasValidPolygon() const
Does this exposure have a valid Polygon.
Definition: ExposureInfo.h:145
Implementation of the WCS standard for a any projection.
Definition: Wcs.h:107
ExposureInfo(boost::shared_ptr< Wcs const > const &wcs=boost::shared_ptr< Wcs const >(), boost::shared_ptr< detection::Psf const > const &psf=boost::shared_ptr< detection::Psf const >(), boost::shared_ptr< Calib const > const &calib=boost::shared_ptr< Calib const >(), boost::shared_ptr< cameraGeom::Detector const > const &detector=boost::shared_ptr< cameraGeom::Detector const >(), boost::shared_ptr< geom::polygon::Polygon const > const &polygon=boost::shared_ptr< geom::polygon::Polygon const >(), Filter const &filter=Filter(), boost::shared_ptr< daf::base::PropertySet > const &metadata=boost::shared_ptr< daf::base::PropertySet >(), boost::shared_ptr< CoaddInputs > const &coaddInputs=boost::shared_ptr< CoaddInputs >(), boost::shared_ptr< ApCorrMap > const &apCorrMap=boost::shared_ptr< ApCorrMap >(), boost::shared_ptr< image::VisitInfo const > const &visitInfo=boost::shared_ptr< image::VisitInfo const >())
Construct an ExposureInfo from its various components.
Definition: ExposureInfo.cc:77
bool hasCoaddInputs() const
Does this exposure have coadd provenance catalogs?
Definition: ExposureInfo.h:174
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:202
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
Definition: PropertySet.cc:190
boost::shared_ptr< cameraGeom::Detector const > getDetector() const
Return the exposure&#39;s Detector information.
Definition: ExposureInfo.h:102
Describe an exposure&#39;s calibration.
Definition: Calib.h:82
static boost::shared_ptr< Calib > _cloneCalib(boost::shared_ptr< Calib const > calib)
Definition: ExposureInfo.cc:58
A simple Persistable struct containing ExposureCatalogs that record the inputs to a coadd...
Definition: CoaddInputs.h:46
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
LSST DM logging module built on log4cxx.
lsst::daf::base::PropertySet PropertySet
Definition: Wcs.cc:59
boost::shared_ptr< daf::base::PropertySet > _metadata
Definition: ExposureInfo.h:296
ExposureInfo & operator=(ExposureInfo const &other)
Assignment; deep-copies all components except the metadata.
void writeFits(fits::Fits &fitsfile) const
Write the archive to an already-open FITS object.
boost::shared_ptr< Wcs > makeWcs(boost::shared_ptr< lsst::daf::base::PropertySet > const &fitsMetadata, bool stripMetadata=false)
Create a Wcs object from a fits header.
Definition: makeWcs.cc:40
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
Definition: VisitInfo.cc:297
boost::shared_ptr< geom::polygon::Polygon const > getValidPolygon() const
Return the valid Polygon.
Definition: ExposureInfo.h:148
A struct passed back and forth between Exposure and ExposureInfo when writing FITS files...
Definition: ExposureInfo.h:240
boost::shared_ptr< detection::Psf > _psf
Definition: ExposureInfo.h:291
void initApCorrMap()
Set the exposure&#39;s aperture correction map to a new, empty map.
boost::shared_ptr< Wcs > getWcs()
Return the coordinate system of the exposure.
Definition: ExposureInfo.h:90
boost::shared_ptr< daf::base::PropertyList > maskMetadata
Definition: ExposureInfo.h:243
boost::shared_ptr< Wcs > _wcs
Definition: ExposureInfo.h:290
boost::shared_ptr< ApCorrMap > getApCorrMap()
Return the exposure&#39;s aperture correction map (null pointer if !hasApCorrMap())
Definition: ExposureInfo.h:157
Classes to support calibration (e.g.
Holds an integer identifier for an LSST filter.
Definition: Filter.h:108
void setHdu(int hdu, bool relative=false)
Set the current HDU.
int stripCalibKeywords(boost::shared_ptr< lsst::daf::base::PropertySet > metadata)
Remove Calib-related keywords from the metadata.
Definition: Calib.cc:136
#define LOGLS_INFO(logger, message)
Log a info-level message using an iostream-based interface.
Definition: Log.h:637
boost::shared_ptr< cameraGeom::Detector const > _detector
Definition: ExposureInfo.h:293
Utilities for working with FITS files.
static boost::shared_ptr< ApCorrMap > _cloneApCorrMap(boost::shared_ptr< ApCorrMap const > apCorrMap)
Definition: ExposureInfo.cc:70
Filter getFilter() const
Return the exposure&#39;s filter.
Definition: ExposureInfo.h:108
Information about a CCD or other imaging detector.
Definition: Detector.h:65
bool hasPsf() const
Does this exposure have a Psf?
Definition: ExposureInfo.h:132
void setCalib(boost::shared_ptr< Calib const > calib)
Set the Exposure&#39;s Calib object.
Definition: ExposureInfo.h:123
#define PTR(...)
Definition: base.h:41
bool hasWcs() const
Does this exposure have a Wcs?
Definition: ExposureInfo.h:87
void _readFits(fits::Fits &fitsfile, boost::shared_ptr< daf::base::PropertySet > metadata, boost::shared_ptr< daf::base::PropertySet > imageMetadata)
Read from a FITS file and metadata.
Class for storing generic metadata.
Definition: PropertySet.h:82
boost::shared_ptr< daf::base::PropertySet > getMetadata() const
Return flexible metadata.
Definition: ExposureInfo.h:126
int stripVisitInfoKeywords(daf::base::PropertySet &metadata)
Remove VisitInfo-related keywords from the metadata.
Definition: VisitInfo.cc:279
int stripFilterKeywords(boost::shared_ptr< lsst::daf::base::PropertySet > metadata)
Remove Filter-related keywords from the metadata.
Definition: Filter.cc:166
Cartesian polygons.
Definition: Polygon.h:55
bool hasApCorrMap() const
Return true if the exposure has an aperture correction map.
Definition: ExposureInfo.h:154
boost::shared_ptr< Calib > _calib
Definition: ExposureInfo.h:292
boost::shared_ptr< CoaddInputs > getCoaddInputs() const
Return a pair of catalogs that record the inputs, if this Exposure is a coadd (otherwise null)...
Definition: ExposureInfo.h:180
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:28
#define CONST_PTR(...)
A shared pointer to a const object.
Definition: base.h:47
boost::shared_ptr< daf::base::PropertyList > metadata
Definition: ExposureInfo.h:241
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:83
A collection of all the things that make an Exposure different from a MaskedImage.
Definition: ExposureInfo.h:83
A polymorphic base class for representing an image&#39;s Point Spread Function.
Definition: Psf.h:68
boost::shared_ptr< daf::base::PropertyList > varianceMetadata
Definition: ExposureInfo.h:244
boost::shared_ptr< Calib > getCalib()
Return the exposure&#39;s photometric calibration.
Definition: ExposureInfo.h:117
daf::base::PropertySet & _metadata
Definition: fits_io_mpl.h:79
bool hasDetector() const
Does this exposure have Detector information?
Definition: ExposureInfo.h:99
FitsWriteData _startWriteFits(geom::Point2I const &xy0=geom::Point2I()) const
Start the process of writing an exposure to FITS.
boost::shared_ptr< geom::polygon::Polygon const > _validPolygon
Definition: ExposureInfo.h:294
boost::shared_ptr< CoaddInputs > _coaddInputs
Definition: ExposureInfo.h:297