Coverage for python/lsst/obs/lsst/script/rewrite_ts8_qe_files.py: 20%

74 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2023-01-04 03:10 -0800

1# This file is part of obs_lsst. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://www.lsst.org). 

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

7# for details of code ownership. 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <https://www.gnu.org/licenses/>. 

21__all__ = ("main", ) 

22 

23import astropy.units as u 

24from astropy.io import fits 

25from astropy.table import QTable 

26import argparse 

27import sys 

28import re 

29import os 

30import dateutil.parser 

31import pickle 

32import numpy 

33 

34from lsst.meas.algorithms.simple_curve import AmpCurve 

35 

36from lsst.obs.lsst import LsstTS8 

37 

38amp_name_map = {'AMP01': 'C10', 'AMP02': 'C11', 'AMP03': 'C12', 'AMP04': 'C13', 'AMP05': 'C14', 

39 'AMP06': 'C15', 'AMP07': 'C16', 'AMP08': 'C17', 'AMP09': 'C07', 'AMP10': 'C06', 

40 'AMP11': 'C05', 'AMP12': 'C04', 'AMP13': 'C03', 'AMP14': 'C02', 'AMP15': 'C01', 

41 'AMP16': 'C00'} 

42 

43 

44def convert_qe_curve(filename): 

45 """Convert a single QE curve from its native FITS format to an 

46 an `astropy.table.QTable` representation. 

47 

48 Parameters 

49 ---------- 

50 filename : `str` 

51 Full path, including filename for the file to be converted. 

52 

53 Returns 

54 ------- 

55 table : `astropy.table.QTable` 

56 A QTable object containing the columns that describe this 

57 QE curve. 

58 

59 Notes 

60 ----- 

61 This function is specific to how the ts8 data are formatted 

62 with a curve per amp. If ther are other formats, a different 

63 converter will be necessary. 

64 """ 

65 with fits.open(filename) as hdu_list: 

66 # qe data is in first extension 

67 data = hdu_list[1].data 

68 wlength = [] 

69 eff = dict() 

70 for row in data: 

71 wlength.append(row['WAVELENGTH']) 

72 for i in range(16): # There are 16 amps 

73 col_name = f'AMP{i+1:02d}' 

74 eff.setdefault(amp_name_map[col_name], []).append(row[col_name]) 

75 out_data = {'amp_name': [], 'wavelength': [], 'efficiency': []} 

76 for k in eff: 

77 amp_names = [k]*len(wlength) 

78 out_data['amp_name'] += amp_names 

79 out_data['wavelength'] += wlength 

80 out_data['efficiency'] += eff[k] 

81 

82 out_data['amp_name'] = numpy.array(out_data['amp_name']) 

83 out_data['wavelength'] = numpy.array(out_data['wavelength'])*u.nanometer 

84 out_data['efficiency'] = numpy.array(out_data['efficiency'])*u.percent 

85 return QTable(out_data) 

86 

87 

88def rewrite_ts8_files(picklefile, out_root='.', valid_start='1970-01-01T00:00:00'): 

89 """Write the QE curves out to the specified location. 

90 

91 Parameters 

92 ---------- 

93 picklefile : `str` 

94 Path to the pickle file that describes a set of QE curves. 

95 out_root : `str`, optional 

96 Path to the output location. If the path doesn't exist, 

97 it will be created. 

98 valid_start : `str`, optional 

99 A string indicating the valid start time for these QE curves. 

100 Any ISO compliant string will work. 

101 """ 

102 ts8 = LsstTS8() 

103 cam = ts8.getCamera() 

104 file_root = os.path.dirname(picklefile) 

105 

106 valid_date = dateutil.parser.parse(valid_start) 

107 datestr = ''.join(re.split(r'[:-]', valid_date.isoformat())) 

108 

109 if not file_root: # no path given 

110 file_root = os.path.curdir() 

111 with open(picklefile, 'rb') as fh: 

112 full_raft_name = pickle.load(fh) 

113 # The pickle file was written with sequential dumps, 

114 # so it needs to be read sequentially as well. 

115 _ = pickle.load(fh) # res 

116 _ = pickle.load(fh) # Detector list 

117 file_list = pickle.load(fh) 

118 

119 for detector_name, f in file_list.items(): 

120 f = os.path.basename(f[0]) 

121 curve_table = convert_qe_curve(os.path.join(file_root, f)) 

122 curve = AmpCurve.fromTable(curve_table) 

123 raft_name = full_raft_name.split('_')[1] # Select just the RTM part. 

124 outpath = os.path.join(out_root, '_'.join([raft_name, detector_name]).lower()) 

125 outfile = os.path.join(outpath, datestr+'.ecsv') 

126 os.makedirs(outpath, exist_ok=True) 

127 full_detector_name = '_'.join([raft_name, detector_name]) 

128 detector_id = cam[full_detector_name].getId() 

129 curve_table.meta.update({'CALIBDATE': valid_start, 'INSTRUME': 'TS8', 

130 'OBSTYPE': 'transmission_sensor', 'TYPE': 'transmission_sensor', 

131 'DETECTOR': detector_id, 'PICKLEFILE': os.path.split(picklefile)[1]}) 

132 

133 curve_table.meta['CALIB_ID'] = (f'raftName={raft_name} detectorName={detector_name} ' 

134 f'detector={detector_id} calibDate={valid_start} ' 

135 f'ccd={detector_id} ccdnum={detector_id} filter=None') 

136 curve.writeText(outfile) 

137 

138 

139def build_argparser(): 

140 """Construct an argument parser for the ``rewrite_ts8_qe_files.py`` script. 

141 

142 Returns 

143 ------- 

144 argparser : `argparse.ArgumentParser` 

145 The argument parser that defines the ``rewrite_ts8_qe_files.py`` 

146 command-line interface. 

147 """ 

148 parser = argparse.ArgumentParser(description = 'Rewrite native FITS files from the test ' 

149 'stand to a standard format') 

150 parser.add_argument('picklefile', help = "Pickle file to read.") 

151 parser.add_argument('--out_root', type = str, 

152 help = "Root directory to which to write outputs", default = '.') 

153 parser.add_argument('--valid_start', type = str, 

154 help = "ISO format date string stating the start of the validity range.", 

155 default = '1970-01-01T00:00:00') 

156 

157 return parser 

158 

159 

160def main(): 

161 args = build_argparser().parse_args() 

162 

163 try: 

164 rewrite_ts8_files(args.picklefile, args.out_root, args.valid_start) 

165 except Exception as e: 

166 print(f"{e}", file=sys.stderr) 

167 return 1 

168 return 0