Coverage for python/astro_metadata_translator/serialize/fits.py: 17%
40 statements
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-12 20:36 -0700
« prev ^ index » next coverage.py v7.2.1, created at 2023-03-12 20:36 -0700
1# This file is part of astro_metadata_translator.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the LICENSE file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# Use of this source code is governed by a 3-clause BSD-style
10# license that can be found in the LICENSE file.
12"""Transform ObservationInfo into "standard" FITS headers."""
13from __future__ import annotations
15__all__ = ("info_to_fits", "dates_to_fits", "group_to_fits")
17from typing import TYPE_CHECKING, Any, Dict, Tuple
19if TYPE_CHECKING: 19 ↛ 20line 19 didn't jump to line 20, because the condition on line 19 was never true
20 import astropy.time
22 from ..observationGroup import ObservationGroup
23 from ..observationInfo import ObservationInfo
26def dates_to_fits(date_begin: astropy.time.Time, date_end: astropy.time.Time) -> Dict[str, Any]:
27 """Convert two dates into FITS form.
29 Parameters
30 ----------
31 date_begin : `astropy.time.Time`
32 Date representing the beginning of the observation.
33 date_end : `astropy.time.Time`
34 Date representing the end of the observation.
36 Returns
37 -------
38 cards : `dict` of `str` to `str` or `float`
39 Header card keys and values following the FITS standard.
40 If neither date is defined this may be empty.
41 """
42 cards: Dict[str, Any] = {}
43 if date_begin is None and date_end is None:
44 # no date headers can be written
45 return cards
47 cards["TIMESYS"] = "TAI"
49 date_avg = None
50 if date_begin is not None and date_end is not None:
51 date_avg = date_begin + (date_end - date_begin) / 2.0
53 for fragment, date in (("OBS", date_begin), ("END", date_end), ("AVG", date_avg)):
54 if date is not None:
55 tai = date.tai
56 cards[f"DATE-{fragment}"] = tai.isot
57 cards[f"MJD-{fragment}"] = tai.mjd
59 return cards
62def info_to_fits(obs_info: ObservationInfo) -> Tuple[Dict[str, Any], Dict[str, str]]:
63 """Convert an `ObservationInfo` to something suitable for writing
64 to a FITS file.
66 Parameters
67 ----------
68 obs_info : `ObservationInfo`
69 Standardized observation information to transform to FITS headers.
71 Returns
72 -------
73 cards : `dict` of `str` to (`int`, `float`, `str`, `bool`)
74 FITS header keys and values in form understood by FITS.
75 comments : `dict` of `str` to `str`
76 Suitable comment string. There will be at most one entry for each key
77 in ``cards``.
78 """
80 cards = {}
81 comments = {}
83 if obs_info.instrument is not None:
84 cards["INSTRUME"] = obs_info.instrument
85 comments["INSTRUME"] = "Name of instrument"
87 cards.update(dates_to_fits(obs_info.datetime_begin, obs_info.datetime_end))
89 return cards, comments
92def group_to_fits(obs_group: ObservationGroup) -> Tuple[Dict[str, Any], Dict[str, str]]:
93 """Convert an `ObservationGroup` to something suitable for writing
94 to a FITS file.
96 Parameters
97 ----------
98 obs_group : `ObservationGroup`
99 Collection of observation information to transform to a single
100 FITS header.
102 Returns
103 -------
104 cards : `dict` of `str` to (`int`, `float`, `str`, `bool`)
105 FITS header keys and values in form understood by FITS.
106 comments : `dict` of `str` to `str`
107 Suitable comment string. There will be at most one entry for each key
108 in ``cards``.
109 """
111 cards = {}
112 comments = {}
114 oldest, newest = obs_group.extremes()
116 instruments = obs_group.property_values("instrument")
117 if len(instruments) == 1:
118 cards["INSTRUME"] = list(instruments)[0]
119 comments["INSTRUME"] = "Name of instrument"
121 cards.update(dates_to_fits(oldest.datetime_begin, newest.datetime_end))
123 return cards, comments