Coverage for soxspipe/recipes/soxs_spatial_solution.py : 89%

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)*
6:Author:
7 David Young & Marco Landoni
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
27class soxs_spatial_solution(_base_recipe_):
28 """
29 *The soxs_spatial_solution recipe*
31 **Key Arguments**
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*
38 See `produce_product` method for usage.
40 ```eval_rst
41 .. todo::
43 - add a tutorial about ``soxs_spatial_solution`` to documentation
44 ```
45 """
46 # Initialisation
48 def __init__(
49 self,
50 log,
51 settings=False,
52 inputFrames=[],
53 verbose=False
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
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()
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")
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")
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"])
96 return None
98 def verify_input_frames(
99 self):
100 """*verify input frames match those required by the `soxs_spatial_solution` recipe*
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')
106 kw = self.kw
108 # BASIC VERIFICATION COMMON TO ALL RECIPES
109 self._verify_input_frames_basics()
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)
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())
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())
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())
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())
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())
148 self.imageType = imageTypes[0]
149 self.log.debug('completed the ``verify_input_frames`` method')
150 return None
152 def produce_product(
153 self):
154 """*generate the 2D dispersion map*
156 **Return:**
157 - ``productPath`` -- the path to the 2D dispersion map
159 **Usage**
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')
173 arm = self.arm
174 kw = self.kw
175 dp = self.detectorParams
177 productPath = None
179 master_bias = False
180 dark = False
181 multi_pinhole_image = False
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')
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')
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')
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')
208 self.multiPinholeFrame = self.subtract_calibrations(
209 inputFrame=multi_pinhole_image, master_bias=master_bias, dark=dark)
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")
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()
226 self.clean_up()
228 self.log.debug('completed the ``produce_product`` method')
229 return mapPath
231 # use the tab-trigger below for new method
232 # xt-class-method
234 # Override Method Attributes
235 # method-override-tmpx