Exemple #1
0
  def sanity_tests(self):
    """
      Checking sanity of 'instrBroadGaussFast'
    """
    from PyAstronomy import pyasl
    import numpy as np
    
    # Set up an input spectrum
    x = np.linspace(5000.0,5100.0,1000)
    y = np.zeros(x.size)
    
    # Introduce some delta-peaked lines
    y[165] = 0.7
    y[187] = 0.3
    y[505] = 0.1
    y[610] = 0.1
    y[615] = 0.7

    # Apply Gaussian instrumental broadening.
    resolution = 12700.
    r, fwhm = pyasl.instrBroadGaussFast(x, y, resolution, edgeHandling=None, fullout=True)
    
    self.assertAlmostEqual(fwhm, np.mean(x)/resolution, 6, "FWHM does not match")
    
    s1 = y.sum()
    s2 = r.sum()
    self.assertAlmostEqual(s1, s2, 6, "EW in spectrum did change")
    def instrumental_profile(x, y, resolution):
        '''
        Inputs
        -----
        x, y : The abscissa and ordinate of the data.
        sigma : The width (i.e., standard deviation) of the Gaussian profile
        used in the convolution.
        edgeHandling : None, "firstlast". Determines the way edges will be
        handled. If None, nothing will be done about it. If set to "firstlast",
        the spectrum will be extended by using the first and last value at the
        start or end. Note that this is not necessarily appropriate.
        The default is None.
        maxsig : The extent of the broadening kernel in terms of standrad
        deviations. By default, the Gaussian broadening kernel will be extended
        over the entire given spectrum, which can cause slow evaluation in the
        case of large spectra. A reasonable choice could, e.g., be five.

        Output
        -----
        y_inst : convolved flux
        '''

        # Deal with zero or None values seperately
        if (resolution is None) or (resolution == 0):
            y_inst = y
        else:
            y_inst = pyasl.instrBroadGaussFast(x,
                                               y,
                                               resolution,
                                               edgeHandling="firstlast",
                                               fullout=False,
                                               maxsig=None)
        return y_inst
Exemple #3
0
def main():
    # Read in the needed values from the command line
    arguments = parseArguments()
    # Read in the spectrum
    try:
        wlc, flux = np.loadtxt(arguments.fileName, unpack=True, skiprows=1)
    except IOError:
        print("Input spectrum " + arguments.fileName + " not found!")
        exit()
    # Resample the input spectrum to even wavelength bins of <binSize> Angstrom
    newWlc = np.arange(wlc[0] + binSize, wlc[-1] - binSize, binSize)
    flux = np.interp(newWlc, wlc, flux)
    wlc = newWlc
    # Apply instrumental broadening
    flux = instrBroadGaussFast(wlc,
                               flux,
                               arguments.res,
                               maxsig=5.0,
                               edgeHandling="firstlast")
    # Apply rotational broadening
    flux = rotBroad(wlc, flux, limbDark, arguments.vrot)
    # Apply macroturbulent broadening
    if arguments.vmacro != -1:
        flux = macroBroad(wlc, flux, arguments.vmacro)
    # Resample to <finalBins> Angstrom
    if finalBins != binSize:
        newWlc = np.arange(wlc[0] + finalBins, wlc[-1] - finalBins, finalBins)
        flux = np.interp(newWlc, wlc, flux)
    # Write output file
    out_f = open(arguments.fileName + ".fin", 'w')
    out_f.write("#" + str(len(wlc)) + "\t" + "#0 \n")
    for i in range(len(wlc) - 1):
        out_f.write(str(wlc[i]) + "\t" + str(flux[i]) + "\n")
    out_f.close()
    exit()
Exemple #4
0
 def sanity_example(self):
   """
     Checking sanity of 'instrBroadGaussFast' example.
   """
   from PyAstronomy import pyasl
   import matplotlib.pylab as plt
   import numpy as np
   
   # Set up an input spectrum
   x = np.linspace(5000.0,5100.0,1000)
   y = np.ones(x.size)
   
   # Introduce some delta-peaked lines
   y[165] = 0.7
   y[187] = 0.3
   y[505] = 0.1
   y[610] = 0.1
   y[615] = 0.7
   
   # Apply Gaussian instrumental broadening, setting the resolution to 10000.
   r, fwhm = pyasl.instrBroadGaussFast(x, y, 10000,
                                       edgeHandling="firstlast", fullout=True)
   
   print "FWHM used for the Gaussian kernel: ", fwhm, " A"
   
   # Plot the output
   plt.plot(x,r, 'r--p')
   plt.plot(x,y, 'b-')
Exemple #5
0
def broaden(even_wl, modelspec_interp, res, vsini=0, limb=0, plot=False):
    """Adds resolution, vsin(i) broadening, taking into account limb darkening.

	Args: 
		even_wl (list): evenly spaced model wavelength vector
		modelspec_interp (list): model spectrum vector
		res (float): desired spectral resolution
		vsini (float): star vsin(i)
		limb (float): the limb darkening coeffecient
		plot (boolean): if True, plots the full input spectrum and the broadened output. Defaults to False.

	Returns:
		a tuple containing an evenly spaced wavelength vector spanning the width of the original wavelength range, and a corresponding flux vector

	"""

    #regrid by finding the smallest wavelength step
    mindiff = np.inf

    for n in range(1, len(even_wl)):
        if even_wl[n] - even_wl[n - 1] < mindiff:
            mindiff = even_wl[n] - even_wl[n - 1]

    #interpolate the input values
    it = interp1d(even_wl, modelspec_interp)

    #make a new wavelength array that's evenly spaced with the smallest wavelength spacing in the input wl array
    w = np.arange(min(even_wl), max(even_wl), mindiff)

    sp = it(w)

    #do the instrumental broadening and truncate the ends because they get messy
    broad = pyasl.instrBroadGaussFast(w, sp, res, maxsig=5)
    broad[0:5] = broad[5]
    broad[len(broad) - 10:len(broad)] = broad[len(broad) - 11]

    #if I want to impose stellar parameters of v sin(i) and limb darkening, do that here
    if vsini != 0 and limb != 0:
        rot = pyasl.rotBroad(w, broad, limb,
                             vsini)  #, edgeHandling='firstlast')
    #otherwise just move on
    else:
        rot = broad

    #Make a plotting option just in case I want to double check that this is doing what it's supposed to
    if plot == True:

        plt.figure()
        plt.plot(w, sp, label='model')
        plt.plot(w, broad, label='broadened')
        plt.plot(w, rot, label='rotation')
        plt.legend(loc='best')
        plt.xlabel('wavelength (angstroms)')
        plt.ylabel('normalized flux')
        plt.savefig('rotation.pdf')

    #return the wavelength array and the broadened flux array
    return w, rot
def convolve_data(fname, R_conv, resonumber):

    flux = fits.getdata(fname)
    hdr = fits.getheader(fname)
    w0, dw, N = hdr['CRVAL1'], hdr['CDELT1'], hdr['NAXIS1']
    wavelength = w0 + dw * np.arange(N)
    
    newflux = pyasl.instrBroadGaussFast(wavelength, flux, R_conv, edgeHandling="firstlast", fullout=False, maxsig=None)
    
    fits.writeto(fname.replace('.fits', '')+'conv'+resonumber+'.fits', newflux, hdr, overwrite=True)
    def GaussianBroadening(self, **kwargs):
        '''
        This function broadens the spectrum using a given Gaussian kernel.
        :param: resolution - float, The spectral resolution.
        '''

        resolution = kwargs["resolution"]

        if 'wv' and 'sp' in kwargs:
            flux = pyasl.instrBroadGaussFast(
                np.reshape(kwargs["wv"][0], (1, -1))[0], kwargs["sp"][0],
                resolution)
        else:
            flux = pyasl.instrBroadGaussFast(
                np.reshape(self.model.wv[0], (1, -1))[0], self.model.sp[0],
                resolution)

        flux = np.reshape(flux, (1, -1))

        self.model.sp = flux

        return flux
    def sanity_instrumentalResolution(self):
        """
        Checking integrity of instrumental resolution in VoigtAstroP
        """
        import numpy as np
        from PyAstronomy import modelSuite as ms
        from PyAstronomy import pyasl

        v = ms.VoigtAstroP()

        w0 = 10830

        for R in [2500, 5000, 80000]:

            v["w0"] = w0
            v["b"] = 10.
            v["gamma"] = 1e-8
            v["f"] = 100.0
            v["R"] = 0

            dw = 40.0
            w = np.linspace(w0 - dw, w0 + dw, 4000)

            m = v.evaluate(w)

            v["R"] = R
            m2 = v.evaluate(w)

            fb = pyasl.instrBroadGaussFast(w,
                                           m,
                                           R,
                                           edgeHandling=None,
                                           fullout=False,
                                           maxsig=None)

            d = 1000

            self.assertAlmostEqual(
                np.max(np.abs(fb[d:-d] - m2[d:-d]) / m2[d:-d]),
                0.0,
                delta=1e-10,
                msg="VoigtAstroP instrumental broadening broken for R = " +
                str(R))
Exemple #9
0
def broaden(even_wl, modelspec_interp, res, vsini, limb, plot=False):
    """Adds resolution, vsin(i) broadening, taking into account limb darkening.

	Args: 
		even_wl (list): evenly spaced model wavelength vector
		modelspec_interp (list): model spectrum vector
		res (float): desired spectral resolution
		vsini (float): star vsin(i)
		limb (float): the limb darkening coeffecient
		plot (boolean): if True, plots the full input spectrum and the broadened output. Defaults to False.

	Returns:
		a tuple containing an evenly spaced wavelength vector spanning the width of the original wavelength range, and a corresponding flux vector

	"""
    #sig = np.mean(even_wl)/res

    broad = pyasl.instrBroadGaussFast(even_wl, modelspec_interp, res, maxsig=5)

    if vsini != 0 and limb != 0:
        rot = pyasl.rotBroad(even_wl, broad, limb,
                             vsini)  #, edgeHandling='firstlast')
    else:
        rot = broad

    #modelspec_interp = [(modelspec_interp[n] / max(modelspec_interp))  for n in range(len(modelspec_interp))]
    #broad = [broad[n]/max(broad) for n in range(len(broad))]
    #rot = [(rot[n]/max(rot))  for n in range(len(rot))]

    if plot == True:

        plt.figure()
        plt.plot(even_wl, modelspec_interp, label='model')
        plt.plot(even_wl, broad, label='broadened')
        plt.plot(even_wl, rot, label='rotation')
        plt.legend(loc='best')
        plt.xlabel('wavelength (angstroms)')
        plt.ylabel('normalized flux')
        plt.savefig('rotation.pdf')

    return even_wl, rot
Exemple #10
0
    dz = np.diff(zlist)
    zdeltaz = dz * (zcent + R0)
    Rplam2 = np.square(R0) + 2.0 * (1.0 -
                                    np.exp(-tautilde)).transpose().dot(zdeltaz)
    Rscgs2 = np.square(Rs * const.R_sun.to(u.m).value)
    trspec = 1.0 - Rplam2 / Rscgs2
    trspecall.append(trspec)

    wvlair = vac2air(wvl_)
    flux = trspec
    stepsize = 0.015
    wvlair_hires = np.arange(wvlair[0], wvlair[-1], stepsize)
    tck = interpolate.splrep(wvlair, flux)
    flx = interpolate.splev(wvlair_hires, tck, der=0)

    rflx_hds = pyasl.instrBroadGaussFast(wvlair_hires,
                                         flx,
                                         115000,
                                         edgeHandling="firstlast")
    h5f_spec.create_dataset("spec_" + str(name[i]),
                            data=rflx_hds,
                            compression="gzip",
                            compression_opts=9)
h5f_spec.create_dataset("wavelength",
                        data=wvlair_hires,
                        compression="gzip",
                        compression_opts=9)

h5f_spec.close()
h5f_cc.close()
xs = np.loadtxt('kurucz.list', unpack=True, dtype=str)

name = []
for i in range(len(xs)):
    name.append(xs[i][18:-4])

h5f_harps = h5py.File('kelt20b-iso-2500K-trans-kurucz-nohmin.h5', 'r')

h5f_carm = h5py.File('kelt20b-iso-2500K-trans-kurucz-nohmin-carmenes.h5', 'w')

wvharsp = h5f_harps["wavelength"][:]
for i in tqdm(range(len(name))):
    spec = h5f_harps["spec_" + str(name[i])][:]
    rflx_hds = pyasl.instrBroadGaussFast(wvharsp,
                                         spec,
                                         94600,
                                         edgeHandling="firstlast")

    h5f_carm.create_dataset("spec_" + str(name[i]),
                            data=rflx_hds,
                            compression="gzip",
                            compression_opts=9)

h5f_carm.create_dataset("wavelength",
                        data=wvlair_hires,
                        compression="gzip",
                        compression_opts=9)

h5f_carm.close()
h5f_harps.close()
Exemple #12
0
if __name__ == '__main__':
    resolution = 100000
    w0, w1 = 10060, 23310
    wpath = os.path.expanduser(
        '~/.plotfits/WAVE_PHOENIX-ACES-AGSS-COND-2011.fits')
    w = get_wavelength(wpath)
    idx = (w0 <= w) & (w <= w1)
    w = w[idx]

    for fname in sorted(glob('lte*.fits'))[3:]:
        fout = params_to_name(fname, resolution)
        print fout

        y = fits.getdata(fname)
        y = y[idx]
        w_new, y_new = same_w_grid(w, y)
        print 'Convolving...'
        y_new = pyasl.instrBroadGaussFast(w_new,
                                          y_new,
                                          resolution,
                                          edgeHandling="firstlast",
                                          fullout=False,
                                          maxsig=None)

        crval1, cdelt1, naxis1 = header_information(w_new)
        hdr = fits.Header()
        hdr["NAXIS1"] = naxis1
        hdr["CDELT1"] = cdelt1
        hdr["CRVAL1"] = crval1
        fits.writeto(fout, y_new, hdr, overwrite=True)
Exemple #13
0
def make_simulation(template_data, uservals, detectorconfig, telescopeconfig,instrumentconfig):#template_data,resolution,wlr,t_aperture,sky_aperture,template_wl_norm,ab,airmass,npix,Instrument,aper_sampl,dit,eff_opt,seeing,atm_dif_ref):

    ####################################################################
    #Set dispersion axis
    cen_wav=(instrumentconfig['wlr'][1]+instrumentconfig['wlr'][0])/2.0*1.0e3
    wav_range_length=(instrumentconfig['wlr'][1]-instrumentconfig['wlr'][0])*1.0e3
    pix_arr=np.arange(0,detectorconfig['npix'],1)
    outputwl = instrumentconfig['wlr'][0]*1.0e4+pix_arr*detectorconfig['disp']
    #FWHM for kernel
    fwhm_kernel=np.sqrt((cen_wav/instrumentconfig['resolution'])**2-(cen_wav/template_data['respow'])**2)
    respow_kernel=cen_wav/fwhm_kernel
    ####################################################################

    ####################################################################
    #obtain Sky spectrum from template (either provided or ESO sky_calc)
    oh_f=get_sky_model(uservals['sky_template'], uservals['airmass_fl'])
    rdwl=oh_f['rdwl']
    rwl0=oh_f['rwl0'] # wavelength of sky model in Angstroms
    rfn0=oh_f['rfn0']*math.pi*(telescopeconfig['t_aperture']*1.e2/2.0)**2*rdwl #Photons/s/arcsec2 per pixel of the OH grid
    atmtr0=oh_f['atmtr'] # atmospheric transmission
    atmwl0=oh_f['atmwl']
    tol = (instrumentconfig['wlr'][1]-instrumentconfig['wlr'][0])*0.05
    min_wl=(instrumentconfig['wlr'][0]-tol)*1.0e4
    max_wl=(instrumentconfig['wlr'][1]+tol)*1.0e4
    iok_sky = np.where((rwl0 > min_wl) & (rwl0 < max_wl))[0]
    iok_atm = np.where((atmwl0 > min_wl) & (atmwl0 < max_wl))[0]
    rfn = rfn0[iok_sky] # flux of OH spectrum
    rwl = rwl0[iok_sky] # wave of OH spectrum
    atmwl=atmwl0[iok_atm]
    atmtr=atmtr0[iok_atm]
    rfn_sky = (rfn)*math.pi*(instrumentconfig['sky_aperture']/2.0)**2 # Photons/s/pix of the OH spectrum ALONE

    ####################################################################

    ####################################################################
    #Prepare the input template
    fl_tpl_in=template_data['flux']
    wl_tpl_in=template_data['wave']
    setup_range_tpl=np.where((wl_tpl_in>min_wl) & (wl_tpl_in<max_wl))[0]
    fl_tpl=fl_tpl_in[setup_range_tpl]
    wl_tpl=wl_tpl_in[setup_range_tpl]
    # normalising the template source spectrum to the magnitude
    i = np.where(wl_tpl >= instrumentconfig['template_wl_norm']*1.0e4)[0]
    templ_fl_ref = fl_tpl[i[0]]
    fl_tpl_normalized_to_one = fl_tpl/templ_fl_ref
    # template photon flux per A in cgs assuming a telescope effective diameter
    templ_phot_fl = fl_tpl_normalized_to_one*3.63e3*10.0**(-(uservals['ab']+57.5)/2.5)*math.pi*(telescopeconfig['t_aperture']*1.0e2/2.0)**2/(wl_tpl*6.626e-27)
    # template photon flux per PER SPECTRAL PIXEL OF THE TEMPLATE
    templ_phot_fl_pix = templ_phot_fl*template_data['cdelt']#*rdwl
    npix_y=detectorconfig['ypix_fwhm']*2.0
    ####################################################################

    ####################################################################
    # Modelling Fibre Injection
    #Obtain Image Quality in corresponding band from seeing provided (seeing defined in zenith at 500nm)
    fwhm_iq=seeing_to_ImageQ(uservals['seeing'],cen_wav,uservals['airmass_fl'])
    uservals['seeing']=fwhm_iq
    fib_frac=1.0 # allowing for tuning of fraction loss manually, keep as 1.0 for no additional loss
    #Calculate atmospheric difraction effect
    Lambda=np.arange(0.5,1.9,0.1)
    atm_diff=get_diffraction(Lambda, uservals['airmass_fl'], uservals['atm_dif_ref'])
    atm_diff_oh=np.interp(wl_tpl,Lambda*1.0e4,atm_diff)
    seeing_arr=np.sqrt(uservals['seeing']**2+atm_diff_oh**2) #Co-added effect of seeing and atm_diff offset.
    seeing_cor_flux= (1.0-1.0/np.exp( (np.sqrt(math.log(2.0)) * instrumentconfig['sky_aperture']/seeing_arr)**2))*templ_phot_fl_pix
    sp_conv_src = fib_frac*seeing_cor_flux
    sp_conv_sky=rfn_sky
    ####################################################################
    #resampling to detector pixels, conserving total flux
    #transmission:
    atminterp_res, fwhm = pyasl.instrBroadGaussFast(atmwl, atmtr, respow_kernel,edgeHandling="firstlast", fullout=True)
    atminterp = np.interp(outputwl,atmwl,atminterp_res)# resample atmospheric transmission to detector pixels
    #
    #source:
    sp_conv_src_res, fwhm = pyasl.instrBroadGaussFast(wl_tpl, sp_conv_src, respow_kernel ,edgeHandling="firstlast", fullout=True)
    sp_det_src = np.interp(outputwl,wl_tpl,sp_conv_src_res)
    inband = np.where((wl_tpl >= outputwl[0]) & (wl_tpl <= outputwl[detectorconfig['npix']-1]))[0]
    sp_conv_src_sum=sp_conv_src_res[inband].sum()
    sp_det_src_sum=sp_det_src.sum()
    renorm=sp_conv_src_sum/sp_det_src_sum
    sp_det_src_rn = sp_det_src*renorm
    if (uservals['set_line_profile']=='YES'):
        line_profile_file='IP_HIRES_m68_wave17834.1A.txt'
        print(' ')
        print('Applying line profile convolution')
        print('Extracting line profile from file: ',line_profile_file)
        sp_det_src_rn=get_line_profile(line_profile_file,outputwl,sp_det_src_rn,detectorconfig['disp'])
    else:
        print('No LSF provided, adopting Gaussian kernel convolution')
        print(' ')
    #
    #sky emission:
    sp_conv_sky_res, fwhm = pyasl.instrBroadGaussFast(rwl, sp_conv_sky, respow_kernel,edgeHandling="firstlast", fullout=True)
    sp_det_sky = np.interp(outputwl,rwl,sp_conv_sky_res)
    inband = np.where((rwl >= outputwl[0]) & (rwl <= outputwl[detectorconfig['npix']-1]))[0]
    sp_conv_sky_sum=sp_conv_sky_res[inband].sum()
    sp_det_sky_sum=sp_det_sky.sum()
    renorm_sky=sp_conv_sky_sum/sp_det_sky_sum
    sp_det_sky_rn = sp_det_sky*renorm_sky # for sky only

    if (uservals['set_line_profile']=='YES'):
        line_profile_file='IP_HIRES_m68_wave17834.1A.txt'
        sp_det_sky_rn=get_line_profile(line_profile_file,outputwl,sp_det_sky_rn,detectorconfig['disp'])
    ####################################################################

    ####################################################################
    #Modelling overall efficiency (not currently enabled!)
    eff=get_efficiency(outputwl,min_wl,max_wl)
    #Calculate telescope and instrument emissivity (not critical for H band)
    ThBK=283.00
    EBK=0.00 #36.0*selector #selector matching temperature of the telescope
    ThBK_ins=283.00
    EBK_ins=0.10 #36.0*selector #selector matching temperature of the telescope
    t_em=1.4*10.0**12*EBK*np.exp(-14388.0/(outputwl/1.0e4*ThBK))/((outputwl/1.0e4)**3/instrumentconfig['resolution'])*detectorconfig['disp']
    ins_em=1.4*10.0**12*EBK_ins*np.exp(-14388.0/(outputwl/1.0e4*ThBK_ins))/((outputwl/1.0e4)**3/instrumentconfig['resolution'])*detectorconfig['disp']
    NBK_tel=(t_em)*math.pi*(instrumentconfig['sky_aperture']/2.0)**2
    NBK_ins=(ins_em)*math.pi*(instrumentconfig['sky_aperture']/2.0)**2
    NBK=NBK_tel+NBK_ins
    #print("Thermal background emissivity Telescope [e-/s]: ",str(round(np.max(NBK_tel*eff),3)))
    #print("Thermal background emissivity Instrument [e-/s]: ",str(round(np.max(NBK_ins*eff),3)))
    #sp_det_sky_rn=sp_det_sky_rn+NBK commented out for the moment.
    ####################################################################
    #Modelling detector influx
    sp_det = sp_det_src_rn+sp_det_sky_rn # total detector flux from both sky and source
    sp_eff=sp_det*eff*atminterp
    sp_eff_src = sp_det_src_rn*eff*atminterp
    sp_eff_sky = sp_det_sky_rn*eff*atminterp
    # number of pixels COLLAPSED ALONG Y DIRECTION for MOS
    #sp_dk = sp_eff+DKsec*npix_y # from total insident flux
#    sp_dk_sky = sp_eff_sky+DKsec*npix_y #from only sky
    # scale by integration time
    spec_total = sp_eff*uservals['dit']
    spec_2d_peak_intensity=get_PeakIntensity(spec_total,npix_y,instrumentconfig['DKsec']*uservals['dit'])
    # the following is for the sky only
    spec_sky = sp_eff_sky*uservals['dit']
    # the following is for the source alone
    spec_source = sp_eff_src*uservals['dit']
    #calculate total noise
    #####################################################
    # Add stray light contribution
    stray=1.0 # 1% difusse stray light contribution as per latest optical modelling
    total_stray=spec_sky.sum()*uservals['N_dit']*500.0/detectorconfig['npix']**2
    spec_stray=total_stray*float(stray)/100.0*npix_y
    #detector NOISE:
    noisedet=np.sqrt(npix_y*(uservals['N_dit']*instrumentconfig['RON']**2+instrumentconfig['DKsec']*uservals['dit']*uservals['N_dit']))
    #background NOISE (including stray):
    noiseback=np.sqrt(spec_sky*uservals['N_dit']+spec_stray)
    #Add residual sky subtraction (optional, if you want then change skyres to percentage):
    if ((uservals['sky_residual'] >= 0) & (uservals['sky_residual'] <= 100)):
        skyres=uservals['sky_residual']
    else:
        if (uservals['sky_residual'] == -1):
            print('Simulation with sky-subtraction OFF')
            print(' ')
            skyres=0
        else:
            print(' Not a valid sky residual value (0-100). Adopting 0.00 percent')
            print(' ')
            skyres=0
    noiseskyres=float(skyres)/100.0*spec_sky
    #total NOISE: comment out when necessary
    noisetot=np.sqrt(noiseback**2+noisedet**2+spec_source*uservals['N_dit'])
    #noise_sim_withsky=np.sqrt(noiseback**2+noisedet**2+spec_source*uservals['N_dit'])
    outnoise=noisetot+noiseskyres
    #outnoise = np.sqrt(outspec+outspec_sky+RON**2*npix_y*2.)
    sn_cont_all = spec_source/outnoise*uservals['N_dit']
    sn_cont = np.median(sn_cont_all)
    cent_range=np.where((outputwl >= (cen_wav-wav_range_length*0.1)*10.0) & (outputwl <= (cen_wav+wav_range_length*0.1)*10.0))[0]
    sn_central=sn_cont_all[cent_range].max()
    print("**** S/N at central wavelength = %.2f ****"%sn_central)
    print(" ")
    count_level=spec_2d_peak_intensity*instrumentconfig['gain']
    saturated=get_saturation(count_level,instrumentconfig['saturation_level'])
    if saturated:
        print('WARNING!!! Counts above saturation/linearity regime!!!')
    #Get figure with summary of results
    #SNR figure
    f=plt.figure(figsize=(10,8),dpi=100)
    ax1=f.add_subplot(221)
    ax1.plot(outputwl/1.0e4, sn_cont_all,label='SNR per pixel')
    ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], sn_cont_all.min(), sn_cont_all.max()])
    ax1.set_xlabel('Wavelength [um]')
    ax1.set_ylabel('SNR (/pix)')
    plt.legend(loc='upper right',prop={'size':8}, numpoints=1)
    #Sky spectrum
    ax1=f.add_subplot(222)
    ax1.plot(outputwl/1.0e4, spec_2d_peak_intensity,label='Peak Intensity')
    ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], spec_2d_peak_intensity.min(), spec_2d_peak_intensity.max()])
    if saturated:
        ax1.plot(outputwl/1.0e4,spec_2d_peak_intensity*0.0+instrumentconfig['saturation_level']/instrumentconfig['gain'],color='red',label='Saturation')
    plt.legend(loc='upper right',prop={'size':8}, numpoints=1)
    ax1.set_xlabel('Wavelength [um]')
    ax1.set_ylabel('Counts (e-)')
    #atmospheric transmission
    ax1=f.add_subplot(223)
    ax1.plot(outputwl/1.0e4, atminterp,label='Atmospheric transmission')
    ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], atminterp.min(), atminterp.max()])
    ax1.set_xlabel('Wavelength [um]')
    ax1.set_ylabel('Transmission fraction')
    plt.legend(loc='lower left',prop={'size':8}, numpoints=1)
    #Simulated spectrum
    ax1=f.add_subplot(224)
    normnoise=np.random.random((detectorconfig['npix']))*2.0-1.0
    res_noise=normnoise*outnoise
    nores_noise=normnoise*noisetot
    sim_spectrum={}
    if uservals['sky_residual']==-1:
        sim_spectrum['flux']=spec_total*uservals['N_dit']+nores_noise
    else:
        sim_spectrum['flux']=spec_source*uservals['N_dit']+res_noise
    if uservals['telluric']==1:
        print('Telluric correction applied (idealistic)')
        print(' ')
        sim_spectrum['flux']=sim_spectrum['flux']/atminterp
    else:
        sim_spectrum['flux']=sim_spectrum['flux']
    sim_spectrum['wave']=outputwl
    sim_spectrum['cdelt']=detectorconfig['disp']
    sim_spectrum['crval']=outputwl[0]
    ax1.plot(outputwl/1.0e4, sim_spectrum['flux'],label='Sim spectrum')
    ax1.plot(outputwl/1.0e4, spec_source*uservals['N_dit'],label='Object (no noise)',alpha=0.6)
    ax1.axis([instrumentconfig['wlr'][0], instrumentconfig['wlr'][1], sim_spectrum['flux'].min(), sim_spectrum['flux'].max()])
    ax1.set_xlabel('Wavelength [um]')
    ax1.set_ylabel('Counts (e-)')
    plt.legend(loc='upper right',prop={'size':8}, numpoints=1)
    plt.tight_layout()
    f.savefig("SIM_results.pdf", bbox_inches='tight')
    plt.close()
    return sim_spectrum
def main(fname, lines=False, linelist=False,
         model=False, telluric=False, sun=False,
         rv=False, rv1=False, rv2=False, ccf='none', ftype='1D',
         fitsext='0', order='77', convert=False, resolution=False,
         nolines=False):
    """Plot a fits file with extensive options

    :fname: Input spectra
    :lines: Absorption lines
    :linelist: A file with the lines
    :model: Model spectrum
    :telluric: Telluric spectrum
    :sun: Solar spectrum
    :rv: RV of input spectrum
    :rv1: RV of Solar/model spectrum
    :rv2: RV of telluric spectrum
    :ccf: Calculate CCF (sun, model, telluric, both)
    :ftype: Type of fits file (1D, CRIRES, GIANO)
    :fitsext: Slecet fits extention to use (0,1,2,3,4)
    :returns: RV if CCF have been calculated
    """
    print('\n-----------------------------------')
    path = os.path.expanduser('~/.plotfits/')
    pathsun = os.path.join(path, 'solarspectrum_01.fits')
    pathtel = os.path.join(path, 'telluric_NIR.fits')
    pathwave = os.path.join(path, 'WAVE_PHOENIX-ACES-AGSS-COND-2011.fits')
    pathGIANO = os.path.join(path, 'wavelength_GIANO.dat')
    if not os.path.isdir(path):
        os.mkdir(path)
        print('Created: %s' % path)
    if sun and (not os.path.isfile(pathsun)):
        print('Downloading solar spectrum...')
        _download_spec(pathsun)
    if telluric and (not os.path.isfile(pathtel)):
        print('Downloading telluric spectrum...')
        _download_spec(pathtel)
    if model and (not os.path.isfile(pathwave)):
        print('Downloading wavelength vector for model...')
        import urllib
        url = 'ftp://phoenix.astro.physik.uni-goettingen.de/HiResFITS//WAVE_PHOENIX-ACES-AGSS-COND-2011.fits'
        urllib.urlretrieve(url, pathwave)

    fitsext = int(fitsext)
    order = int(order)

    if ftype == '1D':
        I = fits.getdata(fname)
        hdr = fits.getheader(fname)
        w = get_wavelength(hdr, convert=convert)
    elif ftype == 'CRIRES':
        d = fits.getdata(fname, fitsext)
        hdr = fits.getheader(fname, fitsext)
        I = d['Extracted_OPT']
        w = d['Wavelength']*10
    elif ftype == 'GIANO':
        d = fits.getdata(fname)
        I = d[order - 32]  # 32 is the first order
        wd = np.loadtxt(pathGIANO)
        w0, w1 = wd[wd[:, 0] == order][0][1:]
        w = np.linspace(w0, w1, len(I), endpoint=True)
    elif ftype == 'UVES':
        raise NotImplementedError('Please be patient. Not quite there yet')
        # d = fits.getdata(fname)
        # I = d['']

    if np.median(I) != 0:
        I /= np.median(I)
    else:
        I /= I.max()
    # Normalization (use first 50 points below 1.2 as constant continuum)
    maxes = I[(I < 1.2)].argsort()[-50:][::-1]
    I /= np.median(I[maxes])
    I[I<0] = 0
    dw = 10  # Some extra coverage for RV shifts

    if rv:
        I, w = dopplerShift(wvl=w, flux=I, v=rv)
    w0, w1 = w[0] - dw, w[-1] + dw

    if sun and not model:
        I_sun = fits.getdata(pathsun)
        hdr = fits.getheader(pathsun)
        w_sun = get_wavelength(hdr)
        i = (w_sun > w0) & (w_sun < w1)
        w_sun = w_sun[i]
        I_sun = I_sun[i]
        if len(w_sun) > 0:
            I_sun /= np.median(I_sun)
            if ccf in ['sun', 'both'] and rv1:
                print('Warning: RV set for Sun. Calculate RV with CCF')
            if rv1 and ccf not in ['sun', 'both']:
                I_sun, w_sun = dopplerShift(wvl=w_sun, flux=I_sun, v=rv1)
        else:
            print('Warning: Solar spectrum not available in wavelength range.')
            sun = False
    elif sun and model:
        print('Warning: Both solar spectrum and a model spectrum are selected. Using model spectrum.')
        sun = False

    if model:
        I_mod = fits.getdata(model)
        hdr = fits.getheader(model)
        if 'WAVE' in hdr.keys():
            w_mod = fits.getdata(pathwave)
        else:
            w_mod = get_wavelength(hdr)
        w_mod = vac2air(w_mod)  # Correction for vacuum to air (ground based)
        i = (w_mod > w0) & (w_mod < w1)
        w_mod = w_mod[i]
        I_mod = I_mod[i]
        if len(w_mod) > 0:
            if resolution:
                I_mod = pyasl.instrBroadGaussFast(w_mod, I_mod, resolution, edgeHandling="firstlast", fullout=False, maxsig=None)
            # https://phoenix.ens-lyon.fr/Grids/FORMAT
            # I_mod = 10 ** (I_mod-8.0)
            I_mod /= np.median(I_mod)
            # Normalization (use first 50 points below 1.2 as continuum)
            maxes = I_mod[(I_mod < 1.2)].argsort()[-50:][::-1]
            I_mod /= np.median(I_mod[maxes])
            if ccf in ['model', 'both'] and rv1:
                print('Warning: RV set for model. Calculate RV with CCF')
            if rv1 and ccf not in ['model', 'both']:
                I_mod, w_mod = dopplerShift(wvl=w_mod, flux=I_mod, v=rv1)
        else:
            print('Warning: Model spectrum not available in wavelength range.')
            model = False

    if telluric:
        I_tel = fits.getdata(pathtel)
        hdr = fits.getheader(pathtel)
        w_tel = get_wavelength(hdr)
        i = (w_tel > w0) & (w_tel < w1)
        w_tel = w_tel[i]
        I_tel = I_tel[i]
        if len(w_tel) > 0:
            I_tel /= np.median(I_tel)
            if ccf in ['telluric', 'both'] and rv2:
                print('Warning: RV set for telluric, Calculate RV with CCF')
            if rv2 and ccf not in ['telluric', 'both']:
                I_tel, w_tel = dopplerShift(wvl=w_tel, flux=I_tel, v=rv2)
        else:
            print('Warning: Telluric spectrum not available in wavelength range.')
            telluric = False

    rvs = {}
    if ccf != 'none':
        if ccf in ['sun', 'both'] and sun:
            # remove tellurics from the Solar spectrum
            if telluric and sun:
                print('Correcting solar spectrum for tellurics...')
            print('Calculating CCF for the Sun...')
            rv1, r_sun, c_sun, x_sun, y_sun = ccf_astro((w, -I + 1), (w_sun, -I_sun + 1))
            if rv1 != 0:
                print('Shifting solar spectrum...')
                I_sun, w_sun = dopplerShift(w_sun, I_sun, v=rv1)
                rvs['sun'] = rv1
                print('DONE\n')

        if ccf in ['model', 'both'] and model:
            print('Calculating CCF for the model...')
            rv1, r_mod, c_mod, x_mod, y_mod = ccf_astro((w, -I + 1), (w_mod, -I_mod + 1))
            if rv1 != 0:
                print('Shifting model spectrum...')
                I_mod, w_mod = dopplerShift(w_mod, I_mod, v=rv1)
                rvs['model'] = rv1
                print('DONE\n')

        if ccf in ['telluric', 'both'] and telluric:
            print('Calculating CCF for the model...')
            rv2, r_tel, c_tel, x_tel, y_tel = ccf_astro((w, -I + 1), (w_tel, -I_tel + 1))
            if rv2 != 0:
                print('Shifting telluric spectrum...')
                I_tel, w_tel = dopplerShift(w_tel, I_tel, v=rv2)
                rvs['telluric'] = rv2
                print('DONE\n')

    if len(rvs) == 0:
        ccf = 'none'

    if ccf != 'none':
        from matplotlib.gridspec import GridSpec
        fig = plt.figure(figsize=(16, 5))
        gs = GridSpec(1, 5)
        if len(rvs) == 1:
            gs.update(wspace=0.25, hspace=0.35, left=0.05, right=0.99)
            ax1 = plt.subplot(gs[:, 0:-1])
            ax2 = plt.subplot(gs[:, -1])
            ax2.set_yticklabels([])
        elif len(rvs) == 2:
            gs.update(wspace=0.25, hspace=0.35, left=0.01, right=0.99)
            ax1 = plt.subplot(gs[:, 1:4])
            ax2 = plt.subplot(gs[:, 0])
            ax3 = plt.subplot(gs[:, -1])
            ax2.set_yticklabels([])
            ax3.set_yticklabels([])
    else:
        fig = plt.figure(figsize=(16, 5))
        ax1 = fig.add_subplot(111)

    # Start in pan mode with these two lines
    # manager = plt.get_current_fig_manager()
    # manager.toolbar.pan()

    # Use nice numbers on x axis (y axis is normalized)...
    x_formatter = matplotlib.ticker.ScalarFormatter(useOffset=False)
    ax1.xaxis.set_major_formatter(x_formatter)

    if sun and not model:
        ax1.plot(w_sun, I_sun, '-C2', lw=1, alpha=0.6, label='Sun')
    if telluric:
        ax1.plot(w_tel, I_tel, '-C3', lw=1, alpha=0.6, label='Telluric')
    if model:
        ax1.plot(w_mod, I_mod, '-C2', lw=1, alpha=0.6, label='Model')
    ax1.plot(w, I, '-k', lw=1, label='Star')

    # Add crosshair
    xlim = ax1.get_xlim()
    cursor = Cursor(ax1)
    plt.connect('motion_notify_event', cursor.mouse_move)
    ax1.set_xlim(xlim)

    if (linelist or lines) and lineidImport and not nolines:
        try:
            lines, elements = np.loadtxt(linelist, usecols=(0, 1), skiprows=1, unpack=True)
            idx = (lines <= max(w)) & (lines >= min(w))
            lines = lines[idx]
            elements = elements[idx]
            Fe1Lines, Fe2Lines, otherLines = [], [], []
            for line, element in zip(lines, elements):
                if np.allclose(element, 26.0):
                    Fe1Lines.append('FeI: {}'.format(line))
                elif np.allclose(element, 26.1):
                    Fe2Lines.append('FeII: {}'.format(line))
                else:
                    otherLines.append('{}: {}'.format(element, line))

            lines = lines*(1.0 + rv1 / 299792.458) if rv1 else lines*1
            if len(Fe1Lines):
                lineid_plot.plot_line_ids(w, I, lines[elements==26.0], Fe1Lines, ax=ax1, add_label_to_artists=False)
            if len(Fe2Lines):
                pk = lineid_plot.initial_plot_kwargs()
                pk['color'] = 'red'
                lineid_plot.plot_line_ids(w, I, lines[elements==26.1], Fe2Lines, ax=ax1, add_label_to_artists=False, plot_kwargs=pk)
        except IOError:
            pass

    ax1.set_ylim(min(I)-0.05*min(I), 1.05*max(I))
    ax1.set_xlabel('Wavelength')
    ax1.set_ylabel('"Normalized" flux')

    if len(rvs) == 1:
        if 'sun' in rvs.keys():
            ax2.plot(r_sun, c_sun, '-k', alpha=0.9, lw=2)
            ax2.plot(x_sun, y_sun, '--C1', lw=2)
            ax2.set_title('CCF (sun)')
        if 'model' in rvs.keys():
            ax2.plot(r_mod, c_mod, '-k', alpha=0.9, lw=2)
            ax2.plot(x_mod, y_mod, '--C1', lw=2)
            ax2.set_title('CCF (mod)')
        if 'telluric' in rvs.keys():
            ax2.plot(r_tel, c_tel, '-k', alpha=0.9, lw=2)
            ax2.plot(x_tel, y_tel, '--C1', lw=2)
            ax2.set_title('CCF (tel)')
        ax2.set_xlabel('RV [km/s]')

    elif len(rvs) == 2:
        if 'sun' in rvs.keys():
            ax2.plot(r_sun, c_sun, '-k', alpha=0.9, lw=2)
            ax2.plot(x_sun, y_sun, '--C1', lw=2)
            ax2.set_title('CCF (sun)')
        if 'model' in rvs.keys():
            ax2.plot(r_mod, c_mod, '-k', alpha=0.9, lw=2)
            ax2.plot(x_mod, y_mod, '--C1', lw=2)
            ax2.set_title('CCF (mod)')
        ax3.plot(r_tel, c_tel, '-k', alpha=0.9, lw=2)
        ax3.plot(x_tel, y_tel, '--C1', lw=2)
        ax3.set_title('CCF (tel)')

        ax2.set_xlabel('RV [km/s]')
        ax3.set_xlabel('RV [km/s]')

    if rv:
        ax1.set_title('%s\nRV correction: %s km/s' % (fname, int(rv)))
    elif rv1 and rv2:
        ax1.set_title('%s\nSun/model: %s km/s, telluric: %s km/s' % (fname, int(rv1), int(rv2)))
    elif rv1 and not rv2:
        ax1.set_title('%s\nSun/model: %s km/s' % (fname, int(rv1)))
    elif not rv1 and rv2:
        ax1.set_title('%s\nTelluric: %s km/s' % (fname, int(rv2)))
    elif ccf == 'model':
        ax1.set_title('%s\nModel(CCF): %s km/s' % (fname, int(rv1)))
    elif ccf == 'sun':
        ax1.set_title('%s\nSun(CCF): %s km/s' % (fname, int(rv1)))
    elif ccf == 'telluric':
        ax1.set_title('%s\nTelluric(CCF): %s km/s' % (fname, int(rv2)))
    elif ccf == 'both':
        ax1.set_title('%s\nSun/model(CCF): %s km/s, telluric(CCF): %s km/s' % (fname, int(rv1), int(rv2)))
    else:
        ax1.set_title(fname)
    if sun or telluric or model:
        ax1.legend(loc=3, frameon=False)
    plt.show()

    return rvs