Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

# This file is part of astro_metadata_translator. 

# 

# Developed for the LSST Data Management System. 

# This product includes software developed by the LSST Project 

# (http://www.lsst.org). 

# See the LICENSE file at the top-level directory of this distribution 

# for details of code ownership. 

# 

# Use of this source code is governed by a 3-clause BSD-style 

# license that can be found in the LICENSE file. 

 

"""Metadata translation code for standard FITS headers""" 

 

__all__ = ("FitsTranslator", ) 

 

from astropy.time import Time 

from astropy.coordinates import EarthLocation 

import astropy.units as u 

 

from ..translator import MetadataTranslator, cache_translation 

 

 

class FitsTranslator(MetadataTranslator): 

"""Metadata translator for FITS standard headers. 

 

Understands: 

 

- DATE-OBS 

- INSTRUME 

- TELESCOP 

- OBSGEO-[X,Y,Z] 

 

""" 

 

# Direct translation from header key to standard form 

_trivial_map = dict(instrument="INSTRUME", 

telescope="TELESCOP") 

 

@classmethod 

def can_translate(cls, header, filename=None): 

"""Indicate whether this translation class can translate the 

supplied header. 

 

Checks the instrument value and compares with the supported 

instruments in the class 

 

Parameters 

---------- 

header : `dict`-like 

Header to convert to standardized form. 

filename : `str`, optional 

Name of file being translated. 

 

Returns 

------- 

can : `bool` 

`True` if the header is recognized by this class. `False` 

otherwise. 

""" 

if cls.supported_instrument is None: 

return False 

 

# Protect against being able to always find a standard 

# header for instrument 

try: 

translator = cls(header, filename=filename) 

instrument = translator.to_instrument() 

except KeyError: 

return False 

 

return instrument == cls.supported_instrument 

 

@classmethod 

def _from_fits_date_string(cls, date_str, scale='utc', time_str=None): 

"""Parse standard FITS ISO-style date string and return time object 

 

Parameters 

---------- 

date_str : `str` 

FITS format date string to convert to standard form. Bypasses 

lookup in the header. 

scale : `str`, optional 

Override the time scale from the TIMESYS header. Defaults to 

UTC. 

time_str : `str`, optional 

If provided, overrides any time component in the ``dateStr``, 

retaining the YYYY-MM-DD component and appending this time 

string, assumed to be of format HH:MM::SS.ss. 

 

Returns 

------- 

date : `astropy.time.Time` 

`~astropy.time.Time` representation of the date. 

""" 

if time_str is not None: 

date_str = "{}T{}".format(date_str[:10], time_str) 

 

return Time(date_str, format="isot", scale=scale) 

 

def _from_fits_date(self, date_key): 

"""Calculate a date object from the named FITS header 

 

Uses the TIMESYS header if present to determine the time scale, 

defaulting to UTC. 

 

Parameters 

---------- 

dateKey : `str` 

The key in the header representing a standard FITS 

ISO-style date. 

 

Returns 

------- 

date : `astropy.time.Time` 

`~astropy.time.Time` representation of the date. 

""" 

used = [date_key, ] 

if "TIMESYS" in self._header: 

scale = self._header["TIMESYS"].lower() 

used.append("TIMESYS") 

else: 

scale = "utc" 

if date_key in self._header: 

date_str = self._header[date_key] 

value = self._from_fits_date_string(date_str, scale=scale) 

self._used_these_cards(*used) 

else: 

value = None 

return value 

 

@cache_translation 

def to_datetime_begin(self): 

"""Calculate start time of observation. 

 

Uses FITS standard ``DATE-OBS`` and ``TIMESYS`` headers. 

 

Returns 

------- 

start_time : `astropy.time.Time` 

Time corresponding to the start of the observation. 

""" 

return self._from_fits_date("DATE-OBS") 

 

@cache_translation 

def to_datetime_end(self): 

"""Calculate end time of observation. 

 

Uses FITS standard ``DATE-END`` and ``TIMESYS`` headers. 

 

Returns 

------- 

start_time : `astropy.time.Time` 

Time corresponding to the end of the observation. 

""" 

return self._from_fits_date("DATE-END") 

 

@cache_translation 

def to_location(self): 

"""Calculate the observatory location. 

 

Uses FITS standard ``OBSGEO-`` headers. 

 

Returns 

------- 

location : `astropy.coordinates.EarthLocation` 

An object representing the location of the telescope. 

""" 

cards = [f"OBSGEO-{c}" for c in ("X", "Y", "Z")] 

coords = [self._header[c] for c in cards] 

value = EarthLocation.from_geocentric(*coords, unit=u.m) 

self._used_these_cards(*cards) 

return value