def main(night_name=None, key=None, filename=None):
    """
    Manually add a file the the calibDB with "key"

    i.e. adds

    key night_name filename human-date unix-time

    to the calibDB and copies "filename" from .../reduced_dir/night_name/ into
    the calibDB

    Note filename must be in .../reduced_dir/night_name/
    """
    # ----------------------------------------------------------------------
    # Set up
    # ----------------------------------------------------------------------
    # get parameters from config files/run time args/load paths + calibdb
    p = spirouStartup.Begin(recipe=__NAME__)
    # deal with arguments being None (i.e. get from sys.argv)
    pos = [0, 1]
    fmt = [str, str]
    names = ['key', 'filename']
    call = [key, filename]
    # now get custom arguments
    customargs = spirouStartup.GetCustomFromRuntime(p,
                                                    pos,
                                                    fmt,
                                                    names,
                                                    calls=call)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsfile='filename',
                                    mainfitsdir='reduced')
    # as we have custom arguments need to load the calibration database
    p = spirouStartup.LoadCalibDB(p)

    # ----------------------------------------------------------------------
    # Read image file
    # ----------------------------------------------------------------------
    # read the image data
    image, hdr, nbo, nx = spirouImage.ReadData(p, p['FITSFILENAME'])

    # ----------------------------------------------------------------------
    # Move to calibDB and update calibDB
    # ----------------------------------------------------------------------
    # set dark key
    keydb = p['KEY']
    # copy dark fits file to the calibDB folder
    spirouDB.PutCalibFile(p, p['FITSFILENAME'])
    # update the master calib DB file with new key
    spirouDB.UpdateCalibMaster(p, keydb, p['FILENAME'], hdr)

    # ----------------------------------------------------------------------
    # End Message
    # ----------------------------------------------------------------------
    p = spirouStartup.End(p)
    # return a copy of locally defined variables in the memory
    return dict(locals())
Beispiel #2
0
def main(night_name=None, reffile=None):
    # ----------------------------------------------------------------------
    # Set up
    # ----------------------------------------------------------------------
    # get parameters from config files/run time args/load paths + calibdb
    p = spirouStartup.Begin(recipe=__NAME__)
    # deal with reference file being None (i.e. get from sys.argv)
    if reffile is None:
        customargs = spirouStartup.GetCustomFromRuntime(p, [0], [str],
                                                        ['reffile'])
    else:
        customargs = dict(reffile=reffile)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p, night_name, customargs=customargs,
                                    mainfitsfile='reffile',
                                    mainfitsdir='reduced')
    # ----------------------------------------------------------------------
    # Construct reference filename and get fiber type
    # ----------------------------------------------------------------------
    p, reffilename = spirouStartup.SingleFileSetup(p, filename=p['REFFILE'],
                                                   skipcheck=True)
    p['REFFILENAME'] = reffilename
    p.set_source('REFFILENAME', __NAME__ + '.main()')
    # ----------------------------------------------------------------------
    # Read image file
    # ----------------------------------------------------------------------
    # read the image data
    data, hdr, nbo, nx = spirouImage.ReadData(p, p['REFFILENAME'])
    # ----------------------------------------------------------------------
    # Add keys and save file
    # ----------------------------------------------------------------------
    newfilename = p['REFFILE'].replace('.fits', '_edit.fits')
    newpath = os.path.join(p['ARG_FILE_DIR'], newfilename)
    # add keys from original header file
    hdict = spirouImage.CopyOriginalKeys(hdr)
    # set the version
    hdict = spirouImage.AddKey(p, hdict, HEADER_KEY, value=HEADER_VALUE)
    # log saving
    wmsg = 'Writing file {0} to {1}'
    WLOG(p, '', wmsg.format(newfilename, p['ARG_FILE_DIR']))
    # save drift values
    p = spirouImage.WriteImage(p, newpath, data, 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,
         e2dsfile=None,
         mask=None,
         rv=None,
         width=None,
         step=None):
    """
    cal_CCF_E2DS_spirou.py main function, if arguments are None uses
    arguments from run time i.e.:
        cal_CCF_E2DS_spirou.py [night_directory] [E2DSfilename] [mask] [RV]
                               [width] [step]

    :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 e2dsfile: string, the E2DS file to use
    :param mask: string, the mask file to use (i.e. "UrNe.mas")
    :param rv: float, the target RV to use
    :param width: float, the CCF width to use
    :param step: float, the CCF step to use

    :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__)
    # deal with arguments being None (i.e. get from sys.argv)
    pos = [0, 1, 2, 3, 4]
    fmt = [str, str, float, float, float]
    name = ['e2dsfile', 'ccf_mask', 'target_rv', 'ccf_width', 'ccf_step']
    lname = ['input_file', 'CCF_mask', 'RV', 'CCF_width', 'CCF_step']
    req = [True, True, True, False, False]
    call = [e2dsfile, mask, rv, width, step]
    call_priority = [True, True, True, True, True]
    # now get custom arguments
    customargs = spirouStartup.GetCustomFromRuntime(p, pos, fmt, name, req,
                                                    call, call_priority, lname)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsfile='e2dsfile',
                                    mainfitsdir='reduced')

    # ----------------------------------------------------------------------
    # Construct reference filename and get fiber type
    # ----------------------------------------------------------------------
    p, e2dsfilename = spirouStartup.SingleFileSetup(p, filename=p['E2DSFILE'])

    # ----------------------------------------------------------------------
    # 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)

    # ----------------------------------------------------------------------
    # Deal with optional run time arguments
    # ----------------------------------------------------------------------
    # define default arguments (if ccf_width and ccf_step are not defined
    # in function call or run time arguments
    if 'ccf_width' not in p:
        p['CCF_WIDTH'] = p['IC_CCF_WIDTH']
    if 'ccf_step' not in p:
        p['CCF_STEP'] = p['IC_CCF_STEP']

    # ----------------------------------------------------------------------
    # Read image file
    # ----------------------------------------------------------------------
    # read the image data
    e2ds, hdr, nbo, nx = spirouImage.ReadData(p, e2dsfilename)
    # add to loc
    loc = ParamDict()
    loc['E2DS'] = e2ds
    loc['NUMBER_ORDERS'] = nbo
    loc.set_sources(['E2DS', 'number_orders'], __NAME__ + '/main()')

    # ----------------------------------------------------------------------
    # Get basic image properties for reference 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')
    # get acquisition time
    p = spirouImage.GetAcqTime(p, hdr, name='acqtime', kind='julian')
    # get obj name
    p = spirouImage.ReadParam(p, hdr, 'KW_OBJNAME', name='OBJNAME', dtype=str)

    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']

    # ----------------------------------------------------------------------
    #  Earth Velocity calculation
    # ----------------------------------------------------------------------
    if p['IC_IMAGE_TYPE'] == 'H4RG':
        p, loc = spirouImage.GetEarthVelocityCorrection(p, loc, hdr)

    # ----------------------------------------------------------------------
    # Read wavelength solution
    # ----------------------------------------------------------------------
    # log
    WLOG(p, '', 'Reading wavelength solution ')
    # 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,
                                       fiber=wave_fiber)
    param_ll, wave_ll, wavefile, wsource = wout
    # save to storage
    loc['PARAM_LL'], loc['WAVE_LL'], loc['WAVEFILE'], loc['WSOURCE'] = wout
    source = __NAME__ + '/main() + spirouTHORCA.GetWaveSolution()'
    loc.set_sources(['WAVE_LL', 'PARAM_LL', 'WAVEFILE', 'WSOURCE'], source)

    # ----------------------------------------------------------------------
    # Read Flat file
    # ----------------------------------------------------------------------
    # TODO We do not need to correct FLAT
    # log
    # WLOG(p, '', 'Reading Flat-Field ')

    # get flat
    # loc['FLAT'] = spirouImage.ReadFlatFile(p, hdr)
    # loc.set_source('FLAT', __NAME__ + '/main() + /spirouImage.ReadFlatFile')
    # get all values in flat that are zero to 1
    # loc['FLAT'] = np.where(loc['FLAT'] == 0, 1.0, loc['FLAT'])

    # get blaze
    # p, loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hdr)
    p, blaze0 = spirouImage.ReadBlazeFile(p, hdr)

    # ----------------------------------------------------------------------
    # Preliminary set up = no flat, no blaze
    # ----------------------------------------------------------------------
    # reset flat to all ones
    # loc['FLAT'] = np.ones((nbo, nx))
    # set blaze to all ones (if not bug in correlbin !!!
    # TODO Check why Blaze makes bugs in correlbin
    loc['BLAZE'] = np.ones((nbo, nx))
    # set sources
    # loc.set_sources(['flat', 'blaze'], __NAME__ + '/main()')
    loc.set_sources(['blaze'], __NAME__ + '/main()')

    # Modification of E2DS array  with N.A.N
    if np.isnan(np.sum(e2ds)):
        WLOG(p, 'warning', 'NaN values found in e2ds, converting process')
        #  First basic approach Replacing N.A.N by zeros
        #    e2ds[np.isnan(e2ds)] = 0

        # Second approach replacing N.A.N by the Adjusted Blaze
        e2dsb = e2ds / blaze0
        for i in np.arange(len(e2ds)):
            with warnings.catch_warnings(record=True) as _:
                rap = np.mean(e2dsb[i][np.isfinite(e2dsb[i])])
            if np.isnan(rap):
                rap = 0.0
            e2ds[i] = np.where(np.isfinite(e2dsb[i]), e2ds[i], blaze0[i] * rap)

    # ----------------------------------------------------------------------
    # correct extracted image for flat
    # ----------------------------------------------------------------------
    # loc['E2DSFF'] = e2ds/loc['FLAT']
    # loc['E2DSFF'] = e2ds*1.
    loc['E2DSFF'] = e2ds
    loc.set_source('E2DSFF', __NAME__ + '/main()')

    # ----------------------------------------------------------------------
    # Compute photon noise uncertainty for reference file
    # ----------------------------------------------------------------------
    # set up the arguments for DeltaVrms2D
    dargs = [loc['E2DS'], loc['WAVE_LL']]
    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))
    wmsg = 'On fiber estimated RV uncertainty on spectrum is {0:.3f} m/s'
    WLOG(p, 'info', wmsg.format(wmeanref))
    # TEST N.A.N
    # loc['E2DSFF'][20:22,2000:3000]=np.nan
    # e2ds[20:30,1000:3000]=np.nan

    # ----------------------------------------------------------------------
    # Reference plots
    # ----------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot FP spectral order
        sPlt.drift_plot_selected_wave_ref(p,
                                          loc,
                                          x=loc['WAVE_LL'],
                                          y=loc['E2DS'])
        # plot photon noise uncertainty
        sPlt.drift_plot_photon_uncertainty(p, loc)

    # ----------------------------------------------------------------------
    # Get template RV (from ccf_mask)
    # ----------------------------------------------------------------------
    # get the CCF mask from file (check location of mask)
    loc = spirouRV.GetCCFMask(p, loc)

    # check and deal with mask in microns (should be in nm)
    if np.mean(loc['LL_MASK_CTR']) < 2.0:
        loc['LL_MASK_CTR'] *= 1000.0
        loc['LL_MASK_D'] *= 1000.0

    # ----------------------------------------------------------------------
    # Do correlation
    # ----------------------------------------------------------------------
    # calculate and fit the CCF
    loc = spirouRV.Coravelation(p, loc)

    # ----------------------------------------------------------------------
    # Correlation stats
    # ----------------------------------------------------------------------
    # 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.max(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=0)
    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 = ('Correlation: C={0:.1f}[%] RV={1:.5f}[km/s] '
            'FWHM={2:.4f}[km/s] maxcpp={3:.1f}')
    wargs = [loc['CONTRAST'], loc['RV'], 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)
        sPlt.ccf_rv_ccf_plot(p, loc['RV_CCF'], normalized_ccf, ccf_fit)

    # ----------------------------------------------------------------------
    # Quality control
    # ----------------------------------------------------------------------
    # set passed variable and fail message list
    passed, fail_msg = True, []
    qc_values, qc_names, qc_logic, qc_pass = [], [], [], []
    # TODO: Needs doing
    # 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]

    # ----------------------------------------------------------------------
    # archive ccf to table
    # ----------------------------------------------------------------------
    # construct filename
    res_table_file = spirouConfig.Constants.CCF_TABLE_FILE(p)
    # log progress
    WLOG(p, '', 'Archiving CCF on file {0}'.format(res_table_file))
    # define column names
    columns = ['order', 'maxcpp', 'nlines', 'contrast', 'RV', 'sig']
    # define values for each column
    values = [
        loc['ORDERS'], loc['CCF_MAX'] / loc['PIX_PASSED_ALL'], loc['TOT_LINE'],
        np.abs(100 * loc['CCF_ALL_RESULTS'][:, 0]),
        loc['CCF_ALL_RESULTS'][:, 1], loc['CCF_ALL_RESULTS'][:, 2]
    ]
    # define the format for each column
    formats = ['2.0f', '5.0f', '4.0f', '4.1f', '9.4f', '7.4f']
    # construct astropy table from column names, values and formats
    table = spirouImage.MakeTable(p, columns, values, formats)
    # save table to file
    spirouImage.WriteTable(p, table, res_table_file, fmt='ascii')

    # ----------------------------------------------------------------------
    # archive ccf to fits file
    # ----------------------------------------------------------------------
    raw_infile = os.path.basename(p['E2DSFILE'])
    # construct folder and filename
    corfile, tag = spirouConfig.Constants.CCF_FITS_FILE(p)
    corfilename = os.path.split(corfile)[-1]
    # log that we are archiving the CCF on file
    WLOG(p, '', 'Archiving CCF on file {0}'.format(corfilename))
    # get constants from p
    mask = p['CCF_MASK']
    # if file exists remove it
    if os.path.exists(corfile):
        os.remove(corfile)
    # add the average ccf to the end of ccf
    data = np.vstack([loc['CCF'], loc['AVERAGE_CCF']])
    # add drs keys
    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_PID'], value=p['PID'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag)
    # 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='file',
                                     values=p['E2DSFILE'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_INCCFMASK'],
                               value=p['CCF_MASK'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_INRV'], value=p['TARGET_RV'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_INWIDTH'], value=p['CCF_WIDTH'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_INSTEP'], value=p['CCF_STEP'])
    # add qc parameters
    hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC'])
    hdict = spirouImage.AddQCKeys(p, hdict, qc_params)
    # add CCF keys
    hdict = spirouImage.AddKey(p, hdict, p['KW_CCF_CTYPE'], value='km/s')
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CCF_CRVAL'],
                               value=loc['RV_CCF'][0])
    # 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)
    # add ccf stats
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CCF_RV'],
                               value=loc['CCF_RES'][1])
    hdict = spirouImage.AddKey(p, hdict, p['KW_CCF_RVC'], value=loc['RV'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_CCF_FWHM'], value=loc['FWHM'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CCF_WMREF'],
                               value=loc['WMEANREF'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CCF_CONTRAST'],
                               value=loc['CONTRAST'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CCF_MAXCPP'],
                               value=loc['MAXCPP'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_CCF_MASK'], value=p['CCF_MASK'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CCF_LINES'],
                               value=np.nansum(loc['TOT_LINE']))
    # add berv values
    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'])
    # write image and add header keys (via hdict)
    p = spirouImage.WriteImage(p, corfile, data, 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, reffile=None):
    """
    cal_DRIFTPEAK_E2DS_spirou.py main function, if arguments are None uses
    arguments from run time i.e.:
        cal_DRIFTPEAK_E2DS_spirou.py [night_directory] [reffile]

    :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 reffile: string, the reference file to use

    :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__)
    # deal with reference file being None (i.e. get from sys.argv)
    if reffile is None:
        customargs = spirouStartup.GetCustomFromRuntime(
            p, [0], [str], ['reffile'])
    else:
        customargs = dict(reffile=reffile)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsfile='reffile',
                                    mainfitsdir='reduced')

    # ----------------------------------------------------------------------
    # Construct reference filename and get fiber type
    # ----------------------------------------------------------------------
    p, reffilename = spirouStartup.SingleFileSetup(p, filename=p['REFFILE'])
    p['REFFILENAME'] = reffilename
    p.set_source('REFFILENAME', __NAME__ + '.main()')

    # ----------------------------------------------------------------------
    # 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)

    # ----------------------------------------------------------------------
    # Read image file
    # ----------------------------------------------------------------------
    # read the image data
    speref, hdr, nbo, nx = spirouImage.ReadData(p, p['REFFILENAME'])
    # add to loc
    loc = ParamDict()
    loc['SPEREF'] = speref
    loc['NUMBER_ORDERS'] = nbo
    loc.set_sources(['SPEREF', 'NUMBER_ORDERS'], __NAME__ + '/main()')

    # ----------------------------------------------------------------------
    # Get lamp type
    # ----------------------------------------------------------------------
    # get lamp type
    if p['KW_EXT_TYPE'][0] in hdr:
        ext_type = hdr[p['KW_EXT_TYPE'][0]]
        drift_types = p['DRIFT_PEAK_ALLOWED_TYPES'].keys()
        found = False
        for kind in drift_types:
            if ext_type == kind:
                loc['LAMP'] = p['DRIFT_PEAK_ALLOWED_TYPES'][kind]
                found = True
        if not found:
            eargs1 = [p['KW_EXT_TYPE'][0], ' or '.join(drift_types)]
            emsg1 = (
                'Wrong type of image for Drift, header key "{0}" should be'
                '{1}'.format(*eargs1))
            emsg2 = '\tPlease check DRIFT_PEAK_ALLOWED_TYPES'
            WLOG(p, 'error', [emsg1, emsg2])
    else:
        emsg = 'Header key = "{0}" missing from file {1}'
        eargs = [p['KW_EXT_TYPE'][0], p['REFFILENAME']]
        WLOG(p, 'error', emsg.format(*eargs))
    loc.set_source('LAMP', __NAME__ + '/main()')

    # ----------------------------------------------------------------------
    # Get basic image properties for reference 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')
    # get acquisition time
    p = spirouImage.GetAcqTime(p, hdr, 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']

    # ----------------------------------------------------------------------
    # Read wavelength solution
    # ----------------------------------------------------------------------
    # Force A and B to AB solution
    if p['FIBER'] in ['A', 'B']:
        wave_fiber = 'AB'
    else:
        wave_fiber = p['FIBER']
    # get wave image
    source = __NAME__ + '/main() + /spirouImage.GetWaveSolution'
    wout = spirouImage.GetWaveSolution(p,
                                       hdr=hdr,
                                       return_wavemap=True,
                                       return_filename=True,
                                       fiber=wave_fiber)
    _, loc['WAVE'], loc['WAVEFILE'], loc['WSOURCE'] = wout
    loc.set_sources(['WAVE', 'WAVEFILE', 'WSOURCE'], source)

    # ----------------------------------------------------------------------
    # Read Flat file
    # ----------------------------------------------------------------------
    # get flat
    p, loc['FLAT'] = spirouImage.ReadFlatFile(p, hdr)
    loc.set_source('FLAT', __NAME__ + '/main() + /spirouImage.ReadFlatFile')
    # get all values in flat that are zero to 1
    loc['FLAT'] = np.where(loc['FLAT'] == 0, 1.0, loc['FLAT'])
    # correct for flat file
    loc['SPEREF'] = loc['SPEREF'] / loc['FLAT']

    # ----------------------------------------------------------------------
    # Background correction
    # ----------------------------------------------------------------------
    # test whether we want to subtract background
    if p['IC_DRIFT_BACK_CORR']:
        # Loop around the orders
        for order_num in range(loc['NUMBER_ORDERS']):
            # get the box size from constants
            bsize = p['DRIFT_PEAK_MINMAX_BOXSIZE']
            # Measurethe min and max flux
            miny, maxy = spirouBACK.MeasureMinMax(loc['SPEREF'][order_num],
                                                  bsize)
            # subtract off the background (miny)
            loc['SPEREF'][order_num] = loc['SPEREF'][order_num] - miny

    # ----------------------------------------------------------------------
    # Identify FP peaks in reference file
    # ----------------------------------------------------------------------
    # log that we are identifying peaks
    wmsg = 'Identification of lines in reference file: {0}'
    WLOG(p, '', wmsg.format(p['REFFILE']))
    # get the position of FP peaks from reference file
    loc = spirouRV.CreateDriftFile(p, loc)

    # ----------------------------------------------------------------------
    # Removal of suspiciously wide FP lines
    # ----------------------------------------------------------------------
    loc = spirouRV.RemoveWidePeaks(p, loc)

    # ----------------------------------------------------------------------
    # Get reference drift
    # ----------------------------------------------------------------------
    # are we using gaussfit?
    gaussfit = p['DRIFT_PEAK_GETDRIFT_GAUSSFIT']
    # get drift
    loc['XREF'] = spirouRV.GetDrift(p,
                                    loc['SPEREF'],
                                    loc['ORDPEAK'],
                                    loc['XPEAK'],
                                    gaussfit=gaussfit)
    loc.set_source('XREF', __NAME__ + '/main()')
    # remove any drifts that are zero (i.e. peak not measured
    loc = spirouRV.RemoveZeroPeaks(p, loc)

    # ------------------------------------------------------------------
    # Reference plots
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot FP spectral order
        sPlt.drift_plot_selected_wave_ref(p, loc)

    # ------------------------------------------------------------------
    # Get all other files that match kw_OUTPUT and kw_EXT_TYPE from
    #    ref file
    # ------------------------------------------------------------------
    # get files
    listfiles, listtypes = spirouImage.GetSimilarDriftFiles(p, hdr)
    # get the number of files
    nfiles = len(listfiles)
    # Log the number of files found
    wmsgs = [
        'Number of files found on directory = {0}'.format(nfiles),
        '\tExtensions allowed:'
    ]
    for listtype in listtypes:
        wmsgs.append('\t\t - {0}'.format(listtype))
    WLOG(p, 'info', wmsgs)

    # ------------------------------------------------------------------
    # Set up Extract storage for all files
    # ------------------------------------------------------------------
    # decide whether we need to skip (for large number of files)
    if len(listfiles) >= p['DRIFT_NLARGE']:
        skip = p['DRIFT_PEAK_FILE_SKIP']
        nfiles = int(nfiles / skip)
    else:
        skip = 1
    # set up storage
    loc['DRIFT'] = np.zeros((nfiles, loc['NUMBER_ORDERS']))
    loc['DRIFT_LEFT'] = np.zeros((nfiles, loc['NUMBER_ORDERS']))
    loc['DRIFT_RIGHT'] = np.zeros((nfiles, loc['NUMBER_ORDERS']))
    loc['ERRDRIFT'] = np.zeros((nfiles, loc['NUMBER_ORDERS']))
    loc['DELTATIME'] = np.zeros(nfiles)
    loc['MEANRV'] = np.zeros(nfiles)
    loc['MEANRV_LEFT'] = np.zeros(nfiles)
    loc['MEANRV_RIGHT'] = np.zeros(nfiles)
    loc['MERRDRIFT'] = np.zeros(nfiles)
    loc['FLUXRATIO'] = np.zeros(nfiles)
    # add sources
    source = __NAME__ + '/main()'
    keys = [
        'drift', 'drift_left', 'drift_right', 'errdrift', 'deltatime',
        'meanrv', 'meanrv_left', 'meanrv_right', 'merrdrift', 'fluxratio'
    ]
    loc.set_sources(keys, source)

    # ------------------------------------------------------------------
    # Loop around all files: correct for dark, reshape, extract and
    #     calculate dvrms and meanpond
    # ------------------------------------------------------------------
    # get the maximum number of orders to use
    nomin = p['IC_DRIFT_PEAK_N_ORDER_MIN']
    nomax = p['IC_DRIFT_PEAK_N_ORDER_MAX']
    # loop around files
    for i_it in range(nfiles):
        # get file for this iteration
        fpfile = listfiles[::skip][i_it]
        # Log the file we are reading
        wmsg = 'Reading file {0}'
        WLOG(p, '', wmsg.format(os.path.split(fpfile)[-1]))
        # ------------------------------------------------------------------
        # read e2ds files and get timestamp
        # ------------------------------------------------------------------
        # read data
        rout = spirouImage.ReadData(p, filename=fpfile, log=False)
        loc['SPE'], hdri, nxi, nyi = rout
        # apply flat
        loc['SPE'] = loc['SPE'] / loc['FLAT']
        # get acqtime
        bjdspe = spirouImage.GetAcqTime(p,
                                        hdri,
                                        name='acqtime',
                                        return_value=1,
                                        kind='julian')
        # ----------------------------------------------------------------------
        # Background correction
        # ----------------------------------------------------------------------
        # test whether we want to subtract background
        if p['IC_DRIFT_BACK_CORR']:
            # Loop around the orders
            for order_num in range(loc['NUMBER_ORDERS']):
                # get the box size from constants
                bsize = p['DRIFT_PEAK_MINMAX_BOXSIZE']
                # Measurethe min and max flux
                miny, maxy = spirouBACK.MeasureMinMax(loc['SPE'][order_num],
                                                      bsize)
                # subtract off the background (miny)
                loc['SPE'][order_num] = loc['SPE'][order_num] - miny

        # ------------------------------------------------------------------
        # calculate flux ratio
        # ------------------------------------------------------------------
        sorder = p['IC_DRIFT_ORDER_PLOT']
        fratio = np.nansum(loc['SPE'][sorder]) / np.nansum(
            loc['SPEREF'][sorder])
        loc['FLUXRATIO'][i_it] = fratio
        # ------------------------------------------------------------------
        # Calculate delta time
        # ------------------------------------------------------------------
        # calculate the time from reference (in hours)
        loc['DELTATIME'][i_it] = (bjdspe - bjdref) * 24
        # ------------------------------------------------------------------
        # Calculate PearsonR coefficient
        # ------------------------------------------------------------------
        pargs = [loc['NUMBER_ORDERS'], loc['SPE'], loc['SPEREF']]
        correlation_coeffs = spirouRV.PearsonRtest(*pargs)
        # ----------------------------------------------------------------------
        # Get drift with comparison to the reference image
        # ----------------------------------------------------------------------
        # only calculate drift if the correlation between orders and
        #   reference file is above threshold
        prcut = p['DRIFT_PEAK_PEARSONR_CUT']
        if np.min(correlation_coeffs[nomin:nomax]) > prcut:
            # get drifts for each order
            dargs = [p, loc['SPE'], loc['ORDPEAK'], loc['XREF']]
            x = spirouRV.GetDrift(*dargs, gaussfit=gaussfit)
            # get delta v
            loc['DV'] = (x - loc['XREF']) * loc['VRPEAK']
            # sigma clip
            loc = spirouRV.SigmaClip(loc, sigma=p['DRIFT_PEAK_SIGMACLIP'])
            # work out median drifts per order
            loc = spirouRV.DriftPerOrder(loc, i_it)
            # work out mean drift across all orders
            loc = spirouRV.DriftAllOrders(p, loc, i_it, nomin, nomax)
            # log the mean drift
            wmsg = ('Time from ref= {0:.2f} h - Flux Ratio= {1:.3f} '
                    '- Drift mean= {2:.2f} +- {3:.2f} m/s')
            wargs = [
                loc['DELTATIME'][i_it], loc['FLUXRATIO'][i_it],
                loc['MEANRV'][i_it], loc['MERRDRIFT'][i_it]
            ]
            WLOG(p, 'info', wmsg.format(*wargs))
        # else we can't use this extract
        else:
            if p['DRS_PLOT'] > 0:
                # start interactive session if needed
                sPlt.plt.ioff()
                # plot comparison between spe and ref
                sPlt.drift_plot_correlation_comp(p, loc, correlation_coeffs,
                                                 i_it)
                sPlt.plt.show()
                sPlt.plt.close()
                # turn interactive plotting back on
                sPlt.plt.ion()
            # log that we cannot use this extraction
            wmsg1 = 'The correlation of some orders compared to the template is'
            wmsg2 = '   < {0}, something went wrong in the extract.'
            WLOG(p, 'warning', wmsg1)
            WLOG(p, 'warning', wmsg2.format(prcut))
    # ------------------------------------------------------------------
    # peak to peak drift
    driftptp = np.max(loc['MEANRV']) - np.min(loc['MEANRV'])
    driftrms = np.std(loc['MEANRV'])
    # log th etotal drift peak-to-peak and rms
    wmsg = ('Total drift Peak-to-Peak={0:.3f} m/s RMS={1:.3f} m/s in '
            '{2:.2f} hour')
    wargs = [driftptp, driftrms, np.max(loc['DELTATIME'])]
    WLOG(p, '', wmsg.format(*wargs))

    # ------------------------------------------------------------------
    # Plot of mean drift
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot delta time against median drift
        sPlt.drift_peak_plot_dtime_against_drift(p, loc)

    # ----------------------------------------------------------------------
    # Quality control
    # ----------------------------------------------------------------------
    # set passed variable and fail message list
    passed, fail_msg = True, []
    qc_values, qc_names, qc_logic, qc_pass = [], [], [], []
    # TODO: Needs doing
    # 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]

    # ------------------------------------------------------------------
    # Save drift values to file
    # ------------------------------------------------------------------
    # get raw input file name
    raw_infile = os.path.basename(p['REFFILE'])
    # construct filename
    driftfits, tag = spirouConfig.Constants.DRIFTPEAK_E2DS_FITS_FILE(p)
    driftfitsname = os.path.split(driftfits)[-1]
    # log that we are saving drift values
    wmsg = 'Saving drift values of Fiber {0} in {1}'
    WLOG(p, '', wmsg.format(p['FIBER'], driftfitsname))
    # 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_OUTPUT'], value=tag)
    # set the input files
    hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFLAT'], value=p['FLATFILE'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_REFFILE'], value=raw_infile)
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CDBWAVE'],
                               value=loc['WAVEFILE'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_WAVESOURCE'],
                               value=loc['WSOURCE'])
    # add qc parameters
    hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC'])
    hdict = spirouImage.AddQCKeys(p, hdict, qc_params)
    # save drift values
    p = spirouImage.WriteImage(p, driftfits, loc['DRIFT'], hdict)

    # ------------------------------------------------------------------
    # print .tbl result
    # ------------------------------------------------------------------
    # construct filename
    drifttbl = spirouConfig.Constants.DRIFTPEAK_E2DS_TBL_FILE(p)
    drifttblname = os.path.split(drifttbl)[-1]
    # construct and write table
    columnnames = ['time', 'drift', 'drifterr', 'drift_left', 'drift_right']
    columnformats = ['7.4f', '6.2f', '6.3f', '6.2f', '6.2f']
    columnvalues = [
        loc['DELTATIME'], loc['MEANRV'], loc['MERRDRIFT'], loc['MEANRV_LEFT'],
        loc['MEANRV_RIGHT']
    ]
    table = spirouImage.MakeTable(p,
                                  columns=columnnames,
                                  values=columnvalues,
                                  formats=columnformats)
    # write table
    wmsg = 'Average Drift saved in {0} Saved '
    WLOG(p, '', wmsg.format(drifttblname))
    spirouImage.WriteTable(p, table, drifttbl, fmt='ascii.rst')

    # ------------------------------------------------------------------
    # Plot amp and llpeak
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] and p['DRIFT_PEAK_PLOT_LINE_LOG_AMP']:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot delta time against median drift
        sPlt.drift_peak_plot_llpeak_amps(p, loc)

    # ----------------------------------------------------------------------
    # End Message
    # ----------------------------------------------------------------------
    p = spirouStartup.End(p)
    # return a copy of locally defined variables in the memory
    return dict(locals())
Beispiel #5
0
def main(night_name=None, e2dsfiles=None):
    """
    cal_CCF_E2DS_spirou.py main function, if arguments are None uses
    arguments from run time i.e.:
        cal_CCF_E2DS_spirou.py [night_directory] [E2DSfilename] [mask] [RV]
                               [width] [step]

    :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 e2dsfiles: list of string, the E2DS files to use

    :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__)
    # need custom args (to accept full path or wild card
    if e2dsfiles is None:
        names, types = ['e2dsfiles'], [str]
        customargs = spirouStartup.GetCustomFromRuntime(p, [0],
                                                        types,
                                                        names,
                                                        last_multi=True)
    else:
        customargs = dict(e2dsfiles=e2dsfiles)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsdir='reduced')

    # ----------------------------------------------------------------------
    # Process files (including wildcards)
    # ----------------------------------------------------------------------
    try:
        e2dsfiles = spirouFile.Paths(p['E2DSFILES'],
                                     root=p['ARG_FILE_DIR']).abs_paths
    except PathException as e:
        WLOG(p, 'error', e)

    # loop around files
    for it, e2dsfile in enumerate(e2dsfiles):
        # get the base file name
        e2dsfilename = os.path.basename(e2dsfile)
        # log the file process
        wargs = [e2dsfilename, it + 1, len(e2dsfiles)]
        wmsg = ' * Processing file {0} ({1} of {2})'.format(*wargs)
        WLOG(p, '', spirouStartup.spirouStartup.HEADER)
        WLOG(p, '', wmsg)
        WLOG(p, '', spirouStartup.spirouStartup.HEADER)

        # ------------------------------------------------------------------
        # Check that we can process file
        # ------------------------------------------------------------------
        # check if ufile exists
        if not os.path.exists(e2dsfile):
            wmsg = 'File {0} does not exist... skipping'
            WLOG(p, 'warning', wmsg.format(e2dsfilename))
            continue
        elif ('e2ds' not in e2dsfilename) and ('e2dsff' not in e2dsfilename):
            wmsg = 'File {0} not a valid E2DS or E2DSFF file'
            WLOG(p, 'warning', wmsg.format(e2dsfilename))
            continue
        elif '.fits' not in e2dsfilename:
            wmsg = 'File {0} not a fits file... skipping'
            WLOG(p, 'warning', wmsg.format(e2dsfilename))
            continue

        # ----------------------------------------------------------------------
        # Read image file
        # ----------------------------------------------------------------------
        # read the image data
        e2ds, hdr, nbo, nx = spirouImage.ReadData(p, e2dsfile)
        # add to loc
        loc = ParamDict()
        loc['E2DS'] = e2ds
        loc['NUMBER_ORDERS'] = nbo
        loc.set_sources(['E2DS', 'number_orders'], __NAME__ + '/main()')

        # ----------------------------------------------------------------------
        # Get basic image properties for reference 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')
        # get acquisition time
        p = spirouImage.GetAcqTime(p, hdr, name='acqtime', kind='julian')

        # ----------------------------------------------------------------------
        # Read star parameters
        # ----------------------------------------------------------------------
        p = spirouImage.ReadParam(p, hdr, 'KW_OBJRA', dtype=str)
        p = spirouImage.ReadParam(p, hdr, 'KW_OBJDEC', dtype=str)
        p = spirouImage.ReadParam(p, hdr, 'KW_OBJEQUIN')
        p = spirouImage.ReadParam(p, hdr, 'KW_OBJRAPM')
        p = spirouImage.ReadParam(p, hdr, 'KW_OBJDECPM')
        p = spirouImage.ReadParam(p, hdr, 'KW_DATE_OBS', dtype=str)
        p = spirouImage.ReadParam(p, hdr, 'KW_UTC_OBS', dtype=str)

        # -----------------------------------------------------------------------
        #  Earth Velocity calculation
        # -----------------------------------------------------------------------
        if p['IC_IMAGE_TYPE'] == 'H4RG':
            loc = spirouImage.EarthVelocityCorrection(p,
                                                      loc,
                                                      method=p['CCF_BERVMODE'])
        else:
            loc['BERV'], loc['BJD'] = 0.0, 0.0
            loc['BERV_MAX'], loc['BERV_SOURCE'] = 0.0, 'None'
            loc.set_sources(['BERV', 'BJD', 'BERV_MAX'], __NAME__ + '.main()')

        # ----------------------------------------------------------------------
        # archive ccf to fits file
        # ----------------------------------------------------------------------
        outfilename = str(e2dsfile)
        # add keys
        hdict = spirouImage.CopyOriginalKeys(hdr)

        # add berv values
        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_BERV_SOURCE'],
                                   value=loc['BERV_SOURCE'])

        # write image and add header keys (via hdict)
        p = spirouImage.WriteImage(p, outfilename, e2ds, hdict)

    # ----------------------------------------------------------------------
    # End Message
    # ----------------------------------------------------------------------
    p = spirouStartup.End(p)
    # return a copy of locally defined variables in the memory
    return dict(locals())
Beispiel #6
0
def main(night_name=None, reffile=None):
    """
    cal_DRIFT_E2DS_spirou.py main function, if arguments are None uses
    arguments from run time i.e.:
        cal_DRIFT_E2DS_spirou.py [night_directory] [reffile]

    :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 reffile: string, the reference file to use

    :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__)
    # deal with reference file being None (i.e. get from sys.argv)
    if reffile is None:
        customargs = spirouStartup.GetCustomFromRuntime(
            p, [0], [str], ['reffile'])
    else:
        customargs = dict(reffile=reffile)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsfile='reffile',
                                    mainfitsdir='reduced')

    # ----------------------------------------------------------------------
    # Construct reference filename and get fiber type
    # ----------------------------------------------------------------------
    p, reffilename = spirouStartup.SingleFileSetup(p, filename=p['REFFILE'])
    p['REFFILENAME'] = reffilename
    p.set_source('REFFILENAME', __NAME__ + '.main()')

    # ----------------------------------------------------------------------
    # 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)

    # ----------------------------------------------------------------------
    # Read image file
    # ----------------------------------------------------------------------
    # read the image data
    speref, hdr, nbo, nx = spirouImage.ReadData(p, reffilename)
    # add to loc
    loc = ParamDict()
    loc['SPEREF'] = speref
    loc['NUMBER_ORDERS'] = nbo
    loc.set_sources(['speref', 'number_orders'], __NAME__ + '/main()')

    # ----------------------------------------------------------------------
    # Get basic image properties for reference 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')
    # get acquisition time
    p = spirouImage.GetAcqTime(p, hdr, 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']
    # manually set OBJNAME to FP
    p['OBJNAME'] = 'FP'

    # ----------------------------------------------------------------------
    #  Earth Velocity calculation
    # ----------------------------------------------------------------------
    if p['IC_IMAGE_TYPE'] == 'H4RG':
        p, loc = spirouImage.GetEarthVelocityCorrection(p, loc, hdr)

    # ----------------------------------------------------------------------
    # Read wavelength solution
    # ----------------------------------------------------------------------
    # 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, fiber=wave_fiber,
    #                                    return_wavemap=True)
    # _, loc['WAVE'] = wout
    # loc.set_source('WAVE', __NAME__+'/main() + /spirouImage.GetWaveSolution')

    # get wave image
    wout = spirouImage.GetWaveSolution(p,
                                       hdr=hdr,
                                       return_wavemap=True,
                                       return_filename=True,
                                       fiber=wave_fiber)
    param_ll, wave_ll, wavefile, wsource = wout
    # save to storage
    loc['PARAM_LL'], loc['WAVE_LL'], loc['WAVEFILE'], loc['WSOURCE'] = wout
    source = __NAME__ + '/main() + spirouTHORCA.GetWaveSolution()'
    loc.set_sources(['WAVE_LL', 'PARAM_LL', 'WAVEFILE', 'WSOURCE'], source)

    # ----------------------------------------------------------------------
    # Read Flat file
    # ----------------------------------------------------------------------
    # get flat
    p, loc['FLAT'] = spirouImage.ReadFlatFile(p, hdr)
    loc.set_source('FLAT', __NAME__ + '/main() + /spirouImage.ReadFlatFile')
    # get all values in flat that are zero to 1
    loc['FLAT'] = np.where(loc['FLAT'] == 0, 1.0, loc['FLAT'])

    # ----------------------------------------------------------------------
    # Background correction
    # ----------------------------------------------------------------------
    # log that we are performing background correction
    if p['IC_DRIFT_BACK_CORR']:
        WLOG(p, '', 'Perform background correction')
        # get the box size from constants
        bsize = p['DRIFT_PEAK_MINMAX_BOXSIZE']
        # Loop around the orders
        for order_num in range(loc['NUMBER_ORDERS']):
            miny, maxy = spirouBACK.MeasureMinMax(loc['SPEREF'][order_num],
                                                  bsize)
            loc['SPEREF'][order_num] = loc['SPEREF'][order_num] - miny

    # ----------------------------------------------------------------------
    # Preliminary set up = no flat, no blaze
    # ----------------------------------------------------------------------
    # reset flat to all ones
    # loc['FLAT'] = np.ones((nbo, nx))
    # set blaze to all ones (if not bug in correlbin !!!
    # TODO Check why Blaze makes bugs in correlbin
    loc['BLAZE'] = np.ones((nbo, nx))
    # set sources
    # loc.set_sources(['flat', 'blaze'], __NAME__ + '/main()')
    loc.set_sources(['blaze'], __NAME__ + '/main()')

    # ------------------------------------------------------------------
    # Compute photon noise uncertainty for reference file
    # ------------------------------------------------------------------
    # set up the arguments for DeltaVrms2D
    dargs = [loc['SPEREF'], loc['WAVE_LL']]
    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))

    # ------------------------------------------------------------------
    # Reference plots
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot FP spectral order
        # sPlt.drift_plot_selected_wave_ref(p, loc)
        # plot photon noise uncertainty
        sPlt.drift_plot_photon_uncertainty(p, loc)

    # ----------------------------------------------------------------------
    # Get template RV (from ccf_mask)
    # ----------------------------------------------------------------------
    # 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']

    # get the CCF mask from file (check location of mask)
    loc = spirouRV.GetCCFMask(p, loc)

    # check and deal with mask in microns (should be in nm)
    if np.mean(loc['LL_MASK_CTR']) < 2.0:
        loc['LL_MASK_CTR'] *= 1000.0
        loc['LL_MASK_D'] *= 1000.0

    # ----------------------------------------------------------------------
    # Do correlation
    # ----------------------------------------------------------------------
    # calculate and fit the CCF
    loc['E2DSFF'] = np.array(loc['SPEREF'])
    loc.set_source('E2DSFF', __NAME__ + '/main()')
    p['CCF_FIT_TYPE'] = 1
    # run the RV coravelation function with these parameters
    loc = spirouRV.Coravelation(p, loc)

    # ----------------------------------------------------------------------
    # Correlation stats
    # ----------------------------------------------------------------------
    # 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 = ('Correlation: C={0:.1f}[%] RV={1:.5f}[km/s] '
            'FWHM={2:.4f}[km/s] maxcpp={3:.1f}')
    wargs = [loc['CONTRAST'], loc['RV'], loc['FWHM'], loc['MAXCPP']]
    WLOG(p, 'info', wmsg.format(*wargs))

    # get the reference RV in m/s
    rvref = loc['RV'] * 1000.

    # ----------------------------------------------------------------------
    # rv ccf plot
    # ----------------------------------------------------------------------

    if p['DRS_PLOT'] > 0:
        # Plot rv vs ccf (and rv vs ccf_fit)
        sPlt.ccf_rv_ccf_plot(p, loc['RV_CCF'], normalized_ccf, ccf_fit)

    # ------------------------------------------------------------------
    # Get all other files that match kw_OUTPUT and kw_EXT_TYPE from
    #    ref file
    # ------------------------------------------------------------------
    # get files
    listfiles, listtypes = spirouImage.GetSimilarDriftFiles(p, hdr)
    # get the number of files
    nfiles = len(listfiles)
    # Log the number of files found
    wmsgs = [
        'Number of files found on directory = {0}'.format(nfiles),
        '\tExtensions allowed:'
    ]
    for listtype in listtypes:
        wmsgs.append('\t\t - {0}'.format(listtype))
    WLOG(p, 'info', wmsgs)

    # ------------------------------------------------------------------
    # Set up Extract storage for all files
    # ------------------------------------------------------------------
    # decide whether we need to skip (for large number of files)
    if len(listfiles) >= p['DRIFT_NLARGE']:
        skip = p['DRIFT_E2DS_FILE_SKIP']
        nfiles = int(nfiles / skip)
    else:
        skip = 1
    # set up storage
    loc['MDRIFT'] = np.zeros(nfiles)
    loc['MERRDRIFT'] = np.zeros(nfiles)
    loc['DELTATIME'] = np.zeros(nfiles)
    loc['FLUXRATIO'] = np.zeros(nfiles)
    # set loc sources
    keys = ['mdrift', 'merrdrift', 'deltatime']
    loc.set_sources(keys, __NAME__ + '/main()()')

    # ------------------------------------------------------------------
    # Loop around all files: correct for dark, reshape, extract and
    #     calculate dvrms and meanpond
    # ------------------------------------------------------------------
    wref = 1
    for i_it in range(nfiles):
        # get file for this iteration
        fpfile = listfiles[::skip][i_it]
        # Log the file we are reading
        wmsg = 'Reading file {0}'
        WLOG(p, '', wmsg.format(os.path.split(fpfile)[-1]))
        # ------------------------------------------------------------------
        # read e2ds files and get timestamp
        # ------------------------------------------------------------------
        # read data
        rout = spirouImage.ReadData(p, filename=fpfile, log=False)
        loc['SPE'], hdri, nxi, nyi = rout
        # get acqtime
        bjdspe = spirouImage.GetAcqTime(p,
                                        hdri,
                                        name='acqtime',
                                        return_value=1,
                                        kind='julian')
        # test whether we want to subtract background
        if p['IC_DRIFT_BACK_CORR']:
            # Loop around the orders
            for order_num in range(loc['NUMBER_ORDERS']):
                # get the box size from constants
                bsize = p['DRIFT_PEAK_MINMAX_BOXSIZE']
                # Measurethe min and max flux
                miny, maxy = spirouBACK.MeasureMinMax(loc['SPE'][order_num],
                                                      bsize)
                # subtract off the background (miny)
                loc['SPE'][order_num] = loc['SPE'][order_num] - miny

        # ------------------------------------------------------------------
        # calculate flux ratio
        # ------------------------------------------------------------------
        sorder = p['IC_DRIFT_ORDER_PLOT']
        fratio = np.nansum(loc['SPE'][sorder]) / np.nansum(
            loc['SPEREF'][sorder])
        loc['FLUXRATIO'][i_it] = fratio

        # ------------------------------------------------------------------
        # Compute photon noise uncertainty for reference file
        # ------------------------------------------------------------------
        # set up the arguments for DeltaVrms2D
        dargs = [loc['SPE'], loc['WAVE_LL']]
        dkwargs = dict(sigdet=p['IC_DRIFT_NOISE'],
                       size=p['IC_DRIFT_BOXSIZE'],
                       threshold=p['IC_DRIFT_MAXFLUX'])
        # run DeltaVrms2D
        dvrmsspe, wmeanspe = spirouRV.DeltaVrms2D(*dargs, **dkwargs)

        # ----------------------------------------------------------------------
        # Do correlation
        # ----------------------------------------------------------------------
        # calculate and fit the CCF
        loc['E2DSFF'] = loc['SPE'] * 1.
        loc.set_source('E2DSFF', __NAME__ + '/main()')

        loc = spirouRV.Coravelation(p, loc)

        # ----------------------------------------------------------------------
        # Correlation stats
        # ----------------------------------------------------------------------
        # 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)
        # calculate the mean RV
        meanrv = ccf_res[1] * 1000. - rvref
        # ------------------------------------------------------------------
        # Calculate delta time
        # ------------------------------------------------------------------
        # calculate the time from reference (in hours)
        deltatime = (bjdspe - bjdref) * 24

        err_meanrv = np.sqrt(dvrmsref + dvrmsspe)
        merr = 1. / np.sqrt(np.nansum((1. / err_meanrv)**2))
        # Log the RV properties
        wmsg = ('Time from ref= {0:.2f} h '
                '- Flux Ratio= {1:.2f} '
                '- Drift mean= {2:.2f} +- '
                '{3:.2f} m/s')
        wargs = [deltatime, loc['FLUXRATIO'][i_it], meanrv, merr]
        WLOG(p, '', wmsg.format(*wargs))
        # add this iteration to storage
        loc['MDRIFT'][i_it] = meanrv
        loc['MERRDRIFT'][i_it] = merr
        loc['DELTATIME'][i_it] = deltatime

    # ------------------------------------------------------------------
    # set source
    loc.set_sources(['mdrift', 'merrdrift'], __NAME__ + '/main()()')
    # ------------------------------------------------------------------
    # peak to peak drift
    driftptp = np.max(loc['MDRIFT']) - np.min(loc['MDRIFT'])
    driftrms = np.std(loc['MDRIFT'])
    # log th etotal drift peak-to-peak and rms
    wmsg = ('Total drift Peak-to-Peak={0:.3f} m/s RMS={1:.3f} m/s in '
            '{2:.2f} hour')
    wargs = [driftptp, driftrms, np.max(loc['DELTATIME'])]
    WLOG(p, '', wmsg.format(*wargs))

    # ------------------------------------------------------------------
    # Plot of mean drift
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot delta time against median drift
        sPlt.drift_plot_dtime_against_mdrift(p, loc, kind='e2ds')

    # ------------------------------------------------------------------
    # Save drift values to file
    # ------------------------------------------------------------------
    # # get raw input file name
    # raw_infile = os.path.basename(p['REFFILE'])
    # # construct filename
    # driftfits, tag = spirouConfig.Constants.DRIFTCCF_E2DS_FITS_FILE(p)
    # driftfitsname = os.path.split(driftfits)[-1]
    # # log that we are saving drift values
    # wmsg = 'Saving drift values of Fiber {0} in {1}'
    # WLOG(p, '', wmsg.format(p['FIBER'], driftfitsname))
    # # add keys from original header file
    # hdict = spirouImage.CopyOriginalKeys(hdr)
    # # add the reference RV
    # hdict = spirouImage.AddKey(p, hdict, p['KW_REF_RV'], value=rvref)
    #
    # # set the version
    # hdict = spirouImage.AddKey(p, hdict, p['KW_VERSION'])
    # hdict = spirouImage.AddKey(p, hdict, p['KW_OUTPUT'], value=tag)
    # # set the input files
    # hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFLAT'], value=p['FLATFILE'])
    # hdict = spirouImage.AddKey(p, hdict, p['KW_REFFILE'], value=raw_infile)
    # # save drift values
    # p = spirouImage.WriteImage(p, driftfits, loc['DRIFT'], hdict)

    # ------------------------------------------------------------------
    # print .tbl result
    # ------------------------------------------------------------------
    # construct filename
    drifttbl = spirouConfig.Constants.DRIFTCCF_E2DS_TBL_FILE(p)
    drifttblname = os.path.split(drifttbl)[-1]
    # construct and write table
    columnnames = ['time', 'drift', 'drifterr']
    columnformats = ['7.4f', '6.2f', '6.3f']
    columnvalues = [loc['DELTATIME'], loc['MDRIFT'], loc['MERRDRIFT']]
    table = spirouImage.MakeTable(p,
                                  columns=columnnames,
                                  values=columnvalues,
                                  formats=columnformats)
    # write table
    wmsg = 'Average Drift saved in {0} Saved '
    WLOG(p, '', wmsg.format(drifttblname))
    spirouImage.WriteTable(p, table, drifttbl, fmt='ascii.rst')

    # ----------------------------------------------------------------------
    # End Message
    # ----------------------------------------------------------------------
    p = spirouStartup.End(p)
    # return a copy of locally defined variables in the memory
    return dict(locals())
Beispiel #7
0
def main(night_name=None, reffile=None):
    """
    cal_DRIFT_E2DS_spirou.py main function, if arguments are None uses
    arguments from run time i.e.:
        cal_DRIFT_E2DS_spirou.py [night_directory] [reffile]

    :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 reffile: string, the reference file to use

    :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__)
    # deal with reference file being None (i.e. get from sys.argv)
    if reffile is None:
        customargs = spirouStartup.GetCustomFromRuntime(
            p, [0], [str], ['reffile'])
    else:
        customargs = dict(reffile=reffile)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsfile='reffile',
                                    mainfitsdir='reduced')

    # ----------------------------------------------------------------------
    # Construct reference filename and get fiber type
    # ----------------------------------------------------------------------
    p, reffilename = spirouStartup.SingleFileSetup(p, filename=p['REFFILE'])
    p['REFFILENAME'] = reffilename
    p.set_source('REFFILENAME', __NAME__ + '.main()')

    # ----------------------------------------------------------------------
    # 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)

    # ----------------------------------------------------------------------
    # Read image file
    # ----------------------------------------------------------------------
    # read the image data
    speref, hdr, nbo, nx = spirouImage.ReadData(p, reffilename)
    # add to loc
    loc = ParamDict()
    loc['SPEREF'] = speref
    loc['NUMBER_ORDERS'] = nbo
    loc.set_sources(['speref', 'number_orders'], __NAME__ + '/main()')

    # ----------------------------------------------------------------------
    # Get basic image properties for reference 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')
    # get acquisition time
    p = spirouImage.GetAcqTime(p, hdr, 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']

    # ----------------------------------------------------------------------
    # Read wavelength solution
    # ----------------------------------------------------------------------
    # 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,
                                       fiber=wave_fiber,
                                       return_wavemap=True,
                                       return_filename=True)
    _, loc['WAVE'], loc['WAVEFILE'], loc['WSOURCE'] = wout
    source = __NAME__ + '/main() + /spirouImage.GetWaveSolution'
    loc.set_sources(['WAVE', 'WAVEFILE', 'WSOURCE'], source)
    # ----------------------------------------------------------------------
    # Read Flat file
    # ----------------------------------------------------------------------
    # get flat
    p, loc['FLAT'] = spirouImage.ReadFlatFile(p, hdr)
    loc.set_source('FLAT', __NAME__ + '/main() + /spirouImage.ReadFlatFile')
    # get all values in flat that are zero to 1
    loc['FLAT'] = np.where(loc['FLAT'] == 0, 1.0, loc['FLAT'])

    # ----------------------------------------------------------------------
    # Background correction
    # ----------------------------------------------------------------------
    # log that we are performing background correction
    if p['IC_DRIFT_BACK_CORR']:
        WLOG(p, '', 'Perform background correction')
        # get the box size from constants
        bsize = p['DRIFT_PEAK_MINMAX_BOXSIZE']
        # Loop around the orders
        for order_num in range(loc['NUMBER_ORDERS']):
            miny, maxy = spirouBACK.MeasureMinMax(loc['SPEREF'][order_num],
                                                  bsize)
            loc['SPEREF'][order_num] = loc['SPEREF'][order_num] - miny

    # ------------------------------------------------------------------
    # Compute photon noise uncertainty for reference file
    # ------------------------------------------------------------------
    # set up the arguments for DeltaVrms2D
    dargs = [loc['SPEREF'], loc['WAVE']]
    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))

    # ------------------------------------------------------------------
    # Reference plots
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot FP spectral order
        sPlt.drift_plot_selected_wave_ref(p, loc)
        # plot photon noise uncertainty
        sPlt.drift_plot_photon_uncertainty(p, loc)

    # ------------------------------------------------------------------
    # Get all other files that match kw_OUTPUT and kw_EXT_TYPE from
    #    ref file
    # ------------------------------------------------------------------
    # get files
    listfiles, listtypes = spirouImage.GetSimilarDriftFiles(p, hdr)
    # get the number of files
    nfiles = len(listfiles)
    # Log the number of files found
    wmsgs = [
        'Number of files found on directory = {0}'.format(nfiles),
        '\tExtensions allowed:'
    ]
    for listtype in listtypes:
        wmsgs.append('\t\t - {0}'.format(listtype))
    WLOG(p, 'info', wmsgs)

    # ------------------------------------------------------------------
    # Set up Extract storage for all files
    # ------------------------------------------------------------------
    # decide whether we need to skip (for large number of files)
    if len(listfiles) >= p['DRIFT_NLARGE']:
        skip = p['DRIFT_E2DS_FILE_SKIP']
        nfiles = int(nfiles / skip)
    else:
        skip = 1
    # set up storage
    loc['DRIFT'] = np.zeros((nfiles, loc['NUMBER_ORDERS']))
    loc['ERRDRIFT'] = np.zeros((nfiles, loc['NUMBER_ORDERS']))
    loc['DELTATIME'] = np.zeros(nfiles)
    # set loc sources
    keys = ['drift', 'errdrift', 'deltatime']
    loc.set_sources(keys, __NAME__ + '/main()()')

    # ------------------------------------------------------------------
    # Loop around all files: correct for dark, reshape, extract and
    #     calculate dvrms and meanpond
    # ------------------------------------------------------------------
    wref = 1
    for i_it in range(nfiles):
        # get file for this iteration
        fpfile = listfiles[::skip][i_it]
        # Log the file we are reading
        wmsg = 'Reading file {0}'
        WLOG(p, '', wmsg.format(os.path.split(fpfile)[-1]))
        # ------------------------------------------------------------------
        # read e2ds files and get timestamp
        # ------------------------------------------------------------------
        # read data
        rout = spirouImage.ReadData(p, filename=fpfile, log=False)
        loc['SPE'], hdri, nxi, nyi = rout
        # get acqtime
        bjdspe = spirouImage.GetAcqTime(p,
                                        hdri,
                                        name='acqtime',
                                        return_value=1,
                                        kind='julian')
        # test whether we want to subtract background
        if p['IC_DRIFT_BACK_CORR']:
            # Loop around the orders
            for order_num in range(loc['NUMBER_ORDERS']):
                # get the box size from constants
                bsize = p['DRIFT_PEAK_MINMAX_BOXSIZE']
                # Measurethe min and max flux
                miny, maxy = spirouBACK.MeasureMinMax(loc['SPE'][order_num],
                                                      bsize)
                # subtract off the background (miny)
                loc['SPE'][order_num] = loc['SPE'][order_num] - miny

        # ------------------------------------------------------------------
        # Compute photon noise uncertainty for iteration file
        # ------------------------------------------------------------------
        # set up the arguments for DeltaVrms2D
        dargs = [loc['SPE'], loc['WAVE']]
        dkwargs = dict(sigdet=p['IC_DRIFT_NOISE'],
                       size=p['IC_DRIFT_BOXSIZE'],
                       threshold=p['IC_DRIFT_MAXFLUX'])
        # run DeltaVrms2D
        dvrmsspe, wmodespe = spirouRV.DeltaVrms2D(*dargs, **dkwargs)

        # ------------------------------------------------------------------
        # Compute the correction of the cosmics and re-normalisation by
        #   comparison with the reference spectrum
        # ------------------------------------------------------------------
        # correction of the cosmics and renomalisation by comparison with
        #   the reference spectrum
        dargs = [p, loc['SPEREF'], loc['SPE']]
        dkwargs = dict(threshold=p['IC_DRIFT_MAXFLUX'],
                       size=p['IC_DRIFT_BOXSIZE'],
                       cut=p['IC_DRIFT_CUT_E2DS'])
        spen, cfluxr, cpt = spirouRV.ReNormCosmic2D(*dargs, **dkwargs)

        # ------------------------------------------------------------------
        # Calculate the RV drift
        # ------------------------------------------------------------------
        dargs = [loc['SPEREF'], spen, loc['WAVE']]
        dkwargs = dict(sigdet=p['IC_DRIFT_NOISE'],
                       threshold=p['IC_DRIFT_MAXFLUX'],
                       size=p['IC_DRIFT_BOXSIZE'])
        rv = spirouRV.CalcRVdrift2D(*dargs, **dkwargs)
        # ------------------------------------------------------------------
        # Calculate delta time
        # ------------------------------------------------------------------
        # calculate the time from reference (in hours)
        deltatime = (bjdspe - bjdref) * 24
        # ------------------------------------------------------------------
        # Calculate RV properties
        # ------------------------------------------------------------------
        # calculate the mean flux ratio
        meanfratio = np.nanmean(cfluxr)
        # calculate the weighted mean radial velocity
        wref = 1.0 / dvrmsref
        meanrv = -1.0 * np.nansum(rv * wref) / np.nansum(wref)
        err_meanrv = np.sqrt(dvrmsref + dvrmsspe)
        merr = 1. / np.sqrt(np.nansum((1. / err_meanrv)**2))
        # Log the RV properties
        wmsg = (
            'Time from ref={0:.2f} h  - Drift mean= {1:.2f} +- {2:.3f} m/s '
            '- Flux ratio= {3:.3f} - Nb Comsic= {4}')
        WLOG(p, '', wmsg.format(deltatime, meanrv, merr, meanfratio, cpt))
        # add this iteration to storage
        loc['DRIFT'][i_it] = -1.0 * rv
        loc['ERRDRIFT'][i_it] = err_meanrv
        loc['DELTATIME'][i_it] = deltatime

    # ------------------------------------------------------------------
    # Calculate drift properties
    # ------------------------------------------------------------------
    # get the maximum number of orders to use
    nomax = nbo  # p['IC_DRIFT_N_ORDER_MAX']
    # ------------------------------------------------------------------
    # if use mean
    if p['DRIFT_TYPE_E2DS'].upper() == 'WEIGHTED MEAN':
        # mean radial velocity
        sumwref = np.nansum(wref[:nomax])
        meanrv = np.nansum(loc['DRIFT'][:, :nomax] * wref[:nomax], 1) / sumwref
        # error in mean radial velocity
        errdrift2 = loc['ERRDRIFT'][:, :nomax]**2
        meanerr = 1.0 / np.sqrt(np.nansum(1.0 / errdrift2, 1))
        # add to loc
        loc['MDRIFT'] = meanrv
        loc['MERRDRIFT'] = meanerr
    # else use median
    else:
        # median drift
        loc['MDRIFT'] = np.nanmedian(loc['DRIFT'][:, :nomax], 1)
        # median err drift
        loc['MERRDRIFT'] = np.nanmedian(loc['ERRDRIFT'][:, :nomax], 1)
    # ------------------------------------------------------------------
    # set source
    loc.set_sources(['mdrift', 'merrdrift'], __NAME__ + '/main()()')
    # ------------------------------------------------------------------
    # peak to peak drift
    driftptp = np.max(loc['MDRIFT']) - np.min(loc['MDRIFT'])
    driftrms = np.std(loc['MDRIFT'])
    # log th etotal drift peak-to-peak and rms
    wmsg = ('Total drift Peak-to-Peak={0:.3f} m/s RMS={1:.3f} m/s in '
            '{2:.2f} hour')
    wargs = [driftptp, driftrms, np.max(loc['DELTATIME'])]
    WLOG(p, '', wmsg.format(*wargs))

    # ------------------------------------------------------------------
    # Plot of mean drift
    # ------------------------------------------------------------------
    if p['DRS_PLOT'] > 0:
        # start interactive session if needed
        sPlt.start_interactive_session(p)
        # plot delta time against median drift
        sPlt.drift_plot_dtime_against_mdrift(p, loc, kind='e2ds')

    # ----------------------------------------------------------------------
    # Quality control
    # ----------------------------------------------------------------------
    # set passed variable and fail message list
    passed, fail_msg = True, []
    qc_values, qc_names, qc_logic, qc_pass = [], [], [], []
    # TODO: Needs doing
    # 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]

    # ------------------------------------------------------------------
    # Save drift values to file
    # ------------------------------------------------------------------
    # get raw input file name
    raw_infile = os.path.basename(p['REFFILE'])
    # construct filename
    driftfits, tag = spirouConfig.Constants.DRIFT_E2DS_FITS_FILE(p)
    driftfitsname = os.path.split(driftfits)[-1]
    # log that we are saving drift values
    wmsg = 'Saving drift values of Fiber {0} in {1}'
    WLOG(p, '', wmsg.format(p['FIBER'], driftfitsname))
    # 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_OUTPUT'], value=tag)
    # set the input files
    hdict = spirouImage.AddKey(p, hdict, p['KW_CDBFLAT'], value=p['FLATFILE'])
    hdict = spirouImage.AddKey(p, hdict, p['KW_REFFILE'], value=raw_infile)
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_CDBWAVE'],
                               value=loc['WAVEFILE'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_WAVESOURCE'],
                               value=loc['WSOURCE'])

    # add qc parameters
    hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC'])
    hdict = spirouImage.AddQCKeys(p, hdict, qc_params)
    # save drift values
    p = spirouImage.WriteImage(p, driftfits, loc['DRIFT'], hdict)

    # ------------------------------------------------------------------
    # print .tbl result
    # ------------------------------------------------------------------
    # construct filename
    drifttbl = spirouConfig.Constants.DRIFT_E2DS_TBL_FILE(p)
    drifttblname = os.path.split(drifttbl)[-1]
    # construct and write table
    columnnames = ['time', 'drift', 'drifterr']
    columnformats = ['7.4f', '6.2f', '6.3f']
    columnvalues = [loc['DELTATIME'], loc['MDRIFT'], loc['MERRDRIFT']]
    table = spirouImage.MakeTable(p,
                                  columns=columnnames,
                                  values=columnvalues,
                                  formats=columnformats)
    # write table
    wmsg = 'Average Drift saved in {0} Saved '
    WLOG(p, '', wmsg.format(drifttblname))
    spirouImage.WriteTable(p, table, drifttbl, fmt='ascii.rst')

    # ----------------------------------------------------------------------
    # End Message
    # ----------------------------------------------------------------------
    p = spirouStartup.End(p)
    # return a copy of locally defined variables in the memory
    return dict(locals())
Beispiel #8
0
def main(night_name=None, flatfile=None):
    # ----------------------------------------------------------------------
    # Set up
    # ----------------------------------------------------------------------
    # get parameters from config files/run time args/load paths + calibdb
    p = spirouStartup.Begin(recipe=__NAME__)
    # deal with arguments being None (i.e. get from sys.argv)
    name, lname = ['flatfile'], ['Reference file']
    req, call, call_priority = [True], [flatfile], [True]
    # now get custom arguments
    customargs = spirouStartup.GetCustomFromRuntime(p, [0], [str], name, req,
                                                    call, call_priority, lname)
    # get parameters from configuration files and run time arguments
    p = spirouStartup.LoadArguments(p,
                                    night_name,
                                    customargs=customargs,
                                    mainfitsfile='flatfile')
    # ----------------------------------------------------------------------
    # Construct reference filename and get fiber type
    # ----------------------------------------------------------------------
    p, reffile = spirouStartup.SingleFileSetup(p, filename=p['FLATFILE'])

    # ----------------------------------------------------------------------
    # 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 the required fiber type from the constants file
    # ----------------------------------------------------------------------
    # get the fiber type (set to AB)
    p['FIBER'] = p['EM_FIB_TYPE']
    p['FIBER_TYPES'] = [p['EM_FIB_TYPE']]

    # ----------------------------------------------------------------------
    # Read flat image file
    # ----------------------------------------------------------------------
    # read the image data (for the header only)
    image, hdr, ny, nx = spirouImage.ReadData(p, reffile)

    # ----------------------------------------------------------------------
    # fix for un-preprocessed files
    # ----------------------------------------------------------------------
    image = spirouImage.FixNonPreProcess(p, image)

    # ----------------------------------------------------------------------
    # Get basic image properties
    # ----------------------------------------------------------------------
    # create loc
    loc = ParamDict()
    # 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')

    # ----------------------------------------------------------------------
    # Resize flat image
    # ----------------------------------------------------------------------
    # rotate the image and convert from ADU/s to e-
    image2 = spirouImage.ConvertToE(spirouImage.FlipImage(p, image), p=p)
    # convert NaN to zeros
    image2 = np.where(~np.isfinite(image2), np.zeros_like(image2), image2)
    # 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)
    image2 = spirouImage.ResizeImage(p, image2, **bkwargs)
    # save flat to to loc and set source
    loc['IMAGE'] = image2
    loc.set_sources(['image'], __NAME__ + '/main()')
    # log change in data size
    wmsg = 'Image format changed to {0}x{1}'
    WLOG(p, '', wmsg.format(*image2.shape))

    # ----------------------------------------------------------------------
    # Read shape or tilt slit angle
    # ----------------------------------------------------------------------
    # set source of tilt file
    tsource = __NAME__ + '/main() + /spirouImage.ReadTiltFile'

    if p['IC_EXTRACT_TYPE'] in EXTRACT_SHAPE_TYPES:
        # log progress
        WLOG(p, '', 'Debananafying (straightening) image')
        # get the shape map
        p, loc['SHAPE'] = spirouImage.ReadShapeMap(p, hdr)
        loc.set_source('SHAPE', tsource)
    else:
        # get tilts
        p, loc['TILT'] = spirouImage.ReadTiltFile(p, hdr)
        loc.set_source('TILT', tsource)

    # ----------------------------------------------------------------------
    # Read blaze
    # ----------------------------------------------------------------------
    # get tilts
    p, loc['BLAZE'] = spirouImage.ReadBlazeFile(p, hdr)
    loc.set_source('BLAZE', __NAME__ + '/main() + /spirouImage.ReadBlazeFile')
    # set number of orders from blaze file
    loc['NBO'] = loc['BLAZE'].shape[0]
    loc.set_source('NBO', __NAME__ + '/main()')

    # ------------------------------------------------------------------
    # Read wavelength solution
    # ------------------------------------------------------------------
    # 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,
                                       fiber=wave_fiber)
    loc['WAVEPARAMS'], loc['WAVE'], loc['WAVEFILE'], loc['WSOURCE'] = wout
    loc.set_sources(['WAVEPARAMS', 'WAVE', 'WAVEFILE', 'WSOURCE'], wsource)

    # ------------------------------------------------------------------
    # Get localisation coefficients
    # ------------------------------------------------------------------
    # storage for fiber parameters
    loc['ALL_ACC'] = OrderedDict()
    loc['ALL_ASS'] = OrderedDict()
    # get this fibers parameters
    for fiber in p['FIBER_TYPES']:
        p = spirouImage.FiberParams(p, fiber, merge=True)
        # get localisation fit coefficients
        p, loc = spirouLOCOR.GetCoeffs(p, hdr, loc=loc)
        # save all fibers
        loc['ALL_ACC'][fiber] = loc['ACC']
        loc['ALL_ASS'][fiber] = loc['ASS']

    # ------------------------------------------------------------------
    # Get telluric and telluric mask and add to loc
    # ------------------------------------------------------------------
    # log process
    wmsg = 'Loading telluric model and locating "good" tranmission'
    WLOG(p, '', wmsg)
    # load telluric and get mask (add to loc)
    loc = spirouExM.get_telluric(p, loc)

    # ------------------------------------------------------------------
    # Make 2D map of orders
    # ------------------------------------------------------------------
    # log progress
    WLOG(p, '', 'Making 2D map of order locations')
    # make the 2D wave-image
    loc = spirouExM.order_profile(p, loc)

    # ------------------------------------------------------------------
    # Make 2D map of wavelengths accounting for shape / tilt
    # ------------------------------------------------------------------
    # log progress
    WLOG(p, '', 'Mapping pixels on to wavelength grid')
    # make the 2D map of wavelength
    loc = spirouExM.create_wavelength_image(p, loc)

    # ------------------------------------------------------------------
    # Use spectra wavelength to create 2D image from wave-image
    # ------------------------------------------------------------------
    if p['EM_SAVE_MASK_MAP'] or p['EM_SAVE_TELL_SPEC']:
        # log progress
        WLOG(p, '', 'Creating image from wave-image interpolation')
        # create image from waveimage
        wkwargs = dict(x=loc['TELL_X'], y=loc['TELL_Y'])
        loc = spirouExM.create_image_from_waveimage(loc, **wkwargs)
    else:
        loc['SPE'] = np.zeros_like(image2).astype(float)

    # ------------------------------------------------------------------
    # Create 2D mask (min to max lambda + transmission threshold)
    # ------------------------------------------------------------------
    if p['EM_SAVE_MASK_MAP']:
        # log progress
        WLOG(p, '', 'Creating wavelength/tranmission mask')
        # create mask
        loc = spirouExM.create_mask(p, loc)
    else:
        loc['TELL_MASK_2D'] = np.zeros_like(image2).astype(bool)

    # ----------------------------------------------------------------------
    # Quality control
    # ----------------------------------------------------------------------
    # set passed variable and fail message list
    passed, fail_msg = True, []
    qc_values, qc_names, qc_logic, qc_pass = [], [], [], []
    # TODO: Needs doing
    # 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]

    # ------------------------------------------------------------------
    # Construct parameters for header
    # ------------------------------------------------------------------
    hdict = OrderedDict()
    # 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
    if loc['SHAPE'] is not None:
        hdict = spirouImage.AddKey(p,
                                   hdict,
                                   p['KW_CDBSHAPE'],
                                   value=p['SHAPFILE'])
    else:
        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_CDBLOCO'], value=p['LOCOFILE'])
    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['FLATFILE'])
    # add name of the TAPAS y data
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['KW_EM_TELLY'],
                               value=loc['TELLSPE'])
    # add name of the localisation fits file used
    hfile = os.path.basename(loc['LOCO_CTR_FILE'])
    hdict = spirouImage.AddKey(p, hdict, p['kw_EM_LOCFILE'], value=hfile)
    # add the max and min wavelength threshold
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['kw_EM_MINWAVE'],
                               value=p['EM_MIN_LAMBDA'])
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['kw_EM_MAXWAVE'],
                               value=p['EM_MAX_LAMBDA'])
    # add qc parameters
    hdict = spirouImage.AddKey(p, hdict, p['KW_DRS_QC'], value=p['QC'])
    hdict = spirouImage.AddQCKeys(p, hdict, qc_params)
    # add the transmission cut
    hdict = spirouImage.AddKey(p,
                               hdict,
                               p['kw_EM_TRASCUT'],
                               value=p['EM_TELL_THRESHOLD'])

    # ------------------------------------------------------------------
    # Deal with output preferences
    # ------------------------------------------------------------------
    # add bad pixel map (if required)
    if p['EM_COMBINED_BADPIX']:
        # get bad pix mask (True where bad)
        badpixmask, bhdr, badfile = spirouImage.GetBadPixMap(p, hdr)
        goodpixels = badpixmask == 0
        # apply mask (multiply)
        loc['TELL_MASK_2D'] = loc['TELL_MASK_2D'] & goodpixels.astype(bool)
    else:
        badfile = 'None'
    # add to hdict
    hdict = spirouImage.AddKey(p, hdict, p['KW_CDBBAD'], value=badfile)

    # convert waveimage mask into float array
    loc['TELL_MASK_2D'] = loc['TELL_MASK_2D'].astype('float')

    # check EM_OUTPUT_TYPE and deal with set to "all"
    if p['EM_OUTPUT_TYPE'] not in ["drs", "raw", "preprocess", "all"]:
        emsg1 = '"EM_OUTPUT_TYPE" not understood'
        emsg2 = '   must be either "drs", "raw" or "preprocess"'
        emsg3 = '   currently EM_OUTPUT_TYPE="{0}"'.format(p['EM_OUTPUT_TYPE'])
        WLOG(p, 'error', [emsg1, emsg2, emsg3])
        outputs = []
    elif p['EM_OUTPUT_TYPE'] != 'all':
        outputs = [str(p['EM_OUTPUT_TYPE'])]
    else:
        outputs = ["drs", "raw", "preprocess"]

    # ----------------------------------------------------------------------
    # loop around output types
    # ----------------------------------------------------------------------
    for output in outputs:
        # log progress
        WLOG(p, '', 'Processing {0} outputs'.format(output))
        # change EM_OUTPUT_TYPE
        p['EM_OUTPUT_TYPE'] = output
        # copy arrays
        out_spe = np.array(loc['SPE'])
        out_wave = np.array(loc['WAVEIMAGE'])
        out_mask = np.array(loc['TELL_MASK_2D'])
        # change image size if needed
        if output in ["raw", "preprocess"]:
            kk = dict(xsize=image.shape[1], ysize=image.shape[0])
            if p['EM_SAVE_TELL_SPEC']:
                WLOG(p, '', 'Resizing/Flipping SPE')
                out_spe = spirouExM.unresize(p, out_spe, **kk)
                WLOG(p, '', 'Rescaling SPE')
                out_spe = out_spe / (p['GAIN'] * p['EXPTIME'])
            if p['EM_SAVE_WAVE_MAP']:
                WLOG(p, '', 'Resizing/Flipping WAVEIMAGE')
                out_wave = spirouExM.unresize(p, out_wave, **kk)
            if p['EM_SAVE_MASK_MAP']:
                WLOG(p, '', 'Resizing/Flipping TELL_MASK_2D')
                out_mask = spirouExM.unresize(p, out_mask, **kk)
        # if raw need to rotate (undo pre-processing)
        if output == "raw":
            if p['EM_SAVE_TELL_SPEC']:
                WLOG(p, '', 'Rotating SPE')
                out_spe = np.rot90(out_spe, 1)
            if p['EM_SAVE_WAVE_MAP']:
                WLOG(p, '', 'Rotating WAVEIMAGE')
                out_wave = np.rot90(out_wave, 1)
            if p['EM_SAVE_MASK_MAP']:
                WLOG(p, '', 'Rotating TELL_MASK_2D')
                out_mask = np.rot90(out_mask, 1)

        # ----------------------------------------------------------------------
        # save 2D spectrum, wavelength image and mask to file
        # ----------------------------------------------------------------------
        # save telluric spectrum
        if p['EM_SAVE_TELL_SPEC']:
            # construct spectrum filename
            specfitsfile, tag = spirouConfig.Constants.EM_SPE_FILE(p)
            specfilename = os.path.split(specfitsfile)[-1]
            # 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=tag)
            # log progress
            wmsg = 'Writing spectrum to file {0}'
            WLOG(p, '', wmsg.format(specfilename))
            # write to file
            p = spirouImage.WriteImage(p, specfitsfile, out_spe, hdict=hdict)

        # ----------------------------------------------------------------------
        # save wave map
        if p['EM_SAVE_WAVE_MAP']:
            # construct waveimage filename
            wavefitsfile, tag = spirouConfig.Constants.EM_WAVE_FILE(p)
            wavefilename = os.path.split(wavefitsfile)[-1]
            # 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=tag)
            # log progress
            wmsg = 'Writing wave image to file {0}'
            WLOG(p, '', wmsg.format(wavefilename))
            # write to file
            p = spirouImage.WriteImage(p, wavefitsfile, out_wave, hdict=hdict)

        # ----------------------------------------------------------------------
        # save mask file
        if p['EM_SAVE_MASK_MAP']:
            # construct tell mask 2D filename
            maskfitsfile, tag = spirouConfig.Constants.EM_MASK_FILE(p)
            maskfilename = os.path.split(maskfitsfile)[-1]
            # 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=tag)
            # log progress
            wmsg = 'Writing telluric mask to file {0}'
            WLOG(p, '', wmsg.format(maskfilename))
            # convert boolean mask to integers
            writablemask = np.array(out_mask, dtype=float)
            # write to file
            p = spirouImage.WriteImage(p,
                                       maskfitsfile,
                                       writablemask,
                                       hdict=hdict)

    # ----------------------------------------------------------------------
    # End Message
    # ----------------------------------------------------------------------
    p = spirouStartup.End(p)
    # return a copy of locally defined variables in the memory
    return dict(locals())