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#!/usr/bin/env python 

2# encoding: utf-8 

3""" 

4*further constrain the first guess locations of the order centres derived in `soxs_disp_solution`* 

5 

6:Author: 

7 David Young & Marco Landoni 

8 

9:Date Created: 

10 September 8, 2020 

11""" 

12################# GLOBAL IMPORTS #################### 

13from builtins import object 

14import sys 

15import os 

16os.environ['TERM'] = 'vt100' 

17from fundamentals import tools 

18from soxspipe.commonutils import set_of_files 

19from ._base_recipe_ import _base_recipe_ 

20import numpy as np 

21from astropy.nddata import CCDData 

22from astropy import units as u 

23import ccdproc 

24from soxspipe.commonutils import keyword_lookup 

25from soxspipe.commonutils import detect_continuum 

26 

27 

28class soxs_order_centres(_base_recipe_): 

29 """ 

30 *The soxs_order_centres recipe* 

31 

32 **Key Arguments** 

33 

34 - ``log`` -- logger 

35 - ``settings`` -- the settings dictionary 

36 - ``inputFrames`` -- input fits frames. Can be a directory, a set-of-files (SOF) file or a list of fits frame paths. 

37 - ``verbose`` -- verbose. True or False. Default *False* 

38 

39 **Usage** 

40 

41 ```python 

42 from soxspipe.recipes import soxs_order_centres 

43 order_table = soxs_order_centres( 

44 log=log, 

45 settings=settings, 

46 inputFrames=a["inputFrames"] 

47 ).produce_product() 

48 ``` 

49 

50 --- 

51 

52 ```eval_rst 

53 .. todo:: 

54 

55 - add a tutorial about ``soxs_order_centres`` to documentation 

56 ``` 

57 """ 

58 # Initialisation 

59 

60 def __init__( 

61 self, 

62 log, 

63 settings=False, 

64 inputFrames=[], 

65 verbose=False 

66 

67 ): 

68 # INHERIT INITIALISATION FROM _base_recipe_ 

69 super(soxs_order_centres, self).__init__( 

70 log=log, settings=settings) 

71 self.log = log 

72 log.debug("instansiating a new 'soxs_order_centres' object") 

73 self.settings = settings 

74 self.inputFrames = inputFrames 

75 self.verbose = verbose 

76 self.recipeName = "soxs-order-centre" 

77 self.recipeSettings = settings[self.recipeName] 

78 # xt-self-arg-tmpx 

79 

80 # INITIAL ACTIONS 

81 # CONVERT INPUT FILES TO A CCDPROC IMAGE COLLECTION (inputFrames > 

82 # imagefilecollection) 

83 sof = set_of_files( 

84 log=self.log, 

85 settings=self.settings, 

86 inputFrames=self.inputFrames 

87 ) 

88 self.inputFrames, self.supplementaryInput = sof.get() 

89 

90 # VERIFY THE FRAMES ARE THE ONES EXPECTED BY SOXS_order_centres - NO MORE, NO LESS. 

91 # PRINT SUMMARY OF FILES. 

92 print("# VERIFYING INPUT FRAMES") 

93 self.verify_input_frames() 

94 sys.stdout.write("\x1b[1A\x1b[2K") 

95 print("# VERIFYING INPUT FRAMES - ALL GOOD") 

96 

97 # SORT IMAGE COLLECTION 

98 self.inputFrames.sort(['mjd-obs']) 

99 if self.verbose: 

100 print("# RAW INPUT FRAMES - SUMMARY") 

101 print(self.inputFrames.summary, "\n") 

102 

103 # PREPARE THE FRAMES - CONVERT TO ELECTRONS, ADD UNCERTAINTY AND MASK 

104 # EXTENSIONS 

105 self.inputFrames = self.prepare_frames( 

106 save=self.settings["save-intermediate-products"]) 

107 

108 return None 

109 

110 def verify_input_frames( 

111 self): 

112 """*verify input frames match those required by the soxs_order_centres recipe* 

113 

114 **Return:** 

115 - ``None`` 

116 

117 If the fits files conform to required input for the recipe everything will pass silently, otherwise an exception shall be raised. 

118 """ 

119 self.log.debug('starting the ``verify_input_frames`` method') 

120 

121 kw = self.kw 

122 

123 # BASIC VERIFICATION COMMON TO ALL RECIPES 

124 self._verify_input_frames_basics() 

125 

126 imageTypes = self.inputFrames.values( 

127 keyword=kw("DPR_TYPE").lower(), unique=True) 

128 imageTech = self.inputFrames.values( 

129 keyword=kw("DPR_TECH").lower(), unique=True) 

130 imageCat = self.inputFrames.values( 

131 keyword=kw("DPR_CATG").lower(), unique=True) 

132 

133 if self.arm == "NIR": 

134 # WANT ON AND OFF PINHOLE FRAMES 

135 # MIXED INPUT IMAGE TYPES ARE BAD 

136 if len(imageTypes) > 1: 

137 imageTypes = " and ".join(imageTypes) 

138 print(self.inputFrames.summary) 

139 raise TypeError( 

140 "Input frames are a mix of %(imageTypes)s" % locals()) 

141 

142 if imageTypes[0] != "LAMP,ORDERDEF": 

143 raise TypeError( 

144 "Input frames for soxspipe order_centres need to be single pinhole flat-lamp on and lamp off frames for NIR" % locals()) 

145 

146 for i in imageTech: 

147 if i not in ['ECHELLE,PINHOLE', 'IMAGE']: 

148 raise TypeError( 

149 "Input frames for soxspipe order_centres need to be single pinhole flat-lamp on and lamp off frames for NIR" % locals()) 

150 

151 else: 

152 for i in imageTypes: 

153 if i not in ["LAMP,ORDERDEF", "BIAS", "DARK", 'LAMP,DORDERDEF', 'LAMP,QORDERDEF']: 

154 raise TypeError( 

155 "Input frames for soxspipe order_centres need to be single pinhole flat-lamp on and a master-bias and possibly a master dark for UVB/VIS" % locals()) 

156 

157 # LOOK FOR DISP MAP 

158 arm = self.arm 

159 if arm not in self.supplementaryInput or "DISP_MAP" not in self.supplementaryInput[arm]: 

160 raise TypeError( 

161 "Need a first guess dispersion map for %(arm)s - none found with the input files" % locals()) 

162 

163 self.imageType = imageTypes[0] 

164 self.log.debug('completed the ``verify_input_frames`` method') 

165 return None 

166 

167 def produce_product( 

168 self): 

169 """*generate the order-table with polynomal fits of order-centres* 

170 

171 **Return:** 

172 - ``productPath`` -- the path to the order-table 

173 """ 

174 self.log.debug('starting the ``produce_product`` method') 

175 

176 arm = self.arm 

177 kw = self.kw 

178 dp = self.detectorParams 

179 

180 productPath = None 

181 

182 master_bias = False 

183 dark = False 

184 orderDef_image = False 

185 

186 add_filters = {kw("DPR_CATG"): 'MASTER_BIAS_' + arm} 

187 for i in self.inputFrames.files_filtered(include_path=True, **add_filters): 

188 master_bias = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

189 hdu_mask='QUAL', hdu_flags='FLAGS', key_uncertainty_type='UTYPE') 

190 

191 # UVB/VIS DARK 

192 add_filters = {kw("DPR_CATG"): 'MASTER_DARK_' + arm} 

193 for i in self.inputFrames.files_filtered(include_path=True, **add_filters): 

194 dark = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

195 hdu_mask='QUAL', hdu_flags='FLAGS', key_uncertainty_type='UTYPE') 

196 

197 # NIR DARK 

198 add_filters = {kw("DPR_TYPE"): 'LAMP,ORDERDEF', 

199 kw("DPR_TECH"): 'IMAGE'} 

200 for i in self.inputFrames.files_filtered(include_path=True, **add_filters): 

201 print(i) 

202 dark = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

203 hdu_mask='QUAL', hdu_flags='FLAGS', key_uncertainty_type='UTYPE') 

204 

205 add_filters = {kw("DPR_TYPE"): 'LAMP,ORDERDEF', 

206 kw("DPR_TECH"): 'ECHELLE,PINHOLE'} 

207 for i in self.inputFrames.files_filtered(include_path=True, **add_filters): 

208 orderDef_image = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

209 hdu_mask='QUAL', hdu_flags='FLAGS', key_uncertainty_type='UTYPE') 

210 

211 # UVB - CHECK FOR D2 LAMP FIRST AND IF NOT FOUND USE THE QTH LAMP 

212 add_filters = {kw("DPR_TYPE"): 'LAMP,QORDERDEF', 

213 kw("DPR_TECH"): 'ECHELLE,PINHOLE'} 

214 for i in self.inputFrames.files_filtered(include_path=True, **add_filters): 

215 orderDef_image = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

216 hdu_mask='QUAL', hdu_flags='FLAGS', key_uncertainty_type='UTYPE') 

217 

218 add_filters = {kw("DPR_TYPE"): 'LAMP,DORDERDEF', 

219 kw("DPR_TECH"): 'ECHELLE,PINHOLE'} 

220 for i in self.inputFrames.files_filtered(include_path=True, **add_filters): 

221 orderDef_image = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

222 hdu_mask='QUAL', hdu_flags='FLAGS', key_uncertainty_type='UTYPE') 

223 

224 self.orderFrame = self.subtract_calibrations( 

225 inputFrame=orderDef_image, master_bias=master_bias, dark=dark) 

226 

227 if self.settings["save-intermediate-products"]: 

228 fileDir = self.intermediateRootPath 

229 filepath = self._write( 

230 self.orderFrame, fileDir, filename=False, overwrite=True) 

231 print(f"\nCalibrated single pinhole frame frame saved to {filepath}\n") 

232 

233 # DETECT THE CONTINUUM OF ORDERE CENTRES - RETURN ORDER TABLE FILE PATH 

234 detector = detect_continuum( 

235 log=self.log, 

236 pinholeFlat=self.orderFrame, 

237 dispersion_map=self.supplementaryInput[arm]["DISP_MAP"], 

238 settings=self.settings, 

239 recipeName="soxs-order-centre" 

240 ) 

241 productPath = detector.get() 

242 

243 self.clean_up() 

244 

245 self.log.debug('completed the ``produce_product`` method') 

246 return productPath 

247 

248 # use the tab-trigger below for new method 

249 # xt-class-method 

250 

251 # Override Method Attributes 

252 # method-override-tmpx