예제 #1
0
def addlines2spec(wavelength, wl_line, fl_line, resolution,
                  scale_spec=1., debug=False):
    """ Create a spectrum with a set of (gaussian) emission lines.
    
    Parameters
    ----------
    wavelength : np.array
        wavelength vector of the input spectrum
    wl_line, fl_line : np.arrays
        wavelength and flux of each individual line
    resolution : np.float
        resolution of the spectrograph. In other words, the lines
        will have a FWHM equal to:
        fwhm_line = wl_line / resolution
    scale_spec : np.float
        rescale all the  normalization of the final spectrum.
        Default scale_spec=1.
    debug : boolean
        If True will show debug plots

    Returns
    -------
    line_spec : np.array
        Spectrum with lines

    """
    line_spec = np.zeros_like(wavelength)
    wl_line_min, wl_line_max = np.min(wavelength), np.max(wavelength)
    good_lines = (wl_line>wl_line_min) & (wl_line<wl_line_max)
    wl_line_good = wl_line[good_lines]
    fl_line_good = fl_line[good_lines]

    # define sigma of the gaussians
    sigma = wl_line_good / resolution / 2.355

    msgs.info("Creating line spectrum")
    for ii in np.arange(len(wl_line_good)):
        line_spec += scale_spec*fl_line_good[ii]*\
                     np.exp(-np.power((wl_line_good[ii]-wavelength),2.)/(2.*np.power(sigma[ii],2.)))

    if debug:
        utils.pyplot_rcparams()
        msgs.info("Plot of the line spectrum.")
        plt.figure()
        plt.plot(wavelength, line_spec,
                 color='navy', linestyle='-', alpha=0.8,
                 label=r'Spectrum with lines included')
        plt.legend()
        plt.xlabel(r'Wavelength')
        plt.ylabel(r'Flux')
        msgs.info("Close the Figure to continue.")
        plt.show(block=True)
        plt.close()
        utils.pyplot_rcparams_default()

    return line_spec
예제 #2
0
def blackbody(wavelength, T_BB=250., debug=False):
    """ Given wavelength [in microns] and Temperature in Kelvin
    it returns the black body emission.

    Parameters
    ----------
    wavelength : np.array
        wavelength vector in microns
    T_BB : float 
        black body temperature in Kelvin. Default is set to:
        T_BB = 250.

    Returns
    -------
    blackbody : np.array
        spectral radiance of the black body in cgs units:
        B_lambda = 2.*h*c^2/lambda^5.*(1./(exp(h*c/(lambda*k_b*T_BB))-1.)
    blackbody_counts : np.array
        Same as above but in flux density
    """

    # Define constants in cgs
    PLANCK = astropy.constants.h.cgs.value  # erg*s
    C_LIGHT = astropy.constants.c.cgs.value  # cm/s
    K_BOLTZ = astropy.constants.k_B.cgs.value  # erg/K
    RADIAN_PER_ARCSEC = 1. / 3600. * np.pi / 180.

    msgs.info("Creating BB spectrum at T={}K".format(T_BB))
    lam = wavelength / 1e4  # convert wave in cm.
    blackbody_pol = 2. * PLANCK * np.power(C_LIGHT, 2) / np.power(lam, 5)
    blackbody_exp = np.exp(PLANCK * C_LIGHT / (lam * K_BOLTZ * T_BB)) - 1.
    blackbody = blackbody_pol / blackbody_exp
    blackbody_counts = blackbody / (PLANCK * C_LIGHT / lam) * 1e-4 \
                 * np.power(RADIAN_PER_ARCSEC, 2.)

    if debug:
        utils.pyplot_rcparams()
        msgs.info("Plot of the blackbody spectrum.")
        plt.figure()
        plt.plot(wavelength,
                 blackbody,
                 color='navy',
                 linestyle='-',
                 alpha=0.8,
                 label=r'T_BB={}'.format(T_BB))
        plt.legend()
        plt.xlabel(r"Wavelength [micron]")
        plt.ylabel(r"Spectral Radiance")
        plt.title(r"Planck's law")
        msgs.info("Close the Figure to continue.")
        plt.show(block=True)
        plt.close()
        utils.pyplot_rcparams_default()

    return blackbody, blackbody_counts
예제 #3
0
def conv2res(wavelength, flux, resolution, central_wl='midpt', debug=False):
    """Convolve an imput spectrum to a specific resolution. This is only
    approximate. It takes a fix FWHM for the entire spectrum given by:
    fwhm = wl_cent / resolution

    Parameters
    ----------
    wavelength : np.array
        wavelength
    flux : np.array
        flux
    resolution : np.float
        resolution of the spectrograph
    central_wl 
        if 'midpt' the central pixel of wavelength is used, otherwise
        the central_wl will be used.
    debug : boolean
        If True will show debug plots

    Returns
    -------
    flux_convolved :np.array
        Resulting flux after convolution
    px_sigma : float
        Size of the sigma in pixels at central_wl
    px_bin : float
        Size of one pixel at central_wl
    """

    if central_wl == 'midpt':
        wl_cent = np.median(wavelength)
    else:
        wl_cent = np.float(central_wl)
    wl_sigma = wl_cent / resolution / 2.355
    wl_bin = np.abs((wavelength - np.roll(wavelength, 1))[np.where(
        np.abs(wavelength - wl_cent) == np.min(np.abs(wavelength - wl_cent)))])
    msgs.info("The binning of the wavelength array at {} is: {}".format(
        wl_cent, wl_bin[0]))
    px_bin = wl_bin[0]
    px_sigma = wl_sigma / px_bin

    msgs.info("Covolving with a Gaussian kernel with sigma = {} pixels".format(
        px_sigma))
    gauss_kernel = Gaussian1DKernel(px_sigma)

    flux_convolved = convolve(flux, gauss_kernel)

    if debug:
        utils.pyplot_rcparams()
        msgs.info("Spectrum Convolved at R = {}".format(resolution))
        plt.figure()
        plt.plot(wavelength,
                 flux,
                 color='navy',
                 linestyle='-',
                 alpha=0.8,
                 label=r'Original')
        plt.plot(wavelength,
                 flux_convolved,
                 color='crimson',
                 linestyle='-',
                 alpha=0.8,
                 label=r'Convolved')
        plt.legend()
        plt.xlabel(r'Wavelength')
        plt.ylabel(r'Flux')
        plt.title(r'Spectrum Convolved at R = {}'.format(resolution))
        msgs.info("Close the Figure to continue.")
        plt.show(block=True)
        plt.close()
        utils.pyplot_rcparams_default()

    return flux_convolved, px_sigma, px_bin
예제 #4
0
def optical_modelThAr(resolution,
                      waveminmax=(3000., 10500.),
                      dlam=40.0,
                      flgd=True,
                      thar_outfile=None,
                      debug=False):
    """ Generate a model of a ThAr lamp in the uvb/optical. This is based on the
    Murphy et al. ThAr spectrum. Detailed information are here:
    http://astronomy.swin.edu.au/~mmurphy/thar/index.html
    Everythins is smoothed at the given resolution.

    Parameters
    ----------
    resolution : np.float
        resolution of the spectrograph. The ThAr lines will have a 
        FWHM equal to:
        fwhm_line = wl_line / resolution
    waveminmax : tuple
        wavelength range in angstrom to be covered by the model.
        Default is: (3000.,10500.)
    dlam : 
        bin to be used to create the wavelength grid of the model.
        If flgd='True' it is a bin in velocity (km/s). If flgd='False'
        it is a bin in linear space (microns).
        Default is: 40.0 (with flgd='True')
    flgd : boolean
        if flgd='True' (default) wavelengths are created with 
        equal steps in log space. If 'False', wavelengths will be
        created wit equal steps in linear space.
    thar_outfile : str
        name of the fits file where the model sky spectrum will be stored.
        default is 'None' (i.e., no file will be written).
    debug : boolean
        If True will show debug plots

    Returns
    -------
    wave, thar_model : np.arrays
        wavelength (in Ang.) and flux of the final model of the ThAr lamp emission.
    """

    # Create the wavelength array:
    wv_min = waveminmax[0]
    wv_max = waveminmax[1]
    if flgd:
        msgs.info("Creating wavelength vector in velocity space.")
        velpix = dlam  # km/s
        loglam = np.log10(1.0 + velpix / 299792.458)
        wave = np.power(10.,
                        np.arange(np.log10(wv_min), np.log10(wv_max), loglam))
    else:
        msgs.info("Creating wavelength vector in linear space.")
        wave = np.arange(wv_min, wv_max, dlam)

    msgs.info("Add in ThAr lines")
    th_wv, th_fx = thar_lines()

    # select spectral region
    filt_wl = (th_wv >= wv_min) & (th_wv <= wv_max)
    # calculate sigma at the mean wavelenght of the ThAr spectrum
    mn_wv = np.mean(th_wv[filt_wl])
    # Convolve to the instrument resolution. This is only
    # approximate.
    smooth_fx, dwv, thar_dwv = conv2res(th_wv,
                                        th_fx,
                                        resolution,
                                        central_wl=mn_wv,
                                        debug=debug)
    # Interpolate over input wavelengths
    interp_thar = scipy.interpolate.interp1d(th_wv,
                                             smooth_fx,
                                             kind='cubic',
                                             fill_value='extrapolate')
    thar_spec = interp_thar(wave)

    # remove negative artifacts
    thar_spec[thar_spec < 0.] = 0.
    # Remove regions of the spectrum outside the wavelength covered by the ThAr model
    if wv_min < np.min(th_wv):
        msgs.warn("Model of the ThAr spectrum outside the template coverage.")
        thar_spec[wave < np.min(th_wv)] = 0.
    if wv_max < np.max(th_wv):
        msgs.warn("Model of the ThAr spectrum outside the template coverage.")
        thar_spec[wave > np.max(th_wv)] = 0.

    if thar_outfile is not None:
        msgs.info("Saving the ThAr model in: {}".format(thar_outfile))
        hdu = fits.PrimaryHDU(np.array(thar_spec))
        header = hdu.header
        if flgd:
            header['CRVAL1'] = np.log10(wv_min)
            header['CDELT1'] = loglam
            header['DC-FLAG'] = 1
        else:
            header['CRVAL1'] = wv_min
            header['CDELT1'] = dlam
            header['DC-FLAG'] = 0
        hdu.writeto(thar_outfile, overwrite=True)

    if debug:
        utils.pyplot_rcparams()
        msgs.info(
            "Plot of the Murphy et al. template at R={}".format(resolution))
        plt.figure()
        plt.plot(th_wv,
                 th_fx,
                 color='navy',
                 linestyle='-',
                 alpha=0.3,
                 label=r'Original')
        plt.plot(th_wv,
                 smooth_fx,
                 color='crimson',
                 linestyle='-',
                 alpha=0.6,
                 label=r'Convolved at R={}'.format(resolution))
        plt.plot(wave,
                 thar_spec,
                 color='maroon',
                 linestyle='-',
                 alpha=1.0,
                 label=r'Convolved at R={} and resampled'.format(resolution))
        plt.legend()
        plt.xlabel(r'Wavelength [Ang.]')
        plt.ylabel(r'Emission')
        plt.title(r'Murphy et al. ThAr spectrum at R={}'.format(resolution))
        msgs.info("Close the Figure to continue.")
        plt.show(block=True)
        plt.close()
        utils.pyplot_rcparams_default()

    return np.array(wave), np.array(thar_spec)
예제 #5
0
def nearIR_modelsky(resolution,
                    waveminmax=(0.8, 2.6),
                    dlam=40.0,
                    flgd=True,
                    nirsky_outfile=None,
                    T_BB=250.,
                    SCL_BB=1.,
                    SCL_OH=1.,
                    SCL_H2O=10.,
                    WAVE_WATER=2.3,
                    debug=False):
    """ Generate a model sky in the near-IR. This includes a continuum model
    to match to gemini broadband level, a black body at T_BB, OH lines, and 
    H2O lines (but only at lambda>WAVE_WATER). Everythins is smoothed at the
    given resolution.

    Parameters
    ----------
    resolution : np.float
        resolution of the spectrograph. The OH and H2O lines will have a 
        FWHM equal to:
        fwhm_line = wl_line / resolution
    waveminmax : tuple
        wavelength range in microns to be covered by the model.
        Default is: (0.8, 2.6)
    dlam : 
        bin to be used to create the wavelength grid of the model.
        If flgd='True' it is a bin in velocity (km/s). If flgd='False'
        it is a bin in linear space (microns).
        Default is: 40.0 (with flgd='True')
    flgd : boolean
        if flgd='True' (default) wavelengths are created with 
        equal steps in log space. If 'False', wavelengths will be
        created wit equal steps in linear space.
    nirsky_outfile : str
        name of the fits file where the model sky spectrum will be stored.
        default is 'None' (i.e., no file will be written).
    T_BB : float 
        black body temperature in Kelvin. Default is set to:
        T_BB = 250.
    SCL_BB : float
        scale factor for modelling the sky black body emssion.
        Default: SCL_BB=1.
    SCL_OH : float
        scale factor for modelling the OH emssion.
        Default: SCL_OH=1.
    SCL_H2O : float
        scale factor for modelling the H2O emssion.
        Default: SCL_H2O=10.
    WAVE_WATER : float
        wavelength (in microns) at which the H2O are inclued.
        Default: WAVE_WATER = 2.3
    debug : boolean
        If True will show debug plots

    Returns
    -------
    wave, sky_model : np.arrays
        wavelength (in Ang.) and flux of the final model of the sky.
    """

    # Create the wavelength array:
    wv_min = waveminmax[0]
    wv_max = waveminmax[1]
    if flgd:
        msgs.info("Creating wavelength vector in velocity space.")
        velpix = dlam  # km/s
        loglam = np.log10(1.0 + velpix / 299792.458)
        wave = np.power(10.,
                        np.arange(np.log10(wv_min), np.log10(wv_max), loglam))
    else:
        msgs.info("Creating wavelength vector in linear space.")
        wave = np.arange(wv_min, wv_max, dlam)

    # Calculate transparency
    # trans = transparency(wave, debug=False)

    # Empirical match to gemini broadband continuum level
    logy = -0.55 - 0.55 * (wave - 1.0)
    y = np.power(10., logy)

    msgs.info("Add in a blackbody for the atmosphere.")
    bb, bb_counts = blackbody(wave, T_BB=T_BB, debug=debug)
    bb_counts = bb_counts

    msgs.info("Add in OH lines")
    oh_wv, oh_fx = oh_lines()
    # produces better wavelength solutions with 1.0 threshold
    msgs.info("Selecting stronger OH lines")
    filt_oh = oh_fx > 1.
    oh_wv, oh_fx = oh_wv[filt_oh], oh_fx[filt_oh]
    # scale_spec was added to match the XIDL code
    ohspec = addlines2spec(wave,
                           oh_wv,
                           oh_fx,
                           resolution=resolution,
                           scale_spec=((resolution / 1000.) / 40.),
                           debug=debug)

    if wv_max > WAVE_WATER:
        msgs.info("Add in H2O lines")
        h2o_wv, h2o_rad = h2o_lines()
        filt_h2o = (h2o_wv > wv_min - 0.1) & (h2o_wv < wv_max + 0.1)
        h2o_wv = h2o_wv[filt_h2o]
        h2o_rad = h2o_rad[filt_h2o]
        # calculate sigma at the mean wavelenght of the H2O spectrum
        filt_h2o_med = h2o_wv > WAVE_WATER
        mn_wv = np.mean(h2o_wv[filt_h2o_med])
        # Convolve to the instrument resolution. This is only
        # approximate.
        smooth_fx, dwv, h2o_dwv = conv2res(h2o_wv,
                                           h2o_rad,
                                           resolution,
                                           central_wl=mn_wv,
                                           debug=debug)
        # Interpolate over input wavelengths
        interp_h2o = scipy.interpolate.interp1d(h2o_wv,
                                                smooth_fx,
                                                kind='cubic',
                                                fill_value='extrapolate')
        h2ospec = interp_h2o(wave)
        # Zero out below WAVE_WATER microns (reconsider)
        h2ospec[wave < WAVE_WATER] = 0.
        h2ospec[wave > np.max(h2o_wv)] = 0.
    else:
        h2ospec = np.zeros(len(wave), dtype='float')

    sky_model = y + bb_counts * SCL_BB + ohspec * SCL_OH + h2ospec * SCL_H2O

    if nirsky_outfile is not None:
        msgs.info("Saving the sky model in: {}".format(nirsky_outfile))
        hdu = fits.PrimaryHDU(np.array(sky_model))
        header = hdu.header
        if flgd:
            header['CRVAL1'] = np.log10(wv_min)
            header['CDELT1'] = loglam
            header['DC-FLAG'] = 1
        else:
            header['CRVAL1'] = wv_min
            header['CDELT1'] = dlam
            header['DC-FLAG'] = 0
        hdu.writeto(nirsky_outfile, overwrite=True)

    if debug:
        utils.pyplot_rcparams()
        msgs.info("Plot of the sky emission at R={}".format(resolution))
        plt.figure()
        plt.plot(wave,
                 sky_model,
                 color='black',
                 linestyle='-',
                 alpha=0.8,
                 label=r'Sky Model')
        plt.plot(wave,
                 y,
                 color='darkorange',
                 linestyle='-',
                 alpha=0.6,
                 label=r'Continuum')
        plt.plot(wave,
                 bb_counts * SCL_BB,
                 color='green',
                 linestyle='-',
                 alpha=0.6,
                 label=r'Black Body at T={}K'.format(T_BB))
        plt.plot(wave,
                 ohspec * SCL_OH,
                 color='darkviolet',
                 linestyle='-',
                 alpha=0.6,
                 label=r'OH')
        plt.plot(wave,
                 h2ospec * SCL_H2O,
                 color='dodgerblue',
                 linestyle='-',
                 alpha=0.6,
                 label=r'H2O')
        plt.legend()
        plt.xlabel(r'Wavelength [microns]')
        plt.ylabel(r'Emission')
        plt.title(r'Sky Emission Spectrum at R={}'.format(resolution))
        msgs.info("Close the Figure to continue.")
        plt.show(block=True)
        plt.close()
        utils.pyplot_rcparams_default()

    return np.array(wave * 10000.), np.array(sky_model)
예제 #6
0
def transparency(wavelength, debug=False):
    """ Interpolate the atmospheric transmission model in the IR over
    a given wavelength (in microns) range.

    Parameters
    ----------
    wavelength : np.array
        wavelength vector in microns
    debug : boolean
        If True will show debug plots

    Returns
    -------
    transparency : np.array
        Transmission of the sky over the considered wavelength rage.
        1. means fully transparent and 0. fully opaque
    """

    msgs.info("Reading in the atmospheric transmission model")
    transparency = np.loadtxt(
        data.get_skisim_filepath('atm_transmission_secz1.5_1.6mm.dat'))
    wave_mod = transparency[:, 0]
    tran_mod = transparency[:, 1]

    # Limit model between 0.8 and np.max(wavelength) microns
    filt_wave_mod = (wave_mod > 0.8) & (wave_mod < np.max(wavelength))
    wave_mod = wave_mod[filt_wave_mod]
    tran_mod = tran_mod[filt_wave_mod]

    # Interpolate over input wavelengths
    interp_tran = scipy.interpolate.interp1d(wave_mod,
                                             tran_mod,
                                             kind='cubic',
                                             fill_value='extrapolate')
    transmission = interp_tran(wavelength)
    transmission[wavelength < 0.9] = 1.

    # Clean for spourious values due to interpolation
    transmission[transmission < 0.] = 0.
    transmission[transmission > 1.] = 1.

    if debug:
        utils.pyplot_rcparams()
        msgs.info("Plot of the sky transmission template")
        plt.figure()
        plt.plot(wave_mod,
                 tran_mod,
                 color='navy',
                 linestyle='-',
                 alpha=0.8,
                 label=r'Original')
        plt.plot(wavelength,
                 transmission,
                 color='crimson',
                 linestyle='-',
                 alpha=0.8,
                 label=r'Resampled')
        plt.legend()
        plt.xlabel(r'Wavelength [microns]')
        plt.ylabel(r'Transmission')
        plt.title(r' IR Transmission Spectra ')
        msgs.info("Close the Figure to continue.")
        plt.show(block=True)
        plt.close()
        utils.pyplot_rcparams_default()

    # Returns
    return transmission
예제 #7
0
    plt.text(mx ,np.max(all_pixels) ,r'residuals $\times$100', \
             ha="right", va="top")
    plt.title(r'Arc 2D FIT, norder_coeff={:d}, nspec_coeff={:d}, RMS={:5.3f} Ang*Order#'.format(
        norder_coeff, nspec_coeff, rms_global))
    plt.xlabel(r'Wavelength [$\AA$]')
    plt.ylabel(r'Row [pixel]')

    # Finish
    if outfile is not None:
        plt.savefig(outfile, dpi=800)
        plt.close()
    else:
        plt.show()

    # restore default rcparams
    utils.pyplot_rcparams_default()


def fit2darc_orders_qa_old(fit_dict, outfile=None):
    """ QA on 2D fit of the wavelength solution of an Echelle spectrograph.
    Each panel contains a single order with the global fit and the
    residuals.

    Parameters
    ----------
    fit_dict: dict
      dict of the 2D arc solution
    outfile:
      parameter for QA

    Returns