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