def main(night_name=None, files=None): """ cal_DARK_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_DARK_spirou.py [night_directory] [fitsfilename] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p) # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='average') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Find the amplitude to use for the local background # ---------------------------------------------------------------------- spirouBACK.MakeLocalBackgroundMap(p, data) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p, outputs=None) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None): """ cal_SLIT_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_SLIT_spirou.py [night_directory] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p, calibdb=True) # set the fiber type p['FIB_TYP'] = 'AB' p.set_source('FIB_TYP', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # ---------------------------------------------------------------------- # Correction of DARK # ---------------------------------------------------------------------- p, datac = spirouImage.CorrectForDark(p, data, hdr) # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to e- data = spirouImage.ConvertToE(spirouImage.FlipImage(p, datac), p=p) # convert NaN to zeros data0 = np.where(~np.isfinite(data), np.zeros_like(data), data) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) data2 = spirouImage.ResizeImage(p, data0, **bkwargs) # log change in data size WLOG(p, '', ('Image format changed to ' '{0}x{1}').format(*data2.shape)) # ---------------------------------------------------------------------- # Correct for the BADPIX mask (set all bad pixels to zero) # ---------------------------------------------------------------------- p, data2 = spirouImage.CorrectForBadPix(p, data2, hdr) # ---------------------------------------------------------------------- # Background computation # ---------------------------------------------------------------------- if p['IC_DO_BKGR_SUBTRACTION']: # log that we are doing background measurement WLOG(p, '', 'Doing background measurement on raw frame') # get the bkgr measurement bargs = [p, data2, hdr] # background, xc, yc, minlevel = spirouBACK.MeasureBackgroundFF(*bargs) p, background = spirouBACK.MeasureBackgroundMap(*bargs) else: background = np.zeros_like(data2) p['BKGRDFILE'] = 'None' p.set_source('BKGRDFILE', __NAME__ + '.main()') # correct data2 with background data2 = data2 - background # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- # get the number of bad pixels n_bad_pix = np.nansum(~np.isfinite(data2)) n_bad_pix_frac = n_bad_pix * 100 / np.product(data2.shape) # Log number wmsg = 'Nb dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- loc = ParamDict() # ---------------------------------------------------------------------- # Loop around fiber types # ---------------------------------------------------------------------- # set fiber p['FIBER'] = p['FIB_TYP'] # ------------------------------------------------------------------ # Get localisation coefficients # ------------------------------------------------------------------ # original there is a loop but it is not used --> removed p = spirouImage.FiberParams(p, p['FIBER'], merge=True) # get localisation fit coefficients p, loc = spirouLOCOR.GetCoeffs(p, hdr, loc) # ------------------------------------------------------------------ # Calculating the tilt # ------------------------------------------------------------------ # get the tilt by extracting the AB fibers and correlating them loc = spirouImage.GetTilt(p, loc, data2) # fit the tilt with a polynomial loc = spirouImage.FitTilt(p, loc) # log the tilt dispersion wmsg = 'Tilt dispersion = {0:.3f} deg' WLOG(p, 'info', wmsg.format(loc['RMS_TILT'])) # ------------------------------------------------------------------ # Plotting # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # plots setup: start interactive plot sPlt.start_interactive_session(p) # plot image with selected order shown sPlt.slit_sorder_plot(p, loc, data2) # plot slit tilt angle and fit sPlt.slit_tilt_angle_and_fit_plot(p, loc) # end interactive section sPlt.end_interactive_session(p) # ------------------------------------------------------------------ # Replace tilt by the global fit # ------------------------------------------------------------------ loc['TILT'] = loc['YFIT_TILT'] oldsource = loc.get_source('tilt') loc.set_source('TILT', oldsource + '+{0}/main()'.format(__NAME__)) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # check that tilt rms is below required if loc['RMS_TILT'] > p['QC_SLIT_RMS']: # add failed message to fail message list fmsg = 'abnormal RMS of SLIT angle ({0:.2f} > {1:.2f} deg)' fail_msg.append(fmsg.format(loc['RMS_TILT'], p['QC_SLIT_RMS'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(loc['RMS_TILT']) qc_names.append('RMS_TILT') qc_logic.append('RMS_TILT > {0:.2f}'.format(p['QC_SLIT_RMS'])) # ---------------------------------------------------------------------- # check that tilt is less than max tilt required max_tilt = np.max(loc['TILT']) if max_tilt > p['QC_SLIT_MAX']: # add failed message to fail message list fmsg = 'abnormal SLIT angle ({0:.2f} > {1:.2f} deg)' fail_msg.append(fmsg.format(max_tilt, p['QC_SLIT_MAX'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(max_tilt) qc_names.append('max_tilt') qc_logic.append('max_tilt > {0:.2f}'.format(p['QC_SLIT_MAX'])) # ---------------------------------------------------------------------- # check that tilt is greater than min tilt required min_tilt = np.min(loc['TILT']) if min_tilt < p['QC_SLIT_MIN']: # add failed message to fail message list fmsg = 'abnormal SLIT angle ({0:.2f} < {1:.2f} deg)' fail_msg.append(fmsg.format(max_tilt, p['QC_SLIT_MIN'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(min_tilt) qc_names.append('min_tilt') qc_logic.append('min_tilt > {0:.2f}'.format(p['QC_SLIT_MIN'])) # ---------------------------------------------------------------------- # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ---------------------------------------------------------------------- # Save and record of tilt table # ---------------------------------------------------------------------- # copy the tilt along the orders tiltima = np.ones((int(loc['NUMBER_ORDERS']/2), data2.shape[1])) tiltima *= loc['TILT'][:, None] # get the raw tilt file name raw_tilt_file = os.path.basename(p['FITSFILENAME']) # construct file name and path tiltfits, tag = spirouConfig.Constants.SLIT_TILT_FILE(p) tiltfitsname = os.path.basename(tiltfits) # Log that we are saving tilt file wmsg = 'Saving tilt information in file: {0}' WLOG(p, '', wmsg.format(tiltfitsname)) # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(hdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBACK'], value=p['BKGRDFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # add qc parameters # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # add tilt parameters as 1d list hdict = spirouImage.AddKey1DList(p, hdict, p['KW_TILT'], values=loc['TILT']) # write tilt file to file p = spirouImage.WriteImage(p, tiltfits, tiltima, hdict) # ---------------------------------------------------------------------- # Update the calibration data base # ---------------------------------------------------------------------- if p['QC']: keydb = 'TILT' # copy localisation file to the calibDB folder spirouDB.PutCalibFile(p, tiltfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, tiltfitsname, hdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def dark_setup(night_name, files): # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p) # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='average') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # ---------------------------------------------------------------------- # Dark exposure time check # ---------------------------------------------------------------------- # log the Dark exposure time WLOG(p, 'info', 'Dark Time = {0:.3f} s'.format(p['EXPTIME'])) # Quality control: make sure the exposure time is longer than qc_dark_time if p['EXPTIME'] < p['QC_DARK_TIME']: emsg = 'Dark exposure time too short (< {0:.1f} s)' WLOG(p, 'error', emsg.format(p['QC_DARK_TIME'])) # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # # rotate the image and conver from ADU/s to e- # data = data[::-1, ::-1] * p['exptime'] * p['gain'] # convert NaN to zeros nanmask = ~np.isfinite(data) data = np.where(nanmask, np.zeros_like(data), data) # resize blue image bkwargs = dict(xlow=p['IC_CCDX_BLUE_LOW'], xhigh=p['IC_CCDX_BLUE_HIGH'], ylow=p['IC_CCDY_BLUE_LOW'], yhigh=p['IC_CCDY_BLUE_HIGH']) datablue, nx2, ny2 = spirouImage.ResizeImage(p, data, **bkwargs) # Make sure we have data in the blue image if nx2 == 0 or ny2 == 0: WLOG(p, 'error', ('IC_CCD(X/Y)_BLUE_(LOW/HIGH) remove ' 'all pixels from image.')) # resize red image rkwargs = dict(xlow=p['IC_CCDX_RED_LOW'], xhigh=p['IC_CCDX_RED_HIGH'], ylow=p['IC_CCDY_RED_LOW'], yhigh=p['IC_CCDY_RED_HIGH']) datared, nx3, ny3 = spirouImage.ResizeImage(p, data, **rkwargs) # Make sure we have data in the red image if nx3 == 0 or ny3 == 0: WLOG(p, 'error', ('IC_CCD(X/Y)_RED_(LOW/HIGH) remove ' 'all pixels from image.')) # ---------------------------------------------------------------------- # Dark Measurement # ---------------------------------------------------------------------- # Log that we are doing dark measurement WLOG(p, '', 'Doing Dark measurement') # measure dark for whole frame p = spirouImage.MeasureDark(p, data, 'Whole det', 'full') # measure dark for blue part p = spirouImage.MeasureDark(p, datablue, 'Blue part', 'blue') # measure dark for rede part p = spirouImage.MeasureDark(p, datared, 'Red part', 'red') # get stats stats1 = [ data.size, np.nansum(~np.isfinite(data)), np.nanmedian(data), np.nansum(~np.isfinite(data)) * 100 / np.product(data.shape), p['DADEAD_FULL'], datablue.size, np.nansum(~np.isfinite(datablue)), np.nanmedian(datablue), np.nansum(~np.isfinite(datablue)) * 100 / np.product(datablue.shape), p['DADEAD_BLUE'], datared.size, np.nansum(~np.isfinite(datared)), np.nanmedian(datared), np.nansum(~np.isfinite(datared)) * 100 / np.product(datared.shape), p['DADEAD_RED'] ] return stats1
def main(night_name=None, files=None): """ cal_loc_RAW_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_loc_RAW_spirou.py [night_name] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p, calibdb=True) # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # ---------------------------------------------------------------------- # Correction of DARK # ---------------------------------------------------------------------- p, datac = spirouImage.CorrectForDark(p, data, hdr) # ---------------------------------------------------------------------- # Interpolation over bad regions (to fill in the holes) # ---------------------------------------------------------------------- # log process # wmsg = 'Interpolating over bad regions' # WLOG(p, '', wmsg) # run interpolation # datac = spirouImage.InterpolateBadRegions(p, datac) # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to e- data = spirouImage.ConvertToE(spirouImage.FlipImage(p, datac), p=p) # convert NaN to zeros data0 = np.where(~np.isfinite(data), np.zeros_like(data), data) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) data2 = spirouImage.ResizeImage(p, data0, **bkwargs) # log change in data size WLOG(p, '', ('Image format changed to ' '{0}x{1}').format(*data2.shape)) # ---------------------------------------------------------------------- # Correct for the BADPIX mask (set all bad pixels to zero) # ---------------------------------------------------------------------- p, data2 = spirouImage.CorrectForBadPix(p, data2, hdr) # ---------------------------------------------------------------------- # Background computation # ---------------------------------------------------------------------- if p['IC_DO_BKGR_SUBTRACTION']: # log that we are doing background measurement WLOG(p, '', 'Doing background measurement on raw frame') # get the bkgr measurement bargs = [p, data2, hdr] # background, xc, yc, minlevel = spirouBACK.MeasureBackgroundFF(*bargs) p, background = spirouBACK.MeasureBackgroundMap(*bargs) else: background = np.zeros_like(data2) p['BKGRDFILE'] = 'None' p.set_source('BKGRDFILE', __NAME__ + '.main()') # apply background correction to data data2 = data2 - background # ---------------------------------------------------------------------- # Construct image order_profile # ---------------------------------------------------------------------- # log that we are doing background measurement WLOG(p, '', 'Creating Order Profile') order_profile = spirouLOCOR.BoxSmoothedImage(data2, p['LOC_BOX_SIZE']) # data 2 is now set to the order profile data2o = data2.copy() data2 = order_profile.copy() # ---------------------------------------------------------------------- # Write image order_profile to file # ---------------------------------------------------------------------- # Construct folder and filename rawfits, tag1 = spirouConfig.Constants.LOC_ORDER_PROFILE_FILE(p) rawfitsname = os.path.split(rawfits)[-1] # log saving order profile wmsg = 'Saving processed raw frame in {0}' WLOG(p, '', wmsg.format(rawfitsname)) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) # write to file p = spirouImage.WriteImage(p, rawfits, order_profile, hdict) # ---------------------------------------------------------------------- # Move order_profile to calibDB and update calibDB # ---------------------------------------------------------------------- # set key for calibDB keydb = 'ORDER_PROFILE_{0}'.format(p['FIBER']) # copy dark fits file to the calibDB folder spirouDB.PutCalibFile(p, rawfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, rawfitsname, hdr) # ###################################################################### # Localization of orders on central column # ###################################################################### # storage dictionary for localization parameters loc = ParamDict() # Plots setup: start interactive plot if p['DRS_PLOT'] > 0: sPlt.start_interactive_session(p) # ---------------------------------------------------------------------- # Measurement and correction of background on the central column # ---------------------------------------------------------------------- loc = spirouBACK.MeasureBkgrdGetCentPixs(p, loc, data2) # ---------------------------------------------------------------------- # Search for order center on the central column - quick estimation # ---------------------------------------------------------------------- # log progress WLOG(p, '', 'Searching order center on central column') # plot the minimum of ycc and ic_locseuil if in debug and plot mode if p['DRS_DEBUG'] > 0 and p['DRS_PLOT']: sPlt.debug_locplot_min_ycc_loc_threshold(p, loc['YCC']) # find the central positions of the orders in the central posc_all = spirouLOCOR.FindPosCentCol(loc['YCC'], p['IC_LOCSEUIL']) # depending on the fiber type we may need to skip some pixels and also # we need to add back on the ic_offset applied start = p['IC_FIRST_ORDER_JUMP'] posc = posc_all[start:] + p['IC_OFFSET'] # work out the number of orders to use (minimum of ic_locnbmaxo and number # of orders found in 'LocateCentralOrderPositions') number_of_orders = np.min([p['IC_LOCNBMAXO'], len(posc)]) # log the number of orders than have been detected wargs = [p['FIBER'], int(number_of_orders / p['NBFIB']), p['NBFIB']] WLOG(p, 'info', ('On fiber {0} {1} orders have been detected ' 'on {2} fiber(s)').format(*wargs)) # ---------------------------------------------------------------------- # Search for order center and profile on specific columns # ---------------------------------------------------------------------- # get fit polynomial orders for position and width fitpos, fitwid = p['IC_LOCDFITC'], p['IC_LOCDFITW'] # Create arrays to store position and width of order for each order loc['CTRO'] = np.zeros((number_of_orders, data2.shape[1]), dtype=float) loc['SIGO'] = np.zeros((number_of_orders, data2.shape[1]), dtype=float) # Create arrays to store coefficients for position and width loc['ACC'] = np.zeros((number_of_orders, fitpos + 1)) loc['ASS'] = np.zeros((number_of_orders, fitpos + 1)) # Create arrays to store rms values for position and width loc['RMS_CENTER'] = np.zeros(number_of_orders) loc['RMS_FWHM'] = np.zeros(number_of_orders) # Create arrays to store point to point max value for position and width loc['MAX_PTP_CENTER'] = np.zeros(number_of_orders) loc['MAX_PTP_FRACCENTER'] = np.zeros(number_of_orders) loc['MAX_PTP_FWHM'] = np.zeros(number_of_orders) loc['MAX_PTP_FRACFWHM'] = np.zeros(number_of_orders) # Create arrays to store rejected points loc['MAX_RMPTS_POS'] = np.zeros(number_of_orders) loc['MAX_RMPTS_WID'] = np.zeros(number_of_orders) # set the central col centers in the cpos_orders array loc['CTRO'][:, p['IC_CENT_COL']] = posc[0:number_of_orders] # set source for all locs loc.set_all_sources(__NAME__ + '/main()') # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # storage for plotting loc['XPLOT'], loc['YPLOT'] = [], [] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # loop around each order rorder_num = 0 for order_num in range(number_of_orders): # find the row centers of the columns loc = spirouLOCOR.FindOrderCtrs(p, data2, loc, order_num) # only keep the orders with non-zero width mask = loc['SIGO'][order_num, :] != 0 loc['X'] = np.arange(data2.shape[1])[mask] loc.set_source('X', __NAME__ + '/main()') # check that we have enough data points to fit data if len(loc['X']) > (fitpos + 1): # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # initial fit params iofargs = [p, loc, mask, rorder_num] # initial fit for center positions for this order loc, cf_data = spirouLOCOR.InitialOrderFit(*iofargs, kind='center') # initial fit for widths for this order loc, wf_data = spirouLOCOR.InitialOrderFit(*iofargs, kind='fwhm') # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # Log order number and fit at central pixel and width and rms wargs = [ rorder_num, cf_data['cfitval'], wf_data['cfitval'], cf_data['rms'] ] WLOG(p, '', ('ORDER: {0} center at pixel {1:.1f} width ' '{2:.1f} rms {3:.3f}').format(*wargs)) # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # sigma fit params sigfargs = [p, loc, cf_data, mask, order_num, rorder_num] # sigma clip fit for center positions for this order cf_data = spirouLOCOR.SigClipOrderFit(*sigfargs, kind='center') # load results into storage arrags for this order loc['ACC'][rorder_num] = cf_data['a'] loc['RMS_CENTER'][rorder_num] = cf_data['rms'] loc['MAX_PTP_CENTER'][rorder_num] = cf_data['max_ptp'] loc['MAX_PTP_FRACCENTER'][rorder_num] = cf_data['max_ptp_frac'] loc['MAX_RMPTS_POS'][rorder_num] = cf_data['max_rmpts'] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # sigma fit params sigfargs = [p, loc, wf_data, mask, order_num, rorder_num] # sigma clip fit for width positions for this order wf_data = spirouLOCOR.SigClipOrderFit(*sigfargs, kind='fwhm') # load results into storage arrags for this order loc['ASS'][rorder_num] = wf_data['a'] loc['RMS_FWHM'][rorder_num] = wf_data['rms'] loc['MAX_PTP_FWHM'][rorder_num] = wf_data['max_ptp'] loc['MAX_PTP_FRACFWHM'][rorder_num] = wf_data['max_ptp_frac'] loc['MAX_RMPTS_WID'][rorder_num] = wf_data['max_rmpts'] # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - # increase the roder_num iterator rorder_num += 1 # else log that the order is unusable else: WLOG(p, '', 'Order found too much incomplete, discarded') # ---------------------------------------------------------------------- # Plot the image (ready for fit points to be overplotted later) if p['DRS_PLOT'] > 0: # get saturation threshold satseuil = p['IC_SATSEUIL'] * p['GAIN'] * p['NBFRAMES'] # plot image above saturation threshold sPlt.locplot_im_sat_threshold(p, loc, data2, satseuil) # ---------------------------------------------------------------------- # Log that order geometry has been measured WLOG(p, 'info', ('On fiber {0} {1} orders geometry have been ' 'measured').format(p['FIBER'], rorder_num)) # Get mean rms mean_rms_center = np.nansum( loc['RMS_CENTER'][:rorder_num]) * 1000 / rorder_num mean_rms_fwhm = np.nansum(loc['RMS_FWHM'][:rorder_num]) * 1000 / rorder_num # Log mean rms values wmsg = 'Average uncertainty on {0}: {1:.2f} [mpix]' WLOG(p, 'info', wmsg.format('position', mean_rms_center)) WLOG(p, 'info', wmsg.format('width', mean_rms_fwhm)) # ---------------------------------------------------------------------- # Plot of RMS for positions and widths # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: sPlt.locplot_order_number_against_rms(p, loc, rorder_num) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # check that max number of points rejected in center fit is below threshold if np.nansum(loc['MAX_RMPTS_POS']) > p['QC_LOC_MAXLOCFIT_REMOVED_CTR']: fmsg = 'abnormal points rejection during ctr fit ({0:.2f} > {1:.2f})' fail_msg.append( fmsg.format(np.nansum(loc['MAX_RMPTS_POS']), p['QC_LOC_MAXLOCFIT_REMOVED_CTR'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.nansum(loc['MAX_RMPTS_POS'])) qc_names.append('sum(MAX_RMPTS_POS)') qc_logic.append('sum(MAX_RMPTS_POS) > {0:.2f}' ''.format(p['QC_LOC_MAXLOCFIT_REMOVED_CTR'])) # ---------------------------------------------------------------------- # check that max number of points rejected in width fit is below threshold if np.nansum(loc['MAX_RMPTS_WID']) > p['QC_LOC_MAXLOCFIT_REMOVED_WID']: fmsg = 'abnormal points rejection during width fit ({0:.2f} > {1:.2f})' fail_msg.append( fmsg.format(np.nansum(loc['MAX_RMPTS_WID']), p['QC_LOC_MAXLOCFIT_REMOVED_WID'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.nansum(loc['MAX_RMPTS_WID'])) qc_names.append('sum(MAX_RMPTS_WID)') qc_logic.append('sum(MAX_RMPTS_WID) > {0:.2f}' ''.format(p['QC_LOC_MAXLOCFIT_REMOVED_WID'])) # ---------------------------------------------------------------------- # check that the rms in center fit is lower than qc threshold if mean_rms_center > p['QC_LOC_RMSMAX_CENTER']: fmsg = 'too high rms on center fitting ({0:.2f} > {1:.2f})' fail_msg.append(fmsg.format(mean_rms_center, p['QC_LOC_RMSMAX_CENTER'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(mean_rms_center) qc_names.append('mean_rms_center') qc_logic.append('mean_rms_center > {0:.2f}' ''.format(p['QC_LOC_RMSMAX_CENTER'])) # ---------------------------------------------------------------------- # check that the rms in center fit is lower than qc threshold if mean_rms_fwhm > p['QC_LOC_RMSMAX_FWHM']: fmsg = 'too high rms on profile fwhm fitting ({0:.2f} > {1:.2f})' fail_msg.append(fmsg.format(mean_rms_fwhm, p['QC_LOC_RMSMAX_CENTER'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(mean_rms_fwhm) qc_names.append('mean_rms_fwhm') qc_logic.append('mean_rms_fwhm > {0:.2f}' ''.format(p['QC_LOC_RMSMAX_CENTER'])) # ---------------------------------------------------------------------- # check for abnormal number of identified orders if rorder_num != p['QC_LOC_NBO']: fmsg = ('abnormal number of identified orders (found {0:.2f} ' 'expected {1:.2f})') fail_msg.append(fmsg.format(rorder_num, p['QC_LOC_NBO'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(rorder_num) qc_names.append('rorder_num') qc_logic.append('rorder_num != {0:.2f}'.format(p['QC_LOC_NBO'])) # ---------------------------------------------------------------------- # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ---------------------------------------------------------------------- # Save and record of image of localization with order center and keywords # ---------------------------------------------------------------------- raw_loco_file = os.path.basename(p['FITSFILENAME']) # construct filename locofits, tag2 = spirouConfig.Constants.LOC_LOCO_FILE(p) locofitsname = os.path.split(locofits)[-1] # log that we are saving localization file WLOG(p, '', ('Saving localization information ' 'in file: {0}').format(locofitsname)) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # define new keys to add hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=raw_loco_file) hdict = spirouImage.AddKey(p, hdict, p['KW_CCD_SIGDET']) hdict = spirouImage.AddKey(p, hdict, p['KW_CCD_CONAD']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_BCKGRD'], value=loc['MEAN_BACKGRD']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_NBO'], value=rorder_num) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DEG_C'], value=p['IC_LOCDFITC']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DEG_W'], value=p['IC_LOCDFITW']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DEG_E']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DELTA']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_MAXFLX'], value=float(loc['MAX_SIGNAL'])) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_SMAXPTS_CTR'], value=np.nansum(loc['MAX_RMPTS_POS'])) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_SMAXPTS_WID'], value=np.nansum(loc['MAX_RMPTS_WID'])) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_RMS_CTR'], value=mean_rms_center) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_RMS_WID'], value=mean_rms_fwhm) # write 2D list of position fit coefficients hdict = spirouImage.AddKey2DList(p, hdict, p['KW_LOCO_CTR_COEFF'], values=loc['ACC'][0:rorder_num]) # write 2D list of width fit coefficients hdict = spirouImage.AddKey2DList(p, hdict, p['KW_LOCO_FWHM_COEFF'], values=loc['ASS'][0:rorder_num]) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # write center fits and add header keys (via hdict) center_fits = spirouLOCOR.CalcLocoFits(loc['ACC'], data2.shape[1]) p = spirouImage.WriteImage(p, locofits, center_fits, hdict) # ---------------------------------------------------------------------- # Save and record of image of sigma # ---------------------------------------------------------------------- # construct filename locofits2, tag3 = spirouConfig.Constants.LOC_LOCO_FILE2(p) locofits2name = os.path.split(locofits2)[-1] # log that we are saving localization file wmsg = 'Saving FWHM information in file: {0}' WLOG(p, '', wmsg.format(locofits2name)) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # define new keys to add hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBACK'], value=p['BKGRDFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # add outputs hdict = spirouImage.AddKey(p, hdict, p['KW_CCD_SIGDET']) hdict = spirouImage.AddKey(p, hdict, p['KW_CCD_CONAD']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_NBO'], value=rorder_num) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DEG_C'], value=p['IC_LOCDFITC']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DEG_W'], value=p['IC_LOCDFITW']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_DEG_E']) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_MAXFLX'], value=float(loc['MAX_SIGNAL'])) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_SMAXPTS_CTR'], value=np.nansum(loc['MAX_RMPTS_POS'])) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_SMAXPTS_WID'], value=np.nansum(loc['MAX_RMPTS_WID'])) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_RMS_CTR'], value=mean_rms_center) hdict = spirouImage.AddKey(p, hdict, p['KW_LOC_RMS_WID'], value=mean_rms_fwhm) # write 2D list of position fit coefficients hdict = spirouImage.AddKey2DList(p, hdict, p['KW_LOCO_CTR_COEFF'], values=loc['ACC'][0:rorder_num]) # write 2D list of width fit coefficients hdict = spirouImage.AddKey2DList(p, hdict, p['KW_LOCO_FWHM_COEFF'], values=loc['ASS'][0:rorder_num]) # add quality control hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) # write image and add header keys (via hdict) width_fits = spirouLOCOR.CalcLocoFits(loc['ASS'], data2.shape[1]) p = spirouImage.WriteImage(p, locofits2, width_fits, hdict) # ---------------------------------------------------------------------- # Save and Record of image of localization # ---------------------------------------------------------------------- if p['IC_LOCOPT1']: # construct filename locofits3, tag4 = spirouConfig.Constants.LOC_LOCO_FILE3(p) locofits3name = os.path.split(locofits3)[-1] # log that we are saving localization file wmsg1 = 'Saving localization image with superposition of orders in ' wmsg2 = 'file: {0}'.format(locofits3name) WLOG(p, '', [wmsg1, wmsg2]) # superpose zeros over the fit in the image data4 = spirouLOCOR.ImageLocSuperimp(data2o, loc['ACC'][0:rorder_num]) # save this image to file hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_FIBER'], value=p['FIBER']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag4) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) p = spirouImage.WriteImage(p, locofits3, data4, hdict) # ---------------------------------------------------------------------- # Update the calibration database # ---------------------------------------------------------------------- if p['QC'] == 1: keydb = 'LOC_' + p['FIBER'] # copy localisation file to the calibDB folder spirouDB.PutCalibFile(p, locofits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, locofitsname, hdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None): """ cal_DARK_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_DARK_spirou.py [night_directory] [fitsfilename] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p) # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='average') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # ---------------------------------------------------------------------- # Dark exposure time check # ---------------------------------------------------------------------- # log the Dark exposure time WLOG(p, 'info', 'Dark Time = {0:.3f} s'.format(p['EXPTIME'])) # Quality control: make sure the exposure time is longer than qc_dark_time if p['EXPTIME'] < p['QC_DARK_TIME']: emsg = 'Dark exposure time too short (< {0:.1f} s)' WLOG(p, 'error', emsg.format(p['QC_DARK_TIME'])) # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # # rotate the image and conver from ADU/s to e- # data = data[::-1, ::-1] * p['exptime'] * p['gain'] # convert NaN to zeros nanmask = ~np.isfinite(data) data0 = np.where(nanmask, np.zeros_like(data), data) # resize blue image bkwargs = dict(xlow=p['IC_CCDX_BLUE_LOW'], xhigh=p['IC_CCDX_BLUE_HIGH'], ylow=p['IC_CCDY_BLUE_LOW'], yhigh=p['IC_CCDY_BLUE_HIGH']) datablue, nx2, ny2 = spirouImage.ResizeImage(p, data, **bkwargs) # Make sure we have data in the blue image if nx2 == 0 or ny2 == 0: WLOG(p, 'error', ('IC_CCD(X/Y)_BLUE_(LOW/HIGH) remove ' 'all pixels from image.')) # resize red image rkwargs = dict(xlow=p['IC_CCDX_RED_LOW'], xhigh=p['IC_CCDX_RED_HIGH'], ylow=p['IC_CCDY_RED_LOW'], yhigh=p['IC_CCDY_RED_HIGH']) datared, nx3, ny3 = spirouImage.ResizeImage(p, data, **rkwargs) # Make sure we have data in the red image if nx3 == 0 or ny3 == 0: WLOG(p, 'error', ('IC_CCD(X/Y)_RED_(LOW/HIGH) remove ' 'all pixels from image.')) # ---------------------------------------------------------------------- # Dark Measurement # ---------------------------------------------------------------------- # Log that we are doing dark measurement WLOG(p, '', 'Doing Dark measurement') # measure dark for whole frame p = spirouImage.MeasureDark(p, data, 'Whole det', 'full') # measure dark for blue part p = spirouImage.MeasureDark(p, datablue, 'Blue part', 'blue') # measure dark for rede part p = spirouImage.MeasureDark(p, datared, 'Red part', 'red') # ---------------------------------------------------------------------- # Identification of bad pixels # ---------------------------------------------------------------------- # get number of bad dark pixels (as a fraction of total pixels) with warnings.catch_warnings(record=True) as w: baddark = 100.0 * np.sum(data0 > p['DARK_CUTLIMIT']) baddark /= np.product(data0.shape) # log the fraction of bad dark pixels wmsg = 'Frac pixels with DARK > {0:.2f} ADU/s = {1:.3f} %' WLOG(p, 'info', wmsg.format(p['DARK_CUTLIMIT'], baddark)) # define mask for values above cut limit or NaN with warnings.catch_warnings(record=True) as w: datacutmask = ~((data0 > p['DARK_CUTLIMIT']) | (~np.isfinite(data))) spirouCore.spirouLog.warninglogger(p, w) # get number of pixels above cut limit or NaN n_bad_pix = np.product(data.shape) - np.nansum(datacutmask) # work out fraction of dead pixels + dark > cut, as percentage p['DADEADALL'] = n_bad_pix * 100 / np.product(data.shape) p.set_source('DADEADALL', __NAME__ + '/main()') # log fraction of dead pixels + dark > cut logargs = [p['DARK_CUTLIMIT'], p['DADEADALL']] WLOG(p, 'info', ('Total Frac dead pixels (N.A.N) + DARK > ' '{0:.2f} ADU/s = {1:.3f} %').format(*logargs)) # ---------------------------------------------------------------------- # Plots # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # start interactive plot sPlt.start_interactive_session(p) # plot the image with blue and red regions sPlt.darkplot_image_and_regions(p, data) # plot histograms sPlt.darkplot_histograms(p) # end interactive session sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # check that med < qc_max_darklevel if p['MED_FULL'] > p['QC_MAX_DARKLEVEL']: # add failed message to fail message list fmsg = 'Unexpected Median Dark level ({0:5.2f} > {1:5.2f} ADU/s)' fail_msg.append(fmsg.format(p['MED_FULL'], p['QC_MAX_DARKLEVEL'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(p['MED_FULL']) qc_names.append('MED_FULL') qc_logic.append('MED_FULL > {0:.2f}'.format(p['QC_MAX_DARKLEVEL'])) # ---------------------------------------------------------------------- # check that fraction of dead pixels < qc_max_dead if p['DADEADALL'] > p['QC_MAX_DEAD']: # add failed message to fail message list fmsg = 'Unexpected Fraction of dead pixels ({0:5.2f} > {1:5.2f} %)' fail_msg.append(fmsg.format(p['DADEADALL'], p['QC_MAX_DEAD'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(p['DADEADALL']) qc_names.append('DADEADALL') qc_logic.append('DADEADALL > {0:.2f}'.format(p['QC_MAX_DEAD'])) # ---------------------------------------------------------------------- # checl that the precentage of dark pixels < qc_max_dark if baddark > p['QC_MAX_DARK']: fmsg = ('Unexpected Fraction of dark pixels > {0:.2f} ADU/s ' '({1:.2f} > {2:.2f}') fail_msg.append( fmsg.format(p['DARK_CUTLIMIT'], baddark, p['QC_MAX_DARK'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(baddark) qc_names.append('baddark') qc_logic.append('baddark > {0:.2f}'.format(p['QC_MAX_DARK'])) # ---------------------------------------------------------------------- # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ---------------------------------------------------------------------- # Save dark to file # ---------------------------------------------------------------------- # get raw dark filename rawdarkfile = os.path.basename(p['FITSFILENAME']) # construct folder and filename darkfits, tag = spirouConfig.Constants.DARK_FILE(p) darkfitsname = os.path.basename(darkfits) # log saving dark frame WLOG(p, '', 'Saving Dark frame in ' + darkfitsname) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # define new keys to add hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_DEAD'], value=p['DADEAD_FULL']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_MED'], value=p['MED_FULL']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_B_DEAD'], value=p['DADEAD_BLUE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_B_MED'], value=p['MED_BLUE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_R_DEAD'], value=p['DADEAD_RED']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_R_MED'], value=p['MED_RED']) hdict = spirouImage.AddKey(p, hdict, p['KW_DARK_CUT'], value=p['DARK_CUTLIMIT']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # Set to zero dark value > dark_cutlimit cutmask = data0 > p['DARK_CUTLIMIT'] data0c = np.where(cutmask, np.zeros_like(data0), data0) # write image and add header keys (via hdict) p = spirouImage.WriteImage(p, darkfits, data0c, hdict) # ---------------------------------------------------------------------- # Save bad pixel mask # ---------------------------------------------------------------------- # construct bad pixel file name badpixelfits, tag = spirouConfig.Constants.DARK_BADPIX_FILE(p) badpixelfitsname = os.path.split(badpixelfits)[-1] # log that we are saving bad pixel map in dir WLOG(p, '', 'Saving Bad Pixel Map in ' + badpixelfitsname) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # define new keys to add hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) hdict['DACUT'] = (p['DARK_CUTLIMIT'], 'Threshold of dark level retain [ADU/s]') # write to file datacutmask = np.array(datacutmask, dtype=float) p = spirouImage.WriteImage(p, badpixelfits, datacutmask, hdict, dtype='float64') # ---------------------------------------------------------------------- # Move to calibDB and update calibDB # ---------------------------------------------------------------------- if p['QC']: # set dark key if p['DPRTYPE'] == 'DARK_DARK': keydb = 'DARK' elif p['USE_SKYDARK_CORRECTION']: keydb = 'SKYDARK' else: emsg = 'Error: Currently {0} only supports DARK_DARK and OBJ_DARK' WLOG(p, 'error', emsg.format(__NAME__)) # copy dark fits file to the calibDB folder spirouDB.PutCalibFile(p, darkfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, darkfitsname, hdr) # # set badpix key # keydb = 'BADPIX_OLD' # # copy badpix fits file to calibDB folder # spirouDB.PutCalibFile(p, badpixelfits) # # update the master calib DB file with new key # spirouDB.UpdateCalibMaster(p, keydb, badpixelfitsname, hdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None): """ cal_shape_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_shape_spirou.py [night_directory] [fitsfilename] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p) # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # ---------------------------------------------------------------------- # Get basic image properties for FP file # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # ---------------------------------------------------------------------- # Correction of reference FP # ---------------------------------------------------------------------- # set the number of frames p['NBFRAMES'] = 1 p.set_source('NBFRAMES', __NAME__ + '.main()') # Correction of DARK p, datac = spirouImage.CorrectForDark(p, data, hdr) # Resize hc data # rotate the image and convert from ADU/s to e- data = spirouImage.ConvertToE(spirouImage.FlipImage(p, datac), p=p) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) data1 = spirouImage.ResizeImage(p, data, **bkwargs) # log change in data size WLOG(p, '', ('FPref Image format changed to {0}x{1}').format(*data1.shape)) # Correct for the BADPIX mask (set all bad pixels to zero) bargs = [p, data1, hdr] p, data1 = spirouImage.CorrectForBadPix(*bargs) p, badpixmask = spirouImage.CorrectForBadPix(*bargs, return_map=True) # log progress WLOG(p, '', 'Cleaning FPref hot pixels') # correct hot pixels data1 = spirouEXTOR.CleanHotpix(data1, badpixmask) # Log the number of dead pixels # get the number of bad pixels with warnings.catch_warnings(record=True) as _: n_bad_pix = np.nansum(data1 <= 0) n_bad_pix_frac = n_bad_pix * 100 / np.product(data1.shape) # Log number wmsg = 'Nb FPref dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ---------------------------------------------------------------------- # Get master FP file # ---------------------------------------------------------------------- # log progress WLOG(p, '', 'Getting FP Master from calibDB') # get master fp p, masterfp = spirouImage.GetFPMaster(p, hdr) # ---------------------------------------------------------------------- # Get transform parameters # ---------------------------------------------------------------------- # log progress wargs = [p['ARG_FILE_NAMES'][0], p['FPMASTERFILE']] WLOG(p, 'info', 'Calculating transforming for {0} onto {1}'.format(*wargs)) gout = spirouImage.GetLinearTransformParams(p, masterfp, data1) transform, xres, yres = gout # ------------------------------------------------------------------ # Need to straighten the fp data for debug # ------------------------------------------------------------------ p, shapem_x = spirouImage.GetShapeX(p, hdr) p, shapem_y = spirouImage.GetShapeY(p, hdr) data2 = spirouImage.EATransform(data1, transform, dxmap=shapem_x, dymap=shapem_y) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # if transform is None means the fp image quality was too poor if transform is None: fail_msg.append('FP Image quality too poor (sigma clip failed)') passed = False qc_pass.append(0) else: qc_pass.append(1) qc_values.append('None') qc_names.append('Image Quality') qc_logic.append('Image too poor') # ---------------------------------------------------------------------- # get residual qc parameter qc_res = p['SHAPE_QC_LINEAR_TRANS_RES_THRES'] # assess quality of x residuals if xres > qc_res: fail_msg.append('x-resdiuals too high {0} > {1}'.format(xres, qc_res)) passed = False qc_pass.append(0) else: qc_pass.append(1) qc_values.append(xres) qc_names.append('XRES') qc_logic.append('XRES > {0}'.format(qc_res)) # assess quality of x residuals if yres > qc_res: fail_msg.append('y-resdiuals too high {0} > {1}'.format(yres, qc_res)) passed = False qc_pass.append(0) else: qc_pass.append(1) qc_values.append(yres) qc_names.append('YRES') qc_logic.append('YRES > {0}'.format(qc_res)) # ---------------------------------------------------------------------- # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ------------------------------------------------------------------ # Writing shape to file # ------------------------------------------------------------------ # get the raw tilt file name raw_shape_file = os.path.basename(p['FITSFILENAME']) # construct file name and path shapefits, tag = spirouConfig.Constants.SLIT_SHAPE_LOCAL_FILE(p) shapefitsname = os.path.basename(shapefits) # Log that we are saving tilt file wmsg = 'Saving shape information in file: {0}' WLOG(p, '', wmsg.format(shapefitsname)) # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(hdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPEX'], value=p['SHAPEXFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPEY'], value=p['SHAPEYFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFPMASTER'], value=p['FPMASTERFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # add the transform parameters hdict = spirouImage.AddKey(p, hdict, p['KW_SHAPE_DX'], value=transform[0]) hdict = spirouImage.AddKey(p, hdict, p['KW_SHAPE_DY'], value=transform[1]) hdict = spirouImage.AddKey(p, hdict, p['KW_SHAPE_A'], value=transform[2]) hdict = spirouImage.AddKey(p, hdict, p['KW_SHAPE_B'], value=transform[3]) hdict = spirouImage.AddKey(p, hdict, p['KW_SHAPE_C'], value=transform[4]) hdict = spirouImage.AddKey(p, hdict, p['KW_SHAPE_D'], value=transform[5]) # write tilt file to file p = spirouImage.WriteImage(p, shapefits, [transform], hdict) # ---------------------------------------------------------------------- # Move to calibDB and update calibDB # ---------------------------------------------------------------------- if p['QC']: # add shape keydb = 'SHAPE' # copy shape file to the calibDB folder spirouDB.PutCalibFile(p, shapefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, shapefitsname, hdr) # ------------------------------------------------------------------ # Writing sanity check files # ------------------------------------------------------------------ if p['SHAPE_DEBUG_OUTPUTS']: # log WLOG(p, '', 'Saving debug sanity check files') # construct file names dargs = [p, p['ARG_FILE_NAMES'][0]] out1 = spirouConfig.Constants.SLIT_SHAPE_IN_FP_FILE(*dargs) input_fp_file, tag1= out1 out2 = spirouConfig.Constants.SLIT_SHAPE_OUT_FP_FILE(*dargs) output_fp_file, tag2 = out2 # write input fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) p = spirouImage.WriteImage(p, input_fp_file, data1, hdict) # write output fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) p = spirouImage.WriteImage(p, output_fp_file, data2, hdict) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None): """ cal_SLIT_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_SLIT_spirou.py [night_directory] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p, calibdb=True) # set the fiber type p['FIBER'] = 'AB' p.set_source('FIBER', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # ---------------------------------------------------------------------- # Correction of DARK # ---------------------------------------------------------------------- p, datac = spirouImage.CorrectForDark(p, data, hdr) datac = data # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to e- data = spirouImage.ConvertToE(spirouImage.FlipImage(p, datac), p=p) # convert NaN to zeros data0 = np.where(~np.isfinite(data), np.zeros_like(data), data) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) data2 = spirouImage.ResizeImage(p, data0, **bkwargs) # log change in data size WLOG(p, '', ('Image format changed to ' '{0}x{1}').format(*data2.shape)) # ---------------------------------------------------------------------- # Correct for the BADPIX mask (set all bad pixels to zero) # ---------------------------------------------------------------------- p, data2 = spirouImage.CorrectForBadPix(p, data2, hdr) p, badpixmap = spirouImage.CorrectForBadPix(p, data2, hdr, return_map=True) # ---------------------------------------------------------------------- # Background computation # ---------------------------------------------------------------------- if p['IC_DO_BKGR_SUBTRACTION']: # log that we are doing background measurement WLOG(p, '', 'Doing background measurement on raw frame') # get the bkgr measurement bargs = [p, data2, hdr, badpixmap] # background, xc, yc, minlevel = spirouBACK.MeasureBackgroundFF(*bargs) p, background = spirouBACK.MeasureBackgroundMap(*bargs) else: background = np.zeros_like(data2) p['BKGRDFILE'] = 'None' p.set_source('BKGRDFILE', __NAME__ + '.main()') # apply background correction to data data2 = data2 - background # save data to loc loc = ParamDict() loc['DATA'] = data2 loc.set_source('DATA', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- # get the number of bad pixels n_bad_pix = np.nansum(data2 <= 0) n_bad_pix_frac = n_bad_pix * 100 / np.product(data2.shape) # Log number wmsg = 'Nb dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ------------------------------------------------------------------ # Get localisation coefficients # ------------------------------------------------------------------ # original there is a loop but it is not used --> removed p = spirouImage.FiberParams(p, p['FIBER'], merge=True) # get localisation fit coefficients p, loc = spirouLOCOR.GetCoeffs(p, hdr, loc) # ------------------------------------------------------------------ # Calculate shape map # ------------------------------------------------------------------ loc = spirouImage.GetShapeMap(p, loc) # ------------------------------------------------------------------ # Plotting # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # plots setup: start interactive plot sPlt.start_interactive_session(p) # plot the shape process for each order sPlt.slit_shape_angle_plot(p, loc) # end interactive section sPlt.end_interactive_session(p) # ------------------------------------------------------------------ # Writing to file # ------------------------------------------------------------------ # get the raw tilt file name raw_shape_file = os.path.basename(p['FITSFILENAME']) # construct file name and path shapefits, tag = spirouConfig.Constants.SLIT_XSHAPE_FILE(p) shapefitsname = os.path.basename(shapefits) # Log that we are saving tilt file wmsg = 'Saving shape information in file: {0}' WLOG(p, '', wmsg.format(shapefitsname)) # Copy keys from fits file # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(hdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPE'], value=raw_shape_file) # write tilt file to file p = spirouImage.WriteImage(p, shapefits, loc['DXMAP'], hdict) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # TODO: Decide on some quality control criteria? # set passed variable and fail message list passed, fail_msg = True, [] # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Move to calibDB and update calibDB # ---------------------------------------------------------------------- if p['QC']: keydb = 'SHAPE' # copy shape file to the calibDB folder spirouDB.PutCalibFile(p, shapefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, shapefitsname, hdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, fpfile=None, hcfiles=None): """ cal_wave_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_wave_spirou.py [night_directory] [fpfile] [hcfiles] :param night_name: string or None, the folder within data reduced directory containing files (also reduced directory) i.e. /data/reduced/20170710 would be "20170710" but /data/reduced/AT5/20180409 is "AT5/20180409" :param fpfile: string, or None, the FP file to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :param hcfiles: string, list or None, the list of HC files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) if hcfiles is None or fpfile is None: names, types = ['fpfile', 'hcfiles'], [str, str] customargs = spirouStartup.GetCustomFromRuntime(p, [0, 1], types, names, last_multi=True) else: customargs = dict(hcfiles=hcfiles, fpfile=fpfile) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, customargs=customargs, mainfitsdir='reduced', mainfitsfile='hcfiles') # ---------------------------------------------------------------------- # Construct reference filename and get fiber type # ---------------------------------------------------------------------- p, fpfitsfilename = spirouStartup.SingleFileSetup(p, filename=p['FPFILE']) fiber1 = str(p['FIBER']) p, hcfilenames = spirouStartup.MultiFileSetup(p, files=p['HCFILES']) fiber2 = str(p['FIBER']) # set the hcfilename to the first hcfilenames hcfitsfilename = hcfilenames[0] # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # ---------------------------------------------------------------------- # Have to check that the fibers match # ---------------------------------------------------------------------- if fiber1 == fiber2: p['FIBER'] = fiber1 fsource = __NAME__ + '/main() & spirouStartup.GetFiberType()' p.set_source('FIBER', fsource) else: emsg = 'Fiber not matching for {0} and {1}, should be the same' eargs = [hcfitsfilename, fpfitsfilename] WLOG(p, 'error', emsg.format(*eargs)) # set the fiber type p['FIB_TYP'] = [p['FIBER']] p.set_source('FIB_TYP', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Read FP and HC files # ---------------------------------------------------------------------- # read and combine all HC files except the first (fpfitsfilename) rargs = [p, 'add', hcfitsfilename, hcfilenames[1:]] p, hcdata, hchdr = spirouImage.ReadImageAndCombine(*rargs) # read first file (fpfitsfilename) fpdata, fphdr, _, _ = spirouImage.ReadImage(p, fpfitsfilename) # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'], loc['HCCDR'] = hcdata, hchdr, hchdr.comments loc['FPDATA'], loc['FPHDR'], loc['FPCDR'] = fpdata, fphdr, fphdr.comments # set the source sources = ['HCDATA', 'HCHDR', 'HCCDR'] loc.set_sources(sources, 'spirouImage.ReadImageAndCombine()') sources = ['FPDATA', 'FPHDR', 'FPCDR'] loc.set_sources(sources, 'spirouImage.ReadImage()') # ---------------------------------------------------------------------- # Get basic image properties for reference file # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hchdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hchdr, name='exptime') # get gain p = spirouImage.GetGain(p, hchdr, name='gain') # get acquisition time p = spirouImage.GetAcqTime(p, hchdr, name='acqtime', kind='julian') bjdref = p['ACQTIME'] # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # get lamp parameters p = spirouWAVE2.get_lamp_parameters(p, hchdr) # get number of orders # we always get fibre A number because AB is doubled in constants file loc['NBO'] = p['QC_LOC_NBO_FPALL']['A'] loc.set_source('NBO', __NAME__ + '.main()') # get number of pixels in x from hcdata size loc['NBPIX'] = loc['HCDATA'].shape[1] loc.set_source('NBPIX', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Read blaze # ---------------------------------------------------------------------- # get tilts p, loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hchdr) loc.set_source('BLAZE', __NAME__ + '/main() + /spirouImage.ReadBlazeFile') # make copy of blaze (as it's overwritten later in CCF part) # TODO is this needed? More sensible to make and set copy in CCF? loc['BLAZE2'] = np.copy(loc['BLAZE']) # ---------------------------------------------------------------------- # Read wave solution # ---------------------------------------------------------------------- # wavelength file; we will use the polynomial terms in its header, # NOT the pixel values that would need to be interpolated # set source of wave file wsource = __NAME__ + '/main() + /spirouImage.GetWaveSolution' # Force A and B to AB solution if p['FIBER'] in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = p['FIBER'] # get wave image wout = spirouImage.GetWaveSolution(p, hdr=hchdr, return_wavemap=True, return_filename=True, fiber=wave_fiber) loc['WAVEPARAMS'], loc['WAVE_INIT'], loc['WAVEFILE'], loc['WSOURCE'] = wout loc.set_sources(['WAVE_INIT', 'WAVEFILE', 'WAVEPARAMS', 'WSOURCE'], wsource) poly_wave_sol = loc['WAVEPARAMS'] # ---------------------------------------------------------------------- # Check that wave parameters are consistent with "ic_ll_degr_fit" # ---------------------------------------------------------------------- loc = spirouImage.CheckWaveSolConsistency(p, loc) # ---------------------------------------------------------------------- # HC wavelength solution # ---------------------------------------------------------------------- # log that we are running the HC part and the mode wmsg = 'Now running the HC solution, mode = {0}' WLOG(p, 'info', wmsg.format(p['WAVE_MODE_HC'])) # get the solution loc = spirouWAVE2.do_hc_wavesol(p, loc) # ---------------------------------------------------------------------- # Quality control - HC solution # ---------------------------------------------------------------------- # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # quality control on sigma clip (sig1 > qc_hc_wave_sigma_max if loc['SIG1'] > p['QC_HC_WAVE_SIGMA_MAX']: fmsg = 'Sigma too high ({0:.5f} > {1:.5f})' fail_msg.append(fmsg.format(loc['SIG1'], p['QC_HC_WAVE_SIGMA_MAX'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(loc['SIG1']) qc_names.append('SIG1 HC') qc_logic.append('SIG1 > {0:.2f}'.format(p['QC_HC_WAVE_SIGMA_MAX'])) # ---------------------------------------------------------------------- # check the difference between consecutive orders is always positive # get the differences wave_diff = loc['WAVE_MAP2'][1:] - loc['WAVE_MAP2'][:-1] if np.min(wave_diff) < 0: fmsg = 'Negative wavelength difference between orders' fail_msg.append(fmsg) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.min(wave_diff)) qc_names.append('MIN WAVE DIFF HC') qc_logic.append('MIN WAVE DIFF < 0') # ---------------------------------------------------------------------- # check the difference between consecutive pixels along an order is # always positive # loop through the orders ord_check = np.zeros((loc['NBO']), dtype=bool) for order in range(loc['NBO']): oc = np.all(loc['WAVE_MAP2'][order, 1:] > loc['WAVE_MAP2'][order, :-1]) ord_check[order] = oc # TODO: Melissa Why is this here???? # ord_check[5] = False if np.all(ord_check): qc_pass.append(1) qc_values.append('None') else: fmsg = 'Negative wavelength difference along an order' fail_msg.append(fmsg) passed = False qc_pass.append(0) qc_values.append(np.ndarray.tolist(np.where(~ord_check)[0])) # add to qc header lists # vale: array of orders where it fails qc_names.append('WAVE DIFF ALONG ORDER HC') qc_logic.append('WAVE DIFF ALONG ORDER < 0') # ---------------------------------------------------------------------- # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ---------------------------------------------------------------------- # log the global stats # ---------------------------------------------------------------------- # calculate catalog-fit residuals in km/s res_hc = [] sumres_hc = 0.0 sumres2_hc = 0.0 for order in range(loc['NBO']): # get HC line wavelengths for the order order_mask = loc['ORD_T'] == order hc_x_ord = loc['XGAU_T'][order_mask] hc_ll_ord = np.polyval(loc['POLY_WAVE_SOL'][order][::-1], hc_x_ord) hc_ll_cat = loc['WAVE_CATALOG'][order_mask] hc_ll_diff = hc_ll_ord - hc_ll_cat res_hc.append(hc_ll_diff * speed_of_light / hc_ll_cat) sumres_hc += np.nansum(res_hc[order]) sumres2_hc += np.nansum(res_hc[order]**2) total_lines_hc = len(np.concatenate(res_hc)) final_mean_hc = sumres_hc / total_lines_hc final_var_hc = (sumres2_hc / total_lines_hc) - (final_mean_hc**2) wmsg1 = 'On fiber {0} HC fit line statistic:'.format(p['FIBER']) wargs2 = [ final_mean_hc * 1000.0, np.sqrt(final_var_hc) * 1000.0, total_lines_hc, 1000.0 * np.sqrt(final_var_hc / total_lines_hc) ] wmsg2 = ('\tmean={0:.3f}[m/s] rms={1:.1f} {2} HC lines (error on mean ' 'value:{3:.4f}[m/s])'.format(*wargs2)) WLOG(p, 'info', [wmsg1, wmsg2]) # ---------------------------------------------------------------------- # Save wave map to file # ---------------------------------------------------------------------- # TODO single file-naming function? Ask Neil # get base input filenames bfilenames = [] for raw_file in p['ARG_FILE_NAMES']: bfilenames.append(os.path.basename(raw_file)) # get wave filename wavefits, tag1 = spirouConfig.Constants.WAVE_FILE_EA(p) wavefitsname = os.path.basename(wavefits) # log progress WLOG(p, '', 'Saving wave map to {0}'.format(wavefitsname)) # log progress wargs = [p['FIBER'], wavefitsname] wmsg = 'Write wavelength solution for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # write solution to fitsfilename header # copy original keys hdict = spirouImage.CopyOriginalKeys(loc['HCHDR'], loc['HCCDR']) # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) # TODO add DRS_DATE and DRS_NOW hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) # set the input files hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BLAZFILE']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # add wave solution date hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME1'], value=p['MAX_TIME_HUMAN']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME2'], value=p['MAX_TIME_UNIX']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_CODE'], value=__NAME__) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBWAVE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVESOURCE'], value=loc['WSOURCE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # add number of orders hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_ORD_N'], value=loc['POLY_WAVE_SOL'].shape[0]) # add degree of fit hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_LL_DEG'], value=loc['POLY_WAVE_SOL'].shape[1] - 1) # add wave solution hdict = spirouImage.AddKey2DList(p, hdict, p['KW_WAVE_PARAM'], values=loc['POLY_WAVE_SOL']) # write the wave "spectrum" p = spirouImage.WriteImage(p, wavefits, loc['WAVE_MAP2'], hdict) # get filename for E2DS calibDB copy of FITSFILENAME e2dscopy_filename, tag2 = spirouConfig.Constants.WAVE_E2DS_COPY(p) wargs = [p['FIBER'], os.path.split(e2dscopy_filename)[-1]] wmsg = 'Write reference E2DS spectra for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # make a copy of the E2DS file for the calibBD hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) p = spirouImage.WriteImage(p, e2dscopy_filename, loc['HCDATA'], hdict) # ---------------------------------------------------------------------- # Save resolution and line profiles to file # ---------------------------------------------------------------------- raw_infile = os.path.basename(p['FITSFILENAME']) # get wave filename resfits, tag3 = spirouConfig.Constants.WAVE_RES_FILE_EA(p) resfitsname = os.path.basename(resfits) WLOG(p, '', 'Saving wave resmap to {0}'.format(resfitsname)) # make a copy of the E2DS file for the calibBD # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) # TODO add DRS_DATE and DRS_NOW hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) # get res data in correct format resdata, hdicts = spirouWAVE2.generate_res_files(p, loc, hdict) # save to file p = spirouImage.WriteImageMulti(p, resfits, resdata, hdicts=hdicts) # ---------------------------------------------------------------------- # Update calibDB # ---------------------------------------------------------------------- if p['QC']: # set the wave key keydb = 'WAVE_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, wavefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, wavefitsname, loc['HCHDR']) # set the hcref key keydb = 'HCREF_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, e2dscopy_filename) # update the master calib DB file with new key e2dscopyfits = os.path.split(e2dscopy_filename)[-1] spirouDB.UpdateCalibMaster(p, keydb, e2dscopyfits, loc['HCHDR']) # ---------------------------------------------------------------------- # Update header of current files # ---------------------------------------------------------------------- # only copy over if QC passed if p['QC']: rdir = os.path.dirname(wavefits) # loop around hc files and update header with for rawhcfile in p['ARG_FILE_NAMES']: hcfile = os.path.join(rdir, rawhcfile) raw_infilepath1 = os.path.join(p['ARG_FILE_DIR'], hcfile) p = spirouImage.UpdateWaveSolutionHC(p, loc, raw_infilepath1) # ---------------------------------------------------------------------- # HC+FP wavelength solution # ---------------------------------------------------------------------- # check if there's a FP input and if HC solution passed QCs if has_fp and p['QC']: # log that we are doing the FP solution wmsg = 'Now running the combined FP-HC solution, mode = {}' WLOG(p, 'info', wmsg.format(p['WAVE_MODE_FP'])) # do the wavelength solution loc = spirouWAVE2.do_fp_wavesol(p, loc) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # get parameters ffrom p p['QC_RMS_LITTROW_MAX'] = p['QC_HC_RMS_LITTROW_MAX'] p['QC_DEV_LITTROW_MAX'] = p['QC_HC_DEV_LITTROW_MAX'] # set passed variable and fail message list # passed, fail_msg = True, [] # qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # check the difference between consecutive orders is always positive # get the differences wave_diff = loc['LL_FINAL'][1:] - loc['LL_FINAL'][:-1] if np.min(wave_diff) < 0: fmsg = 'Negative wavelength difference between orders' fail_msg.append(fmsg) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.min(wave_diff)) qc_names.append('MIN WAVE DIFF FP-HC') qc_logic.append('MIN WAVE DIFF < 0') # ---------------------------------------------------------------------- # check for infinites and NaNs in mean residuals from fit if ~np.isfinite(loc['X_MEAN_2']): # add failed message to the fail message list fmsg = 'NaN or Inf in X_MEAN_2' fail_msg.append(fmsg) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(loc['X_MEAN_2']) qc_names.append('X_MEAN_2') qc_logic.append('X_MEAN_2 not finite') # ---------------------------------------------------------------------- # iterate through Littrow test cut values lit_it = 2 # checks every other value # TODO: This QC check (or set of QC checks needs re-writing it is # TODO: nearly impossible to understand for x_it in range(1, len(loc['X_CUT_POINTS_' + str(lit_it)]), 2): # get x cut point x_cut_point = loc['X_CUT_POINTS_' + str(lit_it)][x_it] # get the sigma for this cut point sig_littrow = loc['LITTROW_SIG_' + str(lit_it)][x_it] # get the abs min and max dev littrow values min_littrow = abs(loc['LITTROW_MINDEV_' + str(lit_it)][x_it]) max_littrow = abs(loc['LITTROW_MAXDEV_' + str(lit_it)][x_it]) # get the corresponding order min_littrow_ord = loc['LITTROW_MINDEVORD_' + str(lit_it)][x_it] max_littrow_ord = loc['LITTROW_MAXDEVORD_' + str(lit_it)][x_it] # check if sig littrow is above maximum rms_littrow_max = p['QC_RMS_LITTROW_MAX'] dev_littrow_max = p['QC_DEV_LITTROW_MAX'] if sig_littrow > rms_littrow_max: fmsg = ('Littrow test (x={0}) failed (sig littrow = ' '{1:.2f} > {2:.2f})') fargs = [x_cut_point, sig_littrow, rms_littrow_max] fail_msg.append(fmsg.format(*fargs)) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(sig_littrow) qc_names.append('sig_littrow') qc_logic.append('sig_littrow > {0:.2f}'.format(rms_littrow_max)) # ---------------------------------------------------------------------- # check if min/max littrow is out of bounds if np.max([max_littrow, min_littrow]) > dev_littrow_max: fmsg = ('Littrow test (x={0}) failed (min|max dev = ' '{1:.2f}|{2:.2f} > {3:.2f} for order {4}|{5})') fargs = [ x_cut_point, min_littrow, max_littrow, dev_littrow_max, min_littrow_ord, max_littrow_ord ] fail_msg.append(fmsg.format(*fargs)) passed = False qc_pass.append(0) # TODO: Should this be the QC header values? # TODO: it does not change the outcome of QC (i.e. passed=False) # TODO: So what is the point? # if sig was out of bounds, recalculate if sig_littrow > rms_littrow_max: # conditions check1 = min_littrow > dev_littrow_max check2 = max_littrow > dev_littrow_max # get the residuals respix = loc['LITTROW_YY_' + str(lit_it)][x_it] # check if both are out of bounds if check1 and check2: # remove respective orders worst_order = (min_littrow_ord, max_littrow_ord) respix_2 = np.delete(respix, worst_order) redo_sigma = True # check if min is out of bounds elif check1: # remove respective order worst_order = min_littrow_ord respix_2 = np.delete(respix, worst_order) redo_sigma = True # check if max is out of bounds elif check2: # remove respective order worst_order = max_littrow_ord respix_2 = np.delete(respix, max_littrow_ord) redo_sigma = True # else do not recalculate sigma else: redo_sigma, respix_2, worst_order = False, None, None wmsg = 'No outlying orders, sig littrow not recalculated' fail_msg.append(wmsg.format()) # if outlying order, recalculate stats if redo_sigma: mean = np.nansum(respix_2) / len(respix_2) mean2 = np.nansum(respix_2**2) / len(respix_2) rms = np.sqrt(mean2 - mean**2) if rms > rms_littrow_max: fmsg = ( 'Littrow test (x={0}) failed (sig littrow = ' '{1:.2f} > {2:.2f} removing order {3})') fargs = [ x_cut_point, rms, rms_littrow_max, worst_order ] fail_msg.append(fmsg.format(*fargs)) else: wargs = [ x_cut_point, rms, rms_littrow_max, worst_order ] wmsg = ( 'Littrow test (x={0}) passed (sig littrow = ' '{1:.2f} > {2:.2f} removing order {3})') fail_msg.append(wmsg.format(*wargs)) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.max([max_littrow, min_littrow])) qc_names.append('max or min littrow') qc_logic.append('max or min littrow > {0:.2f}' ''.format(dev_littrow_max)) # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ------------------------------------------------------------------ # archive result in e2ds spectra # ------------------------------------------------------------------ # get raw input file name(s) raw_infiles1 = [] for hcfile in p['HCFILES']: raw_infiles1.append(os.path.basename(hcfile)) raw_infile2 = os.path.basename(p['FPFILE']) # get wave filename wavefits, tag1 = spirouConfig.Constants.WAVE_FILE_EA_2(p) wavefitsname = os.path.split(wavefits)[-1] # log progress wargs = [p['FIBER'], wavefits] wmsg = 'Write wavelength solution for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # write solution to fitsfilename header # copy original keys hdict = spirouImage.CopyOriginalKeys(loc['HCHDR'], loc['HCCDR']) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) # set the input files hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BLAZFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBWAVE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVESOURCE'], value=loc['WSOURCE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='fpfile', values=p['FPFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE2'], dim1name='hcfile', values=p['HCFILES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # add wave solution date hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME1'], value=p['MAX_TIME_HUMAN']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME2'], value=p['MAX_TIME_UNIX']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_CODE'], value=__NAME__) # add number of orders hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_ORD_N'], value=loc['LL_PARAM_FINAL'].shape[0]) # add degree of fit hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_LL_DEG'], value=loc['LL_PARAM_FINAL'].shape[1] - 1) # add wave solution hdict = spirouImage.AddKey2DList(p, hdict, p['KW_WAVE_PARAM'], values=loc['LL_PARAM_FINAL']) # add FP CCF drift # target RV and width hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_TARG_RV'], value=p['TARGET_RV']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_WIDTH'], value=p['CCF_WIDTH']) # the rv step # rvstep = np.abs(loc['RV_CCF'][0] - loc['RV_CCF'][1]) # hdict = spirouImage.AddKey(p, hdict, p['KW_CCF_CDELT'], value=rvstep) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_STEP'], value=p['CCF_STEP']) # add ccf stats hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_DRIFT'], value=loc['CCF_RES'][1]) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_FWHM'], value=loc['FWHM']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_CONTRAST'], value=loc['CONTRAST']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_MAXCPP'], value=loc['MAXCPP']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_MASK'], value=p['CCF_MASK']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_LINES'], value=np.nansum(loc['TOT_LINE'])) # write the wave "spectrum" hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) p = spirouImage.WriteImage(p, wavefits, loc['LL_FINAL'], hdict) # get filename for E2DS calibDB copy of FITSFILENAME e2dscopy_filename = spirouConfig.Constants.WAVE_E2DS_COPY(p)[0] wargs = [p['FIBER'], os.path.split(e2dscopy_filename)[-1]] wmsg = 'Write reference E2DS spectra for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # make a copy of the E2DS file for the calibBD p = spirouImage.WriteImage(p, e2dscopy_filename, loc['HCDATA'], hdict) # only copy over if QC passed if p['QC']: # loop around hc files and update header with for hcfile in p['HCFILES']: raw_infilepath1 = os.path.join(p['ARG_FILE_DIR'], hcfile) p = spirouImage.UpdateWaveSolution(p, loc, raw_infilepath1) # update fp file raw_infilepath2 = os.path.join(p['ARG_FILE_DIR'], raw_infile2) p = spirouImage.UpdateWaveSolution(p, loc, raw_infilepath2) # ------------------------------------------------------------------ # Save to result table # ------------------------------------------------------------------ # calculate stats for table final_mean = 1000 * loc['X_MEAN_2'] final_var = 1000 * loc['X_VAR_2'] num_lines = loc['TOTAL_LINES_2'] err = 1000 * np.sqrt(loc['X_VAR_2'] / num_lines) sig_littrow = 1000 * np.array(loc['LITTROW_SIG_' + str(lit_it)]) # construct filename wavetbl = spirouConfig.Constants.WAVE_TBL_FILE_EA(p) wavetblname = os.path.basename(wavetbl) # construct and write table columnnames = [ 'night_name', 'file_name', 'fiber', 'mean', 'rms', 'N_lines', 'err', 'rms_L500', 'rms_L1000', 'rms_L1500', 'rms_L2000', 'rms_L2500', 'rms_L3000', 'rms_L3500' ] columnformats = [ '{:20s}', '{:30s}', '{:3s}', '{:7.4f}', '{:6.2f}', '{:3d}', '{:6.3f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}' ] columnvalues = [[p['ARG_NIGHT_NAME']], [p['ARG_FILE_NAMES'][0]], [p['FIBER']], [final_mean], [final_var], [num_lines], [err], [sig_littrow[0]], [sig_littrow[1]], [sig_littrow[2]], [sig_littrow[3]], [sig_littrow[4]], [sig_littrow[5]], [sig_littrow[6]]] # make table table = spirouImage.MakeTable(p, columns=columnnames, values=columnvalues, formats=columnformats) # merge table wmsg = 'Global result summary saved in {0}' WLOG(p, '', wmsg.format(wavetblname)) spirouImage.MergeTable(p, table, wavetbl, fmt='ascii.rst') # ------------------------------------------------------------------ # Save line list table file # ------------------------------------------------------------------ # construct filename # TODO proper column values wavelltbl = spirouConfig.Constants.WAVE_LINE_FILE_EA(p) wavelltblname = os.path.split(wavelltbl)[-1] # construct and write table columnnames = ['order', 'll', 'dv', 'w', 'xi', 'xo', 'dvdx'] columnformats = [ '{:.0f}', '{:12.4f}', '{:13.5f}', '{:12.4f}', '{:12.4f}', '{:12.4f}', '{:8.4f}' ] columnvalues = [] # construct column values (flatten over orders) for it in range(len(loc['X_DETAILS_2'])): for jt in range(len(loc['X_DETAILS_2'][it][0])): row = [ float(it), loc['X_DETAILS_2'][it][0][jt], loc['LL_DETAILS_2'][it][0][jt], loc['X_DETAILS_2'][it][3][jt], loc['X_DETAILS_2'][it][1][jt], loc['X_DETAILS_2'][it][2][jt], loc['SCALE_2'][it][jt] ] columnvalues.append(row) # log saving wmsg = 'List of lines used saved in {0}' WLOG(p, '', wmsg.format(wavelltblname)) # make table columnvalues = np.array(columnvalues).T table = spirouImage.MakeTable(p, columns=columnnames, values=columnvalues, formats=columnformats) # write table spirouImage.WriteTable(p, table, wavelltbl, fmt='ascii.rst') # ------------------------------------------------------------------ # Move to calibDB and update calibDB # ------------------------------------------------------------------ if p['QC']: # set the wave key keydb = 'WAVE_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, wavefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, wavefitsname, loc['HCHDR']) # set the hcref key keydb = 'HCREF_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, e2dscopy_filename) # update the master calib DB file with new key e2dscopyfits = os.path.split(e2dscopy_filename)[-1] spirouDB.UpdateCalibMaster(p, keydb, e2dscopyfits, loc['HCHDR']) # If the HC solution failed QCs we do not compute FP-HC solution elif has_fp and not p['QC']: wmsg = 'HC solution failed quality controls; FP not processed' WLOG(p, 'warning', wmsg) # If there is no FP file we log that elif not has_fp: wmsg = 'No FP file given; FP-HC combined solution cannot be generated' WLOG(p, 'warning', wmsg) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return p and loc return dict(locals())
def main(night_name=None, files=None): """ cal_HC_E2DS.py main function, if night_name and files are None uses arguments from run time i.e.: cal_DARK_spirou.py [night_directory] [fitsfilename] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, files, mainfitsdir='reduced') # setup files and get fiber p = spirouStartup.InitialFileSetup(p, calibdb=True) # set the fiber type p['FIB_TYP'] = [p['FIBER']] p.set_source('FIB_TYP', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read and combine all files p, hcdata, hchdr = spirouImage.ReadImageAndCombine(p, 'add') # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'] = hcdata, hchdr # set the source sources = ['HCDATA', 'HCHDR'] loc.set_sources(sources, 'spirouImage.ReadImageAndCombine()') # ---------------------------------------------------------------------- # Get basic parameters # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, loc['HCHDR'], name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, loc['HCHDR'], name='exptime') # get gain p = spirouImage.GetGain(p, loc['HCHDR'], name='gain') # get acquisition time p = spirouImage.GetAcqTime(p, loc['HCHDR'], name='ACQTIME', kind='julian') bjdref = p['ACQTIME'] # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # get lamp parameters p = spirouTHORCA.GetLampParams(p, loc['HCHDR']) # get number of orders # we always get fibre A number because AB is doubled in constants file loc['NBO'] = p['QC_LOC_NBO_FPALL']['A'] loc.set_source('NBO', __NAME__ + '.main()') # get number of pixels in x from hcdata size loc['NBPIX'] = loc['HCDATA'].shape[1] loc.set_source('NBPIX', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Read blaze # ---------------------------------------------------------------------- # get tilts loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hchdr) loc.set_source('BLAZE', __NAME__ + '/main() + /spirouImage.ReadBlazeFile') # ---------------------------------------------------------------------- # Read wave solution # ---------------------------------------------------------------------- # wavelength file; we will use the polynomial terms in its header, # NOT the pixel values that would need to be interpolated # getting header info with wavelength polynomials # set source of wave file wsource = __NAME__ + '/main() + /spirouImage.GetWaveSolution' # Force A and B to AB solution if p['FIBER'] in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = p['FIBER'] # get wave image wout = spirouImage.GetWaveSolution(p, hdr=hchdr, return_wavemap=True, return_filename=True, fiber=wave_fiber) loc['WAVEPARAMS'], loc['WAVE_INIT'], loc['WAVEFILE'], loc['WSOURCE'] = wout loc.set_sources(['WAVE_INIT', 'WAVEFILE', 'WAVEPARAMS', 'WSOURCE'], wsource) # ---------------------------------------------------------------------- # Check that wave parameters are consistent with "ic_ll_degr_fit" # ---------------------------------------------------------------------- loc = spirouImage.CheckWaveSolConsistency(p, loc) # ---------------------------------------------------------------------- # Read UNe solution # ---------------------------------------------------------------------- wave_u_ne, amp_u_ne = spirouImage.ReadLineList(p) loc['LL_LINE'], loc['AMPL_LINE'] = wave_u_ne, amp_u_ne source = __NAME__ + '.main() + spirouImage.ReadLineList()' loc.set_sources(['ll_line', 'ampl_line'], source) # ---------------------------------------------------------------------- # Generate wave map from wave solution # ---------------------------------------------------------------------- loc = spirouWAVE.generate_wave_map(p, loc) # ---------------------------------------------------------------------- # Find Gaussian Peaks in HC spectrum # ---------------------------------------------------------------------- loc = spirouWAVE.find_hc_gauss_peaks(p, loc) # ---------------------------------------------------------------------- # Start plotting session # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # start interactive plot sPlt.start_interactive_session(p) # ---------------------------------------------------------------------- # Fit Gaussian peaks (in triplets) to # ---------------------------------------------------------------------- loc = spirouWAVE.fit_gaussian_triplets(p, loc) # ---------------------------------------------------------------------- # Generate Resolution map and line profiles # ---------------------------------------------------------------------- # log progress wmsg = 'Generating resolution map and ' # generate resolution map loc = spirouWAVE.generate_resolution_map(p, loc) # map line profile map if p['DRS_PLOT'] > 0: sPlt.wave_ea_plot_line_profiles(p, loc) # ---------------------------------------------------------------------- # End plotting session # ---------------------------------------------------------------------- # end interactive session if p['DRS_PLOT'] > 0: sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # quality control on sigma clip (sig1 > qc_hc_wave_sigma_max if loc['SIG1'] > p['QC_HC_WAVE_SIGMA_MAX']: fmsg = 'Sigma too high ({0:.5f} > {1:.5f})' fail_msg.append(fmsg.format(loc['SIG1'], p['QC_HC_WAVE_SIGMA_MAX'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(loc['SIG1']) qc_names.append('SIG1') qc_logic.append('SIG1 > {0:.2f}'.format(p['QC_HC_WAVE_SIGMA_MAX'])) # ---------------------------------------------------------------------- # check the difference between consecutive orders is always positive # get the differences wave_diff = loc['WAVE_MAP2'][1:]-loc['WAVE_MAP2'][:-1] if np.min(wave_diff) < 0: fmsg = 'Negative wavelength difference between orders' fail_msg.append(fmsg) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.min(wave_diff)) qc_names.append('MIN WAVE DIFF') qc_logic.append('MIN WAVE DIFF < 0') # ---------------------------------------------------------------------- # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ---------------------------------------------------------------------- # log the global stats # ---------------------------------------------------------------------- # calculate catalog-fit residuals in km/s res_hc =[] sumres_hc = 0.0 sumres2_hc = 0.0 for order in range(loc['NBO']): # get HC line wavelengths for the order order_mask = loc['ORD_T'] == order hc_x_ord = loc['XGAU_T'][order_mask] hc_ll_ord = np.polyval(loc['POLY_WAVE_SOL'][order][::-1],hc_x_ord) hc_ll_cat = loc['WAVE_CATALOG'][order_mask] hc_ll_diff = hc_ll_ord - hc_ll_cat res_hc.append(hc_ll_diff*speed_of_light/hc_ll_cat) sumres_hc += np.nansum(res_hc[order]) sumres2_hc += np.nansum(res_hc[order] ** 2) total_lines_hc = len(np.concatenate(res_hc)) final_mean_hc = sumres_hc/total_lines_hc final_var_hc = (sumres2_hc/total_lines_hc) - (final_mean_hc ** 2) wmsg1 = 'On fiber {0} HC fit line statistic:'.format(p['FIBER']) wargs2 = [final_mean_hc * 1000.0, np.sqrt(final_var_hc) * 1000.0, total_lines_hc, 1000.0 * np.sqrt(final_var_hc / total_lines_hc)] wmsg2 = ('\tmean={0:.3f}[m/s] rms={1:.1f} {2} HC lines (error on mean ' 'value:{3:.4f}[m/s])'.format(*wargs2)) WLOG(p, 'info', [wmsg1, wmsg2]) # ---------------------------------------------------------------------- # Save wave map to file # ---------------------------------------------------------------------- # get base input filenames bfilenames = [] for raw_file in p['ARG_FILE_NAMES']: bfilenames.append(os.path.basename(raw_file)) # get wave filename wavefits, tag1 = spirouConfig.Constants.WAVE_FILE_EA(p) wavefitsname = os.path.basename(wavefits) # log progress WLOG(p, '', 'Saving wave map to {0}'.format(wavefitsname)) # log progress wargs = [p['FIBER'], wavefitsname] wmsg = 'Write wavelength solution for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # write solution to fitsfilename header # copy original keys hdict = spirouImage.CopyOriginalKeys(loc['HCHDR']) # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) # set the input files hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBLAZE'], value=p['BLAZFILE']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # add wave solution date hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME1'], value=p['MAX_TIME_HUMAN']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME2'], value=p['MAX_TIME_UNIX']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_CODE'], value=__NAME__) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBWAVE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVESOURCE'], value=loc['WSOURCE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # add number of orders hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_ORD_N'], value=loc['POLY_WAVE_SOL'].shape[0]) # add degree of fit hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_LL_DEG'], value=loc['POLY_WAVE_SOL'].shape[1]-1) # add wave solution hdict = spirouImage.AddKey2DList(p, hdict, p['KW_WAVE_PARAM'], values=loc['POLY_WAVE_SOL']) # write the wave "spectrum" p = spirouImage.WriteImage(p, wavefits, loc['WAVE_MAP2'], hdict) # get filename for E2DS calibDB copy of FITSFILENAME e2dscopy_filename, tag2 = spirouConfig.Constants.WAVE_E2DS_COPY(p) wargs = [p['FIBER'], os.path.split(e2dscopy_filename)[-1]] wmsg = 'Write reference E2DS spectra for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # make a copy of the E2DS file for the calibBD hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) p = spirouImage.WriteImage(p, e2dscopy_filename, loc['HCDATA'], hdict) # ---------------------------------------------------------------------- # Save resolution and line profiles to file # ---------------------------------------------------------------------- raw_infile = os.path.basename(p['FITSFILENAME']) # get wave filename resfits, tag3 = spirouConfig.Constants.WAVE_RES_FILE_EA(p) resfitsname = os.path.basename(resfits) WLOG(p, '', 'Saving wave resmap to {0}'.format(resfitsname)) # make a copy of the E2DS file for the calibBD # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) # get res data in correct format resdata, hdicts = spirouTHORCA.GenerateResFiles(p, loc, hdict) # save to file p = spirouImage.WriteImageMulti(p, resfits, resdata, hdicts=hdicts) # ---------------------------------------------------------------------- # Update calibDB # ---------------------------------------------------------------------- if p['QC']: # set the wave key keydb = 'WAVE_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, wavefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, wavefitsname, loc['HCHDR']) # set the hcref key keydb = 'HCREF_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, e2dscopy_filename) # update the master calib DB file with new key e2dscopyfits = os.path.split(e2dscopy_filename)[-1] spirouDB.UpdateCalibMaster(p, keydb, e2dscopyfits, loc['HCHDR']) # ---------------------------------------------------------------------- # Update header of current files # ---------------------------------------------------------------------- # only copy over if QC passed if p['QC']: rdir = os.path.dirname(wavefits) # loop around hc files and update header with for rawhcfile in p['ARG_FILE_NAMES']: hcfile = os.path.join(rdir, rawhcfile) raw_infilepath1 = os.path.join(p['ARG_FILE_DIR'], hcfile) p = spirouImage.UpdateWaveSolutionHC(p, loc, raw_infilepath1) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, hcfile=None, fpfiles=None): """ cal_SLIT_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_SLIT_spirou.py [night_directory] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) if hcfile is None or fpfiles is None: names, types = ['hcfile', 'fpfiles'], [str, str] customargs = spirouStartup.GetCustomFromRuntime(p, [0, 1], types, names, last_multi=True) else: customargs = dict(hcfile=hcfile, fpfile=fpfiles) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, customargs=customargs, mainfitsfile='fpfiles') # ---------------------------------------------------------------------- # Construct reference filename and get fiber type # ---------------------------------------------------------------------- p, hcfitsfilename = spirouStartup.SingleFileSetup(p, filename=p['HCFILE']) p, fpfitsfiles = spirouStartup.MultiFileSetup(p, files=p['FPFILES']) # set fiber (it doesn't matter with the 2D image but we need this to get # the lamp type for FPFILES and HCFILES, AB == C p['FIBER'] = 'AB' p['FIB_TYP'] = [p['FIBER']] fsource = __NAME__ + '/main()' p.set_sources(['FIBER', 'FIB_TYP'], fsource) # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # add a force plot off p['PLOT_PER_ORDER'] = PLOT_PER_ORDER p.set_source('PLOT_PER_ORDER', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Read FP and HC files # ---------------------------------------------------------------------- # read input fp and hc data rkwargs = dict(filename=fpfitsfiles[0], filenames=fpfitsfiles[1:], framemath='add') p, fpdata, fphdr = spirouImage.ReadImageAndCombine(p, **rkwargs) hcdata, hchdr, _, _ = spirouImage.ReadImage(p, hcfitsfilename) # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'] = hcdata, hchdr loc['FPDATA'], loc['FPHDR'] = fpdata, fphdr # set the source sources = ['HCDATA', 'HCHDR'] loc.set_sources(sources, 'spirouImage.ReadImage()') sources = ['FPDATA', 'FPHDR'] loc.set_sources(sources, 'spirouImage.ReadImage()') # --------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- hcdata = spirouImage.FixNonPreProcess(p, hcdata) fpdata = spirouImage.FixNonPreProcess(p, fpdata) # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # add a force plot off p['PLOT_PER_ORDER'] = PLOT_PER_ORDER p.set_source('PLOT_PER_ORDER', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Get basic image properties for reference file # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, fphdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, fphdr, name='exptime') # get gain p = spirouImage.GetGain(p, fphdr, name='gain') # get lamp parameters p = spirouTHORCA.GetLampParams(p, hchdr) # get FP_FP DPRTYPE p = spirouImage.ReadParam(p, fphdr, 'KW_DPRTYPE', 'DPRTYPE', dtype=str) # ---------------------------------------------------------------------- # Correction of reference FP # ---------------------------------------------------------------------- # set the number of frames p['NBFRAMES'] = len(fpfitsfiles) p.set_source('NBFRAMES', __NAME__ + '.main()') # Correction of DARK p, fpdatac = spirouImage.CorrectForDark(p, fpdata, fphdr) # Resize hc data # rotate the image and convert from ADU/s to e- fpdata = spirouImage.ConvertToE(spirouImage.FlipImage(p, fpdatac), p=p) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) fpdata1 = spirouImage.ResizeImage(p, fpdata, **bkwargs) # log change in data size WLOG(p, '', ('FPref Image format changed to {0}x{1}').format(*fpdata1.shape)) # Correct for the BADPIX mask (set all bad pixels to zero) bargs = [p, fpdata1, fphdr] p, fpdata1 = spirouImage.CorrectForBadPix(*bargs) p, badpixmask = spirouImage.CorrectForBadPix(*bargs, return_map=True) # log progress WLOG(p, '', 'Cleaning FPref hot pixels') # correct hot pixels fpdata1 = spirouEXTOR.CleanHotpix(fpdata1, badpixmask) # add to loc loc['FPDATA1'] = fpdata1 loc.set_source('FPDATA1', __NAME__ + '.main()') # Log the number of dead pixels # get the number of bad pixels with warnings.catch_warnings(record=True) as _: n_bad_pix = np.nansum(fpdata1 <= 0) n_bad_pix_frac = n_bad_pix * 100 / np.product(fpdata1.shape) # Log number wmsg = 'Nb FPref dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ---------------------------------------------------------------------- # Correction of HC # ---------------------------------------------------------------------- # set the number of frames p['NBFRAMES'] = 1 p.set_source('NBFRAMES', __NAME__ + '.main()') # Correction of DARK p, hcdatac = spirouImage.CorrectForDark(p, hcdata, hchdr) # Resize hc data # rotate the image and convert from ADU/s to e- hcdata = spirouImage.ConvertToE(spirouImage.FlipImage(p, hcdatac), p=p) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) hcdata1 = spirouImage.ResizeImage(p, hcdata, **bkwargs) # log change in data size WLOG(p, '', ('HC Image format changed to {0}x{1}').format(*hcdata1.shape)) # Correct for the BADPIX mask (set all bad pixels to zero) bargs = [p, hcdata1, hchdr] p, hcdata1 = spirouImage.CorrectForBadPix(*bargs) p, badpixmask = spirouImage.CorrectForBadPix(*bargs, return_map=True) # log progress WLOG(p, '', 'Cleaning HC hot pixels') # correct hot pixels hcdata1 = spirouEXTOR.CleanHotpix(hcdata1, badpixmask) # add to loc loc['HCDATA1'] = hcdata1 loc.set_source('HCDATA1', __NAME__ + '.main()') # Log the number of dead pixels # get the number of bad pixels with warnings.catch_warnings(record=True) as _: n_bad_pix = np.nansum(hcdata1 <= 0) n_bad_pix_frac = n_bad_pix * 100 / np.product(hcdata1.shape) # Log number wmsg = 'Nb HC dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ------------------------------------------------------------------------- # get all FP_FP files # ------------------------------------------------------------------------- fpfilenames = spirouImage.FindFiles(p, filetype=p['DPRTYPE'], allowedtypes=p['ALLOWED_FP_TYPES']) # convert filenames to a numpy array fpfilenames = np.array(fpfilenames) # julian date to know which file we need to # process together fp_time = np.zeros(len(fpfilenames)) basenames, fp_exp, fp_pp_version, nightnames = [], [], [], [] # log progress WLOG(p, '', 'Reading all fp file headers') # looping through the file headers for it in range(len(fpfilenames)): # log progress wmsg = '\tReading file {0} / {1}' WLOG(p, 'info', wmsg.format(it + 1, len(fpfilenames))) # get fp filename fpfilename = fpfilenames[it] # get night name night_name = os.path.dirname(fpfilenames[it]).split(p['TMP_DIR'])[-1] # read data data_it, hdr_it, _, _ = spirouImage.ReadImage(p, fpfilename) # get header hdr = spirouImage.ReadHeader(p, filepath=fpfilenames[it]) # add MJDATE to dark times fp_time[it] = float(hdr[p['KW_ACQTIME'][0]]) # add other keys (for tabular output) basenames.append(os.path.basename(fpfilenames[it])) nightnames.append(night_name) fp_exp.append(float(hdr[p['KW_EXPTIME'][0]])) fp_pp_version.append(hdr[p['KW_PPVERSION'][0]]) # ------------------------------------------------------------------------- # match files by date # ------------------------------------------------------------------------- # log progress wmsg = 'Matching FP files by observation time (+/- {0} hrs)' WLOG(p, '', wmsg.format(p['DARK_MASTER_MATCH_TIME'])) # get the time threshold time_thres = p['FP_MASTER_MATCH_TIME'] # get items grouped by time matched_id = spirouImage.GroupFilesByTime(p, fp_time, time_thres) # ------------------------------------------------------------------------- # construct the master fp file (+ correct for dark/badpix) # ------------------------------------------------------------------------- cargs = [fpdata1, fpfilenames, matched_id] fpcube, transforms = spirouImage.ConstructMasterFP(p, *cargs) # log process wmsg1 = 'Master FP construction complete.' wmsg2 = '\tAdding {0} group images to form FP master image' WLOG(p, 'info', [wmsg1, wmsg2.format(len(fpcube))]) # sum the cube to make fp data masterfp = np.sum(fpcube, axis=0) # add to loc loc['MASTERFP'] = masterfp loc.set_source('MASTERFP', __NAME__ + '.main()') # ------------------------------------------------------------------ # Get localisation coefficients # ------------------------------------------------------------------ # original there is a loop but it is not used --> removed p = spirouImage.FiberParams(p, p['FIBER'], merge=True) # get localisation fit coefficients p, loc = spirouLOCOR.GetCoeffs(p, fphdr, loc) # ------------------------------------------------------------------ # Get master wave solution map # ------------------------------------------------------------------ # get master wave map masterwavefile = spirouDB.GetDatabaseMasterWave(p) # log process wmsg1 = 'Getting master wavelength grid' wmsg2 = '\tFile = {0}'.format(os.path.basename(masterwavefile)) WLOG(p, '', [wmsg1, wmsg2]) # Force A and B to AB solution if p['FIBER'] in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = p['FIBER'] # read master wave map wout = spirouImage.GetWaveSolution(p, filename=masterwavefile, return_wavemap=True, quiet=True, return_header=True, fiber=wave_fiber) loc['MASTERWAVEP'], loc['MASTERWAVE'] = wout[:2] loc['MASTERWAVEHDR'], loc['WSOURCE'] = wout[2:] # set sources wsource = ['MASTERWAVEP', 'MASTERWAVE', 'MASTERWAVEHDR'] loc.set_sources(wsource, 'spirouImage.GetWaveSolution()') # ---------------------------------------------------------------------- # Read UNe solution # ---------------------------------------------------------------------- wave_u_ne, amp_u_ne = spirouImage.ReadLineList(p) loc['LL_LINE'], loc['AMPL_LINE'] = wave_u_ne, amp_u_ne source = __NAME__ + '.main() + spirouImage.ReadLineList()' loc.set_sources(['LL_LINE', 'AMPL_LINE'], source) # ---------------------------------------------------------------------- # Read cavity length file # ---------------------------------------------------------------------- loc['CAVITY_LEN_COEFFS'] = spirouImage.ReadCavityLength(p) source = __NAME__ + '.main() + spirouImage.ReadCavityLength()' loc.set_source('CAVITY_LEN_COEFFS', source) # ---------------------------------------------------------------------- # Calculate shape map # ---------------------------------------------------------------------- # calculate dx map loc = spirouImage.GetXShapeMap(p, loc) # if dx map is None we shouldn't continue if loc['DXMAP'] is None: fargs = [ loc['MAXDXMAPINFO'][0], loc['MAXDXMAPINFO'][1], loc['MAXDXMAPSTD'], p['SHAPE_QC_DXMAP_STD'] ] fmsg = ('The std of the dxmap for order {0} y-pixel {1} is too large.' ' std = {2} (limit = {3})'.format(*fargs)) wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(fmsg)) WLOG(p, 'warning', 'Cannot continue. Exiting.') # End Message p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals()) # calculate dymap loc = spirouImage.GetYShapeMap(p, loc, fphdr) # ------------------------------------------------------------------ # Need to straighten the dxmap # ------------------------------------------------------------------ # copy it first loc['DXMAP0'] = np.array(loc['DXMAP']) # straighten it loc['DXMAP'] = spirouImage.EATransform(loc['DXMAP'], dymap=loc['DYMAP']) # ------------------------------------------------------------------ # Need to straighten the hc data and fp data for debug # ------------------------------------------------------------------ # log progress WLOG(p, '', 'Shape finding complete. Applying transforms.') # apply very last update of the debananafication tkwargs = dict(dxmap=loc['DXMAP'], dymap=loc['DYMAP']) loc['HCDATA2'] = spirouImage.EATransform(loc['HCDATA1'], **tkwargs) loc['FPDATA2'] = spirouImage.EATransform(loc['FPDATA1'], **tkwargs) loc.set_sources(['HCDATA2', 'FPDATA2'], __NAME__ + '.main()') # ------------------------------------------------------------------ # Plotting # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # plots setup: start interactive plot sPlt.start_interactive_session(p) # plot the shape process for one order sPlt.slit_shape_angle_plot(p, loc) # end interactive section sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # TODO: Decide on some quality control criteria? # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # add to qc header lists qc_values.append(loc['MAXDXMAPSTD']) qc_names.append('DXMAP STD') qc_logic.append('DXMAP STD < {0}'.format(p['SHAPE_QC_DXMAP_STD'])) qc_pass.append(1) # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ------------------------------------------------------------------ # Writing FP big table # ------------------------------------------------------------------ # construct big fp table colnames = [ 'FILENAME', 'NIGHT', 'MJDATE', 'EXPTIME', 'PVERSION', 'GROUPID', 'DXREF', 'DYREF', 'A', 'B', 'C', 'D' ] values = [ basenames, nightnames, fp_time, fp_exp, fp_pp_version, matched_id, transforms[:, 0], transforms[:, 1], transforms[:, 2], transforms[:, 3], transforms[:, 4], transforms[:, 5] ] fptable = spirouImage.MakeTable(p, colnames, values) # ------------------------------------------------------------------ # Writing DXMAP to file # ------------------------------------------------------------------ # get the raw tilt file name raw_shape_file = os.path.basename(p['FITSFILENAME']) # construct file name and path shapexfits, tag = spirouConfig.Constants.SLIT_XSHAPE_FILE(p) shapexfitsname = os.path.basename(shapexfits) # Log that we are saving tilt file wmsg = 'Saving shape x information in file: {0}' WLOG(p, '', wmsg.format(shapexfitsname)) # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(fphdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='hcfile', values=p['HCFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE2'], dim1name='fpfile', values=p['FPFILES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # write tilt file to file p = spirouImage.WriteImageTable(p, shapexfits, image=loc['DXMAP'], table=fptable, hdict=hdict) # ------------------------------------------------------------------ # Writing DYMAP to file # ------------------------------------------------------------------ # get the raw tilt file name raw_shape_file = os.path.basename(p['FITSFILENAME']) # construct file name and path shapeyfits, tag = spirouConfig.Constants.SLIT_YSHAPE_FILE(p) shapeyfitsname = os.path.basename(shapeyfits) # Log that we are saving tilt file wmsg = 'Saving shape y information in file: {0}' WLOG(p, '', wmsg.format(shapeyfitsname)) # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(fphdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='hcfile', values=p['HCFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE2'], dim1name='fpfile', values=p['FPFILES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # write tilt file to file p = spirouImage.WriteImageTable(p, shapeyfits, image=loc['DYMAP'], table=fptable, hdict=hdict) # ------------------------------------------------------------------ # Writing Master FP to file # ------------------------------------------------------------------ # get the raw tilt file name raw_shape_file = os.path.basename(p['FITSFILENAME']) # construct file name and path fpmasterfits, tag = spirouConfig.Constants.SLIT_MASTER_FP_FILE(p) fpmasterfitsname = os.path.basename(fpmasterfits) # Log that we are saving tilt file wmsg = 'Saving master FP file: {0}' WLOG(p, '', wmsg.format(fpmasterfitsname)) # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(fphdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='hcfile', values=p['HCFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE2'], dim1name='fpfile', values=p['FPFILES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # write tilt file to file p = spirouImage.WriteImageTable(p, fpmasterfits, image=masterfp, table=fptable, hdict=hdict) # ------------------------------------------------------------------ # Writing sanity check files # ------------------------------------------------------------------ if p['SHAPE_DEBUG_OUTPUTS']: # log WLOG(p, '', 'Saving debug sanity check files') # construct file names input_fp_file, tag1 = spirouConfig.Constants.SLIT_SHAPE_IN_FP_FILE(p) output_fp_file, tag2 = spirouConfig.Constants.SLIT_SHAPE_OUT_FP_FILE(p) input_hc_file, tag3 = spirouConfig.Constants.SLIT_SHAPE_IN_HC_FILE(p) output_hc_file, tag4 = spirouConfig.Constants.SLIT_SHAPE_OUT_HC_FILE(p) bdxmap_file, tag5 = spirouConfig.Constants.SLIT_SHAPE_BDXMAP_FILE(p) # write input fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) p = spirouImage.WriteImage(p, input_fp_file, loc['FPDATA1'], hdict) # write output fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) p = spirouImage.WriteImage(p, output_fp_file, loc['FPDATA2'], hdict) # write input fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) p = spirouImage.WriteImage(p, input_hc_file, loc['HCDATA1'], hdict) # write output fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag4) p = spirouImage.WriteImage(p, output_hc_file, loc['HCDATA2'], hdict) # write overlap file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag5) p = spirouImage.WriteImage(p, bdxmap_file, loc['DXMAP0'], hdict) # ---------------------------------------------------------------------- # Move to calibDB and update calibDB # ---------------------------------------------------------------------- if p['QC']: # add shape x keydb = 'SHAPEX' # copy shape file to the calibDB folder spirouDB.PutCalibFile(p, shapexfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, shapexfitsname, fphdr) # add shape y keydb = 'SHAPEY' # copy shape file to the calibDB folder spirouDB.PutCalibFile(p, shapeyfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, shapeyfitsname, fphdr) # add fp master keydb = 'FPMASTER' # copy shape file to the calibDB folder spirouDB.PutCalibFile(p, fpmasterfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, fpmasterfitsname, fphdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, fpfile=None, hcfiles=None): """ cal_WAVE_E2DS.py main function, if night_name and files are None uses arguments from run time i.e.: cal_DARK_spirou.py [night_directory] [fpfile] [hcfiles] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param fpfile: string, or None, the FP file to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :param hcfiles: string, list or None, the list of HC files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # test files TC2 # night_name = 'AT5/AT5-12/2018-05-29_17-41-44/' # fpfile = '2279844a_fp_fp_pp_e2dsff_AB.fits' # hcfiles = ['2279845c_hc_pp_e2dsff_AB.fits'] # test files TC3 # night_name = 'TC3/AT5/AT5-12/2018-07-24_16-17-57/' # fpfile = '2294108a_pp_e2dsff_AB.fits' # hcfiles = ['2294115c_pp_e2dsff_AB.fits'] # night_name = 'TC3/AT5/AT5-12/2018-07-25_16-49-50/' # fpfile = '2294223a_pp_e2dsff_AB.fits' # hcfiles = ['2294230c_pp_e2dsff_AB.fits'] # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) if hcfiles is None or fpfile is None: names, types = ['fpfile', 'hcfiles'], [str, str] customargs = spirouStartup.GetCustomFromRuntime(p, [0, 1], types, names, last_multi=True) else: customargs = dict(hcfiles=hcfiles, fpfile=fpfile) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, customargs=customargs, mainfitsdir='reduced', mainfitsfile='hcfiles') # ---------------------------------------------------------------------- # Construct reference filename and get fiber type # ---------------------------------------------------------------------- p, fpfitsfilename = spirouStartup.SingleFileSetup(p, filename=p['FPFILE']) fiber1 = str(p['FIBER']) p, hcfilenames = spirouStartup.MultiFileSetup(p, files=p['HCFILES']) fiber2 = str(p['FIBER']) # set the hcfilename to the first hcfilenames hcfitsfilename = hcfilenames[0] # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # ---------------------------------------------------------------------- # Have to check that the fibers match # ---------------------------------------------------------------------- if fiber1 == fiber2: p['FIBER'] = fiber1 fsource = __NAME__ + '/main() & spirouStartup.GetFiberType()' p.set_source('FIBER', fsource) else: emsg = 'Fiber not matching for {0} and {1}, should be the same' eargs = [hcfitsfilename, fpfitsfilename] WLOG(p, 'error', emsg.format(*eargs)) # set the fiber type p['FIB_TYP'] = [p['FIBER']] p.set_source('FIB_TYP', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Read FP and HC files # ---------------------------------------------------------------------- # read and combine all HC files except the first (fpfitsfilename) rargs = [p, 'add', hcfitsfilename, hcfilenames[1:]] p, hcdata, hchdr = spirouImage.ReadImageAndCombine(*rargs) # read first file (fpfitsfilename) fpdata, fphdr, _, _ = spirouImage.ReadImage(p, fpfitsfilename) # TODO: ------------------------------------------------------------ # TODO remove to test NaNs # TODO: ------------------------------------------------------------ # hcmask = np.isfinite(hcdata) # fpmask = np.isfinite(fpdata) # hcdata[~hcmask] = 0.0 # fpdata[~fpmask] = 0.0 # TODO: ------------------------------------------------------------ # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'] = hcdata, hchdr loc['FPDATA'], loc['FPHDR'] = fpdata, fphdr # set the source sources = ['HCDATA', 'HCHDR'] loc.set_sources(sources, 'spirouImage.ReadImageAndCombine()') sources = ['FPDATA', 'FPHDR'] loc.set_sources(sources, 'spirouImage.ReadImage()') # ---------------------------------------------------------------------- # Get basic image properties for reference file # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hchdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hchdr, name='exptime') # get gain p = spirouImage.GetGain(p, hchdr, name='gain') # get acquisition time p = spirouImage.GetAcqTime(p, hchdr, name='acqtime', kind='julian') bjdref = p['ACQTIME'] # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # get lamp parameters p = spirouTHORCA.GetLampParams(p, hchdr) # get number of orders # we always get fibre A number because AB is doubled in constants file loc['NBO'] = p['QC_LOC_NBO_FPALL']['A'] loc.set_source('NBO', __NAME__ + '.main()') # get number of pixels in x from hcdata size loc['NBPIX'] = loc['HCDATA'].shape[1] loc.set_source('NBPIX', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Read blaze # ---------------------------------------------------------------------- # get tilts p, loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hchdr) loc.set_source('BLAZE', __NAME__ + '/main() + /spirouImage.ReadBlazeFile') # make copy of blaze (as it's overwritten later) loc['BLAZE2'] = np.copy(loc['BLAZE']) # ---------------------------------------------------------------------- # Read wave solution # ---------------------------------------------------------------------- # wavelength file; we will use the polynomial terms in its header, # NOT the pixel values that would need to be interpolated # set source of wave file wsource = __NAME__ + '/main() + /spirouImage.GetWaveSolution' # Force A and B to AB solution if p['FIBER'] in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = p['FIBER'] # get wave image wout = spirouImage.GetWaveSolution(p, hdr=hchdr, return_wavemap=True, return_filename=True, fiber=wave_fiber) loc['WAVEPARAMS'], loc['WAVE_INIT'], loc['WAVEFILE'], loc['WSOURCE'] = wout loc.set_sources(['WAVE_INIT', 'WAVEFILE', 'WAVEPARAMS', 'WSOURCE'], wsource) poly_wave_sol = loc['WAVEPARAMS'] # ---------------------------------------------------------------------- # Check that wave parameters are consistent with "ic_ll_degr_fit" # ---------------------------------------------------------------------- loc = spirouImage.CheckWaveSolConsistency(p, loc) # ---------------------------------------------------------------------- # Read UNe solution # ---------------------------------------------------------------------- wave_u_ne, amp_u_ne = spirouImage.ReadLineList(p) loc['LL_LINE'], loc['AMPL_LINE'] = wave_u_ne, amp_u_ne source = __NAME__ + '.main() + spirouImage.ReadLineList()' loc.set_sources(['ll_line', 'ampl_line'], source) # ---------------------------------------------------------------------- # Generate wave map from wave solution # ---------------------------------------------------------------------- loc = spirouWAVE.generate_wave_map(p, loc) # ---------------------------------------------------------------------- # Find Gaussian Peaks in HC spectrum # ---------------------------------------------------------------------- loc = spirouWAVE.find_hc_gauss_peaks(p, loc) # ---------------------------------------------------------------------- # Start plotting session # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # start interactive plot sPlt.start_interactive_session(p) # ---------------------------------------------------------------------- # Fit Gaussian peaks (in triplets) to # ---------------------------------------------------------------------- loc = spirouWAVE.fit_gaussian_triplets(p, loc) # ---------------------------------------------------------------------- # Generate Resolution map and line profiles # ---------------------------------------------------------------------- # log progress wmsg = 'Generating resolution map and ' # generate resolution map loc = spirouWAVE.generate_resolution_map(p, loc) # map line profile map if p['DRS_PLOT'] > 0: sPlt.wave_ea_plot_line_profiles(p, loc) # ---------------------------------------------------------------------- # End plotting session # ---------------------------------------------------------------------- # end interactive session if p['DRS_PLOT'] > 0: sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # Set up all_lines storage # ---------------------------------------------------------------------- # initialise up all_lines storage all_lines_1 = [] # get parameters from p n_ord_start = p['IC_HC_N_ORD_START_2'] n_ord_final = p['IC_HC_N_ORD_FINAL_2'] pixel_shift_inter = p['PIXEL_SHIFT_INTER'] pixel_shift_slope = p['PIXEL_SHIFT_SLOPE'] # get values from loc xgau = np.array(loc['XGAU_T']) dv = np.array(loc['DV_T']) fit_per_order = np.array(loc['POLY_WAVE_SOL']) ew = np.array(loc['EW_T']) peak = np.array(loc['PEAK_T']) amp_catalog = np.array(loc['AMP_CATALOG']) wave_catalog = np.array(loc['WAVE_CATALOG']) ord_t = np.array(loc['ORD_T']) # loop through orders for iord in range(n_ord_start, n_ord_final): # keep relevant lines # -> right order # -> finite dv gg = (ord_t == iord) & (np.isfinite(dv)) nlines = np.nansum(gg) # put lines into ALL_LINES structure # reminder: # gparams[0] = output wavelengths # gparams[1] = output sigma(gauss fit width) # gparams[2] = output amplitude(gauss fit) # gparams[3] = difference in input / output wavelength # gparams[4] = input amplitudes # gparams[5] = output pixel positions # gparams[6] = output pixel sigma width (gauss fit width in pixels) # gparams[7] = output weights for the pixel position chebval = np.polynomial.chebyshev.chebval # dummy array for weights test = np.ones(np.shape(xgau[gg]), 'd') * 1e4 # get the final wavelength value for each peak in order output_wave_1 = np.polyval(fit_per_order[iord][::-1], xgau[gg]) # output_wave_1 = chebval(xgau[gg], fit_per_order[iord]) # convert the pixel equivalent width to wavelength units xgau_ew_ini = xgau[gg] - ew[gg] / 2 xgau_ew_fin = xgau[gg] + ew[gg] / 2 ew_ll_ini = np.polyval(fit_per_order[iord, :], xgau_ew_ini) ew_ll_fin = np.polyval(fit_per_order[iord, :], xgau_ew_fin) # ew_ll_ini = chebval(xgau_ew_ini, fit_per_order[iord]) # ew_ll_fin = chebval(xgau_ew_fin, fit_per_order[iord]) ew_ll = ew_ll_fin - ew_ll_ini # put all lines in the order into array gau_params = np.column_stack( (output_wave_1, ew_ll, peak[gg], wave_catalog[gg] - output_wave_1, amp_catalog[gg], xgau[gg], ew[gg], test)) # append the array for the order into a list all_lines_1.append(gau_params) # save dv in km/s and auxiliary order number # res_1 = np.concatenate((res_1,2.997e5*(input_wave - output_wave_1)/ # output_wave_1)) # ord_save = np.concatenate((ord_save, test*iord)) # add to loc loc['ALL_LINES_1'] = all_lines_1 loc['LL_PARAM_1'] = np.array(fit_per_order) loc['LL_OUT_1'] = np.array(loc['WAVE_MAP2']) loc.set_sources(['ALL_LINES_1', 'LL_PARAM_1'], __NAME__ + '/main()') # For compatibility w/already defined functions, I need to save # here all_lines_2 all_lines_2 = list(all_lines_1) loc['ALL_LINES_2'] = all_lines_2 # loc['LL_PARAM_2'] = np.fliplr(fit_per_order) # loc['LL_OUT_2'] = np.array(loc['WAVE_MAP2']) # loc.set_sources(['ALL_LINES_2', 'LL_PARAM_2'], __NAME__ + '/main()') # ------------------------------------------------------------------ # Littrow test # ------------------------------------------------------------------ start = p['IC_LITTROW_ORDER_INIT_1'] end = p['IC_LITTROW_ORDER_FINAL_1'] # calculate echelle orders o_orders = np.arange(start, end) echelle_order = p['IC_HC_T_ORDER_START'] - o_orders loc['ECHELLE_ORDERS'] = echelle_order loc.set_source('ECHELLE_ORDERS', __NAME__ + '/main()') # reset Littrow fit degree p['IC_LITTROW_FIT_DEG_1'] = 7 # Do Littrow check ckwargs = dict(ll=loc['LL_OUT_1'][start:end, :], iteration=1, log=True) loc = spirouTHORCA.CalcLittrowSolution(p, loc, **ckwargs) # Plot wave solution littrow check if p['DRS_PLOT'] > 0: # plot littrow x pixels against fitted wavelength solution sPlt.wave_littrow_check_plot(p, loc, iteration=1) # ------------------------------------------------------------------ # extrapolate Littrow solution # ------------------------------------------------------------------ ekwargs = dict(ll=loc['LL_OUT_1'], iteration=1) loc = spirouTHORCA.ExtrapolateLittrowSolution(p, loc, **ekwargs) # ------------------------------------------------------------------ # Plot littrow solution # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # plot littrow x pixels against fitted wavelength solution sPlt.wave_littrow_extrap_plot(p, loc, iteration=1) # ------------------------------------------------------------------ # Incorporate FP into solution # ------------------------------------------------------------------ # Copy LL_OUT_1 and LL_PARAM_1 into new constants (for FP integration) loc['LITTROW_EXTRAP_SOL_1'] = np.array(loc['LL_OUT_1']) loc['LITTROW_EXTRAP_PARAM_1'] = np.array(loc['LL_PARAM_1']) # only use FP if switched on in constants file if p['IC_WAVE_USE_FP']: # ------------------------------------------------------------------ # Find FP lines # ------------------------------------------------------------------ # print message to screen wmsg = 'Identification of lines in reference file: {0}' WLOG(p, '', wmsg.format(fpfile)) # ------------------------------------------------------------------ # Get the FP solution # ------------------------------------------------------------------ loc = spirouTHORCA.FPWaveSolutionNew(p, loc) # ------------------------------------------------------------------ # FP solution plots # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # Plot the FP extracted spectrum against wavelength solution sPlt.wave_plot_final_fp_order(p, loc, iteration=1) # Plot the measured FP cavity width offset against line number sPlt.wave_local_width_offset_plot(p, loc) # Plot the FP line wavelength residuals sPlt.wave_fp_wavelength_residuals(p, loc) # ------------------------------------------------------------------ # Create new wavelength solution # ------------------------------------------------------------------ # TODO: Melissa fault - fix later p['IC_HC_N_ORD_START_2'] = min(p['IC_HC_N_ORD_START_2'], p['IC_FP_N_ORD_START']) p['IC_HC_N_ORD_FINAL_2'] = max(p['IC_HC_N_ORD_FINAL_2'], p['IC_FP_N_ORD_FINAL']) start = p['IC_HC_N_ORD_START_2'] end = p['IC_HC_N_ORD_FINAL_2'] # recalculate echelle orders for Fit1DSolution o_orders = np.arange(start, end) echelle_order = p['IC_HC_T_ORDER_START'] - o_orders loc['ECHELLE_ORDERS'] = echelle_order loc.set_source('ECHELLE_ORDERS', __NAME__ + '/main()') # select the orders to fit lls = loc['LITTROW_EXTRAP_SOL_1'][start:end] loc = spirouTHORCA.Fit1DSolution(p, loc, lls, iteration=2) # from here, LL_OUT_2 wil be 0-47 # ------------------------------------------------------------------ # Repeat Littrow test # ------------------------------------------------------------------ start = p['IC_LITTROW_ORDER_INIT_2'] end = p['IC_LITTROW_ORDER_FINAL_2'] # recalculate echelle orders for Littrow check o_orders = np.arange(start, end) echelle_order = p['IC_HC_T_ORDER_START'] - o_orders loc['ECHELLE_ORDERS'] = echelle_order loc.set_source('ECHELLE_ORDERS', __NAME__ + '/main()') # Do Littrow check ckwargs = dict(ll=loc['LL_OUT_2'][start:end, :], iteration=2, log=True) loc = spirouTHORCA.CalcLittrowSolution(p, loc, **ckwargs) # Plot wave solution littrow check if p['DRS_PLOT'] > 0: # plot littrow x pixels against fitted wavelength solution sPlt.wave_littrow_check_plot(p, loc, iteration=2) # ------------------------------------------------------------------ # extrapolate Littrow solution # ------------------------------------------------------------------ ekwargs = dict(ll=loc['LL_OUT_2'], iteration=2) loc = spirouTHORCA.ExtrapolateLittrowSolution(p, loc, **ekwargs) # ------------------------------------------------------------------ # Plot littrow solution # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # plot littrow x pixels against fitted wavelength solution sPlt.wave_littrow_extrap_plot(p, loc, iteration=2) # ------------------------------------------------------------------ # Join 0-47 and 47-49 solutions # ------------------------------------------------------------------ loc = spirouTHORCA.JoinOrders(p, loc) # ------------------------------------------------------------------ # Plot single order, wavelength-calibrated, with found lines # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: sPlt.wave_ea_plot_single_order(p, loc) # ---------------------------------------------------------------------- # Do correlation on FP spectra # ---------------------------------------------------------------------- # ------------------------------------------------------------------ # Compute photon noise uncertainty for FP # ------------------------------------------------------------------ # set up the arguments for DeltaVrms2D dargs = [loc['FPDATA'], loc['LL_FINAL']] dkwargs = dict(sigdet=p['IC_DRIFT_NOISE'], size=p['IC_DRIFT_BOXSIZE'], threshold=p['IC_DRIFT_MAXFLUX']) # run DeltaVrms2D dvrmsref, wmeanref = spirouRV.DeltaVrms2D(*dargs, **dkwargs) # save to loc loc['DVRMSREF'], loc['WMEANREF'] = dvrmsref, wmeanref loc.set_sources(['dvrmsref', 'wmeanref'], __NAME__ + '/main()()') # log the estimated RV uncertainty wmsg = 'On fiber {0} estimated RV uncertainty on spectrum is {1:.3f} m/s' WLOG(p, 'info', wmsg.format(p['FIBER'], wmeanref)) # Use CCF Mask function with drift constants p['CCF_MASK'] = p['DRIFT_CCF_MASK'] p['TARGET_RV'] = p['DRIFT_TARGET_RV'] p['CCF_WIDTH'] = p['DRIFT_CCF_WIDTH'] p['CCF_STEP'] = p['DRIFT_CCF_STEP'] p['RVMIN'] = p['TARGET_RV'] - p['CCF_WIDTH'] p['RVMAX'] = p['TARGET_RV'] + p['CCF_WIDTH'] + p['CCF_STEP'] # get the CCF mask from file (check location of mask) loc = spirouRV.GetCCFMask(p, loc) # TODO Check why Blaze makes bugs in correlbin loc['BLAZE'] = np.ones((loc['NBO'], loc['NBPIX'])) # set sources # loc.set_sources(['flat', 'blaze'], __NAME__ + '/main()') loc.set_source('blaze', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Do correlation on FP # ---------------------------------------------------------------------- # calculate and fit the CCF loc['E2DSFF'] = np.array(loc['FPDATA']) loc.set_source('E2DSFF', __NAME__ + '/main()') p['CCF_FIT_TYPE'] = 1 loc['BERV'] = 0.0 loc['BERV_MAX'] = 0.0 loc['BJD'] = 0.0 # run the RV coravelation function with these parameters loc['WAVE_LL'] = np.array(loc['LL_FINAL']) loc['PARAM_LL'] = np.array(loc['LL_PARAM_FINAL']) loc = spirouRV.Coravelation(p, loc) # ---------------------------------------------------------------------- # Update the Correlation stats with values using fiber C (FP) drift # ---------------------------------------------------------------------- # get the maximum number of orders to use nbmax = p['CCF_NUM_ORDERS_MAX'] # get the average ccf loc['AVERAGE_CCF'] = np.nansum(loc['CCF'][:nbmax], axis=0) # normalize the average ccf normalized_ccf = loc['AVERAGE_CCF'] / np.nanmax(loc['AVERAGE_CCF']) # get the fit for the normalized average ccf ccf_res, ccf_fit = spirouRV.FitCCF(p, loc['RV_CCF'], normalized_ccf, fit_type=1) loc['CCF_RES'] = ccf_res loc['CCF_FIT'] = ccf_fit # get the max cpp loc['MAXCPP'] = np.nansum(loc['CCF_MAX']) / np.nansum( loc['PIX_PASSED_ALL']) # get the RV value from the normalised average ccf fit center location loc['RV'] = float(ccf_res[1]) # get the contrast (ccf fit amplitude) loc['CONTRAST'] = np.abs(100 * ccf_res[0]) # get the FWHM value loc['FWHM'] = ccf_res[2] * spirouCore.spirouMath.fwhm() # set the source keys = [ 'AVERAGE_CCF', 'MAXCPP', 'RV', 'CONTRAST', 'FWHM', 'CCF_RES', 'CCF_FIT' ] loc.set_sources(keys, __NAME__ + '/main()') # ---------------------------------------------------------------------- # log the stats wmsg = ('FP Correlation: C={0:.1f}[%] DRIFT={1:.5f}[km/s] ' 'FWHM={2:.4f}[km/s] maxcpp={3:.1f}') wargs = [loc['CONTRAST'], float(ccf_res[1]), loc['FWHM'], loc['MAXCPP']] WLOG(p, 'info', wmsg.format(*wargs)) # ---------------------------------------------------------------------- # rv ccf plot # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # Plot rv vs ccf (and rv vs ccf_fit) p['OBJNAME'] = 'FP' sPlt.ccf_rv_ccf_plot(p, loc['RV_CCF'], normalized_ccf, ccf_fit) # TODO : Add QC of the FP CCF # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # get parameters ffrom p p['QC_RMS_LITTROW_MAX'] = p['QC_HC_RMS_LITTROW_MAX'] p['QC_DEV_LITTROW_MAX'] = p['QC_HC_DEV_LITTROW_MAX'] # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # quality control on sigma clip (sig1 > qc_hc_wave_sigma_max if loc['SIG1'] > p['QC_HC_WAVE_SIGMA_MAX']: fmsg = 'Sigma too high ({0:.5f} > {1:.5f})' fail_msg.append(fmsg.format(loc['SIG1'], p['QC_HC_WAVE_SIGMA_MAX'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(loc['SIG1']) qc_names.append('SIG1') qc_logic.append('SIG1 > {0:.2f}'.format(p['QC_HC_WAVE_SIGMA_MAX'])) # ---------------------------------------------------------------------- # check the difference between consecutive orders is always positive # get the differences wave_diff = loc['LL_FINAL'][1:] - loc['LL_FINAL'][:-1] if np.min(wave_diff) < 0: fmsg = 'Negative wavelength difference between orders' fail_msg.append(fmsg) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.min(wave_diff)) qc_names.append('MIN WAVE DIFF') qc_logic.append('MIN WAVE DIFF < 0') # ---------------------------------------------------------------------- # check for infinites and NaNs in mean residuals from fit if ~np.isfinite(loc['X_MEAN_2']): # add failed message to the fail message list fmsg = 'NaN or Inf in X_MEAN_2' fail_msg.append(fmsg) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(loc['X_MEAN_2']) qc_names.append('X_MEAN_2') qc_logic.append('X_MEAN_2 not finite') # ---------------------------------------------------------------------- # iterate through Littrow test cut values lit_it = 2 # checks every other value # TODO: This QC check (or set of QC checks needs re-writing it is # TODO: nearly impossible to understand for x_it in range(1, len(loc['X_CUT_POINTS_' + str(lit_it)]), 2): # get x cut point x_cut_point = loc['X_CUT_POINTS_' + str(lit_it)][x_it] # get the sigma for this cut point sig_littrow = loc['LITTROW_SIG_' + str(lit_it)][x_it] # get the abs min and max dev littrow values min_littrow = abs(loc['LITTROW_MINDEV_' + str(lit_it)][x_it]) max_littrow = abs(loc['LITTROW_MAXDEV_' + str(lit_it)][x_it]) # get the corresponding order min_littrow_ord = loc['LITTROW_MINDEVORD_' + str(lit_it)][x_it] max_littrow_ord = loc['LITTROW_MAXDEVORD_' + str(lit_it)][x_it] # check if sig littrow is above maximum rms_littrow_max = p['QC_RMS_LITTROW_MAX'] dev_littrow_max = p['QC_DEV_LITTROW_MAX'] if sig_littrow > rms_littrow_max: fmsg = ('Littrow test (x={0}) failed (sig littrow = ' '{1:.2f} > {2:.2f})') fargs = [x_cut_point, sig_littrow, rms_littrow_max] fail_msg.append(fmsg.format(*fargs)) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(sig_littrow) qc_names.append('sig_littrow') qc_logic.append('sig_littrow > {0:.2f}'.format(rms_littrow_max)) # ---------------------------------------------------------------------- # check if min/max littrow is out of bounds if np.max([max_littrow, min_littrow]) > dev_littrow_max: fmsg = ('Littrow test (x={0}) failed (min|max dev = ' '{1:.2f}|{2:.2f} > {3:.2f} for order {4}|{5})') fargs = [ x_cut_point, min_littrow, max_littrow, dev_littrow_max, min_littrow_ord, max_littrow_ord ] fail_msg.append(fmsg.format(*fargs)) passed = False qc_pass.append(0) # TODO: Should this be the QC header values? # TODO: it does not change the outcome of QC (i.e. passed=False) # TODO: So what is the point? # if sig was out of bounds, recalculate if sig_littrow > rms_littrow_max: # conditions check1 = min_littrow > dev_littrow_max check2 = max_littrow > dev_littrow_max # get the residuals respix = loc['LITTROW_YY_' + str(lit_it)][x_it] # check if both are out of bounds if check1 and check2: # remove respective orders worst_order = (min_littrow_ord, max_littrow_ord) respix_2 = np.delete(respix, worst_order) redo_sigma = True # check if min is out of bounds elif check1: # remove respective order worst_order = min_littrow_ord respix_2 = np.delete(respix, worst_order) redo_sigma = True # check if max is out of bounds elif check2: # remove respective order worst_order = max_littrow_ord respix_2 = np.delete(respix, max_littrow_ord) redo_sigma = True # else do not recalculate sigma else: redo_sigma, respix_2, worst_order = False, None, None wmsg = 'No outlying orders, sig littrow not recalculated' fail_msg.append(wmsg.format()) # if outlying order, recalculate stats if redo_sigma: mean = np.nansum(respix_2) / len(respix_2) mean2 = np.nansum(respix_2**2) / len(respix_2) rms = np.sqrt(mean2 - mean**2) if rms > rms_littrow_max: fmsg = ('Littrow test (x={0}) failed (sig littrow = ' '{1:.2f} > {2:.2f} removing order {3})') fargs = [ x_cut_point, rms, rms_littrow_max, worst_order ] fail_msg.append(fmsg.format(*fargs)) else: wargs = [ x_cut_point, rms, rms_littrow_max, worst_order ] wmsg = ('Littrow test (x={0}) passed (sig littrow = ' '{1:.2f} > {2:.2f} removing order {3})') fail_msg.append(wmsg.format(*wargs)) else: qc_pass.append(1) # add to qc header lists qc_values.append(np.max([max_littrow, min_littrow])) qc_names.append('max or min littrow') qc_logic.append('max or min littrow > {0:.2f}' ''.format(dev_littrow_max)) # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ------------------------------------------------------------------ # archive result in e2ds spectra # ------------------------------------------------------------------ # get raw input file name(s) raw_infiles1 = [] for hcfile in p['HCFILES']: raw_infiles1.append(os.path.basename(hcfile)) raw_infile2 = os.path.basename(p['FPFILE']) # get wave filename wavefits, tag1 = spirouConfig.Constants.WAVE_FILE_EA_2(p) wavefitsname = os.path.split(wavefits)[-1] # log progress wargs = [p['FIBER'], wavefits] wmsg = 'Write wavelength solution for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # write solution to fitsfilename header # copy original keys hdict = spirouImage.CopyOriginalKeys(loc['HCHDR']) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) # set the input files hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBLAZE'], value=p['BLAZFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBWAVE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVESOURCE'], value=loc['WSOURCE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='fpfile', values=p['FPFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE2'], dim1name='hcfile', values=p['HCFILES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # add wave solution date hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME1'], value=p['MAX_TIME_HUMAN']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME2'], value=p['MAX_TIME_UNIX']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_CODE'], value=__NAME__) # add number of orders hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_ORD_N'], value=loc['LL_PARAM_FINAL'].shape[0]) # add degree of fit hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_LL_DEG'], value=loc['LL_PARAM_FINAL'].shape[1] - 1) # add wave solution hdict = spirouImage.AddKey2DList(p, hdict, p['KW_WAVE_PARAM'], values=loc['LL_PARAM_FINAL']) # add FP CCF drift # target RV and width hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_TARG_RV'], value=p['TARGET_RV']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_WIDTH'], value=p['CCF_WIDTH']) # the rv step # rvstep = np.abs(loc['RV_CCF'][0] - loc['RV_CCF'][1]) # hdict = spirouImage.AddKey(p, hdict, p['KW_CCF_CDELT'], value=rvstep) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_STEP'], value=p['CCF_STEP']) # add ccf stats hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_DRIFT'], value=loc['CCF_RES'][1]) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_FWHM'], value=loc['FWHM']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_CONTRAST'], value=loc['CONTRAST']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_MAXCPP'], value=loc['MAXCPP']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_MASK'], value=p['CCF_MASK']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_LINES'], value=np.nansum(loc['TOT_LINE'])) # write the wave "spectrum" hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) p = spirouImage.WriteImage(p, wavefits, loc['LL_FINAL'], hdict) # get filename for E2DS calibDB copy of FITSFILENAME e2dscopy_filename = spirouConfig.Constants.WAVE_E2DS_COPY(p)[0] wargs = [p['FIBER'], os.path.split(e2dscopy_filename)[-1]] wmsg = 'Write reference E2DS spectra for Fiber {0} in {1}' WLOG(p, '', wmsg.format(*wargs)) # make a copy of the E2DS file for the calibBD p = spirouImage.WriteImage(p, e2dscopy_filename, loc['HCDATA'], hdict) # only copy over if QC passed if p['QC']: # loop around hc files and update header with for hcfile in p['HCFILES']: raw_infilepath1 = os.path.join(p['ARG_FILE_DIR'], hcfile) p = spirouImage.UpdateWaveSolution(p, loc, raw_infilepath1) # update fp file raw_infilepath2 = os.path.join(p['ARG_FILE_DIR'], raw_infile2) p = spirouImage.UpdateWaveSolution(p, loc, raw_infilepath2) # ------------------------------------------------------------------ # Save to result table # ------------------------------------------------------------------ # calculate stats for table final_mean = 1000 * loc['X_MEAN_2'] final_var = 1000 * loc['X_VAR_2'] num_lines = int(np.nansum(loc['X_ITER_2'][:, 2])) # loc['X_ITER_2'] err = 1000 * np.sqrt(loc['X_VAR_2'] / num_lines) sig_littrow = 1000 * np.array(loc['LITTROW_SIG_' + str(lit_it)]) # construct filename wavetbl = spirouConfig.Constants.WAVE_TBL_FILE_EA(p) wavetblname = os.path.basename(wavetbl) # construct and write table columnnames = [ 'night_name', 'file_name', 'fiber', 'mean', 'rms', 'N_lines', 'err', 'rms_L500', 'rms_L1000', 'rms_L1500', 'rms_L2000', 'rms_L2500', 'rms_L3000', 'rms_L3500' ] columnformats = [ '{:20s}', '{:30s}', '{:3s}', '{:7.4f}', '{:6.2f}', '{:3d}', '{:6.3f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}', '{:6.2f}' ] columnvalues = [[p['ARG_NIGHT_NAME']], [p['ARG_FILE_NAMES'][0]], [p['FIBER']], [final_mean], [final_var], [num_lines], [err], [sig_littrow[0]], [sig_littrow[1]], [sig_littrow[2]], [sig_littrow[3]], [sig_littrow[4]], [sig_littrow[5]], [sig_littrow[6]]] # make table table = spirouImage.MakeTable(p, columns=columnnames, values=columnvalues, formats=columnformats) # merge table wmsg = 'Global result summary saved in {0}' WLOG(p, '', wmsg.format(wavetblname)) spirouImage.MergeTable(p, table, wavetbl, fmt='ascii.rst') # ---------------------------------------------------------------------- # Save resolution and line profiles to file # ---------------------------------------------------------------------- raw_infile = os.path.basename(p['FITSFILENAME']) # get wave filename resfits, tag3 = spirouConfig.Constants.WAVE_RES_FILE_EA(p) resfitsname = os.path.basename(resfits) WLOG(p, '', 'Saving wave resmap to {0}'.format(resfitsname)) # make a copy of the E2DS file for the calibBD # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) # get res data in correct format resdata, hdicts = spirouTHORCA.GenerateResFiles(p, loc, hdict) # save to file p = spirouImage.WriteImageMulti(p, resfits, resdata, hdicts=hdicts) # ------------------------------------------------------------------ # Save line list table file # ------------------------------------------------------------------ # construct filename # TODO proper column values wavelltbl = spirouConfig.Constants.WAVE_LINE_FILE_EA(p) wavelltblname = os.path.split(wavelltbl)[-1] # construct and write table columnnames = ['order', 'll', 'dv', 'w', 'xi', 'xo', 'dvdx'] columnformats = [ '{:.0f}', '{:12.4f}', '{:13.5f}', '{:12.4f}', '{:12.4f}', '{:12.4f}', '{:8.4f}' ] columnvalues = [] # construct column values (flatten over orders) for it in range(len(loc['X_DETAILS_2'])): for jt in range(len(loc['X_DETAILS_2'][it][0])): row = [ float(it), loc['X_DETAILS_2'][it][0][jt], loc['LL_DETAILS_2'][it][0][jt], loc['X_DETAILS_2'][it][3][jt], loc['X_DETAILS_2'][it][1][jt], loc['X_DETAILS_2'][it][2][jt], loc['SCALE_2'][it][jt] ] columnvalues.append(row) # log saving wmsg = 'List of lines used saved in {0}' WLOG(p, '', wmsg.format(wavelltblname)) # make table columnvalues = np.array(columnvalues).T table = spirouImage.MakeTable(p, columns=columnnames, values=columnvalues, formats=columnformats) # write table spirouImage.WriteTable(p, table, wavelltbl, fmt='ascii.rst') # ------------------------------------------------------------------ # Move to calibDB and update calibDB # ------------------------------------------------------------------ if p['QC']: # set the wave key keydb = 'WAVE_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, wavefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, wavefitsname, loc['HCHDR']) # set the hcref key keydb = 'HCREF_{0}'.format(p['FIBER']) # copy wave file to calibDB folder spirouDB.PutCalibFile(p, e2dscopy_filename) # update the master calib DB file with new key e2dscopyfits = os.path.split(e2dscopy_filename)[-1] spirouDB.UpdateCalibMaster(p, keydb, e2dscopyfits, loc['HCHDR']) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return p and loc return dict(locals())
def main(night_name=None): # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- main_name = __NAME__ + '.main()' # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, require_night_name=False) # ---------------------------------------------------------------------- # find all directories if night name was None (ARG_NIGHT_NAME = '') files, dirs = find_all_reduced_files(p) # ---------------------------------------------------------------------- # loop around each file # ---------------------------------------------------------------------- for it in range(len(files)): # get file name for this iteration basefilename = os.path.basename(files[it]) # Log process wmsg = 'Processing file {0} ({1}/{2})' wargs = [basefilename, it + 1, len(files)] WLOG(p, 'info', wmsg.format(*wargs)) # get this iteration values p['FITSFILENAME'] = files[it] p['ARG_NIGHT_NAME'] = dirs[it] p['REDUCED_DIR'] = os.path.join(p['DRS_DATA_REDUC'], dirs[it]) p['ARG_FILE_NAMES'] = [basefilename] p['DRS_TYPE'] = "REDUCED" # identify fiber if '_AB.fits' in os.path.basename(files[it]): p['FIBER'] = 'AB' elif '_AB.fits' in os.path.basename(files[it]): p['FIBER'] = 'A' elif '_AB.fits' in os.path.basename(files[it]): p['FIBER'] = 'B' elif '_C.fits' in os.path.basename(files[it]): p['FIBER'] = 'C' else: wmsg1 = 'Wrong fiber type found. This should happen. Skipping' wmsg2 = '\tFile = {0}'.format(files[it]) WLOG(p, 'warning', [wmsg1, wmsg2]) # skip continue # set sources source = ['FITSFILENAME', 'ARG_NIGHT_NAME', 'REDUCED_DIR', 'FIBER', 'ARG_FILE_NAMES'] p.set_sources(source, main_name) # define loc storage parameter dictionary loc = ParamDict() # --------------------------------------------------------------------- # Read image file # --------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # --------------------------------------------------------------------- # Load calibDB for this file # --------------------------------------------------------------------- # as we need a different calibDB for each file p = spirouStartup.LoadCalibDB(p, header=hdr) # ------------------------------------------------------------------ # Read wavelength solution # ------------------------------------------------------------------ # force reading from calibDB p['CALIB_DB_FORCE_WAVESOL'] = True p.set_source('CALIB_DB_FORCE_WAVESOL', main_name) # set source of wave file wsource = __NAME__ + '/main() + /spirouImage.GetWaveSolution' # Force A and B to AB solution if p['FIBER'] in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = p['FIBER'] # get wave image wout = spirouImage.GetWaveSolution(p, hdr=hdr, return_wavemap=True, return_filename=True, return_header=True, fiber=wave_fiber) loc['WAVEPARAMS'], loc['WAVE'], loc['WAVEFILE'] = wout[:3] loc['WAVEHDR'], loc['WSOURCE'] = wout[3:] source_names = ['WAVE', 'WAVEFILE', 'WAVEPARAMS', 'WAVEHDR', 'WSOURCE'] loc.set_sources(source_names, wsource) # get dates loc['WAVE_ACQTIMES'] = spirouDB.GetTimes(p, loc['WAVEHDR']) loc.set_source('WAVE_ACQTIMES', __NAME__ + '.main()') # get the recipe that produced the wave solution if 'WAVECODE' in loc['WAVEHDR']: loc['WAVE_CODE'] = loc['WAVEHDR']['WAVECODE'] else: loc['WAVE_CODE'] = 'UNKNOWN' loc.set_source('WAVE_CODE', __NAME__ + '.main()') # ------------------------------------------------------------------ # Save file with new header # ------------------------------------------------------------------ # log that we are saving E2DS spectrum wmsg = 'Saving E2DS spectrum of Fiber {0} in {1}' WLOG(p, '', wmsg.format(p['FIBER'], basefilename)) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) # set the input files hdict = spirouImage.AddKey(p, hdict, p['KW_CDBWAVE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVESOURCE'], value=loc['WSOURCE']) # add wave solution date hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME1'], value=loc['WAVE_ACQTIMES'][0]) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME2'], value=loc['WAVE_ACQTIMES'][1]) # add wave solution number of orders hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_ORD_N'], value=loc['WAVEPARAMS'].shape[0]) # add wave solution degree of fit hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_LL_DEG'], value=loc['WAVEPARAMS'].shape[1] - 1) # add wave solution coefficients hdict = spirouImage.AddKey2DList(p, hdict, p['KW_WAVE_PARAM'], values=loc['WAVEPARAMS']) # write to file p = spirouImage.WriteImage(p, p['FITSFILENAME'], data, hdict) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p, outputs=None) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None): """ cal_FF_RAW_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_FF_RAW_spirou.py [night_directory] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p, calibdb=True) # run specific start up p['FIB_TYPE'] = p['FIBER_TYPES'] p.set_source('FIB_TYPE', __NAME__ + '__main__()') # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # ---------------------------------------------------------------------- # Correction of DARK # ---------------------------------------------------------------------- p, datac = spirouImage.CorrectForDark(p, data, hdr) # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to e- data = spirouImage.ConvertToADU(spirouImage.FlipImage(p, datac), p=p) # convert NaN to zeros data0 = np.where(~np.isfinite(data), np.zeros_like(data), data) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) data1 = spirouImage.ResizeImage(p, data0, **bkwargs) # log change in data size WLOG(p, '', ('Image format changed to ' '{0}x{1}').format(*data1.shape[::-1])) # ---------------------------------------------------------------------- # Correct for the BADPIX mask (set all bad pixels to zero) # ---------------------------------------------------------------------- p, data1 = spirouImage.CorrectForBadPix(p, data1, hdr) # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- # get the number of bad pixels n_bad_pix = np.sum(~np.isfinite(data1)) n_bad_pix_frac = n_bad_pix * 100 / np.product(data1.shape) # Log number wmsg = 'Nb dead pixels = {0} / {1:.4f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ---------------------------------------------------------------------- # Get the miny, maxy and max_signal for the central column # ---------------------------------------------------------------------- # get the central column y = data1[p['IC_CENT_COL'], :] # get the min max and max signal using box smoothed approach miny, maxy, max_signal, diff_maxmin = spirouBACK.MeasureMinMaxSignal(p, y) # Log max average flux/pixel wmsg = ('Maximum average flux (95th percentile) /pixel in the spectrum: ' '{0:.1f} [ADU]') WLOG(p, 'info', wmsg.format(max_signal / p['NBFRAMES'])) # ---------------------------------------------------------------------- # Background computation # ---------------------------------------------------------------------- # p['ic_bkgr_percent'] = 3.0 if p['IC_DO_BKGR_SUBTRACTION']: # log that we are doing background measurement WLOG(p, '', 'Doing background measurement on raw frame') # get the bkgr measurement bargs = [p, data1, hdr] # background, xc, yc, minlevel = spirouBACK.MeasureBackgroundFF(*bargs) p, background = spirouBACK.MeasureBackgroundMap(*bargs) else: background = np.zeros_like(data1) p['BKGRDFILE'] = 'None' p.set_source('BKGRDFILE', __NAME__ + '.main()') # apply background correction to data data1 = data1 - background # ---------------------------------------------------------------------- # Read tilt slit angle # ---------------------------------------------------------------------- # define loc storage parameter dictionary loc = ParamDict() # get tilts if p['IC_FF_EXTRACT_TYPE'] not in EXTRACT_SHAPE_TYPES: p, loc['TILT'] = spirouImage.ReadTiltFile(p, hdr) else: loc['TILT'] = None loc.set_source('TILT', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Get all fiber data (for all fibers) # ---------------------------------------------------------------------- # TODO: This is temp solution for options 5a and 5b loc_fibers = spirouLOCOR.GetFiberData(p, hdr) # ------------------------------------------------------------------ # Deal with debananafication # ------------------------------------------------------------------ # if mode 4a or 4b we need to straighten in x only if p['IC_FF_EXTRACT_TYPE'] in ['4a', '4b']: # get the shape parameters p, shapem_x = spirouImage.GetShapeX(p, hdr) p, shape_local = spirouImage.GetShapeLocal(p, hdr) # log progress WLOG(p, '', 'Debananafying (straightening) image') # apply shape transforms targs = dict(lin_transform_vect=shape_local, dxmap=shapem_x) data2 = spirouImage.EATransform(data1, **targs) # if mode 5a or 5b we need to straighten in x and y using the # polynomial fits for location elif p['IC_FF_EXTRACT_TYPE'] in ['5a', '5b']: # get the shape parameters p, shapem_x = spirouImage.GetShapeX(p, hdr) p, shapem_y = spirouImage.GetShapeY(p, hdr) p, shape_local = spirouImage.GetShapeLocal(p, hdr) p, fpmaster = spirouImage.GetFPMaster(p, hdr) # get the bad pixel map bkwargs = dict(return_map=True, quiet=True) p, badpix = spirouImage.CorrectForBadPix(p, data1, hdr, **bkwargs) # log progress WLOG(p, '', 'Cleaning image') # clean the image data1 = spirouEXTOR.CleanHotpix(data1, badpix) # log progress WLOG(p, '', 'Debananafying (straightening) image') # apply shape transforms targs = dict(lin_transform_vect=shape_local, dxmap=shapem_x, dymap=shapem_y) data2 = spirouImage.EATransform(data1, **targs) # in any other mode we do not straighten else: data2 = np.array(data1) # ---------------------------------------------------------------------- # Fiber loop # ---------------------------------------------------------------------- # loop around fiber types for fiber in p['FIB_TYPE']: # set fiber in p p['FIBER'] = fiber p.set_source('FIBER', __NAME__ + '/main()') # get fiber parameters params2add = spirouImage.FiberParams(p, p['FIBER']) for param in params2add: p[param] = params2add[param] p.set_source(param, __NAME__ + '.main()') # ------------------------------------------------------------------ # Get fiber specific parameters from loc_fibers # ------------------------------------------------------------------ # get this fibers parameters p = spirouImage.FiberParams(p, p['FIBER'], merge=True) # get localisation parameters for key in loc_fibers[fiber]: loc[key] = loc_fibers[fiber][key] loc.set_source(key, loc_fibers[fiber].sources[key]) # get locofile source p['LOCOFILE'] = loc['LOCOFILE'] p.set_source('LOCOFILE', loc.sources['LOCOFILE']) # get the order_profile order_profile = loc_fibers[fiber]['ORDER_PROFILE'] # ------------------------------------------------------------------ # Set up Extract storage # ------------------------------------------------------------------ # Create array to store extraction (for each order and each pixel # along order) loc['E2DS'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) loc['E2DSLL'] = [] # Create array to store the blaze (for each order and at each pixel # along order) loc['BLAZE'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) # Create array to store the flat (for each order and at each pixel # along order) loc['FLAT'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) # Create array to store the signal to noise ratios for each order loc['SNR'] = np.zeros(loc['NUMBER_ORDERS']) # Create array to store the rms for each order loc['RMS'] = np.zeros(loc['NUMBER_ORDERS']) # Manually set the sigdet to be used in extraction weighting if p['IC_FF_SIGDET'] > 0: p['SIGDET'] = float(p['IC_FF_SIGDET']) # ------------------------------------------------------------------ # Extract orders # old code time: 1 loop, best of 3: 22.3 s per loop # new code time: 3.16 s ± 237 ms per loop # ------------------------------------------------------------------ # get limits of order extraction valid_orders = spirouFLAT.GetValidOrders(p, loc) # loop around each order for order_num in valid_orders: # extract this order eargs = [p, loc, data2, order_num] ekwargs = dict(mode=p['IC_FF_EXTRACT_TYPE'], order_profile=order_profile) with warnings.catch_warnings(record=True) as w: eout = spirouEXTOR.Extraction(*eargs, **ekwargs) # deal with different return if p['IC_FF_EXTRACT_TYPE'] in EXTRACT_LL_TYPES: e2ds, e2dsll, cpt = eout else: e2ds, cpt = eout e2dsll = None # calculate the noise range1, range2 = p['IC_EXT_RANGE1'], p['IC_EXT_RANGE2'] noise = p['SIGDET'] * np.sqrt(range1 + range2) # get window size blaze_win1 = int(data2.shape[1] / 2) - p['IC_EXTFBLAZ'] blaze_win2 = int(data2.shape[1] / 2) + p['IC_EXTFBLAZ'] # get average flux per pixel flux = np.nansum( e2ds[blaze_win1:blaze_win2]) / (2 * p['IC_EXTFBLAZ']) # calculate signal to noise ratio = flux/sqrt(flux + noise^2) snr = flux / np.sqrt(flux + noise**2) # remove edge of orders at low S/N with warnings.catch_warnings(record=True) as _: blazemask = e2ds < (flux / p['IC_FRACMINBLAZE']) e2ds = np.where(blazemask, np.nan, e2ds) # e2ds = np.where(e2ds < p['IC_MINBLAZE'], 0., e2ds) # calcualte the blaze function blaze = spirouFLAT.MeasureBlazeForOrder(p, e2ds) # calculate the flat flat = e2ds / blaze # calculate the rms rms = np.nanstd(flat) # log the SNR RMS wmsg = 'On fiber {0} order {1}: S/N= {2:.1f} - FF rms={3:.2f} %' wargs = [fiber, order_num, snr, rms * 100.0] WLOG(p, '', wmsg.format(*wargs)) # add calculations to storage loc['E2DS'][order_num] = e2ds loc['SNR'][order_num] = snr loc['RMS'][order_num] = rms loc['BLAZE'][order_num] = blaze loc['FLAT'][order_num] = flat # save the longfile if p['IC_FF_EXTRACT_TYPE'] in EXTRACT_LL_TYPES: loc['E2DSLL'].append(e2dsll) # set sources source = __NAME__ + '/main()()' loc.set_sources(['e2ds', 'SNR', 'RMS', 'blaze', 'flat'], source) # Log if saturation level reached satvalue = (flux / p['GAIN']) / (range1 + range2) if satvalue > (p['QC_LOC_FLUMAX'] * p['NBFRAMES']): wmsg = 'SATURATION LEVEL REACHED on Fiber {0} order={1}' WLOG(p, 'warning', wmsg.format(fiber, order_num)) # ---------------------------------------------------------------------- # Plots # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # start interactive session if needed sPlt.start_interactive_session(p) # plot all orders or one order if p['IC_FF_PLOT_ALL_ORDERS']: # plot image with all order fits (slower) sPlt.ff_aorder_fit_edges(p, loc, data1) else: # plot image with selected order fit and edge fit (faster) sPlt.ff_sorder_fit_edges(p, loc, data1) # plot tilt adjusted e2ds and blaze for selected order sPlt.ff_sorder_tiltadj_e2ds_blaze(p, loc) # plot flat for selected order sPlt.ff_sorder_flat(p, loc) # plot the RMS for all but skipped orders # sPlt.ff_rms_plot(p, loc) if p['IC_FF_EXTRACT_TYPE'] in EXTRACT_SHAPE_TYPES: sPlt.ff_debanana_plot(p, loc, data2) # ------------------------------------------------------------------ # Quality control # ------------------------------------------------------------------ passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # saturation check: check that the max_signal is lower than # qc_max_signal # if max_signal > (p['QC_MAX_SIGNAL'] * p['nbframes']): # fmsg = 'Too much flux in the image (max authorized={0})' # fail_msg.append(fmsg.format(p['QC_MAX_SIGNAL'] * p['nbframes'])) # passed = False # # For some reason this test is ignored in old code # passed = True # WLOG(p, 'info', fail_msg[-1]) # get mask for removing certain orders in the RMS calculation remove_orders = np.array(p['FF_RMS_PLOT_SKIP_ORDERS']) mask = np.in1d(np.arange(len(loc['RMS'])), remove_orders) # apply mask and calculate the maximum RMS max_rms = np.nanmax(loc['RMS'][~mask]) # apply the quality control based on the new RMS if max_rms > p['QC_FF_RMS']: fmsg = 'abnormal RMS of FF ({0:.3f} > {1:.3f})' fail_msg.append(fmsg.format(max_rms, p['QC_FF_RMS'])) passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(max_rms) qc_names.append('max_rms') qc_logic.append('max_rms > {0:.3f}'.format(p['QC_FF_RMS'])) # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: wmsg = 'QUALITY CONTROL SUCCESSFUL - Well Done -' WLOG(p, 'info', wmsg) p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ---------------------------------------------------------------------- # Store Blaze in file # ---------------------------------------------------------------------- # get raw flat filename raw_flat_file = os.path.basename(p['FITSFILENAME']) e2dsllfits, tag4 = spirouConfig.Constants.EXTRACT_E2DSLL_FILE(p) # get extraction method and function efout = spirouEXTOR.GetExtMethod(p, p['IC_FF_EXTRACT_TYPE']) extmethod, extfunc = efout # construct filename blazefits, tag1 = spirouConfig.Constants.FF_BLAZE_FILE(p) blazefitsname = os.path.split(blazefits)[-1] # log that we are saving blaze file wmsg = 'Saving blaze spectrum for fiber: {0} in {1}' WLOG(p, '', wmsg.format(fiber, blazefitsname)) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # define new keys to add hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_FIBER'], value=p['FIBER']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBACK'], value=p['BKGRDFILE']) if p['IC_FF_EXTRACT_TYPE'] not in EXTRACT_SHAPE_TYPES: hdict = spirouImage.AddKey(p, hdict, p['KW_CDBTILT'], value=p['TILTFILE']) if p['IC_FF_EXTRACT_TYPE'] in EXTRACT_SHAPE_TYPES: hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPEX'], value=p['SHAPEXFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPEY'], value=p['SHAPEYFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPE'], value=p['SHAPEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFPMASTER'], value=p['FPMASTERFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # add some properties back hdict = spirouImage.AddKey(p, hdict, p['KW_CCD_SIGDET']) hdict = spirouImage.AddKey(p, hdict, p['KW_CCD_CONAD']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # copy extraction method and function to header # (for reproducibility) hdict = spirouImage.AddKey(p, hdict, p['KW_E2DS_EXTM'], value=extmethod) hdict = spirouImage.AddKey(p, hdict, p['KW_E2DS_FUNC'], value=extfunc) # output keys hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) # write 1D list of the SNR hdict = spirouImage.AddKey1DList(p, hdict, p['KW_EXTRA_SN'], values=loc['SNR']) # write center fits and add header keys (via hdict) p = spirouImage.WriteImage(p, blazefits, loc['BLAZE'], hdict) # ---------------------------------------------------------------------- # Store Flat-field in file # ---------------------------------------------------------------------- # construct filename flatfits, tag2 = spirouConfig.Constants.FF_FLAT_FILE(p) flatfitsname = os.path.split(flatfits)[-1] # log that we are saving blaze file wmsg = 'Saving FF spectrum for fiber: {0} in {1}' WLOG(p, '', wmsg.format(fiber, flatfitsname)) # write 1D list of the RMS (add to hdict from blaze) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_FLAT_RMS'], values=loc['RMS']) # write center fits and add header keys (via same hdict as blaze) p = spirouImage.WriteImage(p, flatfits, loc['FLAT'], hdict) # Save E2DSLL file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag4) hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) if p['IC_FF_EXTRACT_TYPE'] in EXTRACT_LL_TYPES: llstack = np.vstack(loc['E2DSLL']) p = spirouImage.WriteImage(p, e2dsllfits, llstack, hdict) # ------------------------------------------------------------------ # Update the calibration database # ------------------------------------------------------------------ if p['QC'] == 1: # copy flatfits to calibdb keydb = 'FLAT_' + p['FIBER'] # copy localisation file to the calibDB folder spirouDB.PutCalibFile(p, flatfits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, flatfitsname, hdr) # copy blazefits to calibdb keydb = 'BLAZE_' + p['FIBER'] # copy localisation file to the calibDB folder spirouDB.PutCalibFile(p, blazefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, blazefitsname, hdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, fpfile=None, hcfiles=None): # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) if hcfiles is None or fpfile is None: names, types = ['fpfile', 'hcfiles'], [str, str] customargs = spirouStartup.GetCustomFromRuntime(p, [0, 1], types, names, last_multi=True) else: customargs = dict(hcfiles=hcfiles, fpfile=fpfile) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, customargs=customargs, mainfitsdir='reduced', mainfitsfile='hcfiles') # ---------------------------------------------------------------------- # Construct reference filename and get fiber type # ---------------------------------------------------------------------- p, fpfitsfilename = spirouStartup.SingleFileSetup(p, filename=p['FPFILE']) fiber1 = str(p['FIBER']) p, hcfilenames = spirouStartup.MultiFileSetup(p, files=p['HCFILES']) fiber2 = str(p['FIBER']) # set the hcfilename to the first hcfilenames hcfitsfilename = hcfilenames[0] # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # ---------------------------------------------------------------------- # Have to check that the fibers match # ---------------------------------------------------------------------- if fiber1 == fiber2: p['FIBER'] = fiber1 fsource = __NAME__ + '/main() & spirouStartup.GetFiberType()' p.set_source('FIBER', fsource) else: emsg = 'Fiber not matching for {0} and {1}, should be the same' eargs = [hcfitsfilename, fpfitsfilename] WLOG(p, 'error', emsg.format(*eargs)) # set the fiber type p['FIB_TYP'] = [p['FIBER']] p.set_source('FIB_TYP', __NAME__ + '/main()') # set find line mode find_lines_mode = p['HC_FIND_LINES_MODE'] # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read and combine all HC files except the first (fpfitsfilename) rargs = [p, 'add', hcfitsfilename, hcfilenames[1:]] p, hcdata, hchdr = spirouImage.ReadImageAndCombine(*rargs) # read first file (fpfitsfilename) fpdata, fphdr, _, _ = spirouImage.ReadImage(p, fpfitsfilename) # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'] = hcdata, hchdr loc['FPDATA'], loc['FPHDR'] = fpdata, fphdr # set the source sources = ['HCDATA', 'HCHDR'] loc.set_sources(sources, 'spirouImage.ReadImageAndCombine()') sources = ['FPDATA', 'FPHDR'] loc.set_sources(sources, 'spirouImage.ReadImage()') # ---------------------------------------------------------------------- # Get basic image properties for reference file # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hchdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hchdr, name='exptime') # get gain p = spirouImage.GetGain(p, hchdr, name='gain') # get acquisition time p = spirouImage.GetAcqTime(p, hchdr, name='acqtime', kind='julian') bjdref = p['ACQTIME'] # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # get lamp parameters p = spirouTHORCA.GetLampParams(p, hchdr) # ---------------------------------------------------------------------- # Obtain the flat # ---------------------------------------------------------------------- # get the flat p, loc = spirouFLAT.GetFlat(p, loc, hchdr) # ---------------------------------------------------------------------- # Read blaze # ---------------------------------------------------------------------- # get tilts p, loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hchdr) loc.set_source('BLAZE', __NAME__ + '/main() + /spirouImage.ReadBlazeFile') # correct the data with the flat # TODO: Should this be used? # log # WLOG(p, '', 'Applying flat correction') # loc['HCDATA'] = loc['HCDATA']/loc['FLAT'] # loc['FPDATA'] = loc['FPDATA']/loc['FLAT'] # ---------------------------------------------------------------------- # Start plotting session # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # start interactive plot sPlt.start_interactive_session(p) # ---------------------------------------------------------------------- # loop around fiber type # ---------------------------------------------------------------------- for fiber in p['FIB_TYP']: # set fiber type for inside loop p['FIBER'] = fiber # ------------------------------------------------------------------ # Instrumental drift computation (if previous solution exists) # ------------------------------------------------------------------ # get key keydb = 'HCREF_{0}'.format(p['FIBER']) # check for key in calibDB if keydb in p['CALIBDB'].keys(): # log process wmsg = ('Doing Instrumental drift computation from previous ' 'calibration') WLOG(p, '', wmsg) # calculate instrument drift loc = spirouTHORCA.CalcInstrumentDrift(p, loc) # ------------------------------------------------------------------ # Wave solution # ------------------------------------------------------------------ # log message for loop wmsg = 'Processing Wavelength Calibration for Fiber {0}' WLOG(p, 'info', wmsg.format(p['FIBER'])) # ------------------------------------------------------------------ # Part 1 of cal_HC # ------------------------------------------------------------------ p, loc = cal_HC_E2DS_spirou.part1(p, loc, mode=find_lines_mode) # ------------------------------------------------------------------ # FP solution # ------------------------------------------------------------------ # log message wmsg = 'Calculating FP wave solution' WLOG(p, '', wmsg) # calculate FP wave solution # spirouTHORCA.FPWaveSolution(p, loc, mode=find_lines_mode) spirouTHORCA.FPWaveSolutionNew(p, loc) # ------------------------------------------------------------------ # FP solution plots # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # Plot the FP extracted spectrum against wavelength solution sPlt.wave_plot_final_fp_order(p, loc, iteration=1) # Plot the measured FP cavity width offset against line number sPlt.wave_local_width_offset_plot(p, loc) # Plot the FP line wavelength residuals sPlt.wave_fp_wavelength_residuals(p, loc) # ------------------------------------------------------------------ # Part 2 of cal_HC # ------------------------------------------------------------------ # set params for part2 p['QC_RMS_LITTROW_MAX'] = p['QC_WAVE_RMS_LITTROW_MAX'] p['QC_DEV_LITTROW_MAX'] = p['QC_WAVE_DEV_LITTROW_MAX'] p['IC_HC_N_ORD_START_2'] = min(p['IC_HC_N_ORD_START_2'], p['IC_FP_N_ORD_START']) p['IC_HC_N_ORD_FINAL_2'] = max(p['IC_HC_N_ORD_FINAL_2'], p['IC_FP_N_ORD_FINAL']) # run part 2 # p, loc = part2test(p, loc) p, loc = cal_HC_E2DS_spirou.part2(p, loc) # ---------------------------------------------------------------------- # End plotting session # ---------------------------------------------------------------------- # end interactive session sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, hcfile=None, fpfiles=None): """ cal_SLIT_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_SLIT_spirou.py [night_directory] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) if hcfile is None or fpfiles is None: names, types = ['hcfile', 'fpfiles'], [str, str] customargs = spirouStartup.GetCustomFromRuntime(p, [0, 1], types, names, last_multi=True) else: customargs = dict(hcfile=hcfile, fpfiles=fpfiles) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, customargs=customargs, mainfitsfile='fpfiles') # ---------------------------------------------------------------------- # Construct reference filename and get fiber type # ---------------------------------------------------------------------- p, hcfitsfilename = spirouStartup.SingleFileSetup(p, filename=p['HCFILE']) p, fpfilenames = spirouStartup.MultiFileSetup(p, files=p['FPFILES']) # set fiber (it doesn't matter with the 2D image but we need this to get # the lamp type for FPFILES and HCFILES, AB == C p['FIBER'] = 'AB' p['FIB_TYP'] = [p['FIBER']] fsource = __NAME__ + '/main()' p.set_sources(['FIBER', 'FIB_TYP'], fsource) # set the hcfilename to the first hcfilenames fpfitsfilename = fpfilenames[0] # ---------------------------------------------------------------------- # Once we have checked the e2dsfile we can load calibDB # ---------------------------------------------------------------------- # as we have custom arguments need to load the calibration database p = spirouStartup.LoadCalibDB(p) # add a force plot off p['PLOT_PER_ORDER'] = PLOT_PER_ORDER p.set_source('PLOT_PER_ORDER', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Read FP and HC files # ---------------------------------------------------------------------- # read and combine all FP files except the first (fpfitsfilename) rargs = [p, 'add', fpfitsfilename, fpfilenames[1:]] p, fpdata, fphdr = spirouImage.ReadImageAndCombine(*rargs) # read first file (hcfitsfilename) hcdata, hchdr, _, _ = spirouImage.ReadImage(p, hcfitsfilename) # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'] = hcdata, hchdr loc['FPDATA'], loc['FPHDR'] = fpdata, fphdr # set the source sources = ['HCDATA', 'HCHDR'] loc.set_sources(sources, 'spirouImage.ReadImageAndCombine()') sources = ['FPDATA', 'FPHDR'] loc.set_sources(sources, 'spirouImage.ReadImage()') # --------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- hcdata = spirouImage.FixNonPreProcess(p, hcdata) fpdata = spirouImage.FixNonPreProcess(p, fpdata) # ---------------------------------------------------------------------- # Get basic image properties for reference file # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, fphdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, fphdr, name='exptime') # get gain p = spirouImage.GetGain(p, fphdr, name='gain') # get lamp parameters p = spirouTHORCA.GetLampParams(p, hchdr) # ---------------------------------------------------------------------- # Correction of DARK # ---------------------------------------------------------------------- # p, hcdatac = spirouImage.CorrectForDark(p, hcdata, hchdr) hcdatac = hcdata p['DARKFILE'] = 'None' # p, fpdatac = spirouImage.CorrectForDark(p, fpdata, fphdr) fpdatac = fpdata # ---------------------------------------------------------------------- # Resize hc data # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to e- hcdata = spirouImage.ConvertToE(spirouImage.FlipImage(p, hcdatac), p=p) # convert NaN to zeros hcdata0 = np.where(~np.isfinite(hcdata), np.zeros_like(hcdata), hcdata) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) hcdata2 = spirouImage.ResizeImage(p, hcdata0, **bkwargs) # log change in data size WLOG(p, '', ('HC Image format changed to ' '{0}x{1}').format(*hcdata2.shape)) # ---------------------------------------------------------------------- # Resize fp data # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to e- fpdata = spirouImage.ConvertToE(spirouImage.FlipImage(p, fpdatac), p=p) # convert NaN to zeros fpdata0 = np.where(~np.isfinite(fpdata), np.zeros_like(fpdata), fpdata) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) fpdata2 = spirouImage.ResizeImage(p, fpdata0, **bkwargs) # log change in data size WLOG(p, '', ('FP Image format changed to ' '{0}x{1}').format(*fpdata2.shape)) # ---------------------------------------------------------------------- # Correct for the BADPIX mask (set all bad pixels to zero) # ---------------------------------------------------------------------- # p, hcdata2 = spirouImage.CorrectForBadPix(p, hcdata2, hchdr) # p, fpdata2 = spirouImage.CorrectForBadPix(p, fpdata2, fphdr) p['BADPFILE'] = 'None' # save data to loc loc['HCDATA'] = hcdata2 loc.set_source('HCDATA', __NAME__ + '/main()') # save data to loc loc['FPDATA'] = fpdata2 loc.set_source('FPDATA', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- # get the number of bad pixels n_bad_pix = np.nansum(hcdata2 <= 0) n_bad_pix_frac = n_bad_pix * 100 / np.product(hcdata2.shape) # Log number wmsg = 'Nb HC dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- # get the number of bad pixels n_bad_pix = np.nansum(fpdata2 <= 0) n_bad_pix_frac = n_bad_pix * 100 / np.product(fpdata2.shape) # Log number wmsg = 'Nb FP dead pixels = {0} / {1:.2f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ------------------------------------------------------------------ # Get localisation coefficients # ------------------------------------------------------------------ # original there is a loop but it is not used --> removed p = spirouImage.FiberParams(p, p['FIBER'], merge=True) # get localisation fit coefficients p, loc = spirouLOCOR.GetCoeffs(p, fphdr, loc) # ------------------------------------------------------------------ # Get master wave solution map # ------------------------------------------------------------------ # get master wave map masterwavefile = spirouDB.GetDatabaseMasterWave(p) # log process wmsg1 = 'Getting master wavelength grid' wmsg2 = '\tFile = {0}'.format(os.path.basename(masterwavefile)) WLOG(p, '', [wmsg1, wmsg2]) # Force A and B to AB solution if p['FIBER'] in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = p['FIBER'] # read master wave map wout = spirouImage.GetWaveSolution(p, filename=masterwavefile, return_wavemap=True, quiet=True, return_header=True, fiber=wave_fiber) loc['MASTERWAVEP'], loc['MASTERWAVE'] = wout[:2] loc['MASTERWAVEHDR'], loc['WSOURCE'] = wout[2:] # set sources wsource = ['MASTERWAVEP', 'MASTERWAVE', 'MASTERWAVEHDR'] loc.set_sources(wsource, 'spirouImage.GetWaveSolution()') # ---------------------------------------------------------------------- # Read UNe solution # ---------------------------------------------------------------------- wave_u_ne, amp_u_ne = spirouImage.ReadLineList(p) loc['LL_LINE'], loc['AMPL_LINE'] = wave_u_ne, amp_u_ne source = __NAME__ + '.main() + spirouImage.ReadLineList()' loc.set_sources(['LL_LINE', 'AMPL_LINE'], source) # ---------------------------------------------------------------------- # Read cavity length file # ---------------------------------------------------------------------- loc['CAVITY_LEN_COEFFS'] = spirouImage.ReadCavityLength(p) source = __NAME__ + '.main() + spirouImage.ReadCavityLength()' loc.set_source('CAVITY_LEN_COEFFS', source) # ------------------------------------------------------------------ # Calculate shape map # ------------------------------------------------------------------ loc = spirouImage.GetShapeMap(p, loc) # ------------------------------------------------------------------ # Plotting # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # plots setup: start interactive plot sPlt.start_interactive_session(p) # plot the shape process for one order sPlt.slit_shape_angle_plot(p, loc) # end interactive section sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- # TODO: Decide on some quality control criteria? # set passed variable and fail message list passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # add to qc header lists qc_values.append('None') qc_names.append('None') qc_logic.append('None') qc_pass.append(1) # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ------------------------------------------------------------------ # Writing DXMAP to file # ------------------------------------------------------------------ # get the raw tilt file name raw_shape_file = os.path.basename(p['FITSFILENAME']) # construct file name and path shapefits, tag = spirouConfig.Constants.SLIT_XSHAPE_FILE(p) shapefitsname = os.path.basename(shapefits) # Log that we are saving tilt file wmsg = 'Saving shape information in file: {0}' WLOG(p, '', wmsg.format(shapefitsname)) # Copy keys from fits file hdict = spirouImage.CopyOriginalKeys(fphdr) # add version number hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='hcfile', values=p['HCFILE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE2'], dim1name='fpfile', values=p['FPFILES']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # write tilt file to file p = spirouImage.WriteImage(p, shapefits, loc['DXMAP'], hdict) # ------------------------------------------------------------------ # Writing sanity check files # ------------------------------------------------------------------ if p['SHAPE_DEBUG_OUTPUTS']: # log WLOG(p, '', 'Saving debug sanity check files') # construct file names input_fp_file, tag1 = spirouConfig.Constants.SLIT_SHAPE_IN_FP_FILE(p) output_fp_file, tag2 = spirouConfig.Constants.SLIT_SHAPE_OUT_FP_FILE(p) input_hc_file, tag3 = spirouConfig.Constants.SLIT_SHAPE_IN_HC_FILE(p) output_hc_file, tag4 = spirouConfig.Constants.SLIT_SHAPE_OUT_HC_FILE(p) overlap_file, tag5 = spirouConfig.Constants.SLIT_SHAPE_OVERLAP_FILE(p) # write input fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) p = spirouImage.WriteImage(p, input_fp_file, loc['FPDATA'], hdict) # write output fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) p = spirouImage.WriteImage(p, output_fp_file, loc['FPDATA2'], hdict) # write input fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) p = spirouImage.WriteImage(p, input_hc_file, loc['HCDATA'], hdict) # write output fp file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag4) p = spirouImage.WriteImage(p, output_hc_file, loc['HCDATA2'], hdict) # write overlap file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag5) p = spirouImage.WriteImage(p, overlap_file, loc['ORDER_OVERLAP'], hdict) # ---------------------------------------------------------------------- # Move to calibDB and update calibDB # ---------------------------------------------------------------------- if p['QC']: keydb = 'SHAPE' # copy shape file to the calibDB folder spirouDB.PutCalibFile(p, shapefits) # update the master calib DB file with new key spirouDB.UpdateCalibMaster(p, keydb, shapefitsname, fphdr) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None, fiber_type=None, **kwargs): """ cal_DRIFT_E2DS_spirou.py main function, if night_name and files are None uses arguments from run time i.e.: cal_DRIFT_E2DS_spirou.py [night_directory] [files] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :param fiber_type: string, if None does all fiber types (defined in constants_SPIROU FIBER_TYPES (default is AB, A, B, C if defined then only does this fiber type (but must be in FIBER_TYPES) :param kwargs: any keyword to overwrite constant in param dict "p" :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) p = spirouStartup.LoadArguments(p, night_name, files) p = spirouStartup.InitialFileSetup(p, calibdb=True) # deal with fiber type if fiber_type is None: fiber_type = p['FIBER_TYPES'] if type(fiber_type) == str: if fiber_type.upper() == 'ALL': fiber_type = p['FIBER_TYPES'] elif fiber_type in p['FIBER_TYPES']: fiber_type = [fiber_type] else: emsg = 'fiber_type="{0}" not understood' WLOG(p, 'error', emsg.format(fiber_type)) # set fiber type p['FIB_TYPE'] = fiber_type p.set_source('FIB_TYPE', __NAME__ + '__main__()') # Overwrite keys from source for kwarg in kwargs: p[kwarg] = kwargs[kwarg] # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read the image data p, data, hdr = spirouImage.ReadImageAndCombine(p, framemath='add') # ---------------------------------------------------------------------- # fix for un-preprocessed files # ---------------------------------------------------------------------- data = spirouImage.FixNonPreProcess(p, data) # ---------------------------------------------------------------------- # Get basic image properties # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, hdr, name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, hdr, name='exptime') # get gain p = spirouImage.GetGain(p, hdr, name='gain') # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # now change the value of sigdet if require if p['IC_EXT_SIGDET'] > 0: p['SIGDET'] = float(p['IC_EXT_SIGDET']) # get DPRTYPE from header (Will have it if valid) p = spirouImage.ReadParam(p, hdr, 'KW_DPRTYPE', required=False, dtype=str) # check the DPRTYPE is not None if (p['DPRTYPE'] == 'None') or (['DPRTYPE'] is None): emsg1 = 'Error: {0} is not set in header for file {1}' eargs = [p['KW_DPRTYPE'][0], p['FITSFILENAME']] emsg2 = '\tPlease run pre-processing on file.' emsg3 = ('\tIf pre-processing fails or skips file, file is not ' 'currrently as valid DRS fits file.') WLOG(p, 'error', [emsg1.format(*eargs), emsg2, emsg3]) else: p['DPRTYPE'] = p['DPRTYPE'].strip() # ---------------------------------------------------------------------- # Correction of DARK # ---------------------------------------------------------------------- p, datac = spirouImage.CorrectForDark(p, data, hdr) # ---------------------------------------------------------------------- # Resize image # ---------------------------------------------------------------------- # rotate the image and convert from ADU/s to ADU data = spirouImage.ConvertToADU(spirouImage.FlipImage(p, datac), p=p) # convert NaN to zeros data0 = np.where(~np.isfinite(data), np.zeros_like(data), data) # resize image bkwargs = dict(xlow=p['IC_CCDX_LOW'], xhigh=p['IC_CCDX_HIGH'], ylow=p['IC_CCDY_LOW'], yhigh=p['IC_CCDY_HIGH'], getshape=False) data1 = spirouImage.ResizeImage(p, data0, **bkwargs) # log change in data size wmsg = 'Image format changed to {1}x{0}' WLOG(p, '', wmsg.format(*data1.shape)) # ---------------------------------------------------------------------- # Correct for the BADPIX mask (set all bad pixels to zero) # ---------------------------------------------------------------------- p, data1 = spirouImage.CorrectForBadPix(p, data1, hdr) # ---------------------------------------------------------------------- # Log the number of dead pixels # ---------------------------------------------------------------------- # get the number of bad pixels n_bad_pix = np.sum(~np.isfinite(data1)) n_bad_pix_frac = n_bad_pix * 100 / np.product(data1.shape) # Log number wmsg = 'Nb dead pixels = {0} / {1:.4f} %' WLOG(p, 'info', wmsg.format(int(n_bad_pix), n_bad_pix_frac)) # ---------------------------------------------------------------------- # Get the miny, maxy and max_signal for the central column # ---------------------------------------------------------------------- # get the central column y = data1[p['IC_CENT_COL'], :] # get the min max and max signal using box smoothed approach miny, maxy, max_signal, diff_maxmin = spirouBACK.MeasureMinMaxSignal(p, y) # Log max average flux/pixel wmsg = 'Maximum average flux/pixel in the spectrum: {0:.1f} [ADU]' WLOG(p, 'info', wmsg.format(max_signal / p['NBFRAMES'])) # ---------------------------------------------------------------------- # Background computation # ---------------------------------------------------------------------- if p['IC_DO_BKGR_SUBTRACTION']: # log that we are doing background measurement WLOG(p, '', 'Doing background measurement on raw frame') # get the bkgr measurement bargs = [p, data1, hdr] # background, xc, yc, minlevel = spirouBACK.MeasureBackgroundFF(*bargs) p, background = spirouBACK.MeasureBackgroundMap(*bargs) else: background = np.zeros_like(data1) p['BKGRDFILE'] = 'None' p.set_source('BKGRDFILE', __NAME__ + '.main()') # apply background correction to data (and set to zero where negative) data1 = data1 - background # ---------------------------------------------------------------------- # Read tilt slit angle # ---------------------------------------------------------------------- # define loc storage parameter dictionary loc = ParamDict() # get tilts (if the mode requires it) if p['IC_EXTRACT_TYPE'] not in EXTRACT_SHAPE_TYPES: p, loc['TILT'] = spirouImage.ReadTiltFile(p, hdr) loc.set_source('TILT', __NAME__ + '/main() + /spirouImage.ReadTiltFile') else: loc['TILT'] = None loc.set_source('TILT', __NAME__ + '/main()') # ---------------------------------------------------------------------- # Earth Velocity calculation # ---------------------------------------------------------------------- if p['IC_IMAGE_TYPE'] == 'H4RG': p, loc = spirouImage.GetEarthVelocityCorrection(p, loc, hdr) # ---------------------------------------------------------------------- # Get all fiber data (for all fibers) # ---------------------------------------------------------------------- # TODO: This is temp solution for options 5a and 5b loc_fibers = spirouLOCOR.GetFiberData(p, hdr) # ------------------------------------------------------------------ # Deal with debananafication # ------------------------------------------------------------------ # if mode 4a or 4b we need to straighten in x only if p['IC_EXTRACT_TYPE'] in ['4a', '4b']: # get the shape parameters p, shapem_x = spirouImage.GetShapeX(p, hdr) p, shape_local = spirouImage.GetShapeLocal(p, hdr) # log progress WLOG(p, '', 'Debananafying (straightening) image') # apply shape transforms targs = dict(lin_transform_vect=shape_local, dxmap=shapem_x) data2 = spirouImage.EATransform(data1, **targs) # if mode 5a or 5b we need to straighten in x and y using the # polynomial fits for location elif p['IC_EXTRACT_TYPE'] in ['5a', '5b']: # get the shape parameters p, shapem_x = spirouImage.GetShapeX(p, hdr) p, shapem_y = spirouImage.GetShapeY(p, hdr) p, shape_local = spirouImage.GetShapeLocal(p, hdr) p, fpmaster = spirouImage.GetFPMaster(p, hdr) # get the bad pixel map bkwargs = dict(return_map=True, quiet=True) p, badpix = spirouImage.CorrectForBadPix(p, data1, hdr, **bkwargs) # log progress WLOG(p, '', 'Cleaning image') # clean the image data1 = spirouEXTOR.CleanHotpix(data1, badpix) # log progress WLOG(p, '', 'Debananafying (straightening) image') # apply shape transforms targs = dict(lin_transform_vect=shape_local, dxmap=shapem_x, dymap=shapem_y) data2 = spirouImage.EATransform(data1, **targs) # in any other mode we do not straighten else: data2 = np.array(data1) # ---------------------------------------------------------------------- # Fiber loop # ---------------------------------------------------------------------- # loop around fiber types for fiber in p['FIB_TYPE']: # set fiber p['FIBER'] = fiber p.set_source('FIBER', __NAME__ + '/main()()') # ------------------------------------------------------------------ # Read wavelength solution # ------------------------------------------------------------------ # set source of wave file wsource = __NAME__ + '/main() + /spirouImage.GetWaveSolution' # Force A and B to AB solution if fiber in ['A', 'B']: wave_fiber = 'AB' else: wave_fiber = fiber # get wave image wkwargs = dict(hdr=hdr, return_wavemap=True, return_filename=True, return_header=True, fiber=wave_fiber) wout = spirouImage.GetWaveSolution(p, **wkwargs) loc['WAVEPARAMS'], loc['WAVE'], loc['WAVEFILE'] = wout[:3] loc['WAVEHDR'], loc['WSOURCE'] = wout[3:] source_names = ['WAVE', 'WAVEFILE', 'WAVEPARAMS', 'WAVEHDR'] loc.set_sources(source_names, wsource) # get dates loc['WAVE_ACQTIMES'] = spirouDB.GetTimes(p, loc['WAVEHDR']) loc.set_source('WAVE_ACQTIMES', __NAME__ + '.main()') # get the recipe that produced the wave solution if 'WAVECODE' in loc['WAVEHDR']: loc['WAVE_CODE'] = loc['WAVEHDR']['WAVECODE'] else: loc['WAVE_CODE'] = 'UNKNOWN' loc.set_source('WAVE_CODE', __NAME__ + '.main()') # ---------------------------------------------------------------------- # Get WFP keys # ---------------------------------------------------------------------- # Read the WFP keys - if they don't exist set to None and deal # with later p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_DRIFT', name='WFP_DRIFT', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_FWHM', name='WFP_FWHM', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_CONTRAST', name='WFP_CONTRAST', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_MAXCPP', name='WFP_MAXCPP', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_MASK', name='WFP_MASK', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_LINES', name='WFP_LINES', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_TARG_RV', name='WFP_TARG_RV', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_WIDTH', name='WFP_WIDTH', required=False) p = spirouImage.ReadParam(p, loc['WAVEHDR'], 'KW_WFP_STEP', name='WFP_STEP', required=False) # ---------------------------------------------------------------------- # Read Flat file # ---------------------------------------------------------------------- fout = spirouImage.ReadFlatFile(p, hdr, return_header=True) p, loc['FLAT'], flathdr = fout loc.set_source('FLAT', __NAME__ + '/main() + /spirouImage.ReadFlatFile') # get flat extraction mode if p['KW_E2DS_EXTM'][0] in flathdr: flat_ext_mode = flathdr[p['KW_E2DS_EXTM'][0]] else: flat_ext_mode = None # ------------------------------------------------------------------ # Check extraction method is same as flat extraction method # ------------------------------------------------------------------ # get extraction method and function extmethod, extfunc = spirouEXTOR.GetExtMethod(p, p['IC_EXTRACT_TYPE']) if not DEBUG: # compare flat extraction mode to extraction mode spirouEXTOR.CompareExtMethod(p, flat_ext_mode, extmethod, 'FLAT', 'EXTRACTION') # ------------------------------------------------------------------ # Read Blaze file # ------------------------------------------------------------------ p, loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hdr) blazesource = __NAME__ + '/main() + /spirouImage.ReadBlazeFile' loc.set_source('BLAZE', blazesource) # ------------------------------------------------------------------ # Get fiber specific parameters from loc_fibers # ------------------------------------------------------------------ # get this fibers parameters p = spirouImage.FiberParams(p, p['FIBER'], merge=True) # get localisation parameters for key in loc_fibers[fiber]: loc[key] = loc_fibers[fiber][key] loc.set_source(key, loc_fibers[fiber].sources[key]) # get locofile source p['LOCOFILE'] = loc['LOCOFILE'] p.set_source('LOCOFILE', loc.sources['LOCOFILE']) # get the order_profile order_profile = loc_fibers[fiber]['ORDER_PROFILE'] # ------------------------------------------------------------------ # Set up Extract storage # ------------------------------------------------------------------ # Create array to store extraction (for each order and each pixel # along order) loc['E2DS'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) loc['E2DSFF'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) loc['E2DSLL'] = [] loc['SPE1'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) loc['SPE3'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) loc['SPE4'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) loc['SPE5'] = np.zeros((loc['NUMBER_ORDERS'], data2.shape[1])) # Create array to store the signal to noise ratios for each order loc['SNR'] = np.zeros(loc['NUMBER_ORDERS']) # ------------------------------------------------------------------ # Extract orders # ------------------------------------------------------------------ # source for parameter dictionary source = __NAME__ + '/main()' # get limits of order extraction valid_orders = spirouEXTOR.GetValidOrders(p, loc) # loop around each order for order_num in valid_orders: # ------------------------------------------------------------- # IC_EXTRACT_TYPE decides the extraction routine # ------------------------------------------------------------- eargs = [p, loc, data2, order_num] ekwargs = dict(mode=p['IC_EXTRACT_TYPE'], order_profile=order_profile) with warnings.catch_warnings(record=True) as w: eout = spirouEXTOR.Extraction(*eargs, **ekwargs) # deal with different return if p['IC_EXTRACT_TYPE'] in EXTRACT_LL_TYPES: e2ds, e2dsll, cpt = eout else: e2ds, cpt = eout e2dsll = None # ------------------------------------------------------------- # calculate the noise range1, range2 = p['IC_EXT_RANGE1'], p['IC_EXT_RANGE2'] # set the noise noise = p['SIGDET'] * np.sqrt(range1 + range2) # get window size blaze_win1 = int(data2.shape[0] / 2) - p['IC_EXTFBLAZ'] blaze_win2 = int(data2.shape[0] / 2) + p['IC_EXTFBLAZ'] # get average flux per pixel flux = np.nansum( e2ds[blaze_win1:blaze_win2]) / (2 * p['IC_EXTFBLAZ']) # calculate signal to noise ratio = flux/sqrt(flux + noise^2) snr = flux / np.sqrt(flux + noise**2) # log the SNR RMS wmsg = 'On fiber {0} order {1}: S/N= {2:.1f} Nbcosmic= {3}' wargs = [p['FIBER'], order_num, snr, cpt] WLOG(p, '', wmsg.format(*wargs)) # add calculations to storage loc['E2DS'][order_num] = e2ds loc['E2DSFF'][order_num] = e2ds / loc['FLAT'][order_num] loc['SNR'][order_num] = snr # save the longfile if p['IC_EXTRACT_TYPE'] in EXTRACT_LL_TYPES: loc['E2DSLL'].append(e2dsll) # set sources loc.set_sources(['e2ds', 'SNR'], source) # Log if saturation level reached satvalue = (flux / p['GAIN']) / (range1 + range2) if satvalue > (p['QC_LOC_FLUMAX'] * p['NBFRAMES']): wmsg = 'SATURATION LEVEL REACHED on Fiber {0} order={1}' WLOG(p, 'warning', wmsg.format(fiber, order_num)) # ------------------------------------------------------------------ # Thermal correction # ------------------------------------------------------------------ # get fiber type if fiber in ['AB', 'A', 'B']: fibertype = p['DPRTYPE'].split('_')[0] else: fibertype = p['DPRTYPE'].split('_')[1] # apply thermal correction based on fiber type if fibertype in p['THERMAL_CORRECTION_TYPE1']: # log progress wmsg = 'Correcting thermal background for {0}={1} mode={2}' wargs = [fiber, fibertype, 1] WLOG(p, 'info', wmsg.format(*wargs)) # correct E2DS tkwargs = dict(image=loc['E2DS'], mode=1, fiber=fiber, hdr=hdr) p, loc['E2DS'] = spirouBACK.ThermalCorrect(p, **tkwargs) # correct E2DSFF tkwargs = dict(image=loc['E2DSFF'], mode=1, fiber=fiber, hdr=hdr, flat=loc['FLAT']) p, loc['E2DSFF'] = spirouBACK.ThermalCorrect(p, **tkwargs) elif fibertype in p['THERMAL_CORRECTION_TYPE2']: # log progress wmsg = 'Correcting thermal background for {0}={1} mode={2}' wargs = [fiber, fibertype, 2] WLOG(p, 'info', wmsg.format(*wargs)) # correct E2DS tkwargs = dict(image=loc['E2DS'], mode=2, fiber=fiber, hdr=hdr) p, loc['E2DS'] = spirouBACK.ThermalCorrect(p, **tkwargs) # correct E2DSFF tkwargs = dict(image=loc['E2DSFF'], mode=2, fiber=fiber, hdr=hdr, flat=loc['FLAT']) p, loc['E2DSFF'] = spirouBACK.ThermalCorrect(p, **tkwargs) else: # log progress wmsg = 'Not correcting thermal background for {0}={1}' wargs = [fiber, fibertype] WLOG(p, 'info', wmsg.format(*wargs)) # set filename for output outfile = 'THERMALFILE_{0}'.format(fiber) p[outfile] = 'None' p.set_source(outfile, __NAME__ + '.main()') # ------------------------------------------------------------------ # Plots # ------------------------------------------------------------------ if p['DRS_PLOT'] > 0: # start interactive session if needed sPlt.start_interactive_session(p) # plot all orders or one order if p['IC_FF_PLOT_ALL_ORDERS']: # plot image with all order fits (slower) sPlt.ext_aorder_fit(p, loc, data1, max_signal / 10.) else: # plot image with selected order fit and edge fit (faster) sPlt.ext_sorder_fit(p, loc, data1, max_signal / 10.) # plot e2ds against wavelength sPlt.ext_spectral_order_plot(p, loc) if p['IC_EXTRACT_TYPE'] in EXTRACT_SHAPE_TYPES: sPlt.ext_debanana_plot(p, loc, data2, max_signal / 10.) # ---------------------------------------------------------------------- # Quality control # ---------------------------------------------------------------------- passed, fail_msg = True, [] qc_values, qc_names, qc_logic, qc_pass = [], [], [], [] # ---------------------------------------------------------------------- # if array is completely NaNs it shouldn't pass if np.sum(np.isfinite(loc['E2DS'])) == 0: fail_msg.append('E2DS image is all NaNs') passed = False qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append('NaN') qc_names.append('image') qc_logic.append('image is all NaN') # ---------------------------------------------------------------------- # saturation check: check that the max_signal is lower than # qc_max_signal max_qcflux = p['QC_MAX_SIGNAL'] * p['NBFRAMES'] if max_signal > max_qcflux: fmsg = 'Too much flux in the image ({0:.2f} > {1:.2f})' fail_msg.append(fmsg.format(max_signal, max_qcflux)) passed = False # Question: Why is this test ignored? # For some reason this test is ignored in old code passed = True WLOG(p, 'info', fail_msg[-1]) qc_pass.append(0) else: qc_pass.append(1) # add to qc header lists qc_values.append(max_signal) qc_names.append('max_signal') qc_logic.append('QC_MAX_SIGNAL > {0:.3f}'.format(max_qcflux)) # finally log the failed messages and set QC = 1 if we pass the # quality control QC = 0 if we fail quality control if passed: WLOG(p, 'info', 'QUALITY CONTROL SUCCESSFUL - Well Done -') p['QC'] = 1 p.set_source('QC', __NAME__ + '/main()') else: for farg in fail_msg: wmsg = 'QUALITY CONTROL FAILED: {0}' WLOG(p, 'warning', wmsg.format(farg)) p['QC'] = 0 p.set_source('QC', __NAME__ + '/main()') # store in qc_params qc_params = [qc_names, qc_values, qc_logic, qc_pass] # ------------------------------------------------------------------ # Store extraction in file(s) # ------------------------------------------------------------------ raw_ext_file = os.path.basename(p['FITSFILENAME']) # construct filename e2dsfits, tag1 = spirouConfig.Constants.EXTRACT_E2DS_FILE(p) e2dsfitsname = os.path.split(e2dsfits)[-1] e2dsfffits, tag2 = spirouConfig.Constants.EXTRACT_E2DSFF_FILE(p) e2dsfffitsname = os.path.split(e2dsfffits)[-1] e2dsllfits, tag4 = spirouConfig.Constants.EXTRACT_E2DSLL_FILE(p) e2dsfllitsname = os.path.split(e2dsllfits)[-1] # log that we are saving E2DS spectrum wmsg = 'Saving E2DS spectrum of Fiber {0} in {1}' WLOG(p, '', wmsg.format(p['FIBER'], e2dsfitsname)) wmsg = 'Saving E2DSFF spectrum of Fiber {0} in {1}' WLOG(p, '', wmsg.format(p['FIBER'], e2dsfffitsname)) # add keys from original header file hdict = spirouImage.CopyOriginalKeys(hdr) # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_PID'], value=p['PID']) hdict = spirouImage.AddKey(p, hdict, p['KW_FIBER'], value=p['FIBER']) # set the input files hdict = spirouImage.AddKey(p, hdict, p['KW_CDBDARK'], value=p['DARKFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=p['BADPFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBLOCO'], value=p['LOCOFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBACK'], value=p['BKGRDFILE']) if p['IC_EXTRACT_TYPE'] not in EXTRACT_SHAPE_TYPES: hdict = spirouImage.AddKey(p, hdict, p['KW_CDBTILT'], value=p['TILTFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBLAZE'], value=p['BLAZFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFLAT'], value=p['FLATFILE']) if p['IC_EXTRACT_TYPE'] in EXTRACT_SHAPE_TYPES: hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPEX'], value=p['SHAPEXFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPEY'], value=p['SHAPEYFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBSHAPE'], value=p['SHAPEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFPMASTER'], value=p['FPMASTERFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBTHERMAL'], value=p['THERMALFILE_{0}'.format(fiber)]) hdict = spirouImage.AddKey(p, hdict, p['KW_CDBWAVE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVESOURCE'], value=loc['WSOURCE']) hdict = spirouImage.AddKey1DList(p, hdict, p['KW_INFILE1'], dim1name='file', values=p['ARG_FILE_NAMES']) # construct loco filename locofile, _ = spirouConfig.Constants.EXTRACT_LOCO_FILE(p) locofilename = os.path.basename(locofile) # add barycentric keys to header hdict = spirouImage.AddKey(p, hdict, p['KW_BERV'], value=loc['BERV']) hdict = spirouImage.AddKey(p, hdict, p['KW_BJD'], value=loc['BJD']) hdict = spirouImage.AddKey(p, hdict, p['KW_BERV_MAX'], value=loc['BERV_MAX']) hdict = spirouImage.AddKey(p, hdict, p['KW_B_OBS_HOUR'], value=loc['BERVHOUR']) # add barycentric estimate keys to header hdict = spirouImage.AddKey(p, hdict, p['KW_BERV_EST'], value=loc['BERV_EST']) hdict = spirouImage.AddKey(p, hdict, p['KW_BJD_EST'], value=loc['BJD_EST']) hdict = spirouImage.AddKey(p, hdict, p['KW_BERV_MAX_EST'], value=loc['BERV_MAX_EST']) hdict = spirouImage.AddKey(p, hdict, p['KW_BERV_SOURCE'], value=loc['BERV_SOURCE']) # add qc parameters hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC']) hdict = spirouImage.AddQCKeys(p, hdict, qc_params) # copy extraction method and function to header # (for reproducibility) hdict = spirouImage.AddKey(p, hdict, p['KW_E2DS_EXTM'], value=extmethod) hdict = spirouImage.AddKey(p, hdict, p['KW_E2DS_FUNC'], value=extfunc) # add localization file name to header hdict = spirouImage.AddKey(p, hdict, p['KW_LOCO_FILE'], value=locofilename) # add wave solution date hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME1'], value=loc['WAVE_ACQTIMES'][0]) hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_TIME2'], value=loc['WAVE_ACQTIMES'][1]) # add wave solution number of orders hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_ORD_N'], value=loc['WAVEPARAMS'].shape[0]) # add wave solution degree of fit hdict = spirouImage.AddKey(p, hdict, p['KW_WAVE_LL_DEG'], value=loc['WAVEPARAMS'].shape[1] - 1) # ------------------------------------------------------------------------- # add keys of the wave solution FP CCF hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_FILE'], value=loc['WAVEFILE']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_DRIFT'], value=p['WFP_DRIFT']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_FWHM'], value=p['WFP_FWHM']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_CONTRAST'], value=p['WFP_CONTRAST']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_MAXCPP'], value=p['WFP_MAXCPP']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_MASK'], value=p['WFP_MASK']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_LINES'], value=p['WFP_LINES']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_TARG_RV'], value=p['WFP_TARG_RV']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_WIDTH'], value=p['WFP_WIDTH']) hdict = spirouImage.AddKey(p, hdict, p['KW_WFP_STEP'], value=p['WFP_STEP']) # write 1D list of the SNR hdict = spirouImage.AddKey1DList(p, hdict, p['KW_E2DS_SNR'], values=loc['SNR']) # add localization file keys to header root = p['KW_ROOT_DRS_LOC'][0] hdict = spirouImage.CopyRootKeys(p, hdict, locofile, root=root) # add wave solution coefficients hdict = spirouImage.AddKey2DList(p, hdict, p['KW_WAVE_PARAM'], values=loc['WAVEPARAMS']) # Save E2DS file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag1) hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) p = spirouImage.WriteImage(p, e2dsfits, loc['E2DS'], hdict) # Save E2DSFF file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag2) hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) p = spirouImage.WriteImage(p, e2dsfffits, loc['E2DSFF'], hdict) # Save E2DSLL file hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag4) hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) if p['IC_EXTRACT_TYPE'] in EXTRACT_LL_TYPES: llstack = np.vstack(loc['E2DSLL']) p = spirouImage.WriteImage(p, e2dsllfits, llstack, hdict) # ------------------------------------------------------------------ # 1-dimension spectral S1D (uniform in wavelength) # ------------------------------------------------------------------ # get arguments for E2DS to S1D e2dsargs = [loc['WAVE'], loc['E2DSFF'], loc['BLAZE']] # get 1D spectrum xs1d1, ys1d1 = spirouImage.E2DStoS1D(p, *e2dsargs, wgrid='wave') # Plot the 1D spectrum if p['DRS_PLOT'] > 0: sPlt.ext_1d_spectrum_plot(p, xs1d1, ys1d1) # construct file name s1dfile1, tag3 = spirouConfig.Constants.EXTRACT_S1D_FILE1(p) s1dfilename1 = os.path.basename(s1dfile1) # add header keys # set the version hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag3) hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) # log writing to file wmsg = 'Saving 1D spectrum (uniform in wavelength) for Fiber {0} in {1}' WLOG(p, '', wmsg.format(p['FIBER'], s1dfilename1)) # Write to file columns = ['wavelength', 'flux', 'eflux'] values = [xs1d1, ys1d1, np.zeros_like(ys1d1)] units = ['nm', None, None] s1d1 = spirouImage.MakeTable(p, columns, values, units=units) spirouImage.WriteTable(p, s1d1, s1dfile1, header=hdict) # ------------------------------------------------------------------ # 1-dimension spectral S1D (uniform in velocity) # ------------------------------------------------------------------ # get arguments for E2DS to S1D e2dsargs = [loc['WAVE'], loc['E2DSFF'], loc['BLAZE']] # get 1D spectrum xs1d2, ys1d2 = spirouImage.E2DStoS1D(p, *e2dsargs, wgrid='velocity') # Plot the 1D spectrum if p['DRS_PLOT'] > 0: sPlt.ext_1d_spectrum_plot(p, xs1d2, ys1d2) # construct file name s1dfile2, tag4 = spirouConfig.Constants.EXTRACT_S1D_FILE2(p) s1dfilename2 = os.path.basename(s1dfile2) # add header keys hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION']) hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_DATE'], value=p['DRS_DATE']) hdict = spirouImage.AddKey(p, hdict, p['KW_DATE_NOW'], value=p['DATE_NOW']) hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag4) hdict = spirouImage.AddKey(p, hdict, p['KW_EXT_TYPE'], value=p['DPRTYPE']) # log writing to file wmsg = 'Saving 1D spectrum (uniform in velocity) for Fiber {0} in {1}' WLOG(p, '', wmsg.format(p['FIBER'], s1dfilename2)) # Write to file columns = ['wavelength', 'flux', 'eflux'] values = [xs1d2, ys1d2, np.zeros_like(ys1d2)] units = ['nm', None, None] s1d2 = spirouImage.MakeTable(p, columns, values, units=units) spirouImage.WriteTable(p, s1d2, s1dfile2, header=hdict) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())
def main(night_name=None, files=None): """ cal_HC_E2DS.py main function, if night_name and files are None uses arguments from run time i.e.: cal_DARK_spirou.py [night_directory] [fitsfilename] :param night_name: string or None, the folder within data raw directory containing files (also reduced directory) i.e. /data/raw/20170710 would be "20170710" but /data/raw/AT5/20180409 would be "AT5/20180409" :param files: string, list or None, the list of files to use for arg_file_names and fitsfilename (if None assumes arg_file_names was set from run time) :return ll: dictionary, containing all the local variables defined in main """ # ---------------------------------------------------------------------- # Set up # ---------------------------------------------------------------------- # get parameters from config files/run time args/load paths + calibdb p = spirouStartup.Begin(recipe=__NAME__) # get parameters from configuration files and run time arguments p = spirouStartup.LoadArguments(p, night_name, files, mainfitsdir='reduced') # setup files and get fiber p = spirouStartup.InitialFileSetup(p, calibdb=True) # set the fiber type p['FIB_TYP'] = [p['FIBER']] p.set_source('FIB_TYP', __NAME__ + '/main()') # set find line mode find_lines_mode = p['HC_FIND_LINES_MODE'] # ---------------------------------------------------------------------- # Read image file # ---------------------------------------------------------------------- # read and combine all files p, hcdata, hchdr = spirouImage.ReadImageAndCombine(p, 'add') # add data and hdr to loc loc = ParamDict() loc['HCDATA'], loc['HCHDR'] = hcdata, hchdr # set the source sources = ['HCDATA', 'HCHDR'] loc.set_sources(sources, 'spirouImage.ReadImageAndCombine()') # ---------------------------------------------------------------------- # Get basic parameters # ---------------------------------------------------------------------- # get sig det value p = spirouImage.GetSigdet(p, loc['HCHDR'], name='sigdet') # get exposure time p = spirouImage.GetExpTime(p, loc['HCHDR'], name='exptime') # get gain p = spirouImage.GetGain(p, loc['HCHDR'], name='gain') # get acquisition time p = spirouImage.GetAcqTime(p, loc['HCHDR'], name='acqtime', kind='julian') bjdref = p['ACQTIME'] # set sigdet and conad keywords (sigdet is changed later) p['KW_CCD_SIGDET'][1] = p['SIGDET'] p['KW_CCD_CONAD'][1] = p['GAIN'] # get lamp parameters p = spirouTHORCA.GetLampParams(p, loc['HCHDR']) # ---------------------------------------------------------------------- # Obtain the flat # ---------------------------------------------------------------------- # get the flat # p, loc = spirouFLAT.GetFlat(p, loc, hchdr) # correct the data with the flat # TODO: Should this be used? # log # WLOG(p, '', 'Applying flat correction') # loc['HCDATA'] = loc['HCDATA']/loc['FLAT'] # ---------------------------------------------------------------------- # Read blaze # ---------------------------------------------------------------------- # get tilts loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hchdr) loc.set_source('BLAZE', __NAME__ + '/main() + /spirouImage.ReadBlazeFile') # ---------------------------------------------------------------------- # Start plotting session # ---------------------------------------------------------------------- if p['DRS_PLOT'] > 0: # start interactive plot sPlt.start_interactive_session(p) # ---------------------------------------------------------------------- # loop around fiber type # ---------------------------------------------------------------------- for fiber in p['FIB_TYP']: # set fiber type for inside loop p['FIBER'] = fiber # ------------------------------------------------------------------ # Wave solution # ------------------------------------------------------------------ # log message for loop wmsg = 'Processing Wavelength Calibration for Fiber {0}' WLOG(p, 'info', wmsg.format(p['FIBER'])) # ------------------------------------------------------------------ # Part 1 # ------------------------------------------------------------------ p, loc = part1(p, loc, mode=find_lines_mode) # ------------------------------------------------------------------ # Part 2 # ------------------------------------------------------------------ # set params for part2 p['QC_RMS_LITTROW_MAX'] = p['QC_HC_RMS_LITTROW_MAX'] p['QC_DEV_LITTROW_MAX'] = p['QC_HC_DEV_LITTROW_MAX'] # ------------------------------------------------------------------ # run part 2 p, loc = part2(p, loc) # ---------------------------------------------------------------------- # End plotting session # ---------------------------------------------------------------------- # end interactive session if p['DRS_PLOT'] > 0: sPlt.end_interactive_session(p) # ---------------------------------------------------------------------- # End Message # ---------------------------------------------------------------------- p = spirouStartup.End(p) # return a copy of locally defined variables in the memory return dict(locals())