24 import astropy.utils.exceptions
25 from astropy.utils
import iers
30 ErfaWarning = erfa.ErfaWarning
32 import astropy._erfa
as erfa
35 from astro_metadata_translator
import ObservationInfo
37 from lsst.log
import Log
38 from lsst.daf.base
import DateTime
39 from lsst.geom
import degrees, radians
40 from lsst.afw.image
import VisitInfo, RotType
41 from lsst.afw.coord
import Observatory, Weather
42 from lsst.geom
import SpherePoint
44 __all__ = [
"MakeRawVisitInfoViaObsInfo"]
48 """Base class functor to make a VisitInfo from the FITS header of a
49 raw image using `~astro_metadata_translator.ObservationInfo` translators.
51 Subclasses can be used if a specific
52 `~astro_metadata_translator.MetadataTranslator` translator should be used.
54 The design philosophy is to make a best effort and log warnings of
55 problems, rather than raising exceptions, in order to extract as much
56 VisitInfo information as possible from a messy FITS header without the
57 user needing to add a lot of error handling.
61 log : `lsst.log.Log` or None
62 Logger to use for messages.
63 (None to use ``Log.getLogger("MakeRawVisitInfoViaObsInfo")``).
64 doStripHeader : `bool`, optional
65 Strip header keywords from the metadata as they are used?
68 metadataTranslator =
None
69 """Header translator to use to construct VisitInfo, defaulting to
70 automatic determination."""
72 def __init__(self, log=None, doStripHeader=False):
74 log = Log.getLogger(
"MakeRawVisitInfoViaObsInfo")
79 """Construct a VisitInfo and strip associated data from the metadata.
83 md : `lsst.daf.base.PropertyList` or `lsst.daf.base.PropertySet`
84 Metadata to pull from.
85 May be modified if ``stripHeader`` is ``True``.
86 exposureId : `int`, optional
87 Ignored. Here for compatibility with `MakeRawVisitInfo`.
91 visitInfo : `lsst.afw.image.VisitInfo`
92 `~lsst.afw.image.VisitInfo` derived from the header using
93 a `~astro_metadata_translator.MetadataTranslator`.
100 for c
in obsInfo.cards_used:
107 """Construct a `~lsst.afw.image.VisitInfo` from an
108 `~astro_metadata_translator.ObservationInfo`
112 obsInfo : `astro_metadata_translator.ObservationInfo`
113 Information gathered from the observation metadata.
114 log : `logging.Logger` or `lsst.log.Log`, optional
115 Logger to use for logging informational messages.
116 If `None` logging will be disabled.
120 visitInfo : `lsst.afw.image.VisitInfo`
121 `~lsst.afw.image.VisitInfo` derived from the supplied
122 `~astro_metadata_translator.ObservationInfo`.
127 if obsInfo.exposure_time
is not None:
128 argDict[
"exposureTime"] = obsInfo.exposure_time.to_value(
"s")
129 if obsInfo.dark_time
is not None:
130 argDict[
"darkTime"] = obsInfo.dark_time.to_value(
"s")
131 argDict[
"exposureId"] = obsInfo.detector_exposure_id
134 if obsInfo.datetime_begin
is not None and obsInfo.datetime_end
is not None:
135 tdelta = obsInfo.datetime_end - obsInfo.datetime_begin
136 middle = obsInfo.datetime_begin + 0.5*tdelta
143 argDict[
"date"] = DateTime(middle.tai.isot, DateTime.TAI)
154 with warnings.catch_warnings():
157 warnings.simplefilter(
"ignore", category=astropy.utils.exceptions.AstropyWarning)
158 if ErfaWarning
is not None:
159 warnings.simplefilter(
"ignore", category=ErfaWarning)
161 except iers.IERSRangeError:
164 era = erfa.era00(ut1time.jd1, ut1time.jd2)
165 argDict[
"era"] = era * radians
167 argDict[
"date"] = DateTime()
170 if obsInfo.tracking_radec
is not None:
171 icrs = obsInfo.tracking_radec.transform_to(
"icrs")
172 argDict[
"boresightRaDec"] = SpherePoint(icrs.ra.degree,
173 icrs.dec.degree, units=degrees)
175 altaz = obsInfo.altaz_begin
176 if altaz
is not None:
177 argDict[
"boresightAzAlt"] = SpherePoint(altaz.az.degree,
178 altaz.alt.degree, units=degrees)
180 argDict[
"boresightAirmass"] = obsInfo.boresight_airmass
182 if obsInfo.boresight_rotation_angle
is not None:
183 argDict[
"boresightRotAngle"] = obsInfo.boresight_rotation_angle.degree*degrees
185 if obsInfo.boresight_rotation_coord
is not None:
186 rotType = RotType.UNKNOWN
187 if obsInfo.boresight_rotation_coord ==
"sky":
188 rotType = RotType.SKY
189 argDict[
"rotType"] = rotType
192 temperature = float(
"nan")
193 if obsInfo.temperature
is not None:
194 temperature = obsInfo.temperature.to_value(
"deg_C", astropy.units.temperature())
195 pressure = float(
"nan")
196 if obsInfo.pressure
is not None:
197 pressure = obsInfo.pressure.to_value(
"Pa")
198 relative_humidity = float(
"nan")
199 if obsInfo.relative_humidity
is not None:
200 relative_humidity = obsInfo.relative_humidity
201 argDict[
"weather"] = Weather(temperature, pressure, relative_humidity)
203 if obsInfo.location
is not None:
204 geolocation = obsInfo.location.to_geodetic()
205 argDict[
"observatory"] = Observatory(geolocation.lon.degree*degrees,
206 geolocation.lat.degree*degrees,
207 geolocation.height.to_value(
"m"))
209 for key
in list(argDict.keys()):
210 if argDict[key]
is None:
212 log.warn(
"argDict[%s] is None; stripping", key)
215 return VisitInfo(**argDict)