LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
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
63int constexpr SERIALIZATION_VERSION = 4;
64
66
75double getDouble(daf::base::PropertySet const& metadata, std::string const& key) {
76 try {
77 return metadata.exists(key) && !metadata.isUndefined(key) ? metadata.getAsDouble(key) : nan;
78 } catch (pex::exceptions::TypeError& err) {
79 // If an exposure has an invalid float here (often NaN)
80 // it should put NaN in the visitInfo because it's the same
81 // as it not being a valid key.
82 return nan;
83 }
84}
85
94lsst::geom::Angle getAngle(daf::base::PropertySet const& metadata, std::string const& key) {
95 return getDouble(metadata, key) * lsst::geom::degrees;
96}
97
106std::string getString(daf::base::PropertySet const& metadata, std::string const& key) {
107 return metadata.exists(key) && !metadata.isUndefined(key) ? metadata.getAsString(key) : "";
108}
109
118bool setDouble(daf::base::PropertySet& metadata, std::string const& key, double value,
119 std::string const& comment) {
120 if (std::isfinite(value)) {
121 metadata.set(key, value);
122 return true;
123 }
124 return false;
125}
126
135bool setAngle(daf::base::PropertySet& metadata, std::string const& key, lsst::geom::Angle const& angle,
136 std::string const& comment) {
137 return setDouble(metadata, key, angle.asDegrees(), comment);
138}
139
148bool setString(daf::base::PropertySet& metadata, std::string const& key, std::string value,
149 std::string const& comment) {
150 if (!value.empty()) {
151 metadata.set(key, value);
152 return true;
153 }
154 return false;
155}
156
162std::string rotTypeStrFromEnum(RotType rotType) {
163 switch (rotType) {
164 case RotType::UNKNOWN:
165 return "UNKNOWN";
166 case RotType::SKY:
167 return "SKY";
168 case RotType::HORIZON:
169 return "HORIZON";
170 case RotType::MOUNT:
171 return "MOUNT";
172 }
174 os << "Unknown RotType enum: " << static_cast<int>(rotType);
176}
177
183RotType rotTypeEnumFromStr(std::string const& rotTypeName) {
184 if (rotTypeName == "UNKNOWN") {
185 return RotType::UNKNOWN;
186 } else if (rotTypeName == "SKY") {
187 return RotType::SKY;
188 } else if (rotTypeName == "HORIZON") {
189 return RotType::HORIZON;
190 } else if (rotTypeName == "MOUNT") {
191 return RotType::MOUNT;
192 }
194 os << "Unknown RotType name: \"" << rotTypeName << "\"";
196}
197
198class VisitInfoSchema {
199public:
200 table::Schema schema;
201 table::Key<table::RecordId> exposureId;
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() {
238 static VisitInfoSchema instance;
239 return instance;
240 }
241
242 // No copying
243 VisitInfoSchema(const VisitInfoSchema&) = delete;
244 VisitInfoSchema& operator=(const VisitInfoSchema&) = delete;
245
246 // No moving
247 VisitInfoSchema(VisitInfoSchema&&) = delete;
248 VisitInfoSchema& operator=(VisitInfoSchema&&) = delete;
249
250private:
251 VisitInfoSchema()
252 : schema(),
253 exposureId(schema.addField<table::RecordId>("exposureid", "exposure ID", "")),
254 exposureTime(schema.addField<double>("exposuretime", "exposure duration", "s")),
255 darkTime(schema.addField<double>("darktime", "time from CCD flush to readout", "s")),
256 tai(schema.addField<std::int64_t>(
257 "tai", "TAI date and time at middle of exposure as nsec from unix epoch", "nsec")),
258 ut1(schema.addField<double>("ut1", "UT1 date and time at middle of exposure", "MJD")),
259 era(schema.addField<lsst::geom::Angle>("era", "earth rotation angle at middle of exposure",
260 "")),
261 boresightRaDec(table::CoordKey::addFields(schema, "boresightradec",
262 "sky position of boresight at middle of exposure")),
263 // CoordKey is intended for ICRS coordinates, so use a pair of lsst::geom::Angle fields
264 // to save boresightAzAlt
266 "boresightazalt_az",
267 "refracted apparent topocentric position of boresight at middle of exposure", "")),
269 "boresightazalt_alt",
270 "refracted apparent topocentric position of boresight at middle of exposure", "")),
271 boresightAirmass(schema.addField<double>(
272 "boresightairmass", "airmass at boresight, relative to zenith at sea level", "")),
274 "boresightrotangle", "rotation angle at boresight at middle of exposure", "")),
275 rotType(schema.addField<int>("rottype", "rotation type; see VisitInfo.getRotType for details",
276 "MJD")),
277
278 // observatory data
279 latitude(schema.addField<lsst::geom::Angle>(
280 "latitude", "latitude of telescope (+ is east of Greenwich)", "")),
281 longitude(schema.addField<lsst::geom::Angle>("longitude", "longitude of telescope", "")),
282 elevation(schema.addField<double>("elevation", "elevation of telescope", "")),
283
284 // weather data
285 airTemperature(schema.addField<double>("airtemperature", "air temperature", "C")),
286 airPressure(schema.addField<double>("airpressure", "air pressure", "Pascal")),
287 humidity(schema.addField<double>("humidity", "humidity (%)", "")),
288
289 instrumentLabel(schema.addField<std::string>(
290 "instrumentlabel", "Short name of the instrument that took this data", "", 0)),
291
292 // for internal support
293 version(schema.addField<int>(VERSION_KEY, "version of this VisitInfo")),
294
295 idnum(schema.addField<table::RecordId>("idnum", "identifier of this full focal plane exposure",
296 "")),
297
298 focusZ(schema.addField<double>("focusz", "defocal distance", "mm")),
299
300 observationType(schema.addField<std::string>(
301 "observationType", "type of this observation (e.g. science, flat, bias)", "", 0)),
302 scienceProgram(schema.addField<std::string>(
303 "scienceProgram", "observing program (survey or proposal) identifier", "", 0)),
304 observationReason(schema.addField<std::string>(
305 "observationReason", "reason this observation was taken, or its purpose", "", 0)),
306 object(schema.addField<std::string>("object", "object of interest or field name", "", 0)),
307 hasSimulatedContent(schema.addField<afw::table::Flag>(
308 "hasSimulatedContent", "Was any part of this observation simulated?")) {}
309};
310std::string const VisitInfoSchema::VERSION_KEY = "version";
311
312class VisitInfoFactory : public table::io::PersistableFactory {
313public:
314 std::shared_ptr<table::io::Persistable> read(InputArchive const& archive,
315 CatalogVector const& catalogs) const override {
316 VisitInfoSchema const& keys = VisitInfoSchema::get();
317 LSST_ARCHIVE_ASSERT(catalogs.size() == 1u);
318 LSST_ARCHIVE_ASSERT(catalogs.front().size() == 1u);
319 table::BaseRecord const& record = catalogs.front().front();
320 int version = getVersion(record);
321 if (version > SERIALIZATION_VERSION) {
322 throw LSST_EXCEPT(pex::exceptions::TypeError, "Cannot read VisitInfo FITS version > " +
323 std::to_string(SERIALIZATION_VERSION));
324 }
325
326 // Version-dependent fields
327 std::string instrumentLabel = version >= 1 ? record.get(keys.instrumentLabel) : "";
328 table::RecordId id = version >= 2 ? record.get(keys.idnum) : 0;
329 double focusZ = version >= 3 ? record.get(keys.focusZ) : nan;
330
331 std::string observationType = version >= 4 ? record.get(keys.observationType) : "";
332 std::string scienceProgram = version >= 4 ? record.get(keys.scienceProgram) : "";
333 std::string observationReason = version >= 4 ? record.get(keys.observationReason) : "";
334 std::string object = version >= 4 ? record.get(keys.object) : "";
335 // default false for backwards compatibility
336 bool hasSimulatedContent = version >= 4 ? record.get(keys.hasSimulatedContent) : false;
337
339 new VisitInfo(record.get(keys.exposureId), record.get(keys.exposureTime),
340 record.get(keys.darkTime), ::DateTime(record.get(keys.tai), ::DateTime::TAI),
341 record.get(keys.ut1), record.get(keys.era), record.get(keys.boresightRaDec),
342 lsst::geom::SpherePoint(record.get(keys.boresightAzAlt_az),
343 record.get(keys.boresightAzAlt_alt)),
344 record.get(keys.boresightAirmass), record.get(keys.boresightRotAngle),
345 static_cast<RotType>(record.get(keys.rotType)),
346 coord::Observatory(record.get(keys.longitude), record.get(keys.latitude),
347 record.get(keys.elevation)),
348 coord::Weather(record.get(keys.airTemperature), record.get(keys.airPressure),
349 record.get(keys.humidity)),
351 object, hasSimulatedContent));
352 return result;
353 }
354
355 explicit VisitInfoFactory(std::string const& name) : table::io::PersistableFactory(name) {}
356
357private:
358 int getVersion(table::BaseRecord const& record) const {
359 try {
360 // Don't assume version is at same index as in VisitInfoSchema
361 auto versionKey = record.getSchema().find<int>(VisitInfoSchema::VERSION_KEY);
362 return record.get(versionKey.key);
363 } catch (pex::exceptions::NotFoundError const&) {
364 // un-versioned files are implicitly version 0
365 return 0;
366 }
367 }
368};
369
370std::string getVisitInfoPersistenceName() { return "VisitInfo"; }
371
372VisitInfoFactory registration(getVisitInfoPersistenceName());
373
374} // namespace
375
376namespace detail {
377
379 int nstripped = 0;
380
381 std::vector<std::string> keyList = {"EXPID",
382 "EXPTIME",
383 "DARKTIME",
384 "DATE-AVG",
385 "TIMESYS",
386 "TIME-MID",
387 "MJD-AVG-UT1",
388 "AVG-ERA",
389 "BORE-RA",
390 "BORE-DEC",
391 "BORE-AZ",
392 "BORE-ALT",
393 "BORE-AIRMASS",
394 "BORE-ROTANG",
395 "ROTTYPE",
396 "OBS-LONG",
397 "OBS-LAT",
398 "OBS-ELEV",
399 "AIRTEMP",
400 "AIRPRESS",
401 "HUMIDITY",
402 "INSTRUMENT",
403 "IDNUM",
404 "FOCUSZ",
405 "OBSTYPE",
406 "PROGRAM",
407 "REASON",
408 "OBJECT",
409 "HAS-SIMULATED-CONTENT"};
410 for (auto&& key : keyList) {
411 if (metadata.exists(key)) {
412 metadata.remove(key);
413 nstripped++;
414 }
415 }
416 return nstripped;
417}
418
420 if (visitInfo.getExposureId() != 0) {
421 metadata.set("EXPID", visitInfo.getExposureId());
422 }
423 setDouble(metadata, "EXPTIME", visitInfo.getExposureTime(), "Exposure time (sec)");
424 setDouble(metadata, "DARKTIME", visitInfo.getDarkTime(), "Time from CCD flush to readout (sec)");
425 if (visitInfo.getDate().isValid()) {
426 metadata.set("DATE-AVG", visitInfo.getDate().toString(::DateTime::TAI),
427 "TAI date at middle of observation");
428 metadata.set("TIMESYS", "TAI");
429 }
430 setDouble(metadata, "MJD-AVG-UT1", visitInfo.getUt1(), "UT1 MJD date at ctr of obs");
431 setAngle(metadata, "AVG-ERA", visitInfo.getEra(), "Earth rot ang at ctr of obs (deg)");
432 auto boresightRaDec = visitInfo.getBoresightRaDec();
433 setAngle(metadata, "BORE-RA", boresightRaDec[0], "ICRS RA (deg) at boresight");
434 setAngle(metadata, "BORE-DEC", boresightRaDec[1], "ICRS Dec (deg) at boresight");
435 auto boresightAzAlt = visitInfo.getBoresightAzAlt();
436 setAngle(metadata, "BORE-AZ", boresightAzAlt[0], "Refr app topo az (deg) at bore");
437 setAngle(metadata, "BORE-ALT", boresightAzAlt[1], "Refr app topo alt (deg) at bore");
438 setDouble(metadata, "BORE-AIRMASS", visitInfo.getBoresightAirmass(), "Airmass at boresight");
439 setAngle(metadata, "BORE-ROTANG", visitInfo.getBoresightRotAngle(), "Rotation angle (deg) at boresight");
440 metadata.set("ROTTYPE", rotTypeStrFromEnum(visitInfo.getRotType()), "Type of rotation angle");
441 auto observatory = visitInfo.getObservatory();
442 setAngle(metadata, "OBS-LONG", observatory.getLongitude(), "Telescope longitude (+E, deg)");
443 setAngle(metadata, "OBS-LAT", observatory.getLatitude(), "Telescope latitude (deg)");
444 setDouble(metadata, "OBS-ELEV", observatory.getElevation(), "Telescope elevation (m)");
445 auto weather = visitInfo.getWeather();
446 setDouble(metadata, "AIRTEMP", weather.getAirTemperature(), "Outside air temperature (C)");
447 setDouble(metadata, "AIRPRESS", weather.getAirPressure(), "Outdoor air pressure (P)");
448 setDouble(metadata, "HUMIDITY", weather.getHumidity(), "Relative humidity (%)");
449 setString(metadata, "INSTRUMENT", visitInfo.getInstrumentLabel(),
450 "Short name of the instrument that took this data");
451 if (visitInfo.getId() != 0) {
452 metadata.set("IDNUM", visitInfo.getId(), "identifier of this full focal plane exposure");
453 }
454 setDouble(metadata, "FOCUSZ", visitInfo.getFocusZ(), "Defocal distance (mm)");
455 setString(metadata, "OBSTYPE", visitInfo.getObservationType(), "Type of this observation");
456 setString(metadata, "PROGRAM", visitInfo.getScienceProgram(),
457 "observing program (survey or proposal) identifier");
458 setString(metadata, "REASON", visitInfo.getObservationReason(),
459 "reason this observation was taken, or its purpose");
460 setString(metadata, "OBJECT", visitInfo.getObject(), "object of interest or field name");
461 metadata.set("HAS-SIMULATED-CONTENT", visitInfo.getHasSimulatedContent(),
462 "Was any part of this observation simulated?");
463}
464
465} // namespace detail
466
467VisitInfo::VisitInfo(daf::base::PropertySet const& metadata)
468 : _exposureId(0),
469 _exposureTime(nan), // don't use getDouble because str values are also accepted
470 _darkTime(getDouble(metadata, "DARKTIME")),
471 _date(),
472 _ut1(getDouble(metadata, "MJD-AVG-UT1")),
473 _era(getAngle(metadata, "AVG-ERA")),
474 _boresightRaDec(
475 lsst::geom::SpherePoint(getAngle(metadata, "BORE-RA"), getAngle(metadata, "BORE-DEC"))),
476 _boresightAzAlt(
477 lsst::geom::SpherePoint(getAngle(metadata, "BORE-AZ"), getAngle(metadata, "BORE-ALT"))),
478 _boresightAirmass(getDouble(metadata, "BORE-AIRMASS")),
479 _boresightRotAngle(getAngle(metadata, "BORE-ROTANG")),
480 _rotType(RotType::UNKNOWN),
481 _observatory(getAngle(metadata, "OBS-LONG"), getAngle(metadata, "OBS-LAT"),
482 getDouble(metadata, "OBS-ELEV")),
483 _weather(getDouble(metadata, "AIRTEMP"), getDouble(metadata, "AIRPRESS"),
484 getDouble(metadata, "HUMIDITY")),
485 _instrumentLabel(getString(metadata, "INSTRUMENT")),
486 _id(0),
487 _focusZ(getDouble(metadata, "FOCUSZ")),
488 _observationType(getString(metadata, "OBSTYPE")),
489 _scienceProgram(getString(metadata, "PROGRAM")),
490 _observationReason(getString(metadata, "REASON")),
491 _object(getString(metadata, "OBJECT")),
492 // default false for backwards compatibility
493 _hasSimulatedContent(false) {
494 auto key = "EXPID";
495 if (metadata.exists(key) && !metadata.isUndefined(key)) {
496 _exposureId = metadata.getAsInt64(key);
497 }
498 key = "IDNUM";
499 if (metadata.exists(key) && !metadata.isUndefined(key)) {
500 _id = metadata.getAsInt64(key);
501 }
502
503 key = "EXPTIME";
504 if (metadata.exists(key) && !metadata.isUndefined(key)) {
505 try {
506 _exposureTime = metadata.getAsDouble(key);
507 } catch (lsst::pex::exceptions::TypeError& err) {
508 // some old exposures have EXPTIME stored as a string
509 std::string exptimeStr = metadata.getAsString(key);
510 _exposureTime = std::stod(exptimeStr);
511 }
512 }
513
514 key = "DATE-AVG";
515 if (metadata.exists(key) && !metadata.isUndefined(key)) {
516 if (metadata.exists("TIMESYS")) {
517 auto timesysName = boost::algorithm::trim_right_copy(metadata.getAsString("TIMESYS"));
518 if (timesysName != "TAI") {
519 // rather than try to deal with all the possible choices, which requires
520 // appending or deleting a "Z", depending on the time system, just give up.
521 // VisitInfo should be used on FITS headers that have been sanitized!
523 os << "TIMESYS = \"" << timesysName
524 << "\"; VisitInfo requires TIMESYS to exist and to equal \"TAI\"";
526 }
527 } else {
529 "TIMESYS not found; VistitInfo requires TIMESYS to exist and to equal \"TAI\"");
530 }
531 _date = ::DateTime(boost::algorithm::trim_right_copy(metadata.getAsString(key)), ::DateTime::TAI);
532 } else {
533 // DATE-AVG not found. For backwards compatibility look for TIME-MID, an outdated LSST keyword
534 // whose time system was UTC, despite a FITS comment claiming it was TAI. Ignore TIMESYS.
535 key = "TIME-MID";
536 if (metadata.exists(key) && !metadata.isUndefined(key)) {
537 _date = ::DateTime(boost::algorithm::trim_right_copy(metadata.getAsString(key)), ::DateTime::UTC);
538 }
539 }
540
541 key = "ROTTYPE";
542 if (metadata.exists(key) && !metadata.isUndefined(key)) {
543 _rotType = rotTypeEnumFromStr(metadata.getAsString(key));
544 }
545
546 key = "HAS-SIMULATED-CONTENT";
547 if (metadata.exists(key) && !metadata.isUndefined(key)) {
548 _hasSimulatedContent = metadata.getAsBool(key);
549 }
550}
551
558bool _eqOrNan(double lhs, double rhs) noexcept { return (std::isnan(lhs) && std::isnan(rhs)) || lhs == rhs; }
559
567 return (!lhs.isFinite() && !rhs.isFinite()) || lhs == rhs;
568}
569
570bool VisitInfo::operator==(VisitInfo const& other) const {
571 return _exposureId == other.getExposureId() && _eqOrNan(_exposureTime, other.getExposureTime()) &&
572 _eqOrNan(_darkTime, other.getDarkTime()) && _date == other.getDate() &&
573 _eqOrNan(_ut1, other.getUt1()) && _eqOrNan(_era, other.getEra()) &&
574 _eqOrNonFinite(_boresightRaDec, other.getBoresightRaDec()) &&
575 _eqOrNonFinite(_boresightAzAlt, other.getBoresightAzAlt()) &&
576 _eqOrNan(_boresightAirmass, other.getBoresightAirmass()) &&
577 _eqOrNan(_boresightRotAngle, other.getBoresightRotAngle()) && _rotType == other.getRotType() &&
578 _observatory == other.getObservatory() && _weather == other.getWeather() &&
579 _instrumentLabel == other.getInstrumentLabel() && _id == other.getId() &&
580 _eqOrNan(_focusZ, other.getFocusZ()) && _observationType == other.getObservationType() &&
581 _scienceProgram == other.getScienceProgram() &&
582 _observationReason == other.getObservationReason() && _object == other.getObject() &&
583 _hasSimulatedContent == other.getHasSimulatedContent();
584}
585
587 // Completely arbitrary seed
588 return utils::hashCombine(17, _exposureId, _exposureTime, _darkTime, _date, _ut1, _era, _boresightRaDec,
589 _boresightAzAlt, _boresightAirmass, _boresightRotAngle, _rotType, _observatory,
590 _weather, _instrumentLabel, _id, _focusZ, _observationType, _scienceProgram,
591 _observationReason, _object, _hasSimulatedContent);
592}
593
594std::string VisitInfo::getPersistenceName() const { return getVisitInfoPersistenceName(); }
595
597 VisitInfoSchema const& keys = VisitInfoSchema::get();
598 table::BaseCatalog cat = handle.makeCatalog(keys.schema);
600 record->set(keys.exposureId, getExposureId());
601 record->set(keys.exposureTime, getExposureTime());
602 record->set(keys.darkTime, getDarkTime());
603 record->set(keys.tai, getDate().nsecs(::DateTime::TAI));
604 record->set(keys.ut1, getUt1());
605 record->set(keys.era, getEra());
606 record->set(keys.boresightRaDec, getBoresightRaDec());
607 auto boresightAzAlt = getBoresightAzAlt();
608 record->set(keys.boresightAzAlt_az, boresightAzAlt[0]);
609 record->set(keys.boresightAzAlt_alt, boresightAzAlt[1]);
610 record->set(keys.boresightAirmass, getBoresightAirmass());
611 record->set(keys.boresightRotAngle, getBoresightRotAngle());
612 record->set(keys.rotType, static_cast<int>(getRotType()));
613 auto observatory = getObservatory();
614 record->set(keys.latitude, observatory.getLatitude());
615 record->set(keys.longitude, observatory.getLongitude());
616 record->set(keys.elevation, observatory.getElevation());
617 auto weather = getWeather();
618 record->set(keys.airTemperature, weather.getAirTemperature());
619 record->set(keys.airPressure, weather.getAirPressure());
620 record->set(keys.humidity, weather.getHumidity());
621 record->set(keys.instrumentLabel, getInstrumentLabel());
622 record->set(keys.version, SERIALIZATION_VERSION);
623 record->set(keys.idnum, getId());
624 record->set(keys.focusZ, getFocusZ());
625 record->set(keys.observationType, getObservationType());
626 record->set(keys.scienceProgram, getScienceProgram());
627 record->set(keys.observationReason, getObservationReason());
628 record->set(keys.object, getObject());
629 record->set(keys.hasSimulatedContent, getHasSimulatedContent());
630 handle.saveCatalog(cat);
631}
632
634
636
642 double _parallactic_y, _parallactic_x, result;
643 _parallactic_y = sin(getBoresightHourAngle().asRadians());
644 _parallactic_x =
645 cos((getBoresightRaDec()[1]).asRadians()) * tan(getObservatory().getLatitude().asRadians()) -
646 sin((getBoresightRaDec()[1]).asRadians()) * cos(getBoresightHourAngle().asRadians());
647 result = atan2(_parallactic_y, _parallactic_x);
649}
650
652 return std::make_unique<VisitInfo>(*this);
653}
654
655bool VisitInfo::equals(typehandling::Storable const& other) const noexcept {
656 return singleClassEquals(*this, other);
657}
658
660 std::stringstream buffer;
661 buffer << "VisitInfo(";
662 buffer << "exposureId=" << getExposureId() << ", ";
663 buffer << "exposureTime=" << getExposureTime() << ", ";
664 buffer << "darkTime=" << getDarkTime() << ", ";
665 buffer << "date=" << (getDate().isValid() ? getDate().toString(daf::base::DateTime::TAI) : "<invalid>")
666 << ", ";
667 buffer << "UT1=" << getUt1() << ", ";
668 buffer << "ERA=" << getEra() << ", ";
669 buffer << "boresightRaDec=" << getBoresightRaDec() << ", ";
670 buffer << "boresightAzAlt=" << getBoresightAzAlt() << ", ";
671 buffer << "boresightAirmass=" << getBoresightAirmass() << ", ";
672 buffer << "boresightRotAngle=" << getBoresightRotAngle() << ", ";
673 buffer << "rotType=" << static_cast<int>(getRotType()) << ", ";
674 buffer << "observatory=" << getObservatory() << ", ";
675 buffer << "weather=" << getWeather() << ", ";
676 buffer << "instrumentLabel='" << getInstrumentLabel() << "', ";
677 buffer << "id=" << getId() << ", ";
678 buffer << "focusZ=" << getFocusZ() << ", ";
679 buffer << "observationType='" << getObservationType() << "', ";
680 buffer << "scienceProgram='" << getScienceProgram() << "', ";
681 buffer << "observationReason='" << getObservationReason() << "', ";
682 buffer << "object='" << getObject() << "', ";
683 buffer << "hasSimulatedContent=" << std::boolalpha << getHasSimulatedContent();
684 buffer << ")";
685 return buffer.str();
686}
687
689 os << visitInfo.toString();
690 return os;
691}
692
693} // namespace image
694} // namespace afw
695} // namespace lsst
py::object result
Definition: _schema.cc:429
table::Key< std::string > name
Definition: Amplifier.cc:116
#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
table::Key< table::RecordId > exposureId
Definition: VisitInfo.cc:201
#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)
Definition: Observatory.cc:50
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:594
daf::base::DateTime getDate() const
get uniform date and time at middle of exposure
Definition: VisitInfo.h:164
coord::Weather getWeather() const
get basic weather information
Definition: VisitInfo.h:199
lsst::geom::Angle getLocalEra() const
Definition: VisitInfo.cc:633
double getUt1() const
get UT1 (universal time) MJD date at middle of exposure
Definition: VisitInfo.h:167
double getBoresightAirmass() const
get airmass at the boresight, relative to zenith at sea level (and at the middle of the exposure,...
Definition: VisitInfo.h:182
std::string getScienceProgram() const
Definition: VisitInfo.h:217
lsst::geom::Angle getBoresightHourAngle() const
Definition: VisitInfo.cc:635
lsst::geom::Angle getBoresightRotAngle() const
Get rotation angle at boresight at middle of exposure.
Definition: VisitInfo.h:190
table::RecordId getExposureId() const
get exposure ID
Definition: VisitInfo.h:153
std::size_t hash_value() const noexcept override
Return a hash of this object.
Definition: VisitInfo.cc:586
bool operator==(VisitInfo const &other) const
Definition: VisitInfo.cc:570
lsst::geom::Angle getEra() const
get earth rotation angle at middle of exposure
Definition: VisitInfo.h:170
table::RecordId getId() const
Definition: VisitInfo.h:211
double getFocusZ() const
Definition: VisitInfo.h:214
std::string getObservationReason() const
Definition: VisitInfo.h:218
std::string toString() const override
Create a string representation of this object.
Definition: VisitInfo.cc:659
double getExposureTime() const
get exposure duration (shutter open time); (sec)
Definition: VisitInfo.h:158
RotType getRotType() const
get rotation type of boresightRotAngle
Definition: VisitInfo.h:193
bool equals(typehandling::Storable const &other) const noexcept override
Compare this object to another Storable.
Definition: VisitInfo.cc:655
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:178
std::string getObject() const
Definition: VisitInfo.h:219
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:174
std::shared_ptr< typehandling::Storable > cloneStorable() const override
Create a new VisitInfo that is a copy of this one.
Definition: VisitInfo.cc:651
std::string getInstrumentLabel() const
Definition: VisitInfo.h:209
bool getHasSimulatedContent() const
Definition: VisitInfo.h:220
double getDarkTime() const
get time from CCD flush to exposure readout, including shutter open time (despite the name); (sec)
Definition: VisitInfo.h:161
coord::Observatory getObservatory() const
get observatory longitude, latitude and elevation
Definition: VisitInfo.h:196
lsst::geom::Angle getBoresightParAngle() const
Get parallactic angle at the boresight.
Definition: VisitInfo.cc:637
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
Definition: VisitInfo.cc:596
std::string getObservationType() const
Definition: VisitInfo.h:216
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:490
bool isValid() const noexcept
Return true if the key was initialized to valid offset.
Definition: Key.h:97
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.
Definition: Persistable.cc:18
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.
Definition: PropertyList.h:68
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 empty(T... args)
T isfinite(T... args)
T isnan(T... args)
int stripVisitInfoKeywords(daf::base::PropertySet &metadata)
Remove VisitInfo-related keywords from the metadata.
Definition: VisitInfo.cc:378
void setVisitInfoMetadata(daf::base::PropertyList &metadata, VisitInfo const &visitInfo)
Set FITS metadata from a VisitInfo.
Definition: VisitInfo.cc:419
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:566
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:558
lsst::geom::Angle Angle
Definition: misc.h:33
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
STL namespace.
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
Definition: warpExposure.cc:0