Coverage for python / astro_metadata_translator / serialize / fits.py: 13%

35 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-30 08:43 +0000

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. 

11 

12"""Transform ObservationInfo into "standard" FITS headers.""" 

13 

14from __future__ import annotations 

15 

16__all__ = ("dates_to_fits", "group_to_fits", "info_to_fits") 

17 

18from typing import TYPE_CHECKING, Any 

19 

20if TYPE_CHECKING: 

21 import astropy.time 

22 

23 from ..observationGroup import ObservationGroup 

24 from ..observationInfo import ObservationInfo 

25 

26 

27def dates_to_fits(date_begin: astropy.time.Time, date_end: astropy.time.Time) -> dict[str, Any]: 

28 """Convert two dates into FITS form. 

29 

30 Parameters 

31 ---------- 

32 date_begin : `astropy.time.Time` 

33 Date representing the beginning of the observation. 

34 date_end : `astropy.time.Time` 

35 Date representing the end of the observation. 

36 

37 Returns 

38 ------- 

39 cards : `dict` [`str`, [`str` | `float` ] ] 

40 Header card keys and values following the FITS standard. 

41 If neither date is defined this may be empty. 

42 """ 

43 cards: dict[str, Any] = {} 

44 if date_begin is None and date_end is None: 

45 # no date headers can be written 

46 return cards 

47 

48 cards["TIMESYS"] = "TAI" 

49 

50 date_avg = None 

51 if date_begin is not None and date_end is not None: 

52 date_avg = date_begin + (date_end - date_begin) / 2.0 

53 

54 for fragment, date in (("OBS", date_begin), ("BEG", date_begin), ("END", date_end), ("AVG", date_avg)): 

55 if date is not None: 

56 tai = date.tai 

57 cards[f"DATE-{fragment}"] = tai.isot 

58 cards[f"MJD-{fragment}"] = tai.mjd 

59 

60 return cards 

61 

62 

63def info_to_fits(obs_info: ObservationInfo) -> tuple[dict[str, Any], dict[str, str]]: 

64 """Convert an `ObservationInfo` to something suitable for writing 

65 to a FITS file. 

66 

67 Parameters 

68 ---------- 

69 obs_info : `ObservationInfo` 

70 Standardized observation information to transform to FITS headers. 

71 

72 Returns 

73 ------- 

74 cards : `dict` of `str` to (`int`, `float`, `str`, `bool`) 

75 FITS header keys and values in form understood by FITS. 

76 comments : `dict` of `str` to `str` 

77 Suitable comment string. There will be at most one entry for each key 

78 in ``cards``. 

79 """ 

80 cards = {} 

81 comments = {} 

82 

83 if obs_info.instrument is not None: 

84 cards["INSTRUME"] = obs_info.instrument 

85 comments["INSTRUME"] = "Name of instrument" 

86 

87 cards.update(dates_to_fits(obs_info.datetime_begin, obs_info.datetime_end)) 

88 

89 return cards, comments 

90 

91 

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. 

95 

96 Parameters 

97 ---------- 

98 obs_group : `ObservationGroup` 

99 Collection of observation information to transform to a single 

100 FITS header. 

101 

102 Returns 

103 ------- 

104 cards : `dict` [`str`, [`int` | `float` | `str` | `bool` ] ] 

105 FITS header keys and values in form understood by FITS. 

106 comments : `dict` [`str`, `str`] 

107 Suitable comment string. There will be at most one entry for each key 

108 in ``cards``. 

109 """ 

110 cards = {} 

111 comments = {} 

112 

113 oldest, newest = obs_group.extremes() 

114 

115 instruments = obs_group.property_values("instrument") 

116 if len(instruments) == 1: 

117 cards["INSTRUME"] = list(instruments)[0] 

118 comments["INSTRUME"] = "Name of instrument" 

119 

120 cards.update(dates_to_fits(oldest.datetime_begin, newest.datetime_end)) 

121 

122 return cards, comments