-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use obs_metadata for all header translations and unit extraction
Many methods no longer abstract because obs_metadata is handling the conversions. VisitInfo is now derived directly from an ObservationInfo. Leave the existing VisitInfo classes to allow for staged migration of obs packages to the new approach.
- Loading branch information
Showing
5 changed files
with
276 additions
and
103 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
# This file is part of obs_base. | ||
# | ||
# Developed for the LSST Data Management System. | ||
# This product includes software developed by the LSST Project | ||
# (http://www.lsst.org). | ||
# See the COPYRIGHT file at the top-level directory of this distribution | ||
# for details of code ownership. | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
# | ||
|
||
import astropy.units | ||
from astropy.utils import iers | ||
|
||
# This is an unofficial ERFA interface | ||
import astropy._erfa as erfa | ||
|
||
from lsst.log import Log | ||
from lsst.daf.base import DateTime | ||
from lsst.geom import degrees, radians | ||
from lsst.afw.image import VisitInfo, RotType | ||
from lsst.afw.coord import Observatory, Weather | ||
from lsst.geom import SpherePoint | ||
from lsst.obs.metadata import ObservationInfo | ||
|
||
__all__ = ["MakeRawVisitInfoViaObsInfo"] | ||
|
||
|
||
class MakeRawVisitInfoViaObsInfo(object): | ||
"""Base class functor to make a VisitInfo from the FITS header of a | ||
raw image using `~lsst.obs.metadata.ObservationInfo` translators. | ||
Subclasses can be used if a specific | ||
`~lsst.obs.metadata.MetadataTranslator` translator should be used. | ||
The design philosophy is to make a best effort and log warnings of | ||
problems, rather than raising exceptions, in order to extract as much | ||
VisitInfo information as possible from a messy FITS header without the | ||
user needing to add a lot of error handling. | ||
Parameters | ||
---------- | ||
log : `lsst.log.Log` or None | ||
Logger to use for messages. | ||
(None to use ``Log.getLogger("MakeRawVisitInfoViaObsInfo")``). | ||
""" | ||
|
||
metadataTranslator = None | ||
"""Header translator to use to construct VisitInfo, defaulting to | ||
automatic determination.""" | ||
|
||
def __init__(self, log=None): | ||
if log is None: | ||
log = Log.getLogger("MakeRawVisitInfoViaObsInfo") | ||
self.log = log | ||
|
||
def __call__(self, md, exposureId=None): | ||
"""Construct a VisitInfo and strip associated data from the metadata. | ||
Parameters | ||
---------- | ||
md : `lsst.daf.base.PropertyList` or `lsst.daf.base.PropertySet` | ||
Metadata to pull from. | ||
Items that are used are stripped from the metadata. | ||
exposureId : `int`, optional | ||
Ignored. Here for compatibility with `MakeRawVisitInfo`. | ||
Returns | ||
------- | ||
visitInfo : `lsst.afw.image.VisitInfo` | ||
`~lsst.afw.image.VisitInfo` derived from the header using | ||
a `~lsst.obs.metadata.MetadataTranslator`. | ||
""" | ||
argDict = dict() | ||
|
||
obsInfo = ObservationInfo(md, translator_class=self.metadataTranslator) | ||
print(obsInfo.__dict__) | ||
|
||
# Strip all the cards out that were used | ||
for c in obsInfo.cards_used: | ||
del md[c] | ||
|
||
# Map the translated information into a form suitable for VisitInfo | ||
argDict["exposureTime"] = obsInfo.exposure_time | ||
argDict["darkTime"] = obsInfo.dark_time | ||
argDict["exposureId"] = obsInfo.detector_exposure_id | ||
|
||
# VisitInfo uses the middle of the observation for the date | ||
if obsInfo.datetime_begin is not None and obsInfo.datetime_end is not None: | ||
tdelta = obsInfo.datetime_end - obsInfo.datetime_begin | ||
middle = obsInfo.datetime_begin + 0.5*tdelta | ||
|
||
# DateTime uses nanosecond resolution, regardless of the resolution | ||
# of the original date | ||
middle.precision = 9 | ||
# isot is ISO8601 format with "T" separating date and time and no | ||
# time zone | ||
argDict["date"] = DateTime(middle.tai.isot, DateTime.TAI) | ||
|
||
# Derive earth rotation angle from UT1 (being out by a second is not | ||
# a big deal given the uncertainty over exactly what part of the | ||
# observation we are needing it for). | ||
# ERFA needs a UT1 time split into two floats | ||
# We ignore any problems with DUT1 not being defined for now. | ||
try: | ||
ut1time = middle.ut1 | ||
except iers.IERSRangeError: | ||
ut1time = middle | ||
|
||
era = erfa.era00(ut1time.jd1, ut1time.jd2) | ||
argDict["era"] = era * radians | ||
else: | ||
argDict["date"] = DateTime() | ||
|
||
# Coordinates | ||
if obsInfo.tracking_radec is not None: | ||
icrs = obsInfo.tracking_radec.transform_to("icrs") | ||
argDict["boresightRaDec"] = SpherePoint(icrs.ra.degree, | ||
icrs.dec.degree, units=degrees) | ||
|
||
altaz = obsInfo.altaz_begin | ||
if altaz is not None: | ||
argDict["boresightAzAlt"] = SpherePoint(altaz.az.degree, | ||
altaz.alt.degree, units=degrees) | ||
|
||
argDict["boresightAirmass"] = obsInfo.boresight_airmass | ||
|
||
if obsInfo.boresight_rotation_angle is not None: | ||
argDict["boresightRotAngle"] = obsInfo.boresight_rotation_angle.degree*degrees | ||
|
||
if obsInfo.boresight_rotation_coord is not None: | ||
rotType = RotType.UNKNOWN | ||
if obsInfo.boresight_rotation_coord == "sky": | ||
rotType = RotType.SKY | ||
argDict["rotType"] = rotType | ||
|
||
# Weather and Observatory Location | ||
temperature = float("nan") | ||
if obsInfo.temperature is not None: | ||
temperature = obsInfo.temperature.to_value("deg_C", astropy.units.temperature()) | ||
pressure = float("nan") | ||
if obsInfo.pressure is not None: | ||
pressure = obsInfo.pressure.to_value("Pa") | ||
relative_humidity = float("nan") | ||
if obsInfo.relative_humidity is not None: | ||
relative_humidity = obsInfo.relative_humidity | ||
argDict["weather"] = Weather(temperature, pressure, relative_humidity) | ||
|
||
if obsInfo.location is not None: | ||
geolocation = obsInfo.location.to_geodetic() | ||
argDict["observatory"] = Observatory(geolocation.lon.degree*degrees, | ||
geolocation.lat.degree*degrees, | ||
geolocation.height.to_value("m")) | ||
|
||
for key in list(argDict.keys()): # use a copy because we may delete items | ||
if argDict[key] is None: | ||
self.log.warn("argDict[{}] is None; stripping".format(key, argDict[key])) | ||
del argDict[key] | ||
|
||
print("CCCCCCCCCCCCCVC VISIT INFO CCCCCCCCCCCC") | ||
return VisitInfo(**argDict) |
Oops, something went wrong.