28 #include "boost/algorithm/string/trim.hpp" 68 double getDouble(daf::base::PropertySet
const& metadata,
std::string const&
key) {
69 return metadata.exists(key) ? metadata.getAsDouble(key) :
nan;
92 bool setDouble(daf::base::PropertySet& metadata,
std::string const& key,
double value,
95 metadata.set(key, value);
111 return setDouble(metadata, key, angle.
asDegrees(), comment);
121 case RotType::UNKNOWN:
125 case RotType::HORIZON:
131 os <<
"Unknown RotType enum: " <<
static_cast<int>(
rotType);
141 if (rotTypeName ==
"UNKNOWN") {
142 return RotType::UNKNOWN;
143 }
else if (rotTypeName ==
"SKY") {
145 }
else if (rotTypeName ==
"HORIZON") {
146 return RotType::HORIZON;
147 }
else if (rotTypeName ==
"MOUNT") {
148 return RotType::MOUNT;
151 os <<
"Unknown RotType name: \"" << rotTypeName <<
"\"";
155 class VisitInfoSchema {
161 table::Key<std::int64_t>
tai;
163 table::Key<lsst::geom::Angle>
era;
179 static VisitInfoSchema
const&
get() {
180 static VisitInfoSchema instance;
185 VisitInfoSchema(
const VisitInfoSchema&) =
delete;
186 VisitInfoSchema& operator=(
const VisitInfoSchema&) =
delete;
189 VisitInfoSchema(VisitInfoSchema&&) =
delete;
190 VisitInfoSchema& operator=(VisitInfoSchema&&) =
delete;
196 exposureTime(schema.addField<
double>(
"exposuretime",
"exposure duration",
"s")),
197 darkTime(schema.addField<
double>(
"darktime",
"time from CCD flush to readout",
"s")),
199 "tai",
"TAI date and time at middle of exposure as nsec from unix epoch",
"nsec")),
200 ut1(schema.addField<
double>(
"ut1",
"UT1 date and time at middle of exposure",
"MJD")),
204 "sky position of boresight at middle of exposure")),
209 "refracted apparent topocentric position of boresight at middle of exposure",
"")),
211 "boresightazalt_alt",
212 "refracted apparent topocentric position of boresight at middle of exposure",
"")),
214 "boresightairmass",
"airmass at boresight, relative to zenith at sea level",
"")),
216 "boresightrotangle",
"rotation angle at boresight at middle of exposure",
"")),
217 rotType(schema.addField<
int>(
"rottype",
"rotation type; see VisitInfo.getRotType for details",
221 "latitude",
"latitude of telescope (+ is east of Greenwich)",
"")),
223 elevation(schema.addField<
double>(
"elevation",
"elevation of telescope",
"")),
225 airTemperature(schema.addField<
double>(
"airtemperature",
"air temperature",
"C")),
226 airPressure(schema.addField<
double>(
"airpressure",
"air pressure",
"Pascal")),
227 humidity(schema.addField<
double>(
"humidity",
"humidity (%)",
"")) {}
230 class VisitInfoFactory :
public table::io::PersistableFactory {
233 CatalogVector
const& catalogs)
const override {
234 VisitInfoSchema
const&
keys = VisitInfoSchema::get();
238 table::BaseRecord
const& record = catalogs.front().front();
240 new VisitInfo(record.get(keys.exposureId), record.get(keys.exposureTime),
241 record.get(keys.darkTime),
::DateTime(record.get(keys.tai), ::DateTime::TAI),
242 record.
get(keys.ut1), record.get(keys.era), record.get(keys.boresightRaDec),
244 record.get(keys.boresightAzAlt_alt)),
245 record.get(keys.boresightAirmass), record.get(keys.boresightRotAngle),
246 static_cast<RotType>(record.get(keys.rotType)),
247 coord::Observatory(record.get(keys.longitude), record.get(keys.latitude),
248 record.get(keys.elevation)),
249 coord::Weather(record.get(keys.airTemperature), record.get(keys.airPressure),
250 record.get(keys.humidity))));
254 explicit VisitInfoFactory(
std::string const&
name) : table::io::PersistableFactory(name) {}
257 std::string getVisitInfoPersistenceName() {
return "VisitInfo"; }
259 VisitInfoFactory registration(getVisitInfoPersistenceName());
269 "EXPID",
"EXPTIME",
"DARKTIME",
"DATE-AVG",
"TIMESYS",
"TIME-MID",
"MJD-AVG-UT1",
270 "AVG-ERA",
"BORE-RA",
"BORE-DEC",
"BORE-AZ",
"BORE-ALT",
"BORE-AIRMASS",
"BORE-ROTANG",
271 "ROTTYPE",
"OBS-LONG",
"OBS-LAT",
"OBS-ELEV",
"AIRTEMP",
"AIRPRESS",
"HUMIDITY"};
272 for (
auto&& key : keyList) {
273 if (metadata.
exists(key)) {
285 setDouble(metadata,
"EXPTIME", visitInfo.
getExposureTime(),
"Exposure time (sec)");
286 setDouble(metadata,
"DARKTIME", visitInfo.
getDarkTime(),
"Time from CCD flush to readout (sec)");
289 "TAI date at middle of observation");
290 metadata.
set(
"TIMESYS",
"TAI");
292 setDouble(metadata,
"MJD-AVG-UT1", visitInfo.
getUt1(),
"UT1 MJD date at ctr of obs");
293 setAngle(metadata,
"AVG-ERA", visitInfo.
getEra(),
"Earth rot ang at ctr of obs (deg)");
295 setAngle(metadata,
"BORE-RA", boresightRaDec[0],
"ICRS RA (deg) at boresight");
296 setAngle(metadata,
"BORE-DEC", boresightRaDec[1],
"ICRS Dec (deg) at boresight");
298 setAngle(metadata,
"BORE-AZ", boresightAzAlt[0],
"Refr app topo az (deg) at bore");
299 setAngle(metadata,
"BORE-ALT", boresightAzAlt[1],
"Refr app topo alt (deg) at bore");
300 setDouble(metadata,
"BORE-AIRMASS", visitInfo.
getBoresightAirmass(),
"Airmass at boresight");
301 setAngle(metadata,
"BORE-ROTANG", visitInfo.
getBoresightRotAngle(),
"Rotation angle (deg) at boresight");
302 metadata.
set(
"ROTTYPE", rotTypeStrFromEnum(visitInfo.
getRotType()),
"Type of rotation angle");
304 setAngle(metadata,
"OBS-LONG",
observatory.getLongitude(),
"Telescope longitude (+E, deg)");
305 setAngle(metadata,
"OBS-LAT",
observatory.getLatitude(),
"Telescope latitude (deg)");
306 setDouble(metadata,
"OBS-ELEV",
observatory.getElevation(),
"Telescope elevation (m)");
308 setDouble(metadata,
"AIRTEMP", weather.getAirTemperature(),
"Outside air temperature (C)");
309 setDouble(metadata,
"AIRPRESS", weather.getAirPressure(),
"Outdoor air pressure (P)");
310 setDouble(metadata,
"HUMIDITY", weather.getHumidity(),
"Relative humidity (%)");
318 _darkTime(getDouble(metadata,
"DARKTIME")),
320 _ut1(getDouble(metadata,
"MJD-AVG-UT1")),
321 _era(getAngle(metadata,
"AVG-ERA")),
326 _boresightAirmass(getDouble(metadata,
"BORE-AIRMASS")),
327 _boresightRotAngle(getAngle(metadata,
"BORE-ROTANG")),
329 _observatory(getAngle(metadata,
"OBS-LONG"), getAngle(metadata,
"OBS-LAT"),
330 getDouble(metadata,
"OBS-ELEV")),
331 _weather(getDouble(metadata,
"AIRTEMP"), getDouble(metadata,
"AIRPRESS"),
332 getDouble(metadata,
"HUMIDITY")) {
334 if (metadata.
exists(key)) {
339 if (metadata.
exists(key)) {
350 if (metadata.
exists(key)) {
351 if (metadata.
exists(
"TIMESYS")) {
352 auto timesysName = boost::algorithm::trim_right_copy(metadata.
getAsString(
"TIMESYS"));
353 if (timesysName !=
"TAI") {
358 os <<
"TIMESYS = \"" << timesysName
359 <<
"\"; VisitInfo requires TIMESYS to exist and to equal \"TAI\"";
364 "TIMESYS not found; VistitInfo requires TIMESYS to exist and to equal \"TAI\"");
371 if (metadata.
exists(key)) {
377 if (metadata.
exists(key)) {
378 _rotType = rotTypeEnumFromStr(metadata.
getAsString(key));
393 return utils::hashCombine(17, _exposureId, _exposureTime, _darkTime, _date, _ut1, _era, _boresightRaDec,
394 _boresightAzAlt, _boresightAirmass, _boresightRotAngle, _rotType, _observatory,
401 VisitInfoSchema
const&
keys = VisitInfoSchema::get();
407 record->set(keys.tai,
getDate().nsecs(::DateTime::TAI));
408 record->set(keys.ut1,
getUt1());
409 record->set(keys.era,
getEra());
412 record->set(keys.boresightAzAlt_az, boresightAzAlt[0]);
413 record->set(keys.boresightAzAlt_alt, boresightAzAlt[1]);
416 record->set(keys.rotType, static_cast<int>(
getRotType()));
418 record->set(keys.latitude,
observatory.getLatitude());
419 record->set(keys.longitude,
observatory.getLongitude());
420 record->set(keys.elevation,
observatory.getElevation());
422 record->set(keys.airTemperature,
weather.getAirTemperature());
423 record->set(keys.airPressure,
weather.getAirPressure());
424 record->set(keys.humidity,
weather.getHumidity());
437 double _parallactic_y, _parallactic_x,
result;
442 result = atan2(_parallactic_y, _parallactic_x);
447 return std::make_unique<VisitInfo>(*this);
456 buffer <<
"VisitInfo(";
461 buffer <<
"UT1=" <<
getUt1() <<
", ";
462 buffer <<
"ERA=" <<
getEra() <<
", ";
467 buffer <<
"rotType=" <<
static_cast<int>(
getRotType()) <<
", ";
std::int64_t RecordId
Type used for unique IDs for records.
double getBoresightAirmass() const
get airmass at the boresight, relative to zenith at sea level (and at the middle of the exposure...
double getAsDouble(std::string const &name) const
Get the last value for any arithmetic property name (possibly hierarchical).
lsst::geom::SpherePoint getBoresightAzAlt() const
get refracted apparent topocentric Az/Alt position at the boresight (and at the middle of the exposur...
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
std::string toString() const override
Create a string representation of this object.
table::Key< lsst::geom::Angle > latitude
double get(DateSystem system=MJD, Timescale scale=TAI) const
Get date as a double in a specified representation, such as MJD.
Class for handling dates/times, including MJD, UTC, and TAI.
constexpr double asDegrees() const noexcept
Return an Angle's value in degrees.
lsst::geom::Angle getLocalEra() const
An object passed to Persistable::write to allow it to persist itself.
table::Key< double > airTemperature
Class for storing ordered metadata with comments.
table::CoordKey boresightRaDec
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Interface supporting iteration over heterogenous containers.
Information about a single exposure of an imaging camera.
lsst::geom::SpherePoint getBoresightRaDec() const
get ICRS RA/Dec position at the boresight (and at the middle of the exposure, if it varies with time)...
double getUt1() const
get UT1 (universal time) MJD date 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 scalar value.
std::string toString(Timescale scale) const
Get date as an ISO8601-formatted string.
table::Key< double > boresightAirmass
double getDarkTime() const
get time from CCD flush to exposure readout, including shutter open time (despite the name); (sec) ...
virtual void remove(std::string const &name)
Remove all values for a property name (possibly hierarchical).
ItemVariant const * other
double sin(Angle const &a)
bool operator==(VisitInfo const &other) const
std::size_t hash_value() const noexcept override
Return a hash of this object.
table::Key< lsst::geom::Angle > era
AngleUnit constexpr radians
constant with units of radians
table::Key< int > rotType
Rotation angle is unknown.
A class representing an angle.
double cos(Angle const &a)
table::Key< lsst::geom::Angle > boresightRotAngle
lsst::geom::Angle getLongitude() const noexcept
get telescope longitude (positive values are E of Greenwich)
table::Key< lsst::geom::Angle > boresightAzAlt_az
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
AngleUnit constexpr degrees
constant with units of degrees
A base class for image defects.
table::Key< double > exposureTime
table::RecordId getExposureId() const
get exposure ID
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< lsst::geom::Angle > boresightAzAlt_alt
table::Key< double > humidity
double tan(Angle const &a)
std::shared_ptr< typehandling::Storable > cloneStorable() const override
Create a new VisitInfo that is a copy of this one.
table::Key< table::RecordId > exposureId
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
table::Key< double > elevation
double getExposureTime() const
get exposure duration (shutter open time); (sec)
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
std::ostream & operator<<(std::ostream &os, Storable const &storable)
Output operator for Storable.
table::Key< lsst::geom::Angle > longitude
RotType getRotType() const
get rotation type of boresightRotAngle
lsst::geom::Angle getEra() const
get earth rotation angle at middle of exposure
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
bool equals(typehandling::Storable const &other) const noexcept override
Compare this object to another Storable.
bool isValid() const
Is this date valid?
table::Key< double > airPressure
daf::base::DateTime getDate() const
get uniform date and time at middle of exposure
Class for storing generic metadata.
static CoordKey addFields(afw::table::Schema &schema, std::string const &name, std::string const &doc)
Add a pair of _ra, _dec fields to a Schema, and return a CoordKey that points to them.
int stripVisitInfoKeywords(daf::base::PropertySet &metadata)
Remove VisitInfo-related keywords from the metadata.
lsst::geom::Angle getBoresightParAngle() const
Get parallactic angle at the boresight.
lsst::geom::SpherePoint SpherePoint
table::Key< std::int64_t > tai
lsst::geom::Angle getBoresightRotAngle() const
Get rotation angle at boresight at middle of exposure.
std::string getAsString(std::string const &name) const
Get the last value for a string property name (possibly hierarchical).
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
Reports errors from accepting an object of an unexpected or inappropriate type.
table::Key< double > darkTime
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
coord::Observatory getObservatory() const
get observatory longitude, latitude and elevation
coord::Weather getWeather() const
get basic weather information
lsst::geom::Angle getBoresightHourAngle() const
Reports errors that are due to events beyond the control of the program.
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
static bool singleClassEquals(T const &lhs, Storable const &rhs)
Test if a Storable is of a particular class and equal to another object.