24 import astropy.utils.exceptions
25 from astropy.utils
import iers
31 import astropy._erfa
as erfa
33 from astro_metadata_translator
import ObservationInfo
35 from lsst.log
import Log
36 from lsst.daf.base
import DateTime
37 from lsst.geom
import degrees, radians
38 from lsst.afw.image
import VisitInfo, RotType
39 from lsst.afw.coord
import Observatory, Weather
40 from lsst.geom
import SpherePoint
42 __all__ = [
"MakeRawVisitInfoViaObsInfo"]
46 """Base class functor to make a VisitInfo from the FITS header of a
47 raw image using `~astro_metadata_translator.ObservationInfo` translators.
49 Subclasses can be used if a specific
50 `~astro_metadata_translator.MetadataTranslator` translator should be used.
52 The design philosophy is to make a best effort and log warnings of
53 problems, rather than raising exceptions, in order to extract as much
54 VisitInfo information as possible from a messy FITS header without the
55 user needing to add a lot of error handling.
59 log : `lsst.log.Log` or None
60 Logger to use for messages.
61 (None to use ``Log.getLogger("MakeRawVisitInfoViaObsInfo")``).
62 doStripHeader : `bool`, optional
63 Strip header keywords from the metadata as they are used?
66 metadataTranslator =
None
67 """Header translator to use to construct VisitInfo, defaulting to
68 automatic determination."""
70 def __init__(self, log=None, doStripHeader=False):
72 log = Log.getLogger(
"MakeRawVisitInfoViaObsInfo")
77 """Construct a VisitInfo and strip associated data from the metadata.
81 md : `lsst.daf.base.PropertyList` or `lsst.daf.base.PropertySet`
82 Metadata to pull from.
83 May be modified if ``stripHeader`` is ``True``.
84 exposureId : `int`, optional
85 Ignored. Here for compatibility with `MakeRawVisitInfo`.
89 visitInfo : `lsst.afw.image.VisitInfo`
90 `~lsst.afw.image.VisitInfo` derived from the header using
91 a `~astro_metadata_translator.MetadataTranslator`.
98 for c
in obsInfo.cards_used:
105 """Construct a `~lsst.afw.image.VisitInfo` from an
106 `~astro_metadata_translator.ObservationInfo`
110 obsInfo : `astro_metadata_translator.ObservationInfo`
111 Information gathered from the observation metadata.
112 log : `logging.Logger` or `lsst.log.Log`, optional
113 Logger to use for logging informational messages.
114 If `None` logging will be disabled.
118 visitInfo : `lsst.afw.image.VisitInfo`
119 `~lsst.afw.image.VisitInfo` derived from the supplied
120 `~astro_metadata_translator.ObservationInfo`.
125 if obsInfo.exposure_time
is not None:
126 argDict[
"exposureTime"] = obsInfo.exposure_time.to_value(
"s")
127 if obsInfo.dark_time
is not None:
128 argDict[
"darkTime"] = obsInfo.dark_time.to_value(
"s")
129 argDict[
"exposureId"] = obsInfo.detector_exposure_id
132 if obsInfo.datetime_begin
is not None and obsInfo.datetime_end
is not None:
133 tdelta = obsInfo.datetime_end - obsInfo.datetime_begin
134 middle = obsInfo.datetime_begin + 0.5*tdelta
141 argDict[
"date"] = DateTime(middle.tai.isot, DateTime.TAI)
152 with warnings.catch_warnings():
153 warnings.simplefilter(
"ignore", category=astropy.utils.exceptions.AstropyWarning)
155 except iers.IERSRangeError:
158 era = erfa.era00(ut1time.jd1, ut1time.jd2)
159 argDict[
"era"] = era * radians
161 argDict[
"date"] = DateTime()
164 if obsInfo.tracking_radec
is not None:
165 icrs = obsInfo.tracking_radec.transform_to(
"icrs")
166 argDict[
"boresightRaDec"] = SpherePoint(icrs.ra.degree,
167 icrs.dec.degree, units=degrees)
169 altaz = obsInfo.altaz_begin
170 if altaz
is not None:
171 argDict[
"boresightAzAlt"] = SpherePoint(altaz.az.degree,
172 altaz.alt.degree, units=degrees)
174 argDict[
"boresightAirmass"] = obsInfo.boresight_airmass
176 if obsInfo.boresight_rotation_angle
is not None:
177 argDict[
"boresightRotAngle"] = obsInfo.boresight_rotation_angle.degree*degrees
179 if obsInfo.boresight_rotation_coord
is not None:
180 rotType = RotType.UNKNOWN
181 if obsInfo.boresight_rotation_coord ==
"sky":
182 rotType = RotType.SKY
183 argDict[
"rotType"] = rotType
186 temperature = float(
"nan")
187 if obsInfo.temperature
is not None:
188 temperature = obsInfo.temperature.to_value(
"deg_C", astropy.units.temperature())
189 pressure = float(
"nan")
190 if obsInfo.pressure
is not None:
191 pressure = obsInfo.pressure.to_value(
"Pa")
192 relative_humidity = float(
"nan")
193 if obsInfo.relative_humidity
is not None:
194 relative_humidity = obsInfo.relative_humidity
195 argDict[
"weather"] = Weather(temperature, pressure, relative_humidity)
197 if obsInfo.location
is not None:
198 geolocation = obsInfo.location.to_geodetic()
199 argDict[
"observatory"] = Observatory(geolocation.lon.degree*degrees,
200 geolocation.lat.degree*degrees,
201 geolocation.height.to_value(
"m"))
203 for key
in list(argDict.keys()):
204 if argDict[key]
is None:
206 log.warn(
"argDict[%s] is None; stripping", key)
209 return VisitInfo(**argDict)