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*enhance the wavelength solution achieved with `soxs_disp_solution` by expanding the solution into the spatial dimension (along the slit)* 

5 

6:Author: 

7 David Young & Marco Landoni 

8 

9:Date Created: 

10 March 17, 2021 

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 

22import ccdproc 

23from astropy import units as u 

24from soxspipe.commonutils import keyword_lookup 

25 

26 

27class soxs_spatial_solution(_base_recipe_): 

28 """ 

29 *The soxs_spatial_solution recipe* 

30 

31 **Key Arguments** 

32 

33 - ``log`` -- logger 

34 - ``settings`` -- the settings dictionary 

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

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

37 

38 See `produce_product` method for usage. 

39 

40 ```eval_rst 

41 .. todo:: 

42 

43 - add a tutorial about ``soxs_spatial_solution`` to documentation 

44 ``` 

45 """ 

46 # Initialisation 

47 

48 def __init__( 

49 self, 

50 log, 

51 settings=False, 

52 inputFrames=[], 

53 verbose=False 

54 

55 ): 

56 # INHERIT INITIALISATION FROM _base_recipe_ 

57 super(soxs_spatial_solution, self).__init__( 

58 log=log, settings=settings) 

59 self.log = log 

60 log.debug("instansiating a new 'soxs_spatial_solution' object") 

61 self.settings = settings 

62 self.inputFrames = inputFrames 

63 self.verbose = verbose 

64 self.recipeName = "soxs-spatial-solution" 

65 self.recipeSettings = settings[self.recipeName] 

66 # xt-self-arg-tmpx 

67 

68 # INITIAL ACTIONS 

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

70 # imagefilecollection) 

71 sof = set_of_files( 

72 log=self.log, 

73 settings=self.settings, 

74 inputFrames=self.inputFrames 

75 ) 

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

77 

78 # VERIFY THE FRAMES ARE THE ONES EXPECTED BY SOXS_spatial_solution - NO MORE, NO LESS. 

79 # PRINT SUMMARY OF FILES. 

80 print("# VERIFYING INPUT FRAMES") 

81 self.verify_input_frames() 

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

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

84 

85 # SORT IMAGE COLLECTION 

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

87 if self.verbose: 

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

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

90 

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

92 # EXTENSIONS 

93 self.inputFrames = self.prepare_frames( 

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

95 

96 return None 

97 

98 def verify_input_frames( 

99 self): 

100 """*verify input frames match those required by the `soxs_spatial_solution` recipe* 

101 

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

103 """ 

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

105 

106 kw = self.kw 

107 

108 # BASIC VERIFICATION COMMON TO ALL RECIPES 

109 self._verify_input_frames_basics() 

110 

111 imageTypes = self.inputFrames.values( 

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

113 imageTech = self.inputFrames.values( 

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

115 imageCat = self.inputFrames.values( 

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

117 

118 if self.arm == "NIR": 

119 # WANT ON AND OFF PINHOLE FRAMES 

120 # MIXED INPUT IMAGE TYPES ARE BAD 

121 if len(imageTypes) > 1: 

122 imageTypes = " and ".join(imageTypes) 

123 print(self.inputFrames.summary) 

124 raise TypeError( 

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

126 

127 if imageTypes[0] != "LAMP,WAVE": 

128 raise TypeError( 

129 "Input frames for soxspipe spatial_solution need to be LAMP,WAVE lamp on and lamp off frames for NIR" % locals()) 

130 

131 for i in imageTech: 

132 if i not in ['ECHELLE,MULTI-PINHOLE', 'IMAGE']: 

133 raise TypeError( 

134 "Input frames for soxspipe spatial_solution need to be LAMP,WAVE lamp on and lamp off frames for NIR" % locals()) 

135 

136 else: 

137 for i in imageTypes: 

138 if i not in ["LAMP,WAVE", "BIAS", "DARK"]: 

139 raise TypeError( 

140 "Input frames for soxspipe spatial_solution need to be LAMP,WAVE and a master-bias and possibly a master dark for UVB/VIS" % locals()) 

141 

142 # LOOK FOR **** 

143 arm = self.arm 

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

145 raise TypeError( 

146 "Need a DISP_MAP for %(arm)s - none found with the input files" % locals()) 

147 

148 self.imageType = imageTypes[0] 

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

150 return None 

151 

152 def produce_product( 

153 self): 

154 """*generate the 2D dispersion map* 

155 

156 **Return:** 

157 - ``productPath`` -- the path to the 2D dispersion map 

158 

159 **Usage** 

160 

161 ```python 

162 from soxspipe.recipes import soxs_spatial_solution 

163 recipe = soxs_spatial_solution( 

164 log=log, 

165 settings=settings, 

166 inputFrames=fileList 

167 ) 

168 disp_map = recipe.produce_product() 

169 ``` 

170 """ 

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

172 

173 arm = self.arm 

174 kw = self.kw 

175 dp = self.detectorParams 

176 

177 productPath = None 

178 

179 master_bias = False 

180 dark = False 

181 multi_pinhole_image = False 

182 

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

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

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

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

187 

188 # UVB/VIS DARK 

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

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

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

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

193 

194 # NIR DARK 

195 add_filters = {kw("DPR_TYPE"): 'LAMP,WAVE', 

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

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

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

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

200 

201 # MULTIPINHOLE IMAGE 

202 add_filters = {kw("DPR_TYPE"): 'LAMP,WAVE', 

203 kw("DPR_TECH"): 'ECHELLE,MULTI-PINHOLE'} 

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

205 multi_pinhole_image = CCDData.read(i, hdu=0, unit=u.adu, hdu_uncertainty='ERRS', 

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

207 

208 self.multiPinholeFrame = self.subtract_calibrations( 

209 inputFrame=multi_pinhole_image, master_bias=master_bias, dark=dark) 

210 

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

212 fileDir = self.intermediateRootPath 

213 filepath = self._write( 

214 self.multiPinholeFrame, fileDir, filename=False, overwrite=True) 

215 print(f"\nCalibrated multi pinhole frame frame saved to {filepath}\n") 

216 

217 # GENERATE AN UPDATED DISPERSION MAP 

218 from soxspipe.commonutils import create_dispersion_map 

219 mapPath = create_dispersion_map( 

220 log=self.log, 

221 settings=self.settings, 

222 pinholeFrame=self.multiPinholeFrame, 

223 firstGuessMap=self.supplementaryInput[arm]["DISP_MAP"] 

224 ).get() 

225 

226 self.clean_up() 

227 

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

229 return mapPath 

230 

231 # use the tab-trigger below for new method 

232 # xt-class-method 

233 

234 # Override Method Attributes 

235 # method-override-tmpx