Skip to content

Commit

Permalink
Add observationType string field to visitInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
parejkoj committed Aug 31, 2022
1 parent 3dc61fd commit ea50d19
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 18 deletions.
11 changes: 8 additions & 3 deletions include/lsst/afw/image/VisitInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class VisitInfo : public table::io::PersistableFacade<VisitInfo>, public typehan
* @param[in] id Identifier of this full focal plane data.
* @param[in] focusZ Defocal distance of main-cam hexapod in mm. 0 is in focus.;
* Extra-focal is negative while intra-focal is positive.
* @param[in] observationType Type of this observation (e.g. science, dark, flat, bias, focus).
*/
// TODO: remove exposureId on DM-32138
explicit VisitInfo(table::RecordId exposureId, double exposureTime, double darkTime,
Expand All @@ -97,8 +98,8 @@ class VisitInfo : public table::io::PersistableFacade<VisitInfo>, public typehan
lsst::geom::SpherePoint const &boresightAzAlt, double boresightAirmass,
lsst::geom::Angle const &boresightRotAngle, RotType const &rotType,
coord::Observatory const &observatory, coord::Weather const &weather,
std::string const &instrumentLabel, table::RecordId const &id,
double focusZ)
std::string const &instrumentLabel, table::RecordId const &id, double focusZ,
std::string const &observationType)
: _exposureId(exposureId),
_exposureTime(exposureTime),
_darkTime(darkTime),
Expand All @@ -114,7 +115,8 @@ class VisitInfo : public table::io::PersistableFacade<VisitInfo>, public typehan
_weather(weather),
_instrumentLabel(instrumentLabel),
_id(id),
_focusZ(focusZ){};
_focusZ(focusZ),
_observationType(observationType){};

explicit VisitInfo(daf::base::PropertySet const &metadata);

Expand Down Expand Up @@ -200,6 +202,8 @@ class VisitInfo : public table::io::PersistableFacade<VisitInfo>, public typehan
// get defocal distance (mm)
double getFocusZ() const { return _focusZ; }

std::string getObservationType() const { return _observationType; }

/**
* Get parallactic angle at the boresight
*
Expand Down Expand Up @@ -246,6 +250,7 @@ class VisitInfo : public table::io::PersistableFacade<VisitInfo>, public typehan
std::string _instrumentLabel;
table::RecordId _id;
double _focusZ;
std::string _observationType;
};

std::ostream &operator<<(std::ostream &os, VisitInfo const &visitInfo);
Expand Down
6 changes: 4 additions & 2 deletions python/lsst/afw/image/_visitInfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void declareVisitInfo(lsst::utils::python::WrapperCollection &wrappers) {
lsst::geom::Angle const &, lsst::geom::SpherePoint const &,
lsst::geom::SpherePoint const &, double, lsst::geom::Angle const &,
RotType const &, coord::Observatory const &, coord::Weather const &,
std::string const &, table::RecordId const &, double>(),
std::string const &, table::RecordId const &, double, std::string const &>(),
"exposureId"_a = 0, "exposureTime"_a = nan, "darkTime"_a = nan,
"date"_a = daf::base::DateTime(), "ut1"_a = nan, "era"_a = nanAngle,
"boresightRaDec"_a = lsst::geom::SpherePoint(nanAngle, nanAngle),
Expand All @@ -73,7 +73,7 @@ void declareVisitInfo(lsst::utils::python::WrapperCollection &wrappers) {
"rotType"_a = RotType::UNKNOWN,
"observatory"_a = coord::Observatory(nanAngle, nanAngle, nan),
"weather"_a = coord::Weather(nan, nan, nan), "instrumentLabel"_a = "", "id"_a = 0,
"focusZ"_a = nan);
"focusZ"_a = nan, "observationType"_a = "");
cls.def(py::init<daf::base::PropertySet const &>(), "metadata"_a);
cls.def(py::init<VisitInfo const &>(), "visitInfo"_a);

Expand Down Expand Up @@ -108,6 +108,7 @@ void declareVisitInfo(lsst::utils::python::WrapperCollection &wrappers) {
cls.def("getInstrumentLabel", &VisitInfo::getInstrumentLabel);
cls.def("getId", &VisitInfo::getId);
cls.def("getFocusZ", &VisitInfo::getFocusZ);
cls.def("getObservationType", &VisitInfo::getObservationType);

/* readonly property accessors */
cls.def_property_readonly("exposureTime", &VisitInfo::getExposureTime);
Expand All @@ -129,6 +130,7 @@ void declareVisitInfo(lsst::utils::python::WrapperCollection &wrappers) {
cls.def_property_readonly("instrumentLabel", &VisitInfo::getInstrumentLabel);
cls.def_property_readonly("id", &VisitInfo::getId);
cls.def_property_readonly("focusZ", &VisitInfo::getFocusZ);
cls.def_property_readonly("observationType", &VisitInfo::getObservationType);

utils::python::addOutputOp(cls, "__repr__");
});
Expand Down
3 changes: 2 additions & 1 deletion src/image/ExposureInfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ void ExposureInfo::setId(table::RecordId id) {
oldVisitInfo->getBoresightRaDec(), oldVisitInfo->getBoresightAzAlt(),
oldVisitInfo->getBoresightAirmass(), oldVisitInfo->getBoresightRotAngle(),
oldVisitInfo->getRotType(), oldVisitInfo->getObservatory(), oldVisitInfo->getWeather(),
oldVisitInfo->getInstrumentLabel(), oldVisitInfo->getId(), oldVisitInfo->getFocusZ());
oldVisitInfo->getInstrumentLabel(), oldVisitInfo->getId(), oldVisitInfo->getFocusZ(),
oldVisitInfo->getObservationType());
// Do not call setVisitInfo, to avoid recursion
_visitInfo = newVisitInfo;
}
Expand Down
27 changes: 19 additions & 8 deletions src/image/VisitInfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ namespace {
// 1: file versioning, instrument label
// 2: id field
// 3: focusZ field
int constexpr SERIALIZATION_VERSION = 3;
// 4: observationType field
int constexpr SERIALIZATION_VERSION = 4;

auto const nan = std::numeric_limits<double>::quiet_NaN();

Expand Down Expand Up @@ -225,6 +226,8 @@ class VisitInfoSchema {

table::Key<double> focusZ;

table::Key<std::string> observationType;

static std::string const VERSION_KEY;

static VisitInfoSchema const& get() {
Expand Down Expand Up @@ -288,7 +291,10 @@ class VisitInfoSchema {
idnum(schema.addField<table::RecordId>("idnum", "identifier of this full focal plane exposure",
"")),

focusZ(schema.addField<double>("focusz", "defocal distance", "mm")) {}
focusZ(schema.addField<double>("focusz", "defocal distance", "mm")),

observationType(
schema.addField<std::string>("observationType", "type of this observation", "", 0)) {}
};
std::string const VisitInfoSchema::VERSION_KEY = "version";

Expand All @@ -310,6 +316,7 @@ class VisitInfoFactory : public table::io::PersistableFactory {
std::string instrumentLabel = version >= 1 ? record.get(keys.instrumentLabel) : "";
table::RecordId id = version >= 2 ? record.get(keys.idnum) : 0;
double focusZ = version >= 3 ? record.get(keys.focusZ) : nan;
std::string observationType = version >= 4 ? record.get(keys.observationType) : "";

std::shared_ptr<VisitInfo> result(
new VisitInfo(record.get(keys.exposureId), record.get(keys.exposureTime),
Expand All @@ -323,7 +330,7 @@ class VisitInfoFactory : public table::io::PersistableFactory {
record.get(keys.elevation)),
coord::Weather(record.get(keys.airTemperature), record.get(keys.airPressure),
record.get(keys.humidity)),
instrumentLabel, id, focusZ));
instrumentLabel, id, focusZ, observationType));
return result;
}

Expand Down Expand Up @@ -357,7 +364,7 @@ int stripVisitInfoKeywords(daf::base::PropertySet& metadata) {
"TIME-MID", "MJD-AVG-UT1", "AVG-ERA", "BORE-RA", "BORE-DEC",
"BORE-AZ", "BORE-ALT", "BORE-AIRMASS", "BORE-ROTANG", "ROTTYPE",
"OBS-LONG", "OBS-LAT", "OBS-ELEV", "AIRTEMP", "AIRPRESS",
"HUMIDITY", "INSTRUMENT", "IDNUM", "FOCUSZ"};
"HUMIDITY", "INSTRUMENT", "IDNUM", "FOCUSZ", "OBSTYPE"};
for (auto&& key : keyList) {
if (metadata.exists(key)) {
metadata.remove(key);
Expand Down Expand Up @@ -403,6 +410,7 @@ void setVisitInfoMetadata(daf::base::PropertyList& metadata, VisitInfo const& vi
metadata.set("IDNUM", visitInfo.getId(), "identifier of this full focal plane exposure");
}
setDouble(metadata, "FOCUSZ", visitInfo.getFocusZ(), "Defocal distance (mm)");
setString(metadata, "OBSTYPE", visitInfo.getObservationType(), "Type of this observation");
}

} // namespace detail
Expand All @@ -427,7 +435,8 @@ VisitInfo::VisitInfo(daf::base::PropertySet const& metadata)
getDouble(metadata, "HUMIDITY")),
_instrumentLabel(getString(metadata, "INSTRUMENT")),
_id(0),
_focusZ(getDouble(metadata, "FOCUSZ")) {
_focusZ(getDouble(metadata, "FOCUSZ")),
_observationType(getString(metadata, "OBSTYPE")) {
auto key = "EXPID";
if (metadata.exists(key)) {
_exposureId = metadata.getAsInt64(key);
Expand Down Expand Up @@ -509,14 +518,14 @@ bool VisitInfo::operator==(VisitInfo const& other) const {
_eqOrNan(_boresightRotAngle, other.getBoresightRotAngle()) && _rotType == other.getRotType() &&
_observatory == other.getObservatory() && _weather == other.getWeather() &&
_instrumentLabel == other.getInstrumentLabel() && _id == other.getId() &&
_eqOrNan(_focusZ, other.getFocusZ());
_eqOrNan(_focusZ, other.getFocusZ()) && _observationType == other.getObservationType();
}

std::size_t VisitInfo::hash_value() const noexcept {
// Completely arbitrary seed
return utils::hashCombine(17, _exposureId, _exposureTime, _darkTime, _date, _ut1, _era, _boresightRaDec,
_boresightAzAlt, _boresightAirmass, _boresightRotAngle, _rotType, _observatory,
_weather, _instrumentLabel, _id, _focusZ);
_weather, _instrumentLabel, _id, _focusZ, _observationType);
}

std::string VisitInfo::getPersistenceName() const { return getVisitInfoPersistenceName(); }
Expand Down Expand Up @@ -550,6 +559,7 @@ void VisitInfo::write(OutputArchiveHandle& handle) const {
record->set(keys.version, SERIALIZATION_VERSION);
record->set(keys.idnum, getId());
record->set(keys.focusZ, getFocusZ());
record->set(keys.observationType, getObservationType());
handle.saveCatalog(cat);
}

Expand Down Expand Up @@ -598,7 +608,8 @@ std::string VisitInfo::toString() const {
buffer << "weather=" << getWeather() << ", ";
buffer << "instrumentLabel='" << getInstrumentLabel() << "', ";
buffer << "id=" << getId() << ", ";
buffer << "focusZ=" << getFocusZ();
buffer << "focusZ=" << getFocusZ() << ", ";
buffer << "observationType='" << getObservationType() << "'";
buffer << ")";
return buffer.str();
}
Expand Down
4 changes: 4 additions & 0 deletions tests/data/visitInfo-version-4.fits

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions tests/test_imageHash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ BOOST_AUTO_TEST_CASE(VisitInfoHash) {
45.1 * degrees, lsst::geom::SpherePoint(23.1 * degrees, 73.2 * degrees),
lsst::geom::SpherePoint(134.5 * degrees, 33.3 * degrees), 1.73, 73.2 * degrees,
RotType::SKY, coord::Observatory(11.1 * degrees, 22.2 * degrees, 0.333),
coord::Weather(1.1, 2.2, 34.5), "testCam1", 123456, 1.5);
coord::Weather(1.1, 2.2, 34.5), "testCam1", 123456, 1.5, "test");
VisitInfo info2(10313423, 10.01, 11.02, DateTime(65321.1, DateTime::MJD, DateTime::TAI), 12345.1,
45.1 * degrees, lsst::geom::SpherePoint(23.1 * degrees, 73.2 * degrees),
lsst::geom::SpherePoint(134.5 * degrees, 33.3 * degrees), 1.73, 73.2 * degrees,
RotType::SKY, coord::Observatory(11.1 * degrees, 22.2 * degrees, 0.333),
coord::Weather(1.1, 2.2, 34.5), "testCam1", 123456, 1.5);
coord::Weather(1.1, 2.2, 34.5), "testCam1", 123456, 1.5, "test");

utils::assertHashesEqual(info1, info2);
}
Expand Down
25 changes: 23 additions & 2 deletions tests/test_visitInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def makeVisitInfo(data):
data.instrumentLabel,
data.id,
data.focusZ,
data.observationType
)


Expand Down Expand Up @@ -97,6 +98,7 @@ def computeLstHA(data):
'instrumentLabel',
'id',
'focusZ',
'observationType',
]
VisitInfoData = collections.namedtuple("VisitInfoData", fields)
data1 = VisitInfoData(exposureId=10313423,
Expand All @@ -119,6 +121,7 @@ def computeLstHA(data):
instrumentLabel="TestCameraOne",
id=987654,
focusZ=1.5,
observationType="flat",
)
self.data1 = data1
self.localEra1, self.hourAngle1 = computeLstHA(data1)
Expand All @@ -141,6 +144,7 @@ def computeLstHA(data):
instrumentLabel="TestCameraTwo",
id=123456,
focusZ=-0.7,
observationType="science",
)
self.data2 = data2
self.localEra2, self.hourAngle2 = computeLstHA(data2)
Expand Down Expand Up @@ -168,6 +172,7 @@ def _testValueConstructor(self, data, localEra, hourAngle):
self.assertEqual(visitInfo.getBoresightHourAngle(), hourAngle)
self.assertEqual(visitInfo.getId(), data.id)
self.assertEqual(visitInfo.getFocusZ(), data.focusZ)
self.assertEqual(visitInfo.getObservationType(), data.observationType)

def _testProperties(self, data, localEra, hourAngle):
"""Test property attribute accessors."""
Expand All @@ -189,6 +194,7 @@ def _testProperties(self, data, localEra, hourAngle):
self.assertEqual(visitInfo.boresightHourAngle, hourAngle)
self.assertEqual(visitInfo.id, data.id)
self.assertEqual(visitInfo.focusZ, data.focusZ)
self.assertEqual(visitInfo.observationType, data.observationType)

def testValueConstructor_data1(self):
self._testValueConstructor(self.data1, self.localEra1, self.hourAngle1)
Expand Down Expand Up @@ -254,6 +260,10 @@ def _testFitsRead(self, data, filePath, version):
self.assertEqual(visitInfo.getFocusZ(), data.focusZ)
else:
self.assertTrue(math.isnan(visitInfo.getFocusZ()))
if version >= 4:
self.assertEqual(visitInfo.getObservationType(), data.observationType)
else:
self.assertEqual(visitInfo.getObservationType(), "")

def testPersistenceVersions(self):
"""Test that older versions are handled appropriately.
Expand All @@ -265,13 +275,14 @@ def testPersistenceVersions(self):
self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-1.fits"), 1)
self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-2.fits"), 2)
self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-3.fits"), 3)
self._testFitsRead(self.data1, os.path.join(dataDir, "visitInfo-version-4.fits"), 4)

def testSetVisitInfoMetadata(self):
for item in (self.data1, self.data2):
visitInfo = makeVisitInfo(item)
metadata = PropertyList()
afwImage.setVisitInfoMetadata(metadata, visitInfo)
self.assertEqual(metadata.nameCount(), 23)
self.assertEqual(metadata.nameCount(), 24)
self.assertEqual(metadata.getScalar("EXPID"), item.exposureId)
self.assertEqual(metadata.getScalar("EXPTIME"), item.exposureTime)
self.assertEqual(metadata.getScalar("DARKTIME"), item.darkTime)
Expand Down Expand Up @@ -312,6 +323,8 @@ def testSetVisitInfoMetadata(self):
item.id)
self.assertEqual(metadata.getScalar("FOCUSZ"),
item.focusZ)
self.assertEqual(metadata.getScalar("OBSTYPE"),
item.observationType)

def testSetVisitInfoMetadataMissingValues(self):
"""If a value is unknown then it should not be written to the metadata"""
Expand All @@ -329,7 +342,7 @@ def testStripVisitInfoKeywords(self):
afwImage.setVisitInfoMetadata(metadata, visitInfo)
# add an extra keyword that will not be stripped
metadata.set("EXTRA", 5)
self.assertEqual(metadata.nameCount(), 24)
self.assertEqual(metadata.nameCount(), 25)
afwImage.stripVisitInfoKeywords(metadata)
self.assertEqual(metadata.nameCount(), 1)

Expand Down Expand Up @@ -364,6 +377,7 @@ def _testIsEmpty(self, visitInfo):
self.assertEqual(visitInfo.getInstrumentLabel(), "")
self.assertEqual(visitInfo.getId(), 0)
self.assertTrue(math.isnan(visitInfo.getFocusZ()))
self.assertTrue(visitInfo.getFocusZ(), "")

def testEquals(self):
"""Test that identical VisitInfo objects compare equal, even if some fields are NaN.
Expand Down Expand Up @@ -525,6 +539,10 @@ def testMetadataConstructor(self):
visitInfo = afwImage.VisitInfo(metadata)
self.assertEqual(visitInfo.getFocusZ(), data.focusZ)

metadata = propertySetFromDict({"OBSTYPE": data.observationType})
visitInfo = afwImage.VisitInfo(metadata)
self.assertEqual(visitInfo.getObservationType(), data.observationType)

def testConstructorKeywordArguments(self):
"""Test VisitInfo with named arguments"""
data = self.data1
Expand Down Expand Up @@ -585,6 +603,9 @@ def testConstructorKeywordArguments(self):
visitInfo = afwImage.VisitInfo(focusZ=data.focusZ)
self.assertEqual(visitInfo.getFocusZ(), data.focusZ)

visitInfo = afwImage.VisitInfo(observationType=data.observationType)
self.assertEqual(visitInfo.getObservationType(), data.observationType)

def testGoodRotTypes(self):
"""Test round trip of all valid rot types"""
for rotType in RotTypeEnumNameDict:
Expand Down

0 comments on commit ea50d19

Please sign in to comment.