LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
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 ) : _wcs(_cloneWcs(wcs)),
88  _psf(std::const_pointer_cast<detection::Psf>(psf)),
89  _calib(calib ? _cloneCalib(calib) : PTR(Calib)(new Calib())),
90  _detector(detector),
91  _validPolygon(polygon),
92  _filter(filter),
93  _metadata(metadata ? metadata : PTR(daf::base::PropertySet)(new daf::base::PropertyList())),
94  _coaddInputs(coaddInputs),
95  _apCorrMap(_cloneApCorrMap(apCorrMap))
96 {}
97 
99  _wcs(_cloneWcs(other._wcs)),
100  _psf(other._psf),
101  _calib(_cloneCalib(other._calib)),
102  _detector(other._detector),
103  _validPolygon(other._validPolygon),
104  _filter(other._filter),
105  _metadata(other._metadata),
106  _coaddInputs(other._coaddInputs),
107  _apCorrMap(_cloneApCorrMap(other._apCorrMap))
108 {}
109 
110 ExposureInfo::ExposureInfo(ExposureInfo const & other, bool copyMetadata) :
111  _wcs(_cloneWcs(other._wcs)),
112  _psf(other._psf),
113  _calib(_cloneCalib(other._calib)),
114  _detector(other._detector),
115  _validPolygon(other._validPolygon),
116  _filter(other._filter),
117  _metadata(other._metadata),
118  _coaddInputs(other._coaddInputs),
119  _apCorrMap(_cloneApCorrMap(other._apCorrMap))
120 {
121  if (copyMetadata) _metadata = _metadata->deepCopy();
122 }
123 
125  if (&other != this) {
126  _wcs = _cloneWcs(other._wcs);
127  _psf = other._psf;
128  _calib = _cloneCalib(other._calib);
129  _detector = other._detector;
131  _filter = other._filter;
132  _metadata = other._metadata;
133  _coaddInputs = other._coaddInputs;
135  }
136  return *this;
137 }
138 
140  _apCorrMap = std::make_shared<ApCorrMap>();
141 }
142 
144 
147 
148  FitsWriteData data;
149 
150  data.metadata.reset(new daf::base::PropertyList());
151  data.imageMetadata.reset(new daf::base::PropertyList());
152  data.maskMetadata = data.imageMetadata;
153  data.varianceMetadata = data.imageMetadata;
154 
155  data.metadata->combine(getMetadata());
156 
157  // In the future, we might not have exactly three image HDUs, but we always do right now,
158  // so 1=primary, 2=image, 3=mask, 4=variance, 5+=archive
159  data.metadata->set("AR_HDU", 5, "HDU containing the archive used to store ancillary objects");
160  if (hasCoaddInputs()) {
161  int coaddInputsId = data.archive.put(getCoaddInputs());
162  data.metadata->set("COADD_INPUTS_ID", coaddInputsId, "archive ID for coadd inputs catalogs");
163  }
164  if (hasApCorrMap()) {
165  int apCorrMapId = data.archive.put(getApCorrMap());
166  data.metadata->set("AP_CORR_MAP_ID", apCorrMapId, "archive ID for aperture correction map");
167  }
168  if (hasPsf() && getPsf()->isPersistable()) {
169  int psfId = data.archive.put(getPsf());
170  data.metadata->set("PSF_ID", psfId, "archive ID for the Exposure's main Psf");
171  }
172  if (hasWcs() && getWcs()->isPersistable()) {
173  int wcsId = data.archive.put(getWcs());
174  data.metadata->set("WCS_ID", wcsId, "archive ID for the Exposure's main Wcs");
175  }
176  if (hasValidPolygon() && getValidPolygon()->isPersistable()) {
177  int polygonId = data.archive.put(getValidPolygon());
178  data.metadata->set("VALID_POLYGON_ID", polygonId, "archive ID for the Exposure's valid polygon");
179  }
180 
181  //LSST convention is that Wcs is in pixel coordinates (i.e relative to bottom left
182  //corner of parent image, if any). The Wcs/Fits convention is that the Wcs is in
183  //image coordinates. When saving an image we convert from pixel to index coordinates.
184  //In the case where this image is a parent image, the reference pixels are unchanged
185  //by this transformation
186  if (hasWcs()) {
187  PTR(Wcs) newWcs = getWcs()->clone(); //Create a copy
188  newWcs->shiftReferencePixel(-xy0.getX(), -xy0.getY() );
189 
190  // We want the WCS to appear in all HDUs
191  data.imageMetadata->combine(newWcs->getFitsMetadata());
192  }
193 
194  //Store _x0 and _y0. If this exposure is a portion of a larger image, _x0 and _y0
195  //indicate the origin (the position of the bottom left corner) of the sub-image with
196  //respect to the origin of the parent image.
197  //This is stored in the fits header using the LTV convention used by STScI
198  //(see \S2.6.2 of HST Data Handbook for STIS, version 5.0
199  // http://www.stsci.edu/hst/stis/documents/handbooks/currentDHB/ch2_stis_data7.html#429287).
200  //This is not a fits standard keyword, but is recognised by ds9
201  //LTV keywords use the opposite convention to the LSST, in that they represent
202  //the position of the origin of the parent image relative to the origin of the sub-image.
203  // _x0, _y0 >= 0, while LTV1 and LTV2 <= 0
204 
205  data.imageMetadata->set("LTV1", static_cast<double>(-xy0.getX()));
206  data.imageMetadata->set("LTV2", static_cast<double>(-xy0.getY()));
207 
208  data.metadata->set("FILTER", getFilter().getName());
209  if (hasDetector()) {
210  data.metadata->set("DETNAME", getDetector()->getName());
211  data.metadata->set("DETSER", getDetector()->getSerial());
212  }
216  data.metadata->set("TIME-MID", getCalib()->getMidTime().toString(daf::base::DateTime::UTC));
217  data.metadata->set("EXPTIME", getCalib()->getExptime());
218  data.metadata->set("FLUXMAG0", getCalib()->getFluxMag0().first);
219  data.metadata->set("FLUXMAG0ERR", getCalib()->getFluxMag0().second);
220 
221  return data;
222 }
223 
224 void ExposureInfo::_finishWriteFits(fits::Fits & fitsfile, FitsWriteData const & data) const {
225  data.archive.writeFits(fitsfile);
226 }
227 
229  fits::Fits & fitsfile,
230  PTR(daf::base::PropertySet) metadata,
231  PTR(daf::base::PropertySet) imageMetadata
232 ) {
233  // true: strip keywords that are related to the created WCS from the input metadata
234  _wcs = makeWcs(imageMetadata, true);
235 
236  if (!imageMetadata->exists("INHERIT")) {
237  // New-style exposures put everything but the Wcs in the primary HDU, use
238  // INHERIT keyword in the others. For backwards compatibility, if we don't
239  // find the INHERIT keyword, we ignore the primary HDU metadata and expect
240  // everything to be in the image HDU metadata. Note that we can't merge them,
241  // because they're probably duplicates.
242  metadata = imageMetadata;
243  }
244 
245  _filter = Filter(metadata, true);
246  detail::stripFilterKeywords(metadata);
247 
248  PTR(Calib) newCalib(new Calib(metadata));
249  setCalib(newCalib);
250  detail::stripCalibKeywords(metadata);
251 
252  int archiveHdu = popInt(*metadata, "AR_HDU");
253 
254  if (archiveHdu) {
255  fitsfile.setHdu(archiveHdu);
257  // Load the Psf and Wcs from the archive; id=0 results in a null pointer.
258  // Note that the binary table Wcs, if present, clobbers the FITS header one,
259  // because the former might be an approximation to something we can't represent
260  // using the FITS WCS standard but can represent with binary tables.
261  int psfId = popInt(*metadata, "PSF_ID");
262  try {
263  _psf = archive.get<detection::Psf>(psfId);
264  } catch (pex::exceptions::NotFoundError & err) {
265  LOGLS_WARN(_log, "Could not read PSF; setting to null: " << err.what());
266  }
267  int wcsId = popInt(*metadata, "WCS_ID");
268  try {
269  auto archiveWcs = archive.get<Wcs>(wcsId);
270  if (archiveWcs) {
271  _wcs = archiveWcs;
272  } else {
273  LOGLS_INFO(_log, "Empty WCS extension, using FITS header");
274  }
275  } catch (pex::exceptions::NotFoundError & err) {
276  auto msg = str(boost::format("Could not read WCS extension; setting to null: %s") % err.what());
277  if (_wcs) {
278  msg += " ; using WCS from FITS header";
279  }
280  LOGLS_WARN(_log, msg);
281  }
282  int coaddInputsId = popInt(*metadata, "COADD_INPUTS_ID");
283  try {
284  _coaddInputs = archive.get<CoaddInputs>(coaddInputsId);
285  } catch (pex::exceptions::NotFoundError & err) {
286  LOGLS_WARN(_log, "Could not read CoaddInputs; setting to null: " << err.what());
287  }
288  int apCorrMapId = popInt(*metadata, "AP_CORR_MAP_ID");
289  try {
290  _apCorrMap = archive.get<ApCorrMap>(apCorrMapId);
291  } catch (pex::exceptions::NotFoundError & err) {
292  LOGLS_WARN(_log, "Could not read ApCorrMap; setting to null: " << err.what());
293  }
294  int validPolygonId = popInt(*metadata, "VALID_POLYGON_ID");
295  try {
296  _validPolygon = archive.get<geom::polygon::Polygon>(validPolygonId);
297  } catch (pex::exceptions::NotFoundError & err) {
298  LOGLS_WARN(_log, "Could not read ValidPolygon; setting to null: " << err.what());
299  }
300  }
301 
302  _metadata = metadata;
303 }
304 
305 }}} // namespace lsst::afw::image
boost::shared_ptr< ApCorrMap > _apCorrMap
Definition: ExposureInfo.h:284
boost::shared_ptr< detection::Psf > getPsf() const
Return the exposure&#39;s point-spread function.
Definition: ExposureInfo.h:132
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:229
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
static InputArchive readFits(fits::Fits &fitsfile)
Read an object from an already open FITS object.
static boost::shared_ptr< Wcs > _cloneWcs(boost::shared_ptr< Wcs const > wcs)
Definition: ExposureInfo.cc:64
tbl::Key< int > wcs
bool hasValidPolygon() const
Does this exposure have a valid Polygon.
Definition: ExposureInfo.h:142
Implementation of the WCS standard for a any projection.
Definition: Wcs.h:107
bool hasCoaddInputs() const
Does this exposure have coadd provenance catalogs?
Definition: ExposureInfo.h:171
#define CONST_PTR(...)
Definition: base.h:47
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:201
boost::shared_ptr< cameraGeom::Detector const > getDetector() const
Return the exposure&#39;s Detector information.
Definition: ExposureInfo.h:99
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
#define LOG_GET(logger)
Definition: Log.h:83
table::Key< table::Array< Kernel::Pixel > > image
Definition: FixedKernel.cc:117
lsst::daf::base::PropertySet PropertySet
Definition: Wcs.cc:59
boost::shared_ptr< daf::base::PropertySet > _metadata
Definition: ExposureInfo.h:282
ExposureInfo & operator=(ExposureInfo const &other)
Assignment; deep-copies all components except the metadata.
boost::shared_ptr< Wcs > makeWcs(boost::shared_ptr< lsst::daf::base::PropertySet > const &fitsMetadata, bool stripMetadata=false)
Definition: makeWcs.cc:40
#define LOGLS_WARN(logger, message)
Definition: Log.h:657
boost::shared_ptr< geom::polygon::Polygon const > getValidPolygon() const
Return the valid Polygon.
Definition: ExposureInfo.h:145
A struct passed back and forth between Exposure and ExposureInfo when writing FITS files...
Definition: ExposureInfo.h:227
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 >())
Construct an ExposureInfo from its various components.
Definition: ExposureInfo.cc:77
boost::shared_ptr< detection::Psf > _psf
Definition: ExposureInfo.h:277
boost::shared_ptr< Wcs > getWcs()
Return the coordinate system of the exposure.
Definition: ExposureInfo.h:87
void writeFits(fits::Fits &fitsfile) const
Write the archive to an already-open FITS object.
boost::shared_ptr< daf::base::PropertyList > maskMetadata
Definition: ExposureInfo.h:230
boost::shared_ptr< Wcs > _wcs
Definition: ExposureInfo.h:276
boost::shared_ptr< ApCorrMap > getApCorrMap()
Return the exposure&#39;s aperture correction map (null pointer if !hasApCorrMap())
Definition: ExposureInfo.h:154
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)
Definition: Calib.cc:165
boost::shared_ptr< cameraGeom::Detector const > _detector
Definition: ExposureInfo.h:279
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:105
bool hasPsf() const
Does this exposure have a Psf?
Definition: ExposureInfo.h:129
void setCalib(boost::shared_ptr< Calib const > calib)
Set the Exposure&#39;s Calib object.
Definition: ExposureInfo.h:120
bool hasWcs() const
Does this exposure have a Wcs?
Definition: ExposureInfo.h:84
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
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...
#define PTR(...)
Definition: base.h:41
boost::shared_ptr< daf::base::PropertySet > getMetadata() const
Return flexible metadata.
Definition: ExposureInfo.h:123
boost::shared_ptr< Persistable > get(int id) const
Load the Persistable with the given ID and return it.
int stripFilterKeywords(boost::shared_ptr< lsst::daf::base::PropertySet > metadata)
Definition: Filter.cc:166
bool hasApCorrMap() const
Return true if the exposure has an aperture correction map.
Definition: ExposureInfo.h:151
boost::shared_ptr< Calib > _calib
Definition: ExposureInfo.h:278
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:177
A multi-catalog archive object used to load table::io::Persistable objects.
Definition: InputArchive.h:28
Include files required for standard LSST Exception handling.
boost::shared_ptr< daf::base::PropertyList > metadata
Definition: ExposureInfo.h:228
A collection of all the things that make an Exposure different from a MaskedImage.
Definition: ExposureInfo.h:80
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:231
boost::shared_ptr< Calib > getCalib()
Return the exposure&#39;s photometric calibration.
Definition: ExposureInfo.h:114
daf::base::PropertySet & _metadata
Definition: fits_io_mpl.h:79
bool exists(std::string const &name) const
Definition: PropertySet.cc:190
bool hasDetector() const
Does this exposure have Detector information?
Definition: ExposureInfo.h:96
#define LOGLS_INFO(logger, message)
Definition: Log.h:637
#define LOG_LOGGER
Definition: Log.h:712
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:280
boost::shared_ptr< CoaddInputs > _coaddInputs
Definition: ExposureInfo.h:283