Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DM-26696: Support new fix_header API #267

Merged
merged 3 commits into from
Nov 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 7 additions & 3 deletions python/lsst/obs/lsst/translators/comCam.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def can_translate(cls, header, filename=None):
return False

@classmethod
def fix_header(cls, header):
def fix_header(cls, header, instrument, obsid, filename=None):
"""Fix ComCam headers.

Notes
Expand All @@ -91,16 +91,20 @@ def fix_header(cls, header):
value and assuming that the ComCam detectors are fixed.

Corrections are reported as debug level log messages.

See `~astro_metadata_translator.fix_header` for details of the general
process.
"""
modified = False

obsid = header.get("OBSID", "unknown")
# Calculate the standard label to use for log messages
log_label = cls._construct_log_prefix(obsid, filename)

if "LSST_NUM" not in header:
slot = header.get("CCDSLOT", None)
if slot in DETECTOR_SERIALS:
header["LSST_NUM"] = DETECTOR_SERIALS[slot]
modified = True
log.debug("%s: Set LSST_NUM to %s", obsid, header["LSST_NUM"])
log.debug("%s: Set LSST_NUM to %s", log_label, header["LSST_NUM"])

return modified
2 changes: 1 addition & 1 deletion python/lsst/obs/lsst/translators/imsim.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def to_physical_filter(self):
break
if throughputs_version is None:
log.warning("%s: throughputs version not found. Using FILTER keyword value '%s'.",
self.to_observation_id(), self._header["FILTER"])
self._log_prefix, self._header["FILTER"])
return self._header["FILTER"]
return "_".join((self._header["FILTER"], "sim", throughputs_version))

Expand Down
63 changes: 39 additions & 24 deletions python/lsst/obs/lsst/translators/latiss.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def is_non_science_or_lab(self):

# This is a science observation on the mountain so we should not
# use defaults
raise KeyError("Required key is missing and this is a mountain science observation")
raise KeyError(f"{self._log_prefix}: Required key is missing and this is a mountain science observation")


class LatissTranslator(LsstBaseTranslator):
Expand Down Expand Up @@ -167,13 +167,21 @@ def can_translate(cls, header, filename=None):
return False

@classmethod
def fix_header(cls, header):
def fix_header(cls, header, instrument, obsid, filename=None):
"""Fix an incorrect LATISS header.

Parameters
----------
header : `dict`
The header to update. Updates are in place.
instrument : `str`
The name of the instrument.
obsid : `str`
Unique observation identifier associated with this header.
Will always be provided.
filename : `str`, optional
Filename associated with this header. May not be set since headers
can be fixed independently of any filename being known.

Returns
-------
Expand All @@ -196,16 +204,23 @@ def fix_header(cls, header):
* SHUTTIME is always forced to be `None`.

Corrections are reported as debug level log messages.

See `~astro_metadata_translator.fix_header` for details of the general
process.
"""
modified = False

# Calculate the standard label to use for log messages
log_label = cls._construct_log_prefix(obsid, filename)

if "OBSID" not in header:
# Very old data used IMGNAME
header["OBSID"] = header.get("IMGNAME", "unknown")
header["OBSID"] = obsid
modified = True
log.debug("Assigning OBSID to a value of '%s'", header["OBSID"])

obsid = header["OBSID"]
# We are reporting the OBSID so no need to repeat it at start
# of log message. Use filename if we have it.
log_prefix = f"{filename}: " if filename else ""
log.debug("%sAssigning OBSID to a value of '%s'", log_prefix, header["OBSID"])

if "DAYOBS" not in header:
# OBS-NITE could have the value for DAYOBS but it is safer
Expand All @@ -219,9 +234,9 @@ def fix_header(cls, header):
pass
if dayObs is None or len(dayObs) != 8:
dayObs = header["OBS-NITE"]
log.debug("%s: Setting DAYOBS to '%s' from OBS-NITE header", obsid, dayObs)
log.debug("%s: Setting DAYOBS to '%s' from OBS-NITE header", log_label, dayObs)
else:
log.debug("%s: Setting DAYOBS to '%s' from OBSID", obsid, dayObs)
log.debug("%s: Setting DAYOBS to '%s' from OBSID", log_label, dayObs)
header["DAYOBS"] = dayObs
modified = True

Expand All @@ -234,7 +249,7 @@ def fix_header(cls, header):
else:
header["SEQNUM"] = int(seqnum)
modified = True
log.debug("%s: Extracting SEQNUM of '%s' from OBSID", obsid, header["SEQNUM"])
log.debug("%s: Extracting SEQNUM of '%s' from OBSID", log_label, header["SEQNUM"])

# The DATE-OBS / MJD-OBS keys can be 1970
if header["DATE-OBS"].startswith("1970"):
Expand All @@ -250,15 +265,15 @@ def fix_header(cls, header):
header["DATE-END"] = None
header["MJD-END"] = None

log.debug("%s: Forcing 1970 dates to '%s'", obsid, header["DATE"])
log.debug("%s: Forcing 1970 dates to '%s'", log_label, header["DATE"])
modified = True

# Create a translator since we need the date
translator = cls(header)
date = translator.to_datetime_begin()
if date > DETECTOR_068_DATE:
header["LSST_NUM"] = "ITL-3800C-068"
log.debug("%s: Forcing detector serial to %s", obsid, header["LSST_NUM"])
log.debug("%s: Forcing detector serial to %s", log_label, header["LSST_NUM"])
modified = True

if date < DATE_END_IS_BAD:
Expand All @@ -268,7 +283,7 @@ def fix_header(cls, header):
header["DATE-END"] = None
header["MJD-END"] = None

log.debug("%s: Clearing DATE-END as being untrustworthy", obsid)
log.debug("%s: Clearing DATE-END as being untrustworthy", log_label)
modified = True

# Up until a certain date GROUPID was the IMGTYPE
Expand All @@ -289,7 +304,7 @@ def fix_header(cls, header):
else:
header["GROUPID"] = None
header["IMGTYPE"] = groupId
log.debug("%s: Setting IMGTYPE to '%s' from GROUPID", obsid, header["IMGTYPE"])
log.debug("%s: Setting IMGTYPE to '%s' from GROUPID", log_label, header["IMGTYPE"])
modified = True
else:
# Someone could be fixing headers in old data
Expand All @@ -304,45 +319,45 @@ def fix_header(cls, header):
if imgType == "OBJECT":
header["IMGTYPE"] = "ENGTEST"
log.debug("%s: Changing OBJECT observation type to %s",
obsid, header["IMGTYPE"])
log_label, header["IMGTYPE"])
modified = True

# Early on the RA/DEC headers were stored in radians
if date < RADEC_IS_RADIANS:
if header.get("RA") is not None:
header["RA"] *= RAD2DEG
log.debug("%s: Changing RA header to degrees", obsid)
log.debug("%s: Changing RA header to degrees", log_label)
modified = True
if header.get("DEC") is not None:
header["DEC"] *= RAD2DEG
log.debug("%s: Changing DEC header to degrees", obsid)
log.debug("%s: Changing DEC header to degrees", log_label)
modified = True

if header.get("SHUTTIME"):
log.debug("%s: Forcing SHUTTIME header to be None", obsid)
log.debug("%s: Forcing SHUTTIME header to be None", log_label)
header["SHUTTIME"] = None
modified = True

if "OBJECT" not in header:
# Only patch OBJECT IMGTYPE
if "IMGTYPE" in header and header["IMGTYPE"] == "OBJECT":
log.debug("%s: Forcing OBJECT header to exist", obsid)
log.debug("%s: Forcing OBJECT header to exist", log_label)
header["OBJECT"] = "NOTSET"
modified = True

if "RADESYS" in header:
if header["RADESYS"] == "":
# Default to ICRS
header["RADESYS"] = "ICRS"
log.debug("%s: Forcing blank RADESYS to '%s'", obsid, header["RADESYS"])
log.debug("%s: Forcing blank RADESYS to '%s'", log_label, header["RADESYS"])
modified = True

if date < RASTART_IS_BAD:
# The wrong telescope position was used. Unsetting these will force
# the RA/DEC demand headers to be used instead.
for h in ("RASTART", "DECSTART", "RAEND", "DECEND"):
header[h] = None
log.debug("%s: Forcing derived RA/Dec headers to undefined", obsid)
log.debug("%s: Forcing derived RA/Dec headers to undefined", log_label)

return modified

Expand Down Expand Up @@ -394,7 +409,7 @@ def to_dark_time(self):
reason = "Dark time not defined."

log.warning("%s: %s Setting dark time to the exposure time.",
self.to_observation_id(), reason)
self._log_prefix, reason)
return exptime

@cache_translation
Expand All @@ -409,7 +424,7 @@ def to_exposure_time(self):
# A missing or undefined EXPTIME is problematic. Set to -1
# to indicate that none was found.
log.warning("%s: Insufficient information to derive exposure time. Setting to -1.0s",
self.to_observation_id())
self._log_prefix)
return -1.0 * u.s

@cache_translation
Expand Down Expand Up @@ -457,7 +472,7 @@ def to_observation_type(self):
else:
obstype = "unknown"
log.warning("%s: Unable to determine observation type. Guessing '%s'",
self.to_observation_id(), obstype)
self._log_prefix, obstype)
return obstype

@cache_translation
Expand Down Expand Up @@ -533,5 +548,5 @@ def to_boresight_airmass(self):
return altaz.secz.to_value()

log.warning("%s: Unable to determine airmass of a science observation, returning 1.",
self.to_observation_id())
self._log_prefix)
return 1.0
6 changes: 3 additions & 3 deletions python/lsst/obs/lsst/translators/lsst.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ def to_dark_time(self):
self._used_these_cards("DARKTIME")
else:
log.warning("%s: Unable to determine dark time. Setting from exposure time.",
self.to_observation_id())
self._log_prefix)
darktime = self.to_exposure_time()
return darktime

Expand Down Expand Up @@ -711,7 +711,7 @@ def _determine_primary_filter(self):
obstype = self.to_observation_type()
if obstype not in ("bias", "dark"):
log.warning("%s: Unable to determine the filter",
self.to_observation_id())
self._log_prefix)

return physical_filter

Expand Down Expand Up @@ -753,5 +753,5 @@ def to_observation_counter(self):

# This indicates a problem so we warn and return a 0
log.warning("%s: Unable to determine the observation counter so returning 0",
self.to_observation_id())
self._log_prefix)
return 0
25 changes: 17 additions & 8 deletions python/lsst/obs/lsst/translators/lsstCam.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def is_non_science_or_lab(self):
return
if not self._is_on_mountain():
return
raise KeyError("Required key is missing and this is a mountain science observation")
raise KeyError(f"{self._log_prefix}: Required key is missing and this is a mountain science observation")


class LsstCamTranslator(LsstBaseTranslator):
Expand Down Expand Up @@ -80,21 +80,30 @@ class LsstCamTranslator(LsstBaseTranslator):
cameraPolicyFile = "policy/lsstCam.yaml"

@classmethod
def fix_header(cls, header):
"""See https://astro-metadata-translator.lsst.io/py-api/astro_metadata_translator.FitsTranslator.html#astro_metadata_translator.FitsTranslator.fix_header""" # noqa: E501, W505
def fix_header(cls, header, instrument, obsid, filename=None):
"""Fix LSSTCam headers.

Notes
-----
See `~astro_metadata_translator.fix_header` for details of the general
process.
"""

modified = False

# Calculate the standard label to use for log messages
log_label = cls._construct_log_prefix(obsid, filename)

if "FILTER" not in header and header.get("FILTER2") is not None:
obsid = header.get("OBSID", "unknown")
ccdslot = header.get("CCDSLOT", "unknown")
raftbay = header.get("RAFTBAY", "unknown")

log.warn("%s %s_%s: No FILTER key found but FILTER2=\"%s\" (removed)",
obsid, raftbay, ccdslot, header["FILTER2"])
log_label, raftbay, ccdslot, header["FILTER2"])
header["FILTER2"] = None
modified = True

return True

return False
return modified

@classmethod
def can_translate(cls, header, filename=None):
Expand Down
2 changes: 1 addition & 1 deletion python/lsst/obs/lsst/translators/lsst_ucdcam.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def to_physical_filter(self):
return self._header["FILTER"].lower()
else:
log.warning("%s: FILTER key not found in header (assuming NONE)",
self.to_observation_id())
self._log_prefix)
return "NONE"

def to_exposure_id(self):
Expand Down
6 changes: 3 additions & 3 deletions python/lsst/obs/lsst/translators/ts8.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def to_detector_group(self):
match = re.search(r"(RTM-\d\d\d)", raft_name)
if match:
return match.group(0)
raise ValueError(f"RAFTNAME has unexpected form of '{raft_name}'")
raise ValueError(f"{self._log_prefix}: RAFTNAME has unexpected form of '{raft_name}'")

@cache_translation
def to_detector_serial(self):
Expand Down Expand Up @@ -206,7 +206,7 @@ def to_physical_filter(self):
self._used_these_cards("FILTPOS")
except KeyError:
log.warning("%s: FILTPOS key not found in header (assuming NONE)",
self.to_observation_id())
self._log_prefix)
return "NONE"

try:
Expand All @@ -219,7 +219,7 @@ def to_physical_filter(self):
}[filter_pos]
except KeyError:
log.warning("%s: Unknown filter position (assuming NONE): %d",
self.to_observation_id(), filter_pos)
self._log_prefix, filter_pos)
return "NONE"

def to_exposure_id(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ def test_checker(self):
from astro_metadata_translator.tests import read_test_file
from astro_metadata_translator import ObservationInfo
header = read_test_file(filename, self.datadir)
obsInfo = ObservationInfo(header, pedantic=True)
obsInfo = ObservationInfo(header, pedantic=True, filename=filename)
self.assertTrue(obsInfo)


Expand Down