def vel_moment(spec, restlam, zabs, vellim=[-50, 50]): wave = spec.wavelength.value flux = spec.flux.value sig = spec.sig.value cont = spec.co conterr = np.zeros_like(sig) # Continuum errors will be garbage EWpix, sigEWf, sigEWc, Npix, sigNf, sigNc = EW_ACD_array(wave, flux, sig, cont, conterr, restlam, zabs, vellim=vellim) ### Transform to velocity space vel = joebgoodies.veltrans(zabs, wave, restlam) velidx = np.where((vel >= vellim[0]) & (vel <= vellim[1]))[0] ### Calculate moments moment0 = np.sum(Npix) moment1 = np.sum(vel[velidx] * Npix) ### Mean velocity meanv = moment1 / moment0 return meanv
def vel_moment_fitcont(wave, flux, sig, restlam, zabs, continuumregions, vellim=[-50, 50], **kwargs): ### Fit the continuum in the line-free regions wave, cont, conterr = contFitLegendreAboutLine(wave, flux, sig, restlam, zabs, continuumregions, **kwargs) EWpix, sigEWf, sigEWc, Npix, sigNf, sigNc = EW_ACD_array(wave, flux, sig, cont, conterr, restlam, zabs, vellim=vellim) ### Transform to velocity space vel = joebgoodies.veltrans(zabs, wave, restlam) velidx = np.where((vel >= vellim[0]) & (vel <= vellim[1]))[0] velup = vel[velidx + 1] veldown = vel[velidx] ### Calculate moments moment0 = np.sum(Npix) moment1 = np.sum(vel[velidx] * Npix) ### Mean velocity meanv = moment1 / moment0 return meanv
def fitpix(wave,pararr): # define bad pixels cfg.bad_pixels = update_bad_pixels() # this variable stores the indices of bad pixels ll=pararr[0] lz=pararr[3] lv1=pararr[5] lv2=pararr[6] relpix=[] for i in range(len(ll)): vels=jbg.veltrans(lz[i],wave,ll[i]) #w1=ll[i]*(1.+lz[i]+lv1[i]/c) #w2=ll[i]*(1.+lz[i]+lv2[i]/c) #p1=jbg.closest(wave,w1) #p2=jbg.closest(wave,w2) p1=jbg.closest(vels,lv1[i]) p2=jbg.closest(vels,lv2[i]) if ((p1>=10) & (p2<=(len(wave)-1-10))): relpix.extend(range(p1-10,p2+10)) elif (p1<10): relpix.extend(range(0, p2 + 10)) else: relpix.extend(range(p1 - 10, len(wave)-1)) rp = np.unique(np.array(relpix)) clean_rp = np.array([i for i in rp if i not in cfg.bad_pixels]) return clean_rp
def fitpix(wave,pararr,find_bad_pixels=True): if find_bad_pixels: # define bad pixels cfg.bad_pixels = update_bad_pixels() # this variable stores the indices of bad pixels else: cfg.bad_pixels = [] ll=pararr[0] lz=pararr[3] lv1=pararr[5] lv2=pararr[6] relpix=[] for i in range(len(ll)): vels=jbg.veltrans(lz[i],wave,ll[i]) p1=jbg.closest(vels,lv1[i]) p2=jbg.closest(vels,lv2[i]) if ((p1>=10) & (p2<=(len(wave)-1-10))): relpix.extend(range(p1-10,p2+10)) elif (p1<10): relpix.extend(range(0, p2 + 10)) else: relpix.extend(range(p1 - 10, len(wave)-1)) rp = np.unique(np.array(relpix)) clean_rp = np.array([i for i in rp if i not in cfg.bad_pixels]) return clean_rp
def fitpix(wave, pararr, find_bad_pixels=True): if find_bad_pixels: # define bad pixels cfg.bad_pixels = update_bad_pixels( ) # this variable stores the indices of bad pixels else: cfg.bad_pixels = [] ll = pararr[0] lz = pararr[3] lv1 = pararr[5] lv2 = pararr[6] relpix = [] for i in range(len(ll)): vels = jbg.veltrans(lz[i], wave, ll[i]) p1 = jbg.closest(vels, lv1[i]) p2 = jbg.closest(vels, lv2[i]) if ((p1 >= 10) & (p2 <= (len(wave) - 1 - 10))): relpix.extend(range(p1 - 10, p2 + 10)) elif (p1 < 10): relpix.extend(range(0, p2 + 10)) else: relpix.extend(range(p1 - 10, len(wave) - 1)) rp = np.unique(np.array(relpix)) clean_rp = np.array([i for i in rp if i not in cfg.bad_pixels]) if len(clean_rp) > 1: # Matt and Kirill trimming off tiny pixel patches max_index_jump = 4 # this is called buf in makevoigt min_group_size = 5 last_idx = clean_rp[0] group_idxs = [last_idx] really_clean_rp = [] for idx in clean_rp[1:]: jump = idx - last_idx if jump <= max_index_jump: group_idxs.append(idx) else: if len(group_idxs) >= min_group_size: really_clean_rp.extend(group_idxs) group_idxs = [idx] # start a new group last_idx = idx if len(group_idxs) >= min_group_size: really_clean_rp.extend(group_idxs) return np.array(really_clean_rp, dtype=int) else: return clean_rp
def contFitLegendreAboutLine(wave, flux, err, restlam, z, velfitregions, uniform=True, **kwargs): ''' Fits a continuum over a spectral region using the formalism of Sembach & Savage 1992, estimating the uncertainty at each point of the continuum. Parameters ---------- wave flux err restlam z velfitregions uniform Returns ------- ''' vels = joebgoodies.veltrans(z, wave, restlam) ### Find indices corresponding to velocities defined in velfitregions fitidxs = [] for reg in velfitregions: thesevels = np.where((vels >= reg[0]) & (vels <= reg[1]))[0] fitidxs.extend(thesevels) if uniform != True: fitsol, err, parsol, errmtx, scalefac = fitLegendre(vels[fitidxs], flux[fitidxs], sig=err[fitidxs], **kwargs) else: fitsol, err, parsol, errmtx, scalefac = fitLegendre( vels[fitidxs], flux[fitidxs], **kwargs) ### Normalize x so that domain of fit is -1 to +1 vscale = vels / scalefac # must scale to fitted domain ### Evaluate continuum using all points, not just those in fit regions continuum = L.legval(vels / scalefac, parsol) err = errorsLegendre(vscale, errmtx) return wave, continuum, err
def EW_ACD_array(wave, flux, ferr, cont, conterr, restlam, zabs, vellim=[-50, 50], **kwargs): ''' Returns arrays of equivalent width and apparent column density per pixel as well as their associated uncertainties due to continuum placement and flux errors. Parameters ---------- wave: 1D float array flux: 1D float array ferr: 1D float array Error in flux cont: 1D float array Continuum fitted to data such as that from contFitLegendreAboutLine() conterr: 1D float array Uncertainty in continuum placement at each pixel restlam: float Rest-frame wavelength of transition to measure zabs: float Redshift of the the absorption system vellim: 2-element list Lower and upper bounds over which to compute arrays Returns ------- EWpix: 1D float array Equivalent width in each pixel sigEWf: 1D float array EW uncertainty in each pixel due to flux errors sigEWc: 1D float array EW uncertainty in each pixel due to continuum placement errors Npix: 1D float array Apparent column density * dv (N) in each pixel sigNf: 1D float array Uncertainty in N due to flux errors sigNc: 1D float array Uncertainty in N due to continuum placement errors ''' ### Set atomic data and constants c = 299792.458 restlam = ad.closestlam([restlam]) osc = ad.lam2osc([restlam]) ### Transform to velocity space vel = joebgoodies.veltrans(zabs, wave, restlam) velidx = np.where((vel >= vellim[0]) & (vel <= vellim[1]))[0] velup = vel[velidx + 1] veldown = vel[velidx] dv = np.abs(velup - veldown) ### Identify pixels where flux level is below noise level & replace w/noise effflux = flux belowerr = np.where(flux < ferr)[0] effflux[belowerr] = ferr[belowerr] ### Calculate EW and errors due to flux and continuum placement print(dv, effflux[velidx], cont[velidx], restlam, c) EWpix = dv * (1. - effflux[velidx] / cont[velidx]) * restlam / c sigEWf = dv / cont[velidx] * ferr[velidx] * restlam / c sigEWc = dv * restlam / c * effflux[velidx] / cont[velidx]**2 * conterr[ velidx] # Will not be added in quad. ### Calculate optical depth and uncertainty due to flux and continuum tauv = np.log(cont[velidx] / (effflux[velidx])) tauverr_f = ferr[velidx] / effflux[velidx] tauverr_c = conterr[velidx] / cont[velidx] Npix = 1. / 2.654e-15 / restlam / osc * dv * tauv sigNf = 1. / 2.654e-15 / restlam / osc * dv * tauverr_f sigNc = 1. / 2.654e-15 / restlam / osc * dv * tauverr_c return EWpix, sigEWf, sigEWc, Npix, sigNf, sigNc