LSST Applications 24.1.6,g063fba187b+56b85ce14a,g0f08755f38+df8a265115,g12f32b3c4e+891a09f10d,g1524ad2192+7a5d7b3fbd,g1653933729+a8ce1bb630,g168dd56ebc+a8ce1bb630,g28da252d5a+07cb1400be,g2bbee38e9b+ae03bbfc84,g2bc492864f+ae03bbfc84,g3156d2b45e+6e55a43351,g347aa1857d+ae03bbfc84,g35bb328faa+a8ce1bb630,g3a166c0a6a+ae03bbfc84,g3e281a1b8c+c5dd892a6c,g414038480c+6b9177ef31,g41af890bb2+8f257c4c0b,g781aacb6e4+a8ce1bb630,g7af13505b9+7137b3b17d,g80478fca09+6df6903293,g82479be7b0+091ce1d07f,g858d7b2824+df8a265115,g89c8672015+f4add4ffd5,g9125e01d80+a8ce1bb630,g9726552aa6+414189b318,ga5288a1d22+4a2bca08d7,gacef1a1666+c9a8ff65f4,gb58c049af0+d64f4d3760,gbcfae0f0a0+de1d42d831,gc28159a63d+ae03bbfc84,gcf0d15dbbd+72117bf34e,gda6a2b7d83+72117bf34e,gdaeeff99f8+1711a396fd,ge500cccec5+c8c9c9af63,ge79ae78c31+ae03bbfc84,gf0baf85859+c1f95f4921,gfa517265be+df8a265115,gfa999e8aa5+17cd334064,gfb92a5be7c+df8a265115
LSST Data Management Base Package
Loading...
Searching...
No Matches
VisitInfo.cc
Go to the documentation of this file.
1// -*- LSST-C++ -*- // fixed format comment for emacs
2/*
3 * LSST Data Management System
4 * Copyright 2016 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#include <cmath>
24#include <limits>
25#include <sstream>
26
27#include "boost/algorithm/string/trim.hpp"
28
30#include "lsst/pex/exceptions.h"
31#include "lsst/geom/Angle.h"
33#include "lsst/afw/table/Key.h"
34#include "lsst/afw/table/aggregates.h" // for CoordKey
36#include "lsst/afw/table/misc.h" // for RecordId
39#include "lsst/afw/table/io/CatalogVector.h" // needed, but why?
42
44
45namespace lsst {
46namespace afw {
47
50
51namespace image {
52
53// the following persistence-related code emulates that in Calib.cc
54
55namespace {
56
57// Version history:
58// unversioned: original VisitInfo schema
59// 1: file versioning, instrument label
60// 2: id field
61// 3: focusZ field
62// 4: observationType, scienceProgram, observationReason, object, hasSimulatedContent fields
63// 5: remove exposureId field
64int constexpr SERIALIZATION_VERSION = 5;
65
67
76double getDouble(daf::base::PropertySet const& metadata, std::string const& key) {
77 try {
78 return metadata.exists(key) && !metadata.isUndefined(key) ? metadata.getAsDouble(key) : nan;
79 } catch (pex::exceptions::TypeError& err) {
80 // If an exposure has an invalid float here (often NaN)
81 // it should put NaN in the visitInfo because it's the same
82 // as it not being a valid key.
83 return nan;
84 }
85}
86
95lsst::geom::Angle getAngle(daf::base::PropertySet const& metadata, std::string const& key) {
96 return getDouble(metadata, key) * lsst::geom::degrees;
97}
98
107std::string getString(daf::base::PropertySet const& metadata, std::string const& key) {
108 return metadata.exists(key) && !metadata.isUndefined(key) ? metadata.getAsString(key) : "";
109}
110
119bool setDouble(daf::base::PropertySet& metadata, std::string const& key, double value,
120 std::string const& comment) {
121 if (std::isfinite(value)) {
122 metadata.set(key, value);
123 return true;
124 }
125 return false;
126}
127
136bool setAngle(daf::base::PropertySet& metadata, std::string const& key, lsst::geom::Angle const& angle,
137 std::string const& comment) {
138 return setDouble(metadata, key, angle.asDegrees(), comment);
139}
140
149bool setString(daf::base::PropertySet& metadata, std::string const& key, std::string value,
150 std::string const& comment) {
151 if (!value.empty()) {
152 metadata.set(key, value);
153 return true;
154 }
155 return false;
156}
157
163std::string rotTypeStrFromEnum(RotType rotType) {
164 switch (rotType) {
165 case RotType::UNKNOWN:
166 return "UNKNOWN";
167 case RotType::SKY:
168 return "SKY";
169 case RotType::HORIZON:
170 return "HORIZON";
171 case RotType::MOUNT:
172 return "MOUNT";
173 }
175 os << "Unknown RotType enum: " << static_cast<int>(rotType);
177}
178
184RotType rotTypeEnumFromStr(std::string const& rotTypeName) {
185 if (rotTypeName == "UNKNOWN") {
186 return RotType::UNKNOWN;
187 } else if (rotTypeName == "SKY") {
188 return RotType::SKY;
189 } else if (rotTypeName == "HORIZON") {
190 return RotType::HORIZON;
191 } else if (rotTypeName == "MOUNT") {
192 return RotType::MOUNT;
193 }
195 os << "Unknown RotType name: \"" << rotTypeName << "\"";
197}
198
199class VisitInfoSchema {
200public:
201 table::Schema schema;
202 table::Key<double> exposureTime;
203 table::Key<double> darkTime;
204 table::Key<std::int64_t> tai;
205 table::Key<double> ut1;
206 table::Key<lsst::geom::Angle> era;
207 table::CoordKey boresightRaDec;
208 table::Key<lsst::geom::Angle> boresightAzAlt_az;
209 table::Key<lsst::geom::Angle> boresightAzAlt_alt;
210 table::Key<double> boresightAirmass;
211 table::Key<lsst::geom::Angle> boresightRotAngle;
212 table::Key<int> rotType;
213 // observatory data
214 table::Key<lsst::geom::Angle> latitude;
215 table::Key<lsst::geom::Angle> longitude;
216 table::Key<double> elevation;
217 // weather data
218 table::Key<double> airTemperature;
219 table::Key<double> airPressure;
220 table::Key<double> humidity;
221
222 table::Key<std::string> instrumentLabel;
223 table::Key<int> version;
224
225 table::Key<table::RecordId> idnum;
226
227 table::Key<double> focusZ;
228
229 table::Key<std::string> observationType;
230 table::Key<std::string> scienceProgram;
231 table::Key<std::string> observationReason;
232 table::Key<std::string> object;
233 table::Key<afw::table::Flag> hasSimulatedContent;
234
235 static std::string const VERSION_KEY;
236
237 static VisitInfoSchema const& get(int version = SERIALIZATION_VERSION) {
238 // This is always the latest version.
239 static VisitInfoSchema instanceLatest(SERIALIZATION_VERSION);
240 // Versions that need to be preserved (e.g., a removed field) should have a separate instance.
241 static VisitInfoSchema instanceWithExposureId(4);
242 if (version < 5) {
243 return instanceWithExposureId;
244 } else {
245 return instanceLatest;
246 }
247 }
248
249 // No copying
250 VisitInfoSchema(const VisitInfoSchema&) = delete;
251 VisitInfoSchema& operator=(const VisitInfoSchema&) = delete;
252
253 // No moving
254 VisitInfoSchema(VisitInfoSchema&&) = delete;
255 VisitInfoSchema& operator=(VisitInfoSchema&&) = delete;
256
257private:
258 VisitInfoSchema(int _version) : schema() {
259 if (_version < 5) {
260 // exposureId was removed in version 5, but we need to reserve space in the schema for old files.
261 // We don't save the field record, as we don't need to read into it.
262 schema.addField<table::RecordId>("exposureid", "exposure ID", "");
263 }
264 exposureTime = schema.addField<double>("exposuretime", "exposure duration", "s");
265 darkTime = schema.addField<double>("darktime", "time from CCD flush to readout", "s");
267 "tai", "TAI date and time at middle of exposure as nsec from unix epoch", "nsec");
268 ut1 = schema.addField<double>("ut1", "UT1 date and time at middle of exposure", "MJD");
269 era = schema.addField<lsst::geom::Angle>("era", "earth rotation angle at middle of exposure", "");
271 "sky position of boresight at middle of exposure");
272 // CoordKey is intended for ICRS coordinates, so use a pair of lsst::geom::Angle fields
273 // to save boresightAzAlt
275 "boresightazalt_az",
276 "refracted apparent topocentric position of boresight at middle of exposure", "");
278 "boresightazalt_alt",
279 "refracted apparent topocentric position of boresight at middle of exposure", "");
281 "boresightairmass", "airmass at boresight, relative to zenith at sea level", "");
283 "boresightrotangle", "rotation angle at boresight at middle of exposure", "");
284 rotType =
285 schema.addField<int>("rottype", "rotation type; see VisitInfo.getRotType for details", "MJD");
286
287 // observatory data
289 "latitude of telescope (+ is east of Greenwich)", "");
290 longitude = schema.addField<lsst::geom::Angle>("longitude", "longitude of telescope", "");
291 elevation = schema.addField<double>("elevation", "elevation of telescope", "");
292
293 // weather data
294 airTemperature = schema.addField<double>("airtemperature", "air temperature", "C");
295 airPressure = schema.addField<double>("airpressure", "air pressure", "Pascal");
296 humidity = schema.addField<double>("humidity", "humidity (%)", "");
297
299 "instrumentlabel", "Short name of the instrument that took this data", "", 0);
300
301 // for internal support
302 version = schema.addField<int>(VERSION_KEY, "version of this VisitInfo");
303
304 idnum = schema.addField<table::RecordId>("idnum", "identifier of this full focal plane exposure", "");
305
306 focusZ = schema.addField<double>("focusz", "defocal distance", "mm");
307
309 "observationType", "type of this observation (e.g. science, flat, bias)", "", 0);
311 "scienceProgram", "observing program (survey or proposal) identifier", "", 0);
313 "observationReason", "reason this observation was taken, or its purpose", "", 0);
314 object = schema.addField<std::string>("object", "object of interest or field name", "", 0);
315 hasSimulatedContent = schema.addField<afw::table::Flag>(
316 "hasSimulatedContent", "Was any part of this observation simulated?");
317 }
318};
319std::string const VisitInfoSchema::VERSION_KEY = "version";
320
321class VisitInfoFactory : public table::io::PersistableFactory {
322public:
323 std::shared_ptr<table::io::Persistable> read(InputArchive const& archive,
324 CatalogVector const& catalogs) const override {
325 LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
326 LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
327 table::BaseRecord const& record = catalogs.front().front();
328 int version = getVersion(record);
329 if (version > SERIALIZATION_VERSION) {
330 throw LSST_EXCEPT(pex::exceptions::TypeError, "Cannot read VisitInfo FITS version > " +
331 std::to_string(SERIALIZATION_VERSION) +
332 ", found version " +
334 }
335
336 VisitInfoSchema const& keys = VisitInfoSchema::get(version);
337 // Version-dependent fields
338 std::string instrumentLabel = version >= 1 ? record.get(keys.instrumentLabel) : "";
339 table::RecordId id = version >= 2 ? record.get(keys.idnum) : 0;
340 double focusZ = version >= 3 ? record.get(keys.focusZ) : nan;
341
342 std::string observationType = version >= 4 ? record.get(keys.observationType) : "";
343 std::string scienceProgram = version >= 4 ? record.get(keys.scienceProgram) : "";
344 std::string observationReason = version >= 4 ? record.get(keys.observationReason) : "";
345 std::string object = version >= 4 ? record.get(keys.object) : "";
346 // default false for backwards compatibility
347 bool hasSimulatedContent = version >= 4 ? record.get(keys.hasSimulatedContent) : false;
348
350 new VisitInfo(record.get(keys.exposureTime), record.get(keys.darkTime),
351 ::DateTime(record.get(keys.tai), ::DateTime::TAI), record.get(keys.ut1),
352 record.get(keys.era), record.get(keys.boresightRaDec),
353 lsst::geom::SpherePoint(record.get(keys.boresightAzAlt_az),
354 record.get(keys.boresightAzAlt_alt)),
355 record.get(keys.boresightAirmass), record.get(keys.boresightRotAngle),
356 static_cast<RotType>(record.get(keys.rotType)),
357 coord::Observatory(record.get(keys.longitude), record.get(keys.latitude),
358 record.get(keys.elevation)),
359 coord::Weather(record.get(keys.airTemperature), record.get(keys.airPressure),
360 record.get(keys.humidity)),
362 object, hasSimulatedContent));
363 return result;
364 }
365
366 explicit VisitInfoFactory(std::string const& name) : table::io::PersistableFactory(name) {}
367
368private:
369 int getVersion(table::BaseRecord const& record) const {
370 try {
371 // Don't assume version is at same index as in VisitInfoSchema
372 auto versionKey = record.getSchema().find<int>(VisitInfoSchema::VERSION_KEY);
373 return record.get(versionKey.key);
374 } catch (pex::exceptions::NotFoundError const&) {
375 // un-versioned files are implicitly version 0
376 return 0;
377 }
378 }
379};
380
381std::string getVisitInfoPersistenceName() { return "VisitInfo"; }
382
383VisitInfoFactory registration(getVisitInfoPersistenceName());
384
385} // namespace
386
387namespace detail {
388
390 int nstripped = 0;
391
392 std::vector<std::string> keyList = {"EXPTIME", "DARKTIME", "DATE-AVG", "TIMESYS",
393 "TIME-MID", "MJD-AVG-UT1", "AVG-ERA", "BORE-RA",
394 "BORE-DEC", "BORE-AZ", "BORE-ALT", "BORE-AIRMASS",
395 "BORE-ROTANG", "ROTTYPE", "OBS-LONG", "OBS-LAT",
396 "OBS-ELEV", "AIRTEMP", "AIRPRESS", "HUMIDITY",
397 "INSTRUMENT", "IDNUM", "FOCUSZ", "OBSTYPE",
398 "PROGRAM", "REASON", "OBJECT", "HAS-SIMULATED-CONTENT"};
399 for (auto&& key : keyList) {
400 if (metadata.exists(key)) {
401 metadata.remove(key);
402 nstripped++;
403 }
404 }
405 return nstripped;
406}
407
409 setDouble(metadata, "EXPTIME", visitInfo.getExposureTime(), "Exposure time (sec)");
410 setDouble(metadata, "DARKTIME", visitInfo.getDarkTime(), "Time from CCD flush to readout (sec)");
411 if (visitInfo.getDate().isValid()) {
412 metadata.set("DATE-AVG", visitInfo.getDate().toString(::DateTime::TAI),
413 "TAI date at middle of observation");
414 metadata.set("TIMESYS", "TAI");
415 }
416 setDouble(metadata, "MJD-AVG-UT1", visitInfo.getUt1(), "UT1 MJD date at ctr of obs");
417 setAngle(metadata, "AVG-ERA", visitInfo.getEra(), "Earth rot ang at ctr of obs (deg)");
418 auto boresightRaDec = visitInfo.getBoresightRaDec();
419 setAngle(metadata, "BORE-RA", boresightRaDec[0], "ICRS RA (deg) at boresight");
420 setAngle(metadata, "BORE-DEC", boresightRaDec[1], "ICRS Dec (deg) at boresight");
421 auto boresightAzAlt = visitInfo.getBoresightAzAlt();
422 setAngle(metadata, "BORE-AZ", boresightAzAlt[0], "Refr app topo az (deg) at bore");
423 setAngle(metadata, "BORE-ALT", boresightAzAlt[1], "Refr app topo alt (deg) at bore");
424 setDouble(metadata, "BORE-AIRMASS", visitInfo.getBoresightAirmass(), "Airmass at boresight");
425 setAngle(metadata, "BORE-ROTANG", visitInfo.getBoresightRotAngle(), "Rotation angle (deg) at boresight");
426 metadata.set("ROTTYPE", rotTypeStrFromEnum(visitInfo.getRotType()), "Type of rotation angle");
427 auto observatory = visitInfo.getObservatory();
428 setAngle(metadata, "OBS-LONG", observatory.getLongitude(), "Telescope longitude (+E, deg)");
429 setAngle(metadata, "OBS-LAT", observatory.getLatitude(), "Telescope latitude (deg)");
430 setDouble(metadata, "OBS-ELEV", observatory.getElevation(), "Telescope elevation (m)");
431 auto weather = visitInfo.getWeather();
432 setDouble(metadata, "AIRTEMP", weather.getAirTemperature(), "Outside air temperature (C)");
433 setDouble(metadata, "AIRPRESS", weather.getAirPressure(), "Outdoor air pressure (P)");
434 setDouble(metadata, "HUMIDITY", weather.getHumidity(), "Relative humidity (%)");
435 setString(metadata, "INSTRUMENT", visitInfo.getInstrumentLabel(),
436 "Short name of the instrument that took this data");
437 if (visitInfo.getId() != 0) {
438 metadata.set("IDNUM", visitInfo.getId(), "identifier of this full focal plane exposure");
439 }
440 setDouble(metadata, "FOCUSZ", visitInfo.getFocusZ(), "Defocal distance (mm)");
441 setString(metadata, "OBSTYPE", visitInfo.getObservationType(), "Type of this observation");
442 setString(metadata, "PROGRAM", visitInfo.getScienceProgram(),
443 "observing program (survey or proposal) identifier");
444 setString(metadata, "REASON", visitInfo.getObservationReason(),
445 "reason this observation was taken, or its purpose");
446 setString(metadata, "OBJECT", visitInfo.getObject(), "object of interest or field name");
447 metadata.set("HAS-SIMULATED-CONTENT", visitInfo.getHasSimulatedContent(),
448 "Was any part of this observation simulated?");
449}
450
451} // namespace detail
452
453VisitInfo::VisitInfo(daf::base::PropertySet const& metadata)
454 : _exposureTime(nan), // don't use getDouble because str values are also accepted
455 _darkTime(getDouble(metadata, "DARKTIME")),
456 _date(),
457 _ut1(getDouble(metadata, "MJD-AVG-UT1")),
458 _era(getAngle(metadata, "AVG-ERA")),
459 _boresightRaDec(
460 lsst::geom::SpherePoint(getAngle(metadata, "BORE-RA"), getAngle(metadata, "BORE-DEC"))),
461 _boresightAzAlt(
462 lsst::geom::SpherePoint(getAngle(metadata, "BORE-AZ"), getAngle(metadata, "BORE-ALT"))),
463 _boresightAirmass(getDouble(metadata, "BORE-AIRMASS")),
464 _boresightRotAngle(getAngle(metadata, "BORE-ROTANG")),
465 _rotType(RotType::UNKNOWN),
466 _observatory(getAngle(metadata, "OBS-LONG"), getAngle(metadata, "OBS-LAT"),
467 getDouble(metadata, "OBS-ELEV")),
468 _weather(getDouble(metadata, "AIRTEMP"), getDouble(metadata, "AIRPRESS"),
469 getDouble(metadata, "HUMIDITY")),
470 _instrumentLabel(getString(metadata, "INSTRUMENT")),
471 _id(0),
472 _focusZ(getDouble(metadata, "FOCUSZ")),
473 _observationType(getString(metadata, "OBSTYPE")),
474 _scienceProgram(getString(metadata, "PROGRAM")),
475 _observationReason(getString(metadata, "REASON")),
476 _object(getString(metadata, "OBJECT")),
477 // default false for backwards compatibility
478 _hasSimulatedContent(false) {
479 auto key = "IDNUM";
480 if (metadata.exists(key) && !metadata.isUndefined(key)) {
481 _id = metadata.getAsInt64(key);
482 }
483
484 key = "EXPTIME";
485 if (metadata.exists(key) && !metadata.isUndefined(key)) {
486 try {
487 _exposureTime = metadata.getAsDouble(key);
488 } catch (lsst::pex::exceptions::TypeError& err) {
489 // some old exposures have EXPTIME stored as a string
490 std::string exptimeStr = metadata.getAsString(key);
491 _exposureTime = std::stod(exptimeStr);
492 }
493 }
494
495 key = "DATE-AVG";
496 if (metadata.exists(key) && !metadata.isUndefined(key)) {
497 if (metadata.exists("TIMESYS")) {
498 auto timesysName = boost::algorithm::trim_right_copy(metadata.getAsString("TIMESYS"));
499 if (timesysName != "TAI") {
500 // rather than try to deal with all the possible choices, which requires
501 // appending or deleting a "Z", depending on the time system, just give up.
502 // VisitInfo should be used on FITS headers that have been sanitized!
504 os << "TIMESYS = \"" << timesysName
505 << "\"; VisitInfo requires TIMESYS to exist and to equal \"TAI\"";
507 }
508 } else {
510 "TIMESYS not found; VistitInfo requires TIMESYS to exist and to equal \"TAI\"");
511 }
512 _date = ::DateTime(boost::algorithm::trim_right_copy(metadata.getAsString(key)), ::DateTime::TAI);
513 } else {
514 // DATE-AVG not found. For backwards compatibility look for TIME-MID, an outdated LSST keyword
515 // whose time system was UTC, despite a FITS comment claiming it was TAI. Ignore TIMESYS.
516 key = "TIME-MID";
517 if (metadata.exists(key) && !metadata.isUndefined(key)) {
518 _date = ::DateTime(boost::algorithm::trim_right_copy(metadata.getAsString(key)), ::DateTime::UTC);
519 }
520 }
521
522 key = "ROTTYPE";
523 if (metadata.exists(key) && !metadata.isUndefined(key)) {
524 _rotType = rotTypeEnumFromStr(metadata.getAsString(key));
525 }
526
527 key = "HAS-SIMULATED-CONTENT";
528 if (metadata.exists(key) && !metadata.isUndefined(key)) {
529 _hasSimulatedContent = metadata.getAsBool(key);
530 }
531}
532
539bool _eqOrNan(double lhs, double rhs) noexcept { return (std::isnan(lhs) && std::isnan(rhs)) || lhs == rhs; }
540
548 return (!lhs.isFinite() && !rhs.isFinite()) || lhs == rhs;
549}
550
551bool VisitInfo::operator==(VisitInfo const& other) const {
552 return _eqOrNan(_exposureTime, other.getExposureTime()) && _eqOrNan(_darkTime, other.getDarkTime()) &&
553 _date == other.getDate() && _eqOrNan(_ut1, other.getUt1()) && _eqOrNan(_era, other.getEra()) &&
554 _eqOrNonFinite(_boresightRaDec, other.getBoresightRaDec()) &&
555 _eqOrNonFinite(_boresightAzAlt, other.getBoresightAzAlt()) &&
556 _eqOrNan(_boresightAirmass, other.getBoresightAirmass()) &&
557 _eqOrNan(_boresightRotAngle, other.getBoresightRotAngle()) && _rotType == other.getRotType() &&
558 _observatory == other.getObservatory() && _weather == other.getWeather() &&
559 _instrumentLabel == other.getInstrumentLabel() && _id == other.getId() &&
560 _eqOrNan(_focusZ, other.getFocusZ()) && _observationType == other.getObservationType() &&
561 _scienceProgram == other.getScienceProgram() &&
562 _observationReason == other.getObservationReason() && _object == other.getObject() &&
563 _hasSimulatedContent == other.getHasSimulatedContent();
564}
565
567 // Completely arbitrary seed
568 return cpputils::hashCombine(17, _exposureTime, _darkTime, _date, _ut1, _era, _boresightRaDec,
569 _boresightAzAlt, _boresightAirmass, _boresightRotAngle, _rotType, _observatory,
570 _weather, _instrumentLabel, _id, _focusZ, _observationType, _scienceProgram,
571 _observationReason, _object, _hasSimulatedContent);
572}
573
574std::string VisitInfo::getPersistenceName() const { return getVisitInfoPersistenceName(); }
575
577 VisitInfoSchema const& keys = VisitInfoSchema::get();
578 table::BaseCatalog cat = handle.makeCatalog(keys.schema);
580 record->set(keys.exposureTime, getExposureTime());
581 record->set(keys.darkTime, getDarkTime());
582 record->set(keys.tai, getDate().nsecs(::DateTime::TAI));
583 record->set(keys.ut1, getUt1());
584 record->set(keys.era, getEra());
585 record->set(keys.boresightRaDec, getBoresightRaDec());
586 auto boresightAzAlt = getBoresightAzAlt();
587 record->set(keys.boresightAzAlt_az, boresightAzAlt[0]);
588 record->set(keys.boresightAzAlt_alt, boresightAzAlt[1]);
589 record->set(keys.boresightAirmass, getBoresightAirmass());
590 record->set(keys.boresightRotAngle, getBoresightRotAngle());
591 record->set(keys.rotType, static_cast<int>(getRotType()));
592 auto observatory = getObservatory();
593 record->set(keys.latitude, observatory.getLatitude());
594 record->set(keys.longitude, observatory.getLongitude());
595 record->set(keys.elevation, observatory.getElevation());
596 auto weather = getWeather();
597 record->set(keys.airTemperature, weather.getAirTemperature());
598 record->set(keys.airPressure, weather.getAirPressure());
599 record->set(keys.humidity, weather.getHumidity());
600 record->set(keys.instrumentLabel, getInstrumentLabel());
601 record->set(keys.version, SERIALIZATION_VERSION);
602 record->set(keys.idnum, getId());
603 record->set(keys.focusZ, getFocusZ());
604 record->set(keys.observationType, getObservationType());
605 record->set(keys.scienceProgram, getScienceProgram());
606 record->set(keys.observationReason, getObservationReason());
607 record->set(keys.object, getObject());
608 record->set(keys.hasSimulatedContent, getHasSimulatedContent());
609 handle.saveCatalog(cat);
610}
611
613
615
621 double _parallactic_y, _parallactic_x, result;
622 _parallactic_y = sin(getBoresightHourAngle().asRadians());
623 _parallactic_x =
624 cos((getBoresightRaDec()[1]).asRadians()) * tan(getObservatory().getLatitude().asRadians()) -
625 sin((getBoresightRaDec()[1]).asRadians()) * cos(getBoresightHourAngle().asRadians());
626 result = atan2(_parallactic_y, _parallactic_x);
628}
629
631 return std::make_unique<VisitInfo>(*this);
632}
633
634bool VisitInfo::equals(typehandling::Storable const& other) const noexcept {
635 return singleClassEquals(*this, other);
636}
637
639 std::stringstream buffer;
640 buffer << "VisitInfo(";
641 buffer << "exposureTime=" << getExposureTime() << ", ";
642 buffer << "darkTime=" << getDarkTime() << ", ";
643 buffer << "date=" << (getDate().isValid() ? getDate().toString(daf::base::DateTime::TAI) : "<invalid>")
644 << ", ";
645 buffer << "UT1=" << getUt1() << ", ";
646 buffer << "ERA=" << getEra() << ", ";
647 buffer << "boresightRaDec=" << getBoresightRaDec() << ", ";
648 buffer << "boresightAzAlt=" << getBoresightAzAlt() << ", ";
649 buffer << "boresightAirmass=" << getBoresightAirmass() << ", ";
650 buffer << "boresightRotAngle=" << getBoresightRotAngle() << ", ";
651 buffer << "rotType=" << static_cast<int>(getRotType()) << ", ";
652 buffer << "observatory=" << getObservatory() << ", ";
653 buffer << "weather=" << getWeather() << ", ";
654 buffer << "instrumentLabel='" << getInstrumentLabel() << "', ";
655 buffer << "id=" << getId() << ", ";
656 buffer << "focusZ=" << getFocusZ() << ", ";
657 buffer << "observationType='" << getObservationType() << "', ";
658 buffer << "scienceProgram='" << getScienceProgram() << "', ";
659 buffer << "observationReason='" << getObservationReason() << "', ";
660 buffer << "object='" << getObject() << "', ";
661 buffer << "hasSimulatedContent=" << std::boolalpha << getHasSimulatedContent();
662 buffer << ")";
663 return buffer.str();
664}
665
667 os << visitInfo.toString();
668 return os;
669}
670
671} // namespace image
672} // namespace afw
673} // namespace lsst
py::object result
Definition _schema.cc:429
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition Exception.h:48
table::Key< double > angle
std::ostream * os
Definition Schema.cc:557
table::Key< lsst::geom::Angle > longitude
Definition VisitInfo.cc:215
table::Key< std::string > observationReason
Definition VisitInfo.cc:231
table::Key< std::string > scienceProgram
Definition VisitInfo.cc:230
table::Key< lsst::geom::Angle > latitude
Definition VisitInfo.cc:214
table::Key< std::string > observationType
Definition VisitInfo.cc:229
table::Key< lsst::geom::Angle > boresightAzAlt_az
Definition VisitInfo.cc:208
table::Key< double > exposureTime
Definition VisitInfo.cc:202
table::Key< lsst::geom::Angle > era
Definition VisitInfo.cc:206
table::Key< double > airPressure
Definition VisitInfo.cc:219
table::Key< lsst::geom::Angle > boresightAzAlt_alt
Definition VisitInfo.cc:209
table::Key< int > rotType
Definition VisitInfo.cc:212
table::Key< double > darkTime
Definition VisitInfo.cc:203
table::Key< table::RecordId > idnum
Definition VisitInfo.cc:225
table::Key< std::string > instrumentLabel
Definition VisitInfo.cc:222
table::CoordKey boresightRaDec
Definition VisitInfo.cc:207
table::Key< double > boresightAirmass
Definition VisitInfo.cc:210
table::Key< std::string > object
Definition VisitInfo.cc:232
table::Key< double > airTemperature
Definition VisitInfo.cc:218
table::Key< std::int64_t > tai
Definition VisitInfo.cc:204
table::Key< double > elevation
Definition VisitInfo.cc:216
table::Key< double > humidity
Definition VisitInfo.cc:220
table::Key< afw::table::Flag > hasSimulatedContent
Definition VisitInfo.cc:233
table::Key< double > focusZ
Definition VisitInfo.cc:227
table::Key< lsst::geom::Angle > boresightRotAngle
Definition VisitInfo.cc:211
table::Key< double > ut1
Definition VisitInfo.cc:205
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
Definition Persistable.h:48
table::Schema schema
Definition python.h:134
T boolalpha(T... args)
lsst::geom::Angle getLongitude() const noexcept
get telescope longitude (positive values are E of Greenwich)
Information about a single exposure of an imaging camera.
Definition VisitInfo.h:68
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
Definition VisitInfo.cc:574
daf::base::DateTime getDate() const
get uniform date and time at middle of exposure
Definition VisitInfo.h:150
coord::Weather getWeather() const
get basic weather information
Definition VisitInfo.h:185
lsst::geom::Angle getLocalEra() const
Definition VisitInfo.cc:612
double getUt1() const
get UT1 (universal time) MJD date at middle of exposure
Definition VisitInfo.h:153
double getBoresightAirmass() const
get airmass at the boresight, relative to zenith at sea level (and at the middle of the exposure,...
Definition VisitInfo.h:168
std::string getScienceProgram() const
Definition VisitInfo.h:203
lsst::geom::Angle getBoresightHourAngle() const
Definition VisitInfo.cc:614
lsst::geom::Angle getBoresightRotAngle() const
Get rotation angle at boresight at middle of exposure.
Definition VisitInfo.h:176
std::size_t hash_value() const noexcept override
Return a hash of this object.
Definition VisitInfo.cc:566
bool operator==(VisitInfo const &other) const
Definition VisitInfo.cc:551
lsst::geom::Angle getEra() const
get earth rotation angle at middle of exposure
Definition VisitInfo.h:156
table::RecordId getId() const
Definition VisitInfo.h:197
std::string getObservationReason() const
Definition VisitInfo.h:204
std::string toString() const override
Create a string representation of this object.
Definition VisitInfo.cc:638
double getExposureTime() const
get exposure duration (shutter open time); (sec)
Definition VisitInfo.h:144
RotType getRotType() const
get rotation type of boresightRotAngle
Definition VisitInfo.h:179
bool equals(typehandling::Storable const &other) const noexcept override
Compare this object to another Storable.
Definition VisitInfo.cc:634
lsst::geom::SpherePoint getBoresightAzAlt() const
get refracted apparent topocentric Az/Alt position at the boresight (and at the middle of the exposur...
Definition VisitInfo.h:164
std::string getObject() const
Definition VisitInfo.h:205
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)
Definition VisitInfo.h:160
std::shared_ptr< typehandling::Storable > cloneStorable() const override
Create a new VisitInfo that is a copy of this one.
Definition VisitInfo.cc:630
std::string getInstrumentLabel() const
Definition VisitInfo.h:195
bool getHasSimulatedContent() const
Definition VisitInfo.h:206
double getDarkTime() const
get time from CCD flush to exposure readout, including shutter open time (despite the name); (sec)
Definition VisitInfo.h:147
coord::Observatory getObservatory() const
get observatory longitude, latitude and elevation
Definition VisitInfo.h:182
lsst::geom::Angle getBoresightParAngle() const
Get parallactic angle at the boresight.
Definition VisitInfo.cc:616
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Definition VisitInfo.cc:576
std::string getObservationType() const
Definition VisitInfo.h:202
std::shared_ptr< RecordT > addNew()
Create a new record, add it to the end of the catalog, and return a pointer to it.
Definition Catalog.h:489
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.
bool isValid() const noexcept
Return true if the key was initialized to valid offset.
Definition Key.h:97
Key< T > addField(Field< T > const &field, bool doReplace=false)
Add a new field to the Schema, and return the associated Key.
Definition Schema.cc:479
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
Interface supporting iteration over heterogenous containers.
Definition Storable.h:58
Class for handling dates/times, including MJD, UTC, and TAI.
Definition DateTime.h:64
std::string toString(Timescale scale) const
Get date as an ISO8601-formatted string.
Definition DateTime.cc:500
bool isValid() const
Is this date valid?
Definition DateTime.h:203
double get(DateSystem system=MJD, Timescale scale=TAI) const
Get date as a double in a specified representation, such as MJD.
Definition DateTime.cc:430
Class for storing ordered metadata with comments.
void set(std::string const &name, T const &value)
Replace all values for a property name (possibly hierarchical) with a new scalar value.
Class for storing generic metadata.
Definition PropertySet.h:66
std::string getAsString(std::string const &name) const
Get the last value for a string property name (possibly hierarchical).
virtual void remove(std::string const &name)
Remove all values for a property name (possibly hierarchical).
int64_t getAsInt64(std::string const &name) const
Get the last value for a bool/char/short/int/int64_t property name (possibly hierarchical).
bool isUndefined(std::string const &name) const
Determine if a name (possibly hierarchical) has a defined value.
bool exists(std::string const &name) const
Determine if a name (possibly hierarchical) exists.
double getAsDouble(std::string const &name) const
Get the last value for any arithmetic property name (possibly hierarchical).
bool getAsBool(std::string const &name) const
Get the last value for a bool property name (possibly hierarchical).
A class representing an angle.
Definition Angle.h:128
Point in an unspecified spherical coordinate system.
Definition SpherePoint.h:57
Reports errors that are due to events beyond the control of the program.
Definition Runtime.h:104
Reports errors from accepting an object of an unexpected or inappropriate type.
Definition Runtime.h:167
T isfinite(T... args)
T isnan(T... args)
int stripVisitInfoKeywords(daf::base::PropertySet &metadata)
Remove VisitInfo-related keywords from the metadata.
Definition VisitInfo.cc:389
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
Definition VisitInfo.cc:408
bool _eqOrNonFinite(lsst::geom::SpherePoint const &lhs, lsst::geom::SpherePoint const &rhs) noexcept
Test whether two SpherePoints are exactly equal or invalid.
Definition VisitInfo.cc:547
std::ostream & operator<<(std::ostream &os, Measurement const &measurement)
Definition PhotoCalib.cc:48
RotType
Type of rotation.
Definition VisitInfo.h:45
@ UNKNOWN
Rotation angle is unknown.
bool _eqOrNan(double lhs, double rhs) noexcept
Test whether two numbers are exactly equal or both NaN.
Definition VisitInfo.cc:539
std::int64_t RecordId
Type used for unique IDs for records.
Definition misc.h:21
std::size_t hashCombine(std::size_t seed) noexcept
Combine hashes.
Definition hashCombine.h:35
AngleUnit constexpr degrees
constant with units of degrees
Definition Angle.h:110
AngleUnit constexpr radians
constant with units of radians
Definition Angle.h:109
T nan(T... args)
T quiet_NaN(T... args)
T stod(T... args)
T str(T... args)
Key< int > visitInfo
Definition Exposure.cc:70
T to_string(T... args)
std::shared_ptr< table::io::Persistable > read(table::io::InputArchive const &archive, table::io::CatalogVector const &catalogs) const override