def update_model(self): if self.parent is None: return all_comp = self.parent.comps_widg.all_comp #selected_components() if len(all_comp) == 0: self.model.flux[:] = 1. return # Setup lines wvmin, wvmax = np.min(self.spec.dispersion), np.max(self.spec.dispersion) gdlin = [] for comp in all_comp: for line in comp.lines: wvobs = (1+line.attrib['z'])*line.wrest if (wvobs>wvmin) & (wvobs<wvmax): line.attrib['N'] = 10.**line.attrib['logN'] / u.cm**2 gdlin.append(line) # Voigt #QtCore.pyqtRemoveInputHook() #xdb.set_trace() #QtCore.pyqtRestoreInputHook() self.model = lav.voigt_from_abslines(self.spec.dispersion, gdlin, fwhm=self.fwhm)#,debug=True) #Define arrays for plotting residuals if self.plot_residuals: self.residual_limit = self.spec.sig * self.residual_normalization_factor self.residual = (self.spec.flux - self.model.flux) * self.residual_normalization_factor
def generate_voigt(self, wave=None, **kwargs): """ Generate a Voigt profile model for the absorption line in a given spectrum. Parameters ---------- wave : Quantity array Wavelength array on which to calculate the line Must be set if self.analy['spec'] is not filled Returns ------- spec : XSpectrum1D Spectrum with the input wavelength and the absorbed flux """ from linetools.analysis import voigt as lav # Checks if self.attrib['N'] < 1./u.cm**2: raise ValueError("Need to initialize log column density in attrib['N']") if self.attrib['b'] < 1.*u.km/u.s: raise ValueError("Need to initialize Doppler parameter in attrib['b']") if wave is None: # Assume a spectrum has been loaded already try: wave = self.analy['spec'].wavelength except: raise ('You must provide a wavelength array in generate_voigt') # Main call spec = lav.voigt_from_abslines(wave, self, **kwargs) return spec
def generate_voigt(self, wave=None, **kwargs): """ Generate a Voigt profile model for the absorption line in a given spectrum. Parameters ---------- wave : Quantity array Wavelength array on which to calculate the line Must be set if self.analy['spec'] is not filled Returns ------- spec : XSpectrum1D Spectrum with the input wavelength and the absorbed flux """ from linetools.analysis import voigt as lav # Checks if self.attrib['N'] < 1. / u.cm**2: raise ValueError( "Need to initialize log column density in attrib['N']") if self.attrib['b'] < 1. * u.km / u.s: raise ValueError( "Need to initialize Doppler parameter in attrib['b']") if wave is None: # Assume a spectrum has been loaded already try: wave = self.analy['spec'].wavelength except: raise ('You must provide a wavelength array in generate_voigt') # Main call spec = lav.voigt_from_abslines(wave, self, **kwargs) return spec
def update_model(self): """Update absorption model""" from linetools.analysis import voigt as lav if len(self.abssys_widg.all_abssys) == 0: self.dla_model = None self.spec_widg.model = None return # use finer wavelength array to resolve absorption features. wa = self.full_model.wavelength # Angstroms # should really make this a constant velocity width array instead. if not self.skip_wveval: wa1 = np.arange(wa[0].value, wa[-1].value, self.dw) * wa.unit else: wa1 = wa #all_tau_model = igmlls.tau_multi_lls(wa1, # self.abssys_widg.all_abssys, skip_wveval=self.skip_wveval) all_lines = [] for abssys in self.abssys_widg.all_abssys: for iline in abssys.dla_lines: all_lines.append(iline) #QtCore.pyqtRemoveInputHook() #import pdb; pdb.set_trace() #QtCore.pyqtRestoreInputHook() tau_Lyman = lav.voigt_from_abslines(wa1, all_lines, ret='tau', skip_wveval=self.skip_wveval) ''' # Loop on forest lines for forest in self.all_forest: tau_Lyman = lav.voigt_from_abslines(wa1, forest.lines, ret='tau', skip_wveval=self.skip_wveval) all_tau_model += tau_Lyman ''' all_tau_model = tau_Lyman # Flux and smooth flux = np.exp(-1. * all_tau_model) if self.smooth > 0: if not self.skip_wveval: mult = np.median(np.diff(wa.value)) / self.dw flux = lsc.convolve_psf(flux, self.smooth * mult) else: flux = lsc.convolve_psf(flux, self.smooth) if not self.skip_wveval: self.dla_model = np.interp(wa.value, wa1.value, flux) else: self.dla_model = flux # Finish self.full_model.flux = self.dla_model * self.conti_dict['co'] # Over-absorbed self.spec_widg.bad_model = np.where((self.dla_model < 0.7) & ( self.full_model.flux < (self.spec_widg.spec.flux - self.spec_widg.spec.sig * 1.5)))[0] # Model self.spec_widg.model = self.full_model
def update_model(self): """Update absorption model""" from linetools.analysis import voigt as lav if len(self.abssys_widg.all_abssys) == 0: self.dla_model = None self.spec_widg.model = None return # use finer wavelength array to resolve absorption features. wa = self.full_model.wavelength # Angstroms # should really make this a constant velocity width array instead. if not self.skip_wveval: wa1 = np.arange(wa[0].value, wa[-1].value, self.dw) * wa.unit else: wa1 = wa #all_tau_model = igmlls.tau_multi_lls(wa1, # self.abssys_widg.all_abssys, skip_wveval=self.skip_wveval) all_lines = [] for abssys in self.abssys_widg.all_abssys: for iline in abssys.dla_lines: all_lines.append(iline) #QtCore.pyqtRemoveInputHook() #import pdb; pdb.set_trace() #QtCore.pyqtRestoreInputHook() tau_Lyman = lav.voigt_from_abslines(wa1, all_lines, ret='tau', skip_wveval=self.skip_wveval) ''' # Loop on forest lines for forest in self.all_forest: tau_Lyman = lav.voigt_from_abslines(wa1, forest.lines, ret='tau', skip_wveval=self.skip_wveval) all_tau_model += tau_Lyman ''' all_tau_model = tau_Lyman # Flux and smooth flux = np.exp(-1. * all_tau_model) if self.smooth > 0: if not self.skip_wveval: mult = np.median(np.diff(wa.value)) / self.dw flux = lsc.convolve_psf(flux, self.smooth * mult) else: flux = lsc.convolve_psf(flux, self.smooth) if not self.skip_wveval: self.dla_model = np.interp(wa.value, wa1.value, flux) else: self.dla_model = flux # Finish self.full_model.flux = self.dla_model * self.conti_dict['co'] # Over-absorbed self.spec_widg.bad_model = np.where( (self.dla_model < 0.7) & (self.full_model.flux < (self.spec_widg.spec.flux- self.spec_widg.spec.sig*1.5)))[0] # Model self.spec_widg.model = self.full_model
def update_model(self): '''Update absorption model ''' from linetools.analysis import voigt as lav if len(self.abssys_widg.all_abssys) == 0: self.lls_model = None self.spec_widg.model = None return ''' # Regenerate (in case we have switched between multiple spectra) if self.spec_widg.spec.nspec > 1: self.full_model = XSpectrum1D.from_tuple(( self.spec_widg.spec.wavelength,np.ones(len(self.spec_widg.spec.wavelength)))) ''' # use finer wavelength array to resolve absorption features. wa = self.full_model.wavelength # Angstroms # should really make this a constant velocity width array instead. if not self.skip_wveval: wa1 = np.arange(wa[0].value, wa[-1].value, self.dw) * wa.unit else: wa1 = wa all_tau_model = igmlls.tau_multi_lls(wa1, self.abssys_widg.all_abssys, skip_wveval=self.skip_wveval) # Loop on forest lines for forest in self.all_forest: tau_Lyman = lav.voigt_from_abslines(wa1, forest.lines, ret='tau', skip_wveval=self.skip_wveval) all_tau_model += tau_Lyman # Flux and smooth flux = np.exp(-1. * all_tau_model) if self.smooth > 0: if not self.skip_wveval: mult = np.median(np.diff(wa.value)) / self.dw flux = lsc.convolve_psf(flux, self.smooth * mult) else: flux = lsc.convolve_psf(flux, self.smooth) if not self.skip_wveval: self.lls_model = np.interp(wa.value, wa1.value, flux) else: self.lls_model = flux # Finish self.full_model.flux = self.lls_model * self.continuum.flux # Over-absorbed try: self.spec_widg.bad_model = np.where((self.lls_model < 0.7) & ( self.full_model.flux < (self.spec_widg.spec.flux - self.spec_widg.spec.sig * 1.5)))[0] except: pass # Model self.spec_widg.model = self.full_model
def dla_vary_NHI(outfil='Figures/dla_vary_NHI.pdf'): """ DLA profiles with NHI varying """ # Wavelength array for my 'perfect' instrument wave = np.linspace(1160., 1270., 20000) * u.AA vel = (wave-1215.67*u.AA)/(1215.67*u.AA) * const.c.to('km/s') # Lya line lya = AbsLine(1215.6700*u.AA) #lya.attrib['N'] = 10.**(13.6)/u.cm**2 lya.attrib['b'] = 30 * u.km/u.s lya.attrib['z'] = 0. aNHI = [20.3, 21., 21.5, 22.] # Start the plot xmnx = (-10000, 10000) ymnx = (0., 1.0) pp = PdfPages(outfil) fig = plt.figure(figsize=(8.0, 5.0)) plt.clf() gs = gridspec.GridSpec(1,1) # Lya line ax = plt.subplot(gs[0]) #ax.xaxis.set_minor_locator(plt.MultipleLocator(0.5)) #ax.xaxis.set_major_locator(plt.MultipleLocator(20.)) #ax.yaxis.set_minor_locator(plt.MultipleLocator(0.1)) #ax.yaxis.set_major_locator(plt.MultipleLocator(0.2)) ax.set_xlim(xmnx) ax.set_ylim(ymnx) ax.set_ylabel('Normalized Flux') ax.set_xlabel('Relative Velocity (km/s)') lw = 1.5 # Data for NHI in aNHI: lyai = copy.deepcopy(lya) lyai.attrib['N'] = 10**NHI / u.cm**2 f_obsi = ltav.voigt_from_abslines(wave, [lyai]) ax.plot(vel, f_obsi.flux, linewidth=lw, label=r'$\log N_{\rm HI} = $'+'{:0.2f}'.format(NHI)) # Legend legend = plt.legend(loc='lower left', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='large', numpoints=1) xputils.set_fontsize(ax, 17.) # Layout and save print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2,h_pad=0.0,w_pad=0.4) plt.subplots_adjust(hspace=0) pp.savefig(bbox_inches='tight') plt.close() # Finish pp.close()
def test_voigt_sngl_tau(): # Wavelength array wave = np.linspace(3644, 3650, 100) * u.AA imn = np.argmin(np.abs(wave.value - 3647)) # HI line abslin = AbsLine(1215.670 * u.AA, z=2.) abslin.attrib['N'] = 10**14. / u.cm**2 abslin.attrib['b'] = 25. * u.km / u.s # Tau tau = lav.voigt_from_abslines(wave, abslin, ret='tau') np.testing.assert_allclose(tau[imn], 2.9681283001576779)
def test_voigt_sngl_tau(): # Wavelength array wave = np.linspace(3644, 3650, 100)*u.AA imn = np.argmin(np.abs(wave.value-3647)) # HI line abslin = AbsLine(1215.670*u.AA, z=2.) abslin.attrib['N'] = 10**14./u.cm**2 abslin.attrib['b'] = 25.*u.km/u.s # Tau tau = lav.voigt_from_abslines(wave,abslin,ret='tau') np.testing.assert_allclose(tau[imn], 2.9681283001576779)
def flux_model(self, spec, smooth=0): """ Generate a LLS model given an input spectrum Parameters ---------- spec : Spectrum1D smooth : int, optional Number of pixels to smooth by Returns ------- model : XSpectrum1D Output model is passed back as a Spectrum """ from linetools.analysis import voigt as lav # Energies in LLS rest-frame wv_rest = spec.wavelength / (self.zabs + 1) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau tau_LL = (10.**self.NHI / u.cm**2) * ltaa.photo_cross(1, 1, energy) # Check for lines if 'lls_lines' not in self.__dict__.keys(): self.fill_lls_lines() tau_Lyman = lav.voigt_from_abslines(spec.wavelength, self.lls_lines, ret='tau') # Combine tau_model = tau_LL + tau_Lyman # Kludge around the limit pix_LL = np.argmin(np.fabs(wv_rest - 911.3 * u.AA)) pix_kludge = np.where((wv_rest > 911.5 * u.AA) & (wv_rest < 912.8 * u.AA))[0] tau_model[pix_kludge] = tau_model[pix_LL] # Fill in flux model = spec.copy() model.flux = np.exp(-1. * tau_model).value # Smooth? if smooth > 0: model.gauss_smooth(smooth) # Return return model
def test_voigt_multi_line(): # Wavelength array wave = np.linspace(3644, 3650, 100)*u.AA imn = np.argmin(np.abs(wave.value-3646.2)) # HI line abslin = AbsLine(1215.670*u.AA, z=2.) abslin.attrib['N'] = 10**17.5/u.cm**2 abslin.attrib['b'] = 20.*u.km/u.s # DI line abslin2 = AbsLine('DI 1215', z=2.) abslin2.attrib['N'] = 10**13./u.cm**2 abslin2.attrib['b'] = 15.*u.km/u.s # Voigt vmodel3 = lav.voigt_from_abslines(wave,[abslin,abslin2]) np.testing.assert_allclose(vmodel3.flux[imn].value,0.5715512949324375)
def test_voigt_multi_line(): # Wavelength array wave = np.linspace(3644, 3650, 100) * u.AA imn = np.argmin(np.abs(wave.value - 3646.2)) # HI line abslin = AbsLine(1215.670 * u.AA, z=2.) abslin.attrib['N'] = 10**17.5 / u.cm**2 abslin.attrib['b'] = 20. * u.km / u.s # DI line abslin2 = AbsLine('DI 1215', z=2.) abslin2.attrib['N'] = 10**13. / u.cm**2 abslin2.attrib['b'] = 15. * u.km / u.s # Voigt vmodel3 = lav.voigt_from_abslines(wave, [abslin, abslin2]) np.testing.assert_allclose(vmodel3.flux[imn].value, 0.5715512949324375)
def generate_tau(iwave, HIlines, HI_comps, kludge=True): """Generate optical depth array given lines and components Parameters: ----------- iwave : Quantity array Input Spectrum wavelengths HIlines : list of AbsLines HI_comps : QTable of components kludge : bool, optional Kludge the opacity Returns: -------- tau : ndarray Optical depth at subgrid wavelengths. Will need to rebin back """ # Rebin to subgrid wmin = np.min(iwave.to('AA').value) wmax = np.max(iwave.to('AA').value) nsub = int(np.round((np.log10(wmax) - np.log10(wmin)) / 1.449E-6)) + 1 wave = 10.**(np.log10(wmin) + np.arange(nsub) * 1.449E-6) * u.AA # Voigt for Lyman series tau_Lyman = lav.voigt_from_abslines(wave, HIlines, fwhm=0., ret='tau') # Continuum opacity LL_comps = HI_comps['lgNHI'] > 15.0 tau_LL = np.zeros(wave.size) for row in HI_comps[LL_comps]: # Energies in LLS rest-frame wv_rest = wave / (row['z'] + 1) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau itau_LL = (10.**row['lgNHI'] / u.cm**2) * photo_cross(1, 1, energy) # Kludge around the limit if kludge: pix_LL = np.argmin(np.fabs(wv_rest - 911.3 * u.AA)) pix_kludge = np.where((wv_rest > 911.5 * u.AA) & (wv_rest < 912.8 * u.AA))[0] itau_LL[pix_kludge] = itau_LL[pix_LL] # Sum tau_LL += itau_LL.decompose().value # Total return wave, tau_LL + tau_Lyman
def flux_model(self, spec, smooth=0): """ Generate a LLS model given an input spectrum Parameters ---------- spec : Spectrum1D smooth : int, optional Number of pixels to smooth by Returns ------- model : XSpectrum1D Output model is passed back as a Spectrum """ from linetools.analysis import voigt as lav # Energies in LLS rest-frame wv_rest = spec.dispersion / (self.zabs+1) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau tau_LL = (10.**self.NHI / u.cm**2) * ltaa.photo_cross(1, 1, energy) # Check for lines if 'lls_lines' not in self.__dict__.keys(): self.fill_lls_lines() tau_Lyman = lav.voigt_from_abslines(spec.dispersion, self.lls_lines, ret='tau') # Combine tau_model = tau_LL + tau_Lyman # Kludge around the limit pix_LL = np.argmin(np.fabs( wv_rest- 911.3*u.AA)) pix_kludge = np.where((wv_rest > 911.5*u.AA) & (wv_rest < 912.8*u.AA))[0] tau_model[pix_kludge] = tau_model[pix_LL] # Fill in flux model = spec.copy() model.flux = np.exp(-1. * tau_model).value # Smooth? if smooth > 0: model.gauss_smooth(smooth) # Return return model
def generate_tau(iwave, HIlines, HI_comps, kludge=True): """Generate optical depth array given lines and components Parameters: ----------- iwave : Quantity array Input Spectrum wavelengths HIlines : list of AbsLines HI_comps : QTable of components kludge : bool, optional Kludge the opacity Returns: -------- tau : ndarray Optical depth at subgrid wavelengths. Will need to rebin back """ # Rebin to subgrid wmin = np.min(iwave.to('AA').value) wmax = np.max(iwave.to('AA').value) nsub = int(np.round( (np.log10(wmax)- np.log10(wmin)) / 1.449E-6)) + 1 wave = 10.**(np.log10(wmin) + np.arange(nsub)*1.449E-6) * u.AA # Voigt for Lyman series tau_Lyman = lav.voigt_from_abslines(wave,HIlines,fwhm=0.,ret='tau') # Continuum opacity LL_comps = HI_comps['lgNHI'] > 15.0 tau_LL = np.zeros(wave.size) for row in HI_comps[LL_comps]: # Energies in LLS rest-frame wv_rest = wave / (row['z']+1) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau itau_LL = (10.**row['lgNHI'] / u.cm**2) * photo_cross(1,1,energy) # Kludge around the limit if kludge: pix_LL = np.argmin(np.fabs(wv_rest- 911.3*u.AA)) pix_kludge = np.where((wv_rest > 911.5*u.AA) & (wv_rest < 912.8*u.AA))[0] itau_LL[pix_kludge] = itau_LL[pix_LL] # Sum tau_LL += itau_LL # Total return wave, tau_LL + tau_Lyman
def tau_multi_lls(wave, all_lls, **kwargs): """Calculate opacities on an input observed wavelength grid Parameters ---------- wave : Quantity array Wavelengths all_lls : list List of LLS Class **kwargs : dict extra keywords go to lav.voigt_from_abslines Returns ------- tau : ndarray Optical depth values at input wavelengths """ from linetools.analysis import voigt as lav # all_tau_model = np.zeros(len(wave)) # Loop on LLS for lls in all_lls: # LL wv_rest = wave / (lls.zabs + 1) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau tau_LL = (10.**lls.NHI / u.cm**2) * ltaa.photo_cross(1, 1, energy) # Lyman tau_Lyman = lav.voigt_from_abslines(wave, lls.lls_lines, ret='tau', **kwargs) tau_model = tau_LL + tau_Lyman # Kludge around the limit pix_LL = np.argmin(np.fabs(wv_rest - 911.3 * u.AA)) pix_kludge = np.where((wv_rest > 911.5 * u.AA) & (wv_rest < 912.8 * u.AA))[0] tau_model[pix_kludge] = tau_model[pix_LL] # Add all_tau_model += tau_model # Return return all_tau_model
def tau_multi_lls(wave, all_lls, **kwargs): """Calculate opacities on an input observed wavelength grid Parameters ---------- wave : Quantity array Wavelengths all_lls : list List of LLS Class **kwargs : dict extra keywords go to lav.voigt_from_abslines Returns ------- tau : ndarray Optical depth values at input wavelengths """ from linetools.analysis import voigt as lav # all_tau_model = np.zeros(len(wave)) # Loop on LLS for lls in all_lls: # LL wv_rest = wave / (lls.zabs+1) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau tau_LL = (10.**lls.NHI / u.cm**2) * ltaa.photo_cross(1,1,energy) # Lyman tau_Lyman = lav.voigt_from_abslines(wave, lls.lls_lines, ret='tau', **kwargs) tau_model = tau_LL + tau_Lyman # Kludge around the limit pix_LL = np.argmin(np.fabs( wv_rest- 911.3*u.AA )) pix_kludge = np.where((wv_rest > 911.5*u.AA) & (wv_rest < 912.8*u.AA))[0] tau_model[pix_kludge] = tau_model[pix_LL] # Add all_tau_model += tau_model # Return return all_tau_model
def example_ew(outfil='Figures/example_ew.pdf'): """ A simple example of EW """ # Generate a simple Lya line lya = AbsLine(1215.6700 * u.AA) NHI = 13.6 bval = 30. lya.attrib['N'] = 10.**(NHI) / u.cm**2 lya.attrib['b'] = bval * u.km / u.s lya.attrib['z'] = 0. # Spectrum wave = np.linspace(1180., 1250., 20000) * u.AA f_obs = ltav.voigt_from_abslines(wave, [lya]) f_obs.sig = 0.1 * np.ones(f_obs.npix) # Measure EW lya.analy['spec'] = f_obs lya.analy['wvlim'] = [1210., 1220] * u.AA lya.measure_ew() # Initialize xmnx = (1214.2, 1217.2) ymnx = (-0.05, 1.08) ms = 7. # Start the plot pp = PdfPages(outfil) fig = plt.figure(figsize=(8.5, 3.7)) plt.clf() gs = gridspec.GridSpec(1, 2) # Lya line ax = plt.subplot(gs[0, 0]) #ax.xaxis.set_minor_locator(plt.MultipleLocator(0.5)) #ax.xaxis.set_major_locator(plt.MultipleLocator(20.)) #ax.yaxis.set_minor_locator(plt.MultipleLocator(0.1)) #ax.yaxis.set_major_locator(plt.MultipleLocator(0.2)) ax.set_xlim(xmnx) ax.set_ylim(ymnx) ax.set_ylabel('Normalized Flux') ax.set_xlabel('Wavelength (Angstroms)') lw = 2 ax.plot(f_obs.wavelength, f_obs.flux, 'k', linewidth=lw) ax.fill_between(f_obs.wavelength.value, f_obs.flux.value, np.ones(f_obs.npix), color='blue', alpha=0.7) # Label csz = 12. cNHI = '{:0.1f}'.format(NHI) ax.text(0.05, 0.2, r'$N_{\rm HI} = 10^{' + cNHI + r'} \rm cm^{-2}$', transform=ax.transAxes, size=csz, ha='left') #, bbox={'facecolor':'white'}) ax.text(0.05, 0.12, r'$b = $' + '{:d} km/s'.format(int(bval)), transform=ax.transAxes, size=csz, ha='left') #, bbox={'facecolor':'white'}) ax.text(0.05, 0.04, r'$W_\lambda = $' + '{:0.2f} Ang'.format(lya.attrib['EW'].value), transform=ax.transAxes, size=csz, ha='left') #, bbox={'facecolor':'white'}) # EW panel ax = plt.subplot(gs[0, 1]) ax.set_xlim(xmnx) ax.set_ylim(ymnx) ax.set_ylabel('Normalized Flux') ax.set_xlabel('Wavelength (Angstroms)') xval = [0] + [1215.67 - lya.attrib['EW'].value / 2 ] * 2 + [1215.67 + lya.attrib['EW'].value / 2] * 2 + [1500] ax.plot(xval, [1, 1, 0, 0, 1, 1], 'k', linewidth=lw) ax.fill_between( np.array([lya.attrib['EW'].value / 2] * 2) * np.array([-1, 1]) + 1215.67, [0, 0], [1, 1], color='red', alpha=0.7) # Layout and save print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2, h_pad=0.0, w_pad=0.4) plt.subplots_adjust(hspace=0) pp.savefig(bbox_inches='tight') plt.close() # Finish pp.close()
def dla_vary_NHI(outfil='Figures/dla_vary_NHI.pdf'): """ DLA profiles with NHI varying """ # Wavelength array for my 'perfect' instrument wave = np.linspace(1160., 1270., 20000) * u.AA vel = (wave - 1215.67 * u.AA) / (1215.67 * u.AA) * const.c.to('km/s') # Lya line lya = AbsLine(1215.6700 * u.AA) #lya.attrib['N'] = 10.**(13.6)/u.cm**2 lya.attrib['b'] = 30 * u.km / u.s lya.attrib['z'] = 0. aNHI = [20.3, 21., 21.5, 22.] # Start the plot xmnx = (-10000, 10000) ymnx = (0., 1.0) pp = PdfPages(outfil) fig = plt.figure(figsize=(8.0, 5.0)) plt.clf() gs = gridspec.GridSpec(1, 1) # Lya line ax = plt.subplot(gs[0]) #ax.xaxis.set_minor_locator(plt.MultipleLocator(0.5)) #ax.xaxis.set_major_locator(plt.MultipleLocator(20.)) #ax.yaxis.set_minor_locator(plt.MultipleLocator(0.1)) #ax.yaxis.set_major_locator(plt.MultipleLocator(0.2)) ax.set_xlim(xmnx) ax.set_ylim(ymnx) ax.set_ylabel('Normalized Flux') ax.set_xlabel('Relative Velocity (km/s)') lw = 1.5 # Data for NHI in aNHI: lyai = copy.deepcopy(lya) lyai.attrib['N'] = 10**NHI / u.cm**2 f_obsi = ltav.voigt_from_abslines(wave, [lyai]) ax.plot(vel, f_obsi.flux, linewidth=lw, label=r'$\log N_{\rm HI} = $' + '{:0.2f}'.format(NHI)) # Legend legend = plt.legend(loc='lower left', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='large', numpoints=1) xputils.set_fontsize(ax, 17.) # Layout and save print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2, h_pad=0.0, w_pad=0.4) plt.subplots_adjust(hspace=0) pp.savefig(bbox_inches='tight') plt.close() # Finish pp.close()
def dla_deviation(outfil='Figures/dla_deviation.pdf'): """ Deviations from Voigt (Lee 2003) """ # Wavelength array for my 'perfect' instrument wave = np.linspace(1140., 1290., 20000) * u.AA vel = (wave - 1215.67 * u.AA) / (1215.67 * u.AA) * const.c.to('km/s') nu = (const.c / wave).to('Hz') # Lya line lya = AbsLine(1215.6700 * u.AA) lya.attrib['N'] = 10.**(22) / u.cm**2 lya.attrib['b'] = 30 * u.km / u.s lya.attrib['z'] = 0. # Lee sigmaT = (6.65e-29 * u.m**2).to('cm**2') # Approximate! f_jk = 0.4162 nu_jk = (const.c / lya.wrest).to('Hz') def eval_cross_Lee(nu): return sigmaT * (f_jk / 2)**2 * (nu_jk / (nu - nu_jk))**2 * (1 - 1.792 * (nu - nu_jk) / nu_jk) tau_lee = lya.attrib['N'] * eval_cross_Lee(nu) flux_lee = np.exp(-1 * tau_lee.value) # Start the plot xmnx = (-15000, 15000) ymnx = (0., 1.0) pp = PdfPages(outfil) fig = plt.figure(figsize=(8.0, 5.0)) plt.clf() gs = gridspec.GridSpec(1, 1) # Lya line ax = plt.subplot(gs[0]) #ax.xaxis.set_minor_locator(plt.MultipleLocator(0.5)) #ax.xaxis.set_major_locator(plt.MultipleLocator(20.)) #ax.yaxis.set_minor_locator(plt.MultipleLocator(0.1)) #ax.yaxis.set_major_locator(plt.MultipleLocator(0.2)) ax.set_xlim(xmnx) ax.set_ylim(ymnx) ax.set_ylabel('Normalized Flux') ax.set_xlabel('Relative Velocity (km/s)') f_voigt = ltav.voigt_from_abslines(wave, [lya]) lw = 2 ax.plot(vel, f_voigt.flux, 'k', linewidth=lw, label=r'Voigt: $\log N_{\rm HI} = 22$') ax.plot(vel, flux_lee, 'r', linewidth=lw, label=r'Lee2003: $\log N_{\rm HI} = 22$') # Legend legend = plt.legend(loc='lower left', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='large', numpoints=1) xputils.set_fontsize(ax, 17.) # Layout and save print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2, h_pad=0.0, w_pad=0.4) plt.subplots_adjust(hspace=0) pp.savefig(bbox_inches='tight') plt.close() # Finish pp.close()
def fig_lya_lines(outfil='Figures/fig_lya_lines.pdf'): """ Plot the LLS models Parameters ---------- Returns ------- """ # # Initialize ms = 7. # Start the plot if outfil is not None: pp = PdfPages(outfil) # Dummy line lya = AbsLine(1215.6700 * u.AA) lya.attrib['N'] = 10.**(13.6) / u.cm**2 b0 = 20 lya.attrib['b'] = b0 * u.km / u.s lya.attrib['z'] = 0. # Wavelength array wave = np.linspace(1200., 1230., 10000) * u.AA fig = plt.figure(figsize=(8, 5)) plt.clf() gs = gridspec.GridSpec(1, 2) lsz = 12. # NHI varies first ax = plt.subplot(gs[0]) NHIs = [12., 13., 14., 15.] # Loop for jj, NHI in enumerate(NHIs): lya.attrib['N'] = 10.**(NHI) / u.cm**2 f_obs = ltav.voigt_from_abslines(wave, [lya]) # Plot ax.plot(f_obs.wavelength, f_obs.flux, '-', label=r'log $N_{\rm HI}$ ' + '= {:g}'.format(NHI)) legend = plt.legend(loc='upper right', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='small', numpoints=1, title=r'$b = $' + '{:g} km/s'.format(b0)) ax.xaxis.set_major_locator(plt.MultipleLocator(1.)) ax.xaxis.set_major_locator(MaxNLocator(integer=True)) x_formatter = mpl.ticker.ScalarFormatter(useOffset=False) ax.xaxis.set_major_formatter(x_formatter) ax.minorticks_on() ax.set_xlabel('Wavelength (Ang)') ax.set_xlim(1214.8, 1216.6) ax.set_ylabel('Normalized Flux') # Now b ax = plt.subplot(gs[1]) N0 = 14. lya.attrib['N'] = 10.**(N0) / u.cm**2 bvals = [10., 30., 50.] # Loop for jj, bval in enumerate(bvals): lya.attrib['b'] = bval * u.km / u.s f_obs = ltav.voigt_from_abslines(wave, [lya]) # Plot velo = f_obs.relative_vel(lya.wrest) ax.plot(velo, f_obs.flux, '-', label=r'log $N_{\rm HI}$ ' + '= {:g}'.format(NHI)) #ax.plot(f_obs.wavelength, f_obs.flux, '-', label=r'$b$ '+'= {:g} km/s'.format(bval)) legend = plt.legend(loc='lower right', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='small', numpoints=1, title=r'log $N_{\rm HI} =$' + '{:g}'.format(N0)) ax.set_xlabel('Relative Velocity (km/s)') ax.set_xlim(-150., 150.) ax.set_ylabel('Normalized Flux') # Layout and save print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2, h_pad=0.1, w_pad=0.2) pp.savefig(bbox_inches='tight') plt.close() # Finish pp.close()
def fig_lya_lines(outfil='Figures/fig_lya_lines.pdf'): """ Plot the LLS models Parameters ---------- Returns ------- """ # # Initialize ms = 7. # Start the plot if outfil is not None: pp = PdfPages(outfil) # Dummy line lya = AbsLine(1215.6700*u.AA) lya.attrib['N'] = 10.**(13.6)/u.cm**2 b0 = 20 lya.attrib['b'] = b0 * u.km/u.s lya.attrib['z'] = 0. # Wavelength array wave = np.linspace(1200., 1230., 10000) * u.AA fig = plt.figure(figsize=(8, 5)) plt.clf() gs = gridspec.GridSpec(1, 2) lsz = 12. # NHI varies first ax = plt.subplot(gs[0]) NHIs = [12., 13., 14., 15.] # Loop for jj, NHI in enumerate(NHIs): lya.attrib['N'] = 10.**(NHI)/u.cm**2 f_obs = ltav.voigt_from_abslines(wave, [lya]) # Plot ax.plot(f_obs.wavelength, f_obs.flux, '-', label=r'log $N_{\rm HI}$ '+'= {:g}'.format(NHI)) legend = plt.legend(loc='upper right', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='small', numpoints=1, title=r'$b = $'+'{:g} km/s'.format(b0)) ax.xaxis.set_major_locator(plt.MultipleLocator(1.)) ax.xaxis.set_major_locator(MaxNLocator(integer=True)) x_formatter = mpl.ticker.ScalarFormatter(useOffset=False) ax.xaxis.set_major_formatter(x_formatter) ax.minorticks_on() ax.set_xlabel('Wavelength (Ang)') ax.set_xlim(1214.8, 1216.6) ax.set_ylabel('Normalized Flux') # Now b ax = plt.subplot(gs[1]) N0 = 14. lya.attrib['N'] = 10.**(N0)/u.cm**2 bvals = [10., 30., 50.] # Loop for jj, bval in enumerate(bvals): lya.attrib['b'] = bval*u.km/u.s f_obs = ltav.voigt_from_abslines(wave, [lya]) # Plot velo = f_obs.relative_vel(lya.wrest) ax.plot(velo, f_obs.flux, '-', label=r'log $N_{\rm HI}$ '+'= {:g}'.format(NHI)) #ax.plot(f_obs.wavelength, f_obs.flux, '-', label=r'$b$ '+'= {:g} km/s'.format(bval)) legend = plt.legend(loc='lower right', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='small', numpoints=1, title=r'log $N_{\rm HI} =$'+'{:g}'.format(N0)) ax.set_xlabel('Relative Velocity (km/s)') ax.set_xlim(-150., 150.) ax.set_ylabel('Normalized Flux') # Layout and save print('Writing {:s}'.format(outfil)) plt.tight_layout(pad=0.2,h_pad=0.1,w_pad=0.2) pp.savefig(bbox_inches='tight') plt.close() # Finish pp.close()
def __init__(self, ispec, guessfile=None, parent=None, zsys=None, norm=None, exten=None, rsp_kwargs={}, unit_test=False, screen_scale=1., **kwargs): QMainWindow.__init__(self, parent) """ ispec = str, XSpectrum1D or tuple of arrays Input spectrum or spectrum filename. If tuple then (wave, fx), (wave, fx, sig) or (wave, fx, sig, co) guessfile : str, optional name of the .json file generated with igmguesses GUI in Pyigm (see https://github.com/pyigm/pyigm/blob/master/docs/igmguesses.rst) if not None - overplot fitted line profiles from igmguesses parent : Widget parent, optional zsys : float, optional intial redshift exten : int, optional extension for the spectrum in multi-extension FITS file norm : bool, optional True if the spectrum is normalized screen_scale : float, optional Scale the default sizes for the gui size """ #reload(ltgl) #reload(ltgsp) # INIT #QtCore.pyqtRemoveInputHook() #xdb.set_trace() #QtCore.pyqtRestoreInputHook() self.scale = screen_scale # Needed to avoid crash in large spectral files rcParams['agg.path.chunksize'] = 20000 rcParams[ 'axes.formatter.useoffset'] = False # avoid scientific notation in axes tick labels # Build a widget combining several others self.main_widget = QWidget() # Status bar self.create_status_bar() # Grab the pieces and tie together self.pltline_widg = ltgl.PlotLinesWidget(status=self.statusBar, init_z=zsys, screen_scale=self.scale) self.pltline_widg.setMaximumWidth(300 * self.scale) ## Abs sys abs_sys = None voigtsfit = None if guessfile is not None: # Load ism = LineList('ISM') igm_guess = ltu.loadjson(guessfile) comps = [] for key in igm_guess['cmps'].keys(): comp = AbsComponent.from_dict(igm_guess['cmps'][key], chk_vel=False, linelist=ism) comps.append(comp) abs_sys = ltiu.build_systems_from_components( comps, vsys=500. * u.km / u.s) # ,chk_z=False) ### 100000.*u.km/u.s ok ### voigt fit - added # Spectrum spec, spec_fil = ltgu.read_spec(ispec, exten=exten, norm=norm, rsp_kwargs=rsp_kwargs) voigtsfit = np.asarray([0] * len(spec.wavelength)) alllines = [] for iabs_sys in abs_sys: lines = iabs_sys.list_of_abslines() alllines = alllines + lines if len(alllines) > 0: voigtsfit = lav.voigt_from_abslines(spec.wavelength, alllines, fwhm=3.).flux.value if not norm: voigtsfit = voigtsfit * spec.co # Hook the spec widget to Plot Line self.spec_widg = ltgsp.ExamineSpecWidget(ispec, guessfile=guessfile, voigtsfit=voigtsfit, status=self.statusBar, parent=self, llist=self.pltline_widg.llist, zsys=zsys, norm=norm, exten=exten, abs_sys=abs_sys, screen_scale=self.scale, rsp_kwargs=rsp_kwargs, **kwargs) # Reset redshift from spec if zsys is None: if hasattr(self.spec_widg.spec, 'z'): self.pltline_widg.setz( str(self.spec_widg.spec.z[self.spec_widg.select])) # Auto set line list if spec has proper object type if hasattr(self.spec_widg.spec, 'stypes'): if self.spec_widg.spec.stypes[ self.spec_widg.select].lower() == 'galaxy': self.pltline_widg.llist = ltgu.set_llist( 'Galaxy', in_dict=self.pltline_widg.llist) elif self.spec_widg.spec.stypes[ self.spec_widg.select].lower() == 'absorber': self.pltline_widg.llist = ltgu.set_llist( 'Strong', in_dict=self.pltline_widg.llist) self.pltline_widg.llist['Plot'] = True idx = self.pltline_widg.lists.index( self.pltline_widg.llist['List']) self.pltline_widg.llist_widget.setCurrentRow(idx) # self.pltline_widg.spec_widg = self.spec_widg # Multi spec self.mspec_widg = ltgsp.MultiSpecWidget(self.spec_widg) self.spec_widg.canvas.mpl_connect('button_press_event', self.on_click) # Layout # Extras extras = QWidget() extras.setMinimumWidth(180 * self.scale) extras.setMaximumWidth(280 * self.scale) vbox = QVBoxLayout() qbtn = QPushButton(self) qbtn.setText('Quit') qbtn.clicked.connect(self.quit) vbox.addWidget(self.pltline_widg) vbox.addWidget(self.mspec_widg) vbox.addWidget(qbtn) extras.setLayout(vbox) # Main window hbox = QHBoxLayout() hbox.addWidget(self.spec_widg) hbox.addWidget(extras) self.main_widget.setLayout(hbox) # Point MainWindow self.setCentralWidget(self.main_widget) if unit_test: self.quit()
def redshift(outfil='Figures/redshift.pdf'): """ Series of plots illustrating redshift in the Lya forest """ lrest = np.array([900., 1250]) # Ang zem = 3. toff = 0.15 yqso = 0.7 sqso = 35 # QSO lines qsolya = AbsLine(1215.6700 * u.AA) qsolya.attrib['N'] = 10.**(16.0) / u.cm**2 qsolya.attrib['b'] = 40 * u.km / u.s qsolya.attrib['z'] = zem qsolyb = AbsLine('HI 1025') qsolyb.attrib['N'] = qsolya.attrib['N'] qsolyb.attrib['b'] = qsolya.attrib['b'] qsolyb.attrib['z'] = qsolya.attrib['z'] def tick_function(z, X): V = X * (1 + z) return ["{:d}".format(int(round(x))) for x in V] def add_lines(axi, z): wvtwo = (1 + z) * 1215.67 / (1 + zem) axi.scatter([wvtwo], [yqso], marker='o', facecolor='none', edgecolor='green', s=sqso * 5) axi.text(wvtwo, yqso - 1.7 * toff, 'HI Gas (z={:0.1f})'.format(z), color='green', ha='center') # twolya = copy.deepcopy(qsolya) twolya.attrib['z'] = z twolyb = copy.deepcopy(qsolyb) twolyb.attrib['z'] = z return [twolya, twolyb] # Telfer telfer = pyicq.get_telfer_spec() # Start the plot pp = PdfPages(outfil) scl = 1.0 fig = plt.figure(figsize=(8.0 * scl, 5.0 * scl)) plt.clf() gs = gridspec.GridSpec(5, 1) jet = cm = plt.get_cmap('jet') # Loop for qq in range(9): # Cartoon ax0 = plt.subplot(gs[0, 0]) ax0.set_xlim(lrest) ax0.set_ylim(0., 1.) ax0.set_frame_on(False) ax0.axes.get_yaxis().set_visible(False) ax0.axes.get_xaxis().set_visible(False) # QSO ax0.scatter([1215.67], [yqso], marker='o', facecolor='blue', s=sqso) ax0.text(1215.67, yqso + toff, 'Quasar (z=3)', color='blue', ha='center') # Redshifted light if qq > 0: light = np.linspace(1215.67, lrest[0], 20) ax0.scatter(light, [yqso] * len(light), marker='_', s=40, cmap=cm, c=1. / light) # Gas at QSO if qq > 1: ax0.scatter([1215.67], [yqso], marker='o', facecolor='none', edgecolor='green', s=sqso * 5) ax0.text(1215.67, yqso - 1.7 * toff, 'HI Gas (z=3)', color='green', ha='center') # Spectrum ax = plt.subplot(gs[1:, 0]) ax.set_xlim(lrest) #ax.set_ylim(ymnx) ax.set_ylabel('Relative Flux') ax.set_xlabel("Rest Wavelength") if qq < 3: tsty = 'k' else: tsty = 'b:' ax.plot(telfer.wavelength, telfer.flux, tsty) # Observer frame axis if qq > 0: ax2 = ax.twiny() ax2.set_xlim(ax.get_xlim()) xtcks = ax.get_xticks() ax2.set_xticks(xtcks) ax2.set_xticklabels(tick_function(zem, xtcks)) ax2.set_xlabel('Observed Wavelength (Angstroms)') # Absorption lines abslines = [] if (qq > 2) and (qq != 8): # Lya at zem abslines.append(qsolya) if qq > 3: # Lyb at zem abslines.append(qsolyb) # Gas at z=2.8 if qq > 4: zadd = 2.8 abslines += add_lines(ax0, zadd) # Gas at z=2.5 if qq > 5: zadd = 2.5 abslines += add_lines(ax0, zadd) if qq > 6: zadd = 2.2 abslines += add_lines(ax0, zadd) # abs_model = ltav.voigt_from_abslines(telfer.wavelength * (1 + zem), abslines) #ax.plot(telfer.wavelength, telfer.flux*abs_model.flux, 'k') ax.plot(telfer.wavelength, telfer.flux.value * abs_model.flux, 'k') # Final plot if qq == 8: nlin = 100 dotwv = np.linspace(900, 1215., nlin) ax0.scatter(dotwv, [yqso] * nlin, marker='o', facecolor='none', edgecolor='green', s=sqso * 5) # Mock spectrum fN_model = FNModel.default_model() gdp = np.where(telfer.wavelength > 900. * u.AA)[0] mock_spec, HI_comps, misc = pyimock.mk_mock( telfer.wavelength[gdp] * (1 + zem), zem, fN_model, s2n=100., fwhm=3, add_conti=False) ax.plot(telfer.wavelength[gdp], telfer.flux[gdp].value * mock_spec.flux, 'k') # Layout and save plt.tight_layout(pad=0.2, h_pad=0.0, w_pad=0.4) plt.subplots_adjust(hspace=0) pp.savefig(bbox_inches='tight', transparent=True) plt.close() # Finish print('Writing {:s}'.format(outfil)) pp.close() return mock_spec
def hi_model(abssys, spec, lya_only=False, add_lls=False, ret_tau=False, ignore_abslines=False, bval=30 * u.km / u.s, **kwargs): """ Generate a model of the absorption from the absorption system on an input spectrum. Parameters ---------- abssys : AbsSystem or list If list, must be a list of AbsSystem's spec : XSpectrum1D lya_only : bool, optional Only generate Lya ignore_abslines : bool, optional Ignore any existing abslines in the object NHI tag must be set add_lls : bool, optional Add Lyman continuum absorption bval : Quantity, optional Doppler parameter to use if abslines not adopted ret_tau : bool, optional Return only the optical depth (used for multiple systems) kwargs : Passed to voigt_from_abslines Returns ------- vmodel : XSpectrum1D or ndarray Model spectrum with same wavelength as input spectrum Assumes a normalized flux Or optical depth array [used for multiple systems] lyman_lines : list List of AbsLine's that contributed to the model """ from astropy.units import Quantity from linetools.spectra.xspectrum1d import XSpectrum1D from linetools.spectralline import AbsLine from linetools.analysis.voigt import voigt_from_abslines from linetools.analysis.absline import photo_cross # Input if isinstance(abssys, list): tau = None all_lines = [] for iabssys in abssys: itau, ly_lines = hi_model(iabssys, spec, lya_only=lya_only, add_lls=add_lls, ignore_abslines=ignore_abslines, bval=bval, ret_tau=True, **kwargs) all_lines += ly_lines if tau is None: tau = itau else: tau += itau # Flux flux = np.exp(-1 * tau) vmodel = XSpectrum1D.from_tuple((spec.wavelength, flux)) return vmodel, all_lines else: # Scan abs lines if not ignore_abslines: alines = [] else: alines = abssys.list_of_abslines() lyman_lines = [] lya_lines = [] logNHIs = [] # Scan alines for aline in alines: # Lya if aline.name == 'HI 1215': lya_lines.append(aline) logNHIs.append(np.log10(aline.attrib['N'].value)) # Any HI if 'HI' in aline.name: lyman_lines.append(aline) if len(lya_lines) > 0: # Use the lines # Check we have a DLA worth if np.log10(np.sum(10**np.array(logNHIs))) < abssys.NHI: raise ValueError( "Total NHI of the Lya lines is less than NHI of the system! Something is wrong.." ) else: # Generate one warnings.warn( "Generating the absorption lines from the system info, not abslines" ) if lya_only: lya_line = AbsLine('HI 1215', z=abssys.zabs) lya_line.attrib['N'] = 10**abssys.NHI / u.cm**2 lya_line.attrib['b'] = bval lyman_lines.append(lya_line) else: HIlines = LineList('HI') wrest = Quantity(HIlines._data['wrest']) for iwrest in wrest: # On the spectrum? if iwrest >= spec.wvmin / (1 + abssys.zabs): lyman_line = AbsLine(iwrest, linelist=HIlines, z=abssys.zabs) lyman_line.attrib['N'] = 10**abssys.NHI / u.cm**2 lyman_line.attrib['b'] = bval lyman_lines.append(lyman_line) # tau for abs lines if len(lyman_lines) == 0: pdb.set_trace() tau_Lyman = voigt_from_abslines(spec.wavelength, lyman_lines, ret='tau', **kwargs) # LLS? if add_lls: wv_rest = spec.wavelength / (1 + abssys.zabs) energy = wv_rest.to(u.eV, equivalencies=u.spectral()) # Get photo_cross and calculate tau tau_LL = (10.**abssys.NHI / u.cm**2) * photo_cross(1, 1, energy) # Kludge pix_LL = np.argmin(np.fabs(wv_rest - 911.3 * u.AA)) pix_kludge = np.where((wv_rest > 911.3 * u.AA) & (wv_rest < 913.0 * u.AA))[0] tau_LL[pix_kludge] = tau_LL[pix_LL] tau_Lyman[pix_kludge] = 0. # Generate the spectrum else: tau_LL = 0. # Sum tau_tot = tau_LL + tau_Lyman if ret_tau: vmodel = tau_tot else: flux = np.exp(-1 * tau_tot) vmodel = XSpectrum1D.from_tuple((spec.wavelength, flux)) # Return return vmodel, lyman_lines
abslin.attrib['N'] = 10**17.5 / u.cm**2 abslin.attrib['b'] = 20. * u.km / u.s wave = np.linspace(3644, 3650, 100) * u.AA vmodel2 = abslin.generate_voigt(wave=wave) plt_line(vmodel2) abslin2 = AbsLine('DI 1215') abslin2.attrib['N'] = 10**13. / u.cm**2 # log N abslin2.attrib['b'] = 15. * u.km / u.s abslin2.attrib['z'] = 2.0 vmodel3 = lav.voigt_from_abslines(wave, [abslin, abslin2]) plt_line(vmodel3) tau = lav.voigt_from_abslines(wave, abslin, ret='tau') plt.plot(wave, tau, 'k-', drawstyle='steps-mid', lw=1.5) plt.xlim(3642., 3652.) plt.ylim(0., 15000.) plt.ylabel('Optical Depth', fontsize=20.) plt.xlabel('Wavelength', fontsize=20.) plt.show() plt.close() from astropy.modeling import fitting
def fig_lya_line(lw=1.5, csz=15.): """ Generate a DLA in optical depth and flux space Parameters ---------- """ llist = LineList('ISM') # Lya lya = AbsLine('HI 1215', z=0., llist=llist) # Wavelength wave = np.linspace(1100., 1310., 100000)*u.AA outfile = 'fig_lya_line.png' # Figure plt.figure(figsize=(8, 4)) plt.clf() gs = gridspec.GridSpec(1, 2) # Tau plot ax1 = plt.subplot(gs[0]) # Optical depth lya.attrib['N'] = 1e21 / u.cm**2 lya.attrib['b'] = 20 * u.km/u.s tau = voigt_from_abslines(wave, lya, ret='tau') # Plot ax1.plot(wave, tau, 'g') # Axes ax1.set_xlim(1200., 1230.) ax1.set_ylim(1e-2, 5e7) ax1.set_yscale("log", nonposy='clip') ax1.set_ylabel(r'Optical Depth for $N_{\rm HI} = 10^{21} \, \rm cm^{-2}$') ax1.set_xlabel(r'Wavelength ($\AA$)') ax1.xaxis.set_major_locator(plt.MultipleLocator(10.)) # set_spines(ax1, 2.) set_fontsize(ax1,csz) # Flux space ax2 = plt.subplot(gs[1]) for logN in [19., 20., 21., 22.]: lya.attrib['N'] = 10**logN / u.cm**2 spec = voigt_from_abslines(wave, lya) # Plot ax2.plot(spec.wavelength, spec.flux, label=r'$\log N_{\rm HI} = $'+'{:d}'.format(int(logN))) # Axes wvoff = 100. ax2.set_xlim(1215.-wvoff, 1215.+wvoff) ax2.set_ylim(-0.05, 1.1) #ax2.set_yscale("log", nonposy='clip') ax2.set_ylabel('Normalized Flux') ax2.set_xlabel(r'Wavelength ($\AA$)') ax2.xaxis.set_major_locator(plt.MultipleLocator(50.)) # set_spines(ax2, 2.) set_fontsize(ax2,csz) legend = ax2.legend(loc='lower left', scatterpoints=1, borderpad=0.3, handletextpad=0.3, fontsize='small', numpoints=1) # Write plt.tight_layout(pad=0.2,h_pad=0.,w_pad=0.1) plt.savefig(outfile, dpi=750) plt.close() print("Wrote {:s}".format(outfile))