28 #include "boost/algorithm/string/trim.hpp"
44 namespace lsst {
namespace afw {
namespace image {
50 auto const nan = std::numeric_limits<double>::quiet_NaN();
62 return metadata.exists(key) ? metadata.getAsDouble(key) : nan;
87 std::string
const & key,
89 std::string
const & comment
91 if (std::isfinite(value)) {
92 metadata.set(key, value);
108 std::string
const & key,
110 std::string
const & comment
112 return setDouble(metadata, key, angle.
asDegrees(), comment);
131 std::ostringstream os;
132 os <<
"Unknown RotType enum: " <<
static_cast<int>(
rotType);
133 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, os.str());
141 RotType rotTypeEnumFromStr(std::string
const & rotTypeName) {
142 if (rotTypeName ==
"UNKNOWN") {
144 }
else if (rotTypeName ==
"SKY") {
146 }
else if (rotTypeName ==
"HORIZON") {
148 }
else if (rotTypeName ==
"MOUNT") {
151 std::ostringstream os;
152 os <<
"Unknown RotType name: \"" << rotTypeName <<
"\"";
153 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, os.str());
156 class VisitInfoSchema {
162 table::Key<std::int64_t>
tai;
164 table::Key<geom::Angle>
era;
180 static VisitInfoSchema
const &
get() {
181 static VisitInfoSchema instance;
186 VisitInfoSchema (
const VisitInfoSchema&) =
delete;
187 VisitInfoSchema& operator=(
const VisitInfoSchema&) =
delete;
190 VisitInfoSchema (VisitInfoSchema&&) =
delete;
191 VisitInfoSchema& operator=(VisitInfoSchema&&) =
delete;
198 darkTime(
schema.addField<double>(
"darktime",
"time from CCD flush to readout",
"s")),
200 "TAI date and time at middle of exposure as nsec from unix epoch",
"nsec")),
201 ut1(
schema.addField<double>(
"ut1",
"UT1 date and time at middle of exposure",
"MJD")),
202 era(
schema.addField<geom::
Angle>(
"era",
"earth rotation angle at middle of exposure",
"")),
204 "sky position of boresight at middle of exposure")),
208 "refracted apparent topocentric position of boresight at middle of exposure",
"")),
210 "refracted apparent topocentric position of boresight at middle of exposure",
"")),
212 "airmass at boresight, relative to zenith at sea level",
"")),
214 "rotation angle at boresight at middle of exposure",
"")),
215 rotType(
schema.addField<int>(
"rottype",
216 "rotation type; see VisitInfo.getRotType for details",
"MJD")),
219 "latitude of telescope (+ is east of Greenwich)",
"")),
221 elevation(
schema.addField<double>(
"elevation",
"elevation of telescope",
"")),
227 schema.getCitizen().markPersistent();
231 class VisitInfoFactory :
public table::io::PersistableFactory {
234 virtual PTR(table::io::Persistable)
235 read(InputArchive const & archive, CatalogVector const & catalogs)
const {
236 VisitInfoSchema
const & keys = VisitInfoSchema::get();
240 table::BaseRecord
const & record = catalogs.front().front();
241 PTR(VisitInfo) result(new VisitInfo(
246 record.get(keys.
ut1),
247 record.get(keys.
era),
252 static_cast<
RotType>(record.get(keys.rotType)),
267 explicit VisitInfoFactory(std::
string const &
name) : table::io::PersistableFactory(
name) {}
271 std::string getVisitInfoPersistenceName() {
return "VisitInfo"; }
273 VisitInfoFactory registration(getVisitInfoPersistenceName());
282 std::vector<std::string> keyList = {
283 "EXPID",
"EXPTIME",
"DARKTIME",
"DATE-AVG",
"TIMESYS",
"TIME-MID",
"MJD-AVG-UT1",
"AVG-ERA",
284 "BORE-RA",
"BORE-DEC",
"BORE-AZ",
"BORE-ALT",
"BORE-AIRMASS",
"BORE-ROTANG",
"ROTTYPE",
285 "OBS-LONG",
"OBS-LAT",
"OBS-ELEV",
286 "AIRTEMP",
"AIRPRESS",
"HUMIDITY"
288 for (
auto&& key : keyList) {
289 if (metadata.
exists(key)) {
301 setDouble(metadata,
"EXPTIME", visitInfo.
getExposureTime(),
"Exposure time (sec)");
302 setDouble(metadata,
"DARKTIME", visitInfo.
getDarkTime(),
"Time from CCD flush to readout (sec)");
305 "TAI date at middle of observation");
306 metadata.
set(
"TIMESYS",
"TAI");
308 setDouble(metadata,
"MJD-AVG-UT1", visitInfo.
getUt1(),
"UT1 MJD date at ctr of obs");
309 setAngle(metadata,
"AVG-ERA", visitInfo.
getEra(),
"Earth rot ang at ctr of obs (deg)");
311 setAngle(metadata,
"BORE-RA", boresightRaDec[0],
"ICRS RA (deg) at boresight");
312 setAngle(metadata,
"BORE-DEC", boresightRaDec[1],
"ICRS Dec (deg) at boresight");
314 setAngle(metadata,
"BORE-AZ", boresightAzAlt[0],
"Refr app topo az (deg) at bore");
315 setAngle(metadata,
"BORE-ALT", boresightAzAlt[1],
"Refr app topo alt (deg) at bore");
316 setDouble(metadata,
"BORE-AIRMASS", visitInfo.
getBoresightAirmass(),
"Airmass at boresight");
317 setAngle(metadata,
"BORE-ROTANG", visitInfo.
getBoresightRotAngle(),
"Rotation angle (deg) at boresight");
318 metadata.
set(
"ROTTYPE", rotTypeStrFromEnum(visitInfo.
getRotType()),
"Type of rotation angle");
320 setAngle(metadata,
"OBS-LONG", observatory.getLongitude(),
"Telescope longitude (+E, deg)");
321 setAngle(metadata,
"OBS-LAT", observatory.getLatitude(),
"Telescope latitude (deg)");
322 setDouble(metadata,
"OBS-ELEV", observatory.getElevation(),
"Telescope elevation (m)");
324 setDouble(metadata,
"AIRTEMP", weather.getAirTemperature(),
"Outside air temperature (C)");
325 setDouble(metadata,
"AIRPRESS", weather.getAirPressure() ,
"Outdoor air pressure (P)");
326 setDouble(metadata,
"HUMIDITY", weather.getHumidity(),
"Relative humidity (%)");
335 _darkTime(getDouble(metadata,
"DARKTIME")),
337 _ut1(getDouble(metadata,
"MJD-AVG-UT1")),
338 _era(getAngle(metadata,
"AVG-ERA")),
339 _boresightRaDec(coord::
IcrsCoord(getAngle(metadata,
"BORE-RA"), getAngle(metadata,
"BORE-DEC"))),
340 _boresightAzAlt(coord::
Coord(getAngle(metadata,
"BORE-AZ"), getAngle(metadata,
"BORE-ALT"))),
341 _boresightAirmass(getDouble(metadata,
"BORE-AIRMASS")),
342 _boresightRotAngle(getAngle(metadata,
"BORE-ROTANG")),
345 getAngle(metadata,
"OBS-LONG"),
346 getAngle(metadata,
"OBS-LAT"),
347 getDouble(metadata,
"OBS-ELEV")),
349 getDouble(metadata,
"AIRTEMP"),
350 getDouble(metadata,
"AIRPRESS"),
351 getDouble(metadata,
"HUMIDITY"))
354 if (metadata.
exists(key)) {
359 if (metadata.
exists(key)) {
362 }
catch (lsst::pex::exceptions::TypeError & err) {
364 std::string exptimeStr = metadata.
getAsString(key);
370 if (metadata.
exists(key)) {
371 if (metadata.
exists(
"TIMESYS")) {
372 auto timesysName = boost::algorithm::trim_right_copy(metadata.
getAsString(
"TIMESYS"));
373 if (timesysName !=
"TAI") {
377 std::ostringstream os;
378 os <<
"TIMESYS = \"" << timesysName <<
379 "\"; VisitInfo requires TIMESYS to exist and to equal \"TAI\"";
380 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError, os.str());
383 throw LSST_EXCEPT(lsst::pex::exceptions::RuntimeError,
384 "TIMESYS not found; VistitInfo requires TIMESYS to exist and to equal \"TAI\"");
391 if (metadata.
exists(key)) {
397 if (metadata.
exists(key)) {
419 return getVisitInfoPersistenceName();
423 VisitInfoSchema
const & keys = VisitInfoSchema::get();
429 record->set(keys.tai,
getDate().nsecs(::DateTime::TAI));
430 record->set(keys.ut1,
getUt1());
431 record->set(keys.era,
getEra());
434 record->set(keys.boresightAzAlt_az, boresightAzAlt[0]);
435 record->set(keys.boresightAzAlt_alt, boresightAzAlt[1]);
438 record->set(keys.rotType, static_cast<int>(
getRotType()));
440 record->set(keys.latitude, observatory.getLatitude());
441 record->set(keys.longitude, observatory.getLongitude());
442 record->set(keys.elevation, observatory.getElevation());
444 record->set(keys.airTemperature, weather.getAirTemperature());
445 record->set(keys.airPressure, weather.getAirPressure());
446 record->set(keys.humidity, weather.getHumidity());
geom::Angle getBoresightHourAngle() const
virtual void write(OutputArchiveHandle &handle) const
Write the object to one or more catalogs.
table::Key< double > exposureTime
geom::Angle getBoresightRotAngle() const
Get rotation angle at boresight at middle of exposure.
table::Key< table::RecordId > exposureId
bool operator==(VisitInfo const &other) const
Class for handling dates/times, including MJD, UTC, and TAI.
table::Key< double > darkTime
lsst::afw::coord::Coord Coord
table::Key< std::string > name
table::RecordId getExposureId() const
get exposure ID
An object passed to Persistable::write to allow it to persist itself.
AngleUnit const radians
constant with units of radians
table::CoordKey boresightRaDec
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
A custom container class for records, based on std::vector.
Class for storing ordered metadata with comments.
coord::Coord getBoresightAzAlt() const
get refracted apparent topocentric Az/Alt position at the boresight (and at the middle of the exposur...
afw::table::Schema schema
table::Key< std::int64_t > tai
Include files required for standard LSST Exception handling.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
Information about a single exposure of an imaging camera.
daf::base::DateTime _date
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
geom::Angle getEra() const
get earth rotation angle at middle of exposure
void set(std::string const &name, T const &value)
Replace all values for a property name (possibly hierarchical) with a new value.
lsst::afw::coord::IcrsCoord IcrsCoord
table::Key< geom::Angle > latitude
double getAsDouble(std::string const &name) const
Get the last value for any arithmetic property name (possibly hierarchical).
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
Rotation angle is unknown.
table::RecordId _exposureId
table::Key< table::Array< Kernel::Pixel > > image
lsst::daf::base::PropertySet PropertySet
boost::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
std::int64_t RecordId
Type used for unique IDs for records.
coord::IcrsCoord _boresightRaDec
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
A class representing an Angle.
double getBoresightAirmass() const
get airmass at the boresight, relative to zenith at sea level (and at the middle of the exposure...
bool isValid() const
Is this date valid?
lsst::afw::geom::Angle getLongitude() const
get telescope longitude (positive values are E of Greenwich)
table::Key< geom::Angle > longitude
coord::Coord _boresightAzAlt
daf::base::DateTime getDate() const
get uniform date and time at middle of exposure
coord::Weather getWeather() const
get basic weather information
std::string toString(Timescale scale) const
Get date as an ISO8601-formatted string.
coord::Observatory _observatory
table::Key< double > boresightAirmass
geom::Angle _boresightRotAngle
double getUt1() const
get UT1 (universal time) MJD date at middle of exposure
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Base class for all records.
virtual std::string getPersistenceName() const
Return the unique name used to persist this object and look up its factory.
Orientation of E,N with respected to detector X,Y; X is flipped, if necessary, to match the handednes...
lsst::afw::geom::Angle Angle
table::Key< double > airPressure
Class for storing generic metadata.
geom::Angle getLocalEra() const
table::Key< geom::Angle > boresightAzAlt_az
table::Key< int > rotType
VisitInfo(table::RecordId exposureId, double exposureTime, double darkTime, daf::base::DateTime const &date, double ut1, geom::Angle const &era, coord::IcrsCoord const &boresightRaDec, coord::Coord const &boresightAzAlt, double boresightAirmass, geom::Angle const &boresightRotAngle, RotType const &rotType, coord::Observatory const &observatory, coord::Weather const &weather)
Construct a VisitInfo.
int stripVisitInfoKeywords(daf::base::PropertySet &metadata)
Remove VisitInfo-related keywords from the metadata.
orientation of Az/Alt with respect to detector X,Y; X is flipped, if necessary, to match the handedne...
virtual void remove(std::string const &name)
Removes all values for a property name (possibly hierarchical).
table::Key< double > airTemperature
double asDegrees() const
Return an Angle's value as a double in degrees.
coord::Observatory getObservatory() const
get observatory longitude, latitude and elevation
table::Key< geom::Angle > era
int64_t getAsInt64(std::string const &name) const
Get the last value for a bool/char/short/int/int64_t property name (possibly hierarchical).
table::Key< double > elevation
table::Key< double > humidity
std::string getAsString(std::string const &name) const
Get the last value for a string property name (possibly hierarchical).
table::Key< geom::Angle > boresightRotAngle
double getExposureTime() const
get exposure duration (shutter open time); (sec)
RotType getRotType() const
get rotation type of boresightRotAngle
The position sent to the instrument rotator; the details depend on the rotator.
double getDarkTime() const
get time from CCD flush to exposure readout, including shutter open time (despite the name); (sec) ...
coord::IcrsCoord getBoresightRaDec() const
get ICRS RA/Dec position at the boresight (and at the middle of the exposure, if it varies with time)...
table::Key< geom::Angle > boresightAzAlt_alt
Functions to handle coordinates.