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 2022-11-05 01:10 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-05 01:10 -0700
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", )
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
34from lsst.meas.algorithms.simple_curve import AmpCurve
36from lsst.obs.lsst import LsstTS8
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'}
44def convert_qe_curve(filename):
45 """Convert a single QE curve from its native FITS format to an
46 an `astropy.table.QTable` representation.
48 Parameters
49 ----------
50 filename : `str`
51 Full path, including filename for the file to be converted.
53 Returns
54 -------
55 table : `astropy.table.QTable`
56 A QTable object containing the columns that describe this
57 QE curve.
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]
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)
88def rewrite_ts8_files(picklefile, out_root='.', valid_start='1970-01-01T00:00:00'):
89 """Write the QE curves out to the specified location.
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)
106 valid_date = dateutil.parser.parse(valid_start)
107 datestr = ''.join(re.split(r'[:-]', valid_date.isoformat()))
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)
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', 'OBSTYPE': 'qe_curve',
130 'DETECTOR': detector_id, 'PICKLEFILE': os.path.split(picklefile)[1]})
131 curve_table.meta['CALIB_ID'] = (f'raftName={raft_name} detectorName={detector_name} '
132 f'detector={detector_id} calibDate={valid_start} '
133 f'ccd={detector_id} ccdnum={detector_id} filter=None')
134 curve.writeText(outfile)
137def build_argparser():
138 """Construct an argument parser for the ``rewrite_ts8_qe_files.py`` script.
140 Returns
141 -------
142 argparser : `argparse.ArgumentParser`
143 The argument parser that defines the ``rewrite_ts8_qe_files.py``
144 command-line interface.
145 """
146 parser = argparse.ArgumentParser(description = 'Rewrite native FITS files from the test '
147 'stand to a standard format')
148 parser.add_argument('picklefile', help = "Pickle file to read.")
149 parser.add_argument('--out_root', type = str,
150 help = "Root directory to which to write outputs", default = '.')
151 parser.add_argument('--valid_start', type = str,
152 help = "ISO format date string stating the start of the validity range.",
153 default = '1970-01-01T00:00:00')
155 return parser
158def main():
159 args = build_argparser().parse_args()
161 try:
162 rewrite_ts8_files(args.picklefile, args.out_root, args.valid_start)
163 except Exception as e:
164 print(f"{e}", file=sys.stderr)
165 return 1
166 return 0