def womreddening(hop): """redden or deredden with various reddening laws""" import matplotlib.pyplot as plt import extinction from tmath.wombat.inputter_single import inputter_single from tmath.wombat.inputter import inputter from tmath.wombat.yesno import yesno r_v=3.1 print('Redden or deredden a spectrum') plt.cla() plt.plot(hop[0].wave,hop[0].flux,drawstyle='steps-mid',color='k') plt.xlabel('Wavelength') plt.ylabel('Flux') plt.title(hop[0].obname) flux=hop[0].flux.copy() action=inputter_single('(r)edden or (d)eredden the spectrum? (r/d) ', 'rd') print(' ') type=inputter_single('Do you want to enter the (c)olor excess, or (v)isual extinction? ','cv') print(' ') if (type == 'v'): av=inputter('Enter A_V in magnitudes: ','float',False) else: ebv=inputter('Enter E(B-V) in magnitudes: ','float',False) av=r_v*ebv print(' ') print('Do you want to use: ') print('(c)ardelli, Clayton, Mathis 1989') print("(o)'donnell 1994") print('(f)itzpatrick 1999\n') method=inputter_single('(c/o/f) ','cof') if (action == 'r'): if (method == 'c'): newflux=extinction.apply(extinction.ccm89(hop[0].wave,av,r_v),flux) elif (method == 'o'): newflux=extinction.apply(extinction.odonnell94(hop[0].wave,av,r_v),flux) else: newflux=extinction.apply(extinction.fitzpatrick99(hop[0].wave,av,r_v),flux) else: if (method == 'c'): ext=extinction.ccm89(hop[0].wave,av,r_v) elif (method == 'o'): ext=extinction.odonnell94(hop[0].wave,av,r_v) else: ext=extinction.fitzpatrick99(hop[0].wave,av,r_v) newflux=flux*10**(0.4*ext) plt.plot(hop[0].wave,newflux,drawstyle='steps-mid',color='r') print('\nOriginal spectrum in black, red/dered in red\n') print('Is this OK?\n') answer=yesno('y') if (answer == 'y'): hop[0].flux=newflux.copy() print('\nActive spectrum now changed') else: print('\nSorry to disappoint you, active spectrum unchanged') return hop
def deredden_df(tb, ebv): """ perform extinction correction """ if 'mag' in tb.columns: tb['mag0'] = tb['mag'] - extinction.ccm89( tb['wave'].values, 3.1 * ebv, 3.1) # extinction in magnitude if "limmag" in tb.columns: tb['limmag0'] = tb["limmag"] - extinction.ccm89( tb['wave'].values, 3.1 * ebv, 3.1) # extinction in magnitude return tb
def Mdot_to_UbandExcess(Mdot, dist, mass, radius, Av, Rin=5, unc=False): ''' This function will transform a mass accretion rate estimate into a U band flux value by following the process described in Robinson 2019. Inputs: Mdot - mass accretion rate [Msun/yr] dist - distance to object [pc] mass - mass of object [Msun] radius - radius of object [Rsun] Optional: Rin - magnetospheric radius (default 5 [Rsun]) Outputs: Uexcess - U band continuum excess flux [erg/(s*cm^2)] ''' #Mdot to accretion luminosity Lacc = Mdot_to_Lacc(Mdot, mass, radius, Rin) #ln Lacc logLacc = np.log(Lacc) #Lacc to Lu using Robinson paper -- natural logarithms #uncertainties 0.03 for each constant if unc == False: logLu = (logLacc - 0.5) / 0.93 else: logLu = (logLacc - (0.5 + np.random.normal(0.03))) / (0.93 + np.random.normal(0.03)) Lu = np.exp(logLu) #convert Lu to erg/s Lu = Lu * const.L_sun.to('erg/s').value #Lu to U-band flux Uexcess = luminosity_to_flux(Lu, dist) #extinction correction of flux #reddening law to U-band if type(Av) == float: Au = ex.ccm89(np.array([3650.0]), Av, 3.1)[0] elif type(Av) == list or type(Av) == np.ndarray: Au = [] for av in Av: Au.append(ex.ccm89(np.array([3650.0]), av, 3.1)[0]) Au = np.array(Au) #extinction correction redU = ex.apply(Au, Uexcess) return redU
def extract_spec(data, ebv=0, RV=3.1): mask = data["AND_MASK"].data > 0 logwave_obs = data["LOGLAM"].astype(float).data spec = data["FLUX"].astype(float).data spec[mask] = np.nan spec_ivar = data["IVAR"].astype(float).data spec_ivar[mask] = np.nan spec_off = data["MODEL"].astype(float).data # spec = np.ma.masked_array(data["FLUX"].astype(float).data, mask=mask) # spec_off = np.ma.masked_array(data["MODEL"].astype(float).data, mask=mask) # spec_ivar = np.ma.masked_array(data["IVAR"].astype(float).data, mask=mask) if ebv > 0: extinction_sed = ebv * extinction.ccm89( 10**logwave_obs, 1.0, RV, unit="aa") spec = extinction.remove(extinction_sed, spec) spec_off = extinction.remove(extinction_sed, spec_off) spec_ivar = extinction.apply(extinction_sed, spec_ivar) # ind = np.isfinite(logwave_obs) # ind &= np.isfinite(spec) # ind &= np.isfinite(spec_ivar) # ind &= np.isfinite(spec_off) return logwave_obs, spec, spec_ivar, spec_off
def apply_dust(self): import extinction for ii in range(self.n_zz): if self.dust['flag'] == 'calzetti': self.lum_em[:, ii] = extinction.apply( extinction.calzetti00(self.wav_em, self.dust['Av'], 4.05), self.lum_em[:, ii]) elif self.dust['flag'] == 'cardelli': self.lum_em[:, ii] = extinction.apply( extinction.ccm89(self.wav_em, self.dust['Av'], 4.05), self.lum_em[:, ii]) elif self.dust['flag'] == 'odonnell': self.lum_em[:, ii] = extinction.apply( extinction.odonnell94(self.wav_em, self.dust['Av'], 4.05), self.lum_em[:, ii]) elif self.dust['flag'] == 'fitzpatrick': self.lum_em[:, ii] = extinction.apply( extinction.fitzpatrick99(self.wav_em, self.dust['Av'], 3.1), self.lum_em[:, ii]) elif self.dust['flag'] == 'fitzpatrick07': self.lum_em[:, ii] = extinction.apply( extinction.fm07(self.wav_em, self.dust['Av']), self.lum_em[:, ii])
def get_keck(z=0.0213, date = "20190412_Keck1_v2", vkernel = 200, t0jd = 58583.2, ebv = 0.022):# Keck spectrum myfile = "../data/spectra/ZTF18abfcmjw_"+date+".ascii" f = open(myfile) lines = f.readlines() f.close() lines = np.array(lines) #lines = lines[100:200] ind = np.array([x[:11]=="# MJD =" for x in lines]) myline = lines[ind] [0] mjd= float(myline[15:-30]) phase = mjd - t0jd tb= asci.read(myfile) tb = tb[tb["col1"]>3190] dt = {} dt["phase"] = np.round(phase, 2) xx = tb['col1'].data/(1+z) yy = tb['col2'].data ind = ~np.isnan(yy) dt["wave"] = xx[ind]*(1+z) dt['wave_rest'] = xx[ind] dt['spec_obs'] = yy[ind] dt['spec_obs_sky'] = tb['col3'].data[ind] Aextmag = extinction.ccm89(dt['wave_rest'], 3.1*ebv, 3.1) # extinction in magnitudes tau = Aextmag / 1.086 dt['spec_obs0'] = dt['spec_obs'] * np.exp(tau) dt["ln_spec_obs"] = np.log(dt['spec_obs0']) ww, ff = convolve_with_constant_velocity_kernel(dt['wave_rest'], dt['spec_obs0'], vkernel) dt['wave_con'] = ww dt['spec_con'] = ff dt["ln_spec_con"] = np.log(ff) return dt
def deredden_spectrum(wave, flux, ebv, r_v=3.1, unit='aa', model='fm07'): """Deredden a spectrum based on a Galactic extinction model.""" model = model.lower().strip() if model == 'fm07': mw_extinction = fm07(wave, ebv * r_v, unit=unit) elif model == 'ccm89': mw_extinction = ccm89(wave, ebv * r_v, r_v, unit=unit) elif model == 'odonnell94': mw_extinction = ccm89(wave, ebv * r_v, r_v, unit=unit) else: raise Exception( "# Wrong choice of extinction model: fm07/ccm89/odonnell94") return remove(mw_extinction, flux)
def get_ltspec(z=0.0213, date = '0409', vkernel = 800, t0jd = 58583.2, ebv = 0.022): myfile = "../data/spectra/ZTF18abfcmjw_2019"+date+"_LT_v1.ascii" f = open(myfile) lines = f.readlines() f.close() lines = np.array(lines) ind = np.array([x[:11]=="# MJD =" for x in lines]) myline = lines[ind] [0] mjd= float(myline[15:-30]) phase = mjd - t0jd tb = asci.read(myfile) dt = {} dt["phase"] = np.round(phase, 2) dt['wave_rest'] = tb['col1'].data/(1+z) dt['spec_obs'] = tb['col2'].data*8e-17 Aextmag = extinction.ccm89(dt['wave_rest'], 3.1*ebv, 3.1) # extinction in magnitudes tau = Aextmag / 1.086 dt['spec_obs0'] = dt['spec_obs'] * np.exp(tau) dt["ln_spec_obs"] = np.log(dt['spec_obs0']) ww, ff = convolve_with_constant_velocity_kernel(dt['wave_rest'], dt['spec_obs0'], vkernel) dt['wave_con'] = ww dt['spec_con'] = ff dt["ln_spec_con"] = np.log(ff) return dt
def get_P60_eff_wave(myfilter="i'", return_type='R'): tb = pd.read_csv('../data/filters/P60/AstrodonSloanGen2Transmission.csv') if myfilter == "i'": wavecol = "Wavelength (nm).3" elif myfilter == "r'": wavecol = "Wavelength (nm).2" elif myfilter == "g'": wavecol = "Wavelength (nm).1" wv = tb[wavecol].values * 10 fg = tb[myfilter].values ix = (~np.isnan(wv)) & (~np.isnan(fg)) wv = wv[ix] fg = fg[ix] fg /= max(fg) wv_diff_ = wv[1:] - wv[:-1] wv_diff = 0.5 * (np.hstack([wv_diff_[0], wv_diff_]) + np.hstack([wv_diff_, wv_diff_[-1]])) g_eff = np.sum(wv_diff * fg * wv) / np.sum(wv_diff * fg) ebv = 1 Rg = extinction.ccm89(np.array([g_eff]), 3.1 * ebv, 3.1)[0] # print ("effective wavelength of %s is %f AA"%(myfilter, g_eff)) if return_type == 'R': return Rg elif return_type == 'more': return g_eff, wv, fg
def get_sn2018gep(): z = 0.03154 ebv = 0.01 D = cosmo.luminosity_distance([z])[0].value * 1e+6 # in pc dis_mod = 5 * np.log10(D / 10) tb = asci.read('../data/otherSN/SN2018gep/table5.txt') tb = tb.to_pandas() tb = tb.rename( columns={ 'col1': 'jd', 'col2': 'phase', 'col3': 'instrument', 'col4': 'filter', 'col5': 'mag', 'col6': 'emag' }) tb = tb[tb.instrument == "P48+ZTF"] ixg = tb['filter'].values == "g" ixr = tb['filter'].values == "r" ixi = tb['filter'].values == "i" tb['wave'] = np.zeros(len(tb)) tb['wave'].values[ixg] = 4814 tb['wave'].values[ixr] = 6422 tb['wave'].values[ixi] = 7883 tb['mag0'] = tb['mag'] - extinction.ccm89(tb['wave'].values, 3.1 * ebv, 3.1) tb['mag0_abs'] = tb['mag0'] - dis_mod tb = tb[tb.wave != 0] tb["mjd"] = tb["jd"] - 2400000.5 t_max = 2458374.6845 - 2400000.5 # from my eye-inspection tb['tmax_rf'] = (tb['mjd'] - t_max) / (1 + z) return tb
def test_ccm89(): # NOTE: Test is only to precision of 0.016 because there is a discrepancy # of 0.014 for the B band wavelength of unknown origin (and up to 0.002 in # other bands). # # Note that a and b can be obtained with: # b = ccm89(wave, 0.) # a = ccm89(wave, 1.) - b # # These differ from the values tablulated in the original paper. # Could be due to floating point errors in the original paper? # # U, B, V, R, I, J, H, K band effective wavelengths from CCM '89 table 3 x_inv_microns = np.array([2.78, 2.27, 1.82, 1.43, 1.11, 0.80, 0.63, 0.46]) wave = 1.e4 / x_inv_microns # A(lambda)/A(V) for R_V = 3.1 from Table 3 of CCM '89 ref_values = np.array( [1.569, 1.337, 1.000, 0.751, 0.479, 0.282, 0.190, 0.114]) assert_allclose(extinction.ccm89(wave, 1.0, 3.1), ref_values, rtol=0.016, atol=0.)
def get_ptf09dav(): tb = asci.read('../data/otherSN/Sullivan2011/ptf09dav') tb.rename_column('band', 'filter') tb.rename_column('magnitude', 'mag') tb.rename_column('e_magnitude', 'emag') tb.remove_column("instrument") tb = tb[tb['mag'] > 19.7] ix = np.any([tb['filter'] == 'r', tb['filter'] == 'R'], axis=0) tb = tb[ix] tb['filter'] == 'r' z = 0.0359 D = cosmo.luminosity_distance([z])[0].value * 1e+6 # in pc ebv = 0.044 dis_mod = 5 * np.log10(D / 10) t_max = 55054 # r band maximum tb['wave'] = np.ones(len(tb)) * 6422 tb['mag0'] = tb['mag'] - extinction.ccm89(tb['wave'], 3.1 * ebv, 3.1) tb['mag0_abs'] = tb['mag0'] - dis_mod tb['tmax_rf'] = (tb['time'] - t_max) / (1 + z) tb['emag'] = np.ones(len(tb)) * 0.1 tb.remove_row(2) tb['mag0_abs'][1] = -15.4 tb = tb.to_pandas() return tb
def UbandExcess_to_Mdot(Uexcess, dist, mass, radius, Av, Rin=5, unc=False): ''' This function will transform a U band flux value into a mass accretion rate estimate by following the process described in Robinson 2019. Inputs: Uexcess - U band continuum excess flux [erg/(s*cm^2)] dist - distance to object [pc] mass - mass of object [Msun] radius - radius of object [Rsun] Optional: Rin - magnetospheric radius (default 5 [Rsun]) Outputs: Mdot - mass accretion rate [Msun/yr] ''' #Extinction correction of flux #reddening law to U-band if type(Av) == float: Au = ex.ccm89(np.array([3650.0]), Av, 3.1)[0] elif type(Av) == list or type(Av) == np.ndarray: Au = [] for av in Av: Au.append(ex.ccm89(np.array([3650.0]), av, 3.1)[0]) Au = np.array(Au) #extinction correction deredU = ex.remove(Au, Uexcess) #U-band flux to Lu Lu = flux_to_luminosity(deredU, dist) #convert Lu to solar luminosity Lu = Lu / const.L_sun.to('erg/s').value #Lu to Lacc using Robinson paper -- natural logarithms #uncertainties 0.03 for each constant if unc == False: logLacc = 0.93 * np.log(Lu) + 0.5 else: logLacc = (0.93 + np.random.normal(0.03)) * np.log(Lu) + ( 0.5 + np.random.normal(0.03)) Lacc = np.exp(logLacc) #accretion luminosity to Mdot Mdot = Lacc_to_Mdot(Lacc, mass, radius, Rin) return Mdot
def UVExcess_to_Mdot(UVexcess, bc, dist, mass, radius, Av, Rin=5): ''' This function will transform a UV Excess flux value into a mass accretion rate estimate by following the process described in Herczeg 2008. Inputs: UVexcess - UV continuum excess flux [erg/(s*cm^2)] bc - bolometric correction dist - distance to object [pc] mass - mass of object [Msun] radius - radius of object [Rsun] Optional: Rin - magnetospheric radius (default 5 [Rsun]) Outputs: Mdot - mass accretion rate [Msun/yr] ''' #Extinction correction of flux #reddening law to U-band Au = Av if type(Av) == float: Au = ex.ccm89(np.array([3650.0]), Av, 3.1)[0] elif type(Av) == list or type(Av) == np.ndarray: Au = [] for av in Av: Au.append(ex.ccm89(np.array([3650.0]), av, 3.1)[0]) Au = np.array(Au) #extinction correction deredUV = ex.remove(Au, UVexcess) #use the bolometric correction factor to scale the UV excess flux to total accretion flux total_excess = deredUV * bc #accretion flux to accretion luminosity Lacc = flux_to_luminosity(total_excess, dist) #convert accretion luminosity to solar luminosity Lacc = Lacc / const.L_sun.to('erg/s').value #accretion luminosity to Mdot Mdot = Lacc_to_Mdot(Lacc, mass, radius, Rin) return Mdot
def get_sn2018kzr(colorplt=False): """ Owen R. Mcbrien 2019 """ ebv = 0.113 / 3.1 z = 0.053 D = cosmo.luminosity_distance([z])[0].value * 1e+6 # in pc dis_mod = 5 * np.log10(D / 10) t_max = 58480.422 + 0.1 f = open('../data/otherSN/Mcbrien2019/table1.tex') lines = f.readlines() f.close() lines = lines[:-4] dates = [x.split("&")[0] for x in lines] mjds = [float(x.split("&")[1]) for x in lines] phases = [ float(x.split("&")[2].replace('$', '').replace('\t', '')) for x in lines ] gs = [x.split("&")[3].replace('$', '') for x in lines] rs = [x.split("&")[4].replace('$', '') for x in lines] iis = [x.split("&")[5].replace('$', '') for x in lines] zs = [x.split("&")[6].replace('$', '') for x in lines] insts = [x.split("&")[7] for x in lines] dtg = digital_latex(mjds, phases, gs, insts) dtr = digital_latex(mjds, phases, rs, insts) dti = digital_latex(mjds, phases, iis, insts) filt = np.hstack([ np.repeat("g", len(dtg[0])), np.repeat("r", len(dtr[0])), np.repeat("i", len(dti[0])) ]) phase = np.hstack([dtg[1], dtr[1], dti[1]]) mag = np.hstack([dtg[2], dtr[2], dti[2]]) emag = np.hstack([dtg[3], dtr[3], dti[3]]) mjd = np.hstack([dtg[0], dtr[0], dti[0]]) tb = Table(data=[(mjd - t_max) / (1 + z), mag, emag, filt], names=['tmax_rf', 'mag', 'emag', 'filter']) ixr = tb['filter'] == "r" ixg = tb['filter'] == "g" ixi = tb['filter'] == "i" tb['wave'] = np.zeros(len(tb)) tb['wave'][ixg] = 4814 tb['wave'][ixr] = 6422 tb['wave'][ixi] = 7883 tb['mag0'] = tb['mag'] - extinction.ccm89(tb['wave'], 3.1 * ebv, 3.1) tb['mag0_abs'] = tb['mag0'] - dis_mod tb = tb.to_pandas() return tb
def deredden_MW_extinction(sp, EBV_MW, colwave='wave', colf='fnu', colfu='fnu_u', colcont='fnu_cont', colcontu='fnu_cont_u') : #print "Dereddening Milky Way extinction" Rv = 3.1 Av = -1 * Rv * EBV_MW # Want to deredden, so negative sign print("jrr.spec.deredden_MW_extinction, applying Av EBV_MW: ", Av, EBV_MW) #sp['oldfnu'] = sp[colf] # Debugging MW_extinction = extinction.ccm89(sp[colwave].astype('float64').as_matrix(), Av, Rv) sp['MWredcor'] = 10**(-0.4 * MW_extinction) sp[colf] = pandas.Series(extinction.apply(MW_extinction, sp[colf].astype('float64').as_matrix())) sp[colfu] = pandas.Series(extinction.apply(MW_extinction, sp[colfu].astype('float64').as_matrix())) if colcont in list(sp.keys()) : sp[colcont] = pandas.Series(extinction.apply(MW_extinction, sp[colcont].astype('float64').as_matrix())) if colcontu in list(sp.keys()) : sp[colcontu] = pandas.Series(extinction.apply(MW_extinction, sp[colcontu].astype('float64').as_matrix())) return(0)
def deredden(spectrum, r_v): """ Removes the extinction from the supernova and repopulates the signal types. Note that this function overrides the data stored in the spectrum object and creates a new set of data based on the new r_v value. :spectrum: (snmc.Spectrum object) the supernova to deredden :r_v: (float) the r_v value to use in the dereddening """ dust = extinction.ccm89(spectrum.wvs, r_v * spectrum.ebv, r_v) exp_dust = np.power(10, np.multiply(-0.4, dust)) spectrum.signal['dust_flux'] = np.divide(spectrum.signal['flux'], exp_dust) spectrum.populate_signals() spectrum.normalize()
def correct_for_galactic_extinction(spec, E_BV, R_V=3.1): ''' Correct flux for galactic (Milky Way) extinction using a Cardelli law Inputs: spec: spectrum1d object to be corrected (has wave and flux attributes) E_BV: E(B-V) for correction R_V: default to 3.1 values Output: spectrum1d object with the dust corrected flux ''' A_V = R_V * E_BV new_flux = extinction.apply(-extinction.ccm89(spec.wave, A_V, R_V), spec.flux) return spectrum1d(spec.wave, new_flux)
def deredden(self, wvs, flux, ebv): """ Removes the extinction from the supernova based on the quoted ebv value :wvs: (float array) wavelengths :flux: (float array) flux values :ebv: (float) the quoted color excess pulled from the scraper :returns: (float array) corrected flux values """ wvs = np.array(wvs) dust = extinction.ccm89(wvs, self.pars.r_v * ebv, self.pars.r_v) exp_dust = np.power(10, np.multiply(-0.4, dust)) return np.divide(flux, exp_dust)
def get_model(Rs, Av): #print Rs,Av Rscm = Rs * 6.95700e10 flxs = apply(ccm89(nsyn_wavs, Av, 3.1), nsyn_flxs * Rscm * Rscm) #outsw,nsyn_flxs = syn_flux(mod_wav,flxs,band) #loglog(mod_wav,mod_flx*Rscm*Rscm) #loglog(mod_wav,flxs*Rscm*Rscm) #loglog(outsw,nsyn_flxs*Rscm*Rscm,'ro') #loglog(refw,fluxes*distance*distance,'bo') #show() #Al = [] #for bd in band: # Al.append(get_avge_ext(Av,bd)) #Al = np.array(Al) return flxs #*Rscm*Rscm
def get_PS1_eff_wave(myfilter="g", return_type='more'): tb = asci.read("../data/filters/PS1/PAN-STARRS_PS1." + myfilter + ".dat") wv = tb["col1"].data fg = tb["col2"].data fg /= max(fg) wv_diff_ = wv[1:] - wv[:-1] wv_diff = 0.5 * (np.hstack([wv_diff_[0], wv_diff_]) + np.hstack([wv_diff_, wv_diff_[-1]])) g_eff = np.sum(wv_diff * fg * wv) / np.sum(wv_diff * fg) ebv = 1 Rg = extinction.ccm89(np.array([float(g_eff)]), 3.1 * ebv, 3.1)[0] if return_type == 'R': return Rg elif return_type == 'more': return g_eff, wv, fg
def deredden_photometry(ext_mag, ext_mag_err, filter_eff_lambda, a_v, r_v=3.1): """Use an extinction law to deredden photometry from a given band. Relies on: https://github.com/kbarbary/extinction With documentation at: https://extinction.readthedocs.io/en/latest/ Parameters ---------- ext_mag: np.array of type float The extincted magnitude. ext_mag_err: np.array of type float Error in the extincted magnitude filter_eff_lamda: np.array of type float Effective wavelength of the broad-band photometric filter specific to stellar spectral type. a_v : np.array of type float Scaling parameter, A_V: extinction in magnitudes at characteristic V band wavelength. r_v : np.array of type float Ratio of total to selective extinction, A_V / E(B-V). Returns ------- a_mags: float array Array of photometric extinction of form [W, S], where W is the number of wavelengths, and S is the number of stars. de_ext_mag_err: np.array of type float Error in the de-extincted magnitude. """ # Create grid of extinction a_mags = np.zeros(ext_mag.shape) # Use the Cardelli, Clayton, & Mathis 1989 extinction model. The extinction # module is not vectorised, so we have to work with one star at a time for star_i, star in enumerate(ext_mag.itertuples(index=False)): a_mags[star_i,:] = extinction.ccm89(filter_eff_lambda, a_v[star_i], r_v) return a_mags
def get_ZTF_eff_wave(filename, return_type='R'): specg = np.loadtxt('../data/filters/P48/' + filename).T wv = specg[0] fg = specg[1] fg /= max(fg) wv_diff_ = wv[1:] - wv[:-1] wv_diff = 0.5 * (np.hstack([wv_diff_[0], wv_diff_]) + np.hstack([wv_diff_, wv_diff_[-1]])) g_eff = np.sum(wv_diff * fg * wv) / np.sum(wv_diff * fg) ebv = 1 Rg = extinction.ccm89(np.array([g_eff]), 3.1 * ebv, 3.1)[0] #print ("effective wavelength of %s is %f AA"%(filename, g_eff)) if return_type == 'R': return Rg elif return_type == 'more': return g_eff, wv, fg
def Alam(lamin): A_v = 1 R_v = 3.1 ''' Add extinction with R_v = 3.1 and A_v = 1, A_v = 1 in order to find the constant of proportionality for the extinction law. ''' flux = np.ones(len(lamin)) redreturn = apply(ccm89(lamin, A_v, R_v), flux) #redreturn = A_v*extinction.a_lambda_cardelli_fast(lamin*1e-4,R_v) return redreturn
def rf_spec_from_merged(self): """ Returns the rest frame spectrum as calculated by normalizing and dereddening the merged spectrum. """ wave, flux, var = self.merged_spec() zhelio = self.sn_data['host.zhelio'] zcmb = self.sn_data['host.zcmb'] mwebv = self.sn_data['target.mwebv'] # Remove dust extinction from Milky Way in observer frame flux = apply(ccm89(wave, -mwebv * 3.1, 3.1), flux) # Convert observer frame wavelengths to rest frame wave = wave / (1 + zhelio) # Convert flux to luminosity at z=0.05 dl = (1 + zhelio) * COSMO.comoving_transverse_distance(zcmb) cosmo_factor = (1 + zhelio) / 1.05 * (dl / DLREF)**2 flux = flux * cosmo_factor * 1e15 var = flux * (cosmo_factor * 1e15)**2 return wave, flux, var
def get_LT_eff_wave(filename, return_type='R'): specg = asci.read('../data/filters/LT/' + filename) wv = specg['Wavelength(nm)'].data * 10 fg = specg['T%'].data fg /= max(fg) wv_diff_ = wv[1:] - wv[:-1] wv_diff = 0.5 * (np.hstack([wv_diff_[0], wv_diff_]) + np.hstack([wv_diff_, wv_diff_[-1]])) g_eff = np.sum(wv_diff * fg * wv) / np.sum(wv_diff * fg) ebv = 1 Rg = extinction.ccm89(np.array([g_eff]), 3.1 * ebv, 3.1)[0] #print ("effective wavelength of %s is %f AA"%(filename, g_eff)) if return_type == 'R': return Rg elif return_type == 'more': return g_eff, wv, fg
def get_hstspec(z=0.0213, t0jd = 58583.2, ebv = 0.022): """ https://archive.stsci.edu/cgi-bin/mastpreview?mission=hst&dataid=IDYQ7B030 Apr 22 2019 5:08AM """ mjd = Time('2019-04-22T05:08:00', format='isot', scale = 'utc').mjd phase = mjd - t0jd tb = asci.read("../data/spectra/spectrum.txt") tb = tb[~np.isnan(tb["col2"])] dt = {} dt['wave_rest'] = tb['col1'].data/(1+z) dt['spec_obs'] = tb['col2'].data Aextmag = extinction.ccm89(dt['wave_rest'], 3.1*ebv, 3.1) # extinction in magnitudes tau = Aextmag / 1.086 dt['spec_obs0'] = dt['spec_obs'] * np.exp(tau) dt["ln_spec_obs"] = np.log(dt['spec_obs0']) dt["phase"] = np.round(phase, 2) return dt
def get_SDSS_eff_wave(ext=2, return_type='more'): """ extension 2: g band """ tb = Table(fits.open("../data/filters/SDSS/filter_curves.fits")[ext].data) wv = tb["wavelength"].data fg = tb["respt"].data fg /= max(fg) wv_diff_ = wv[1:] - wv[:-1] wv_diff = 0.5 * (np.hstack([wv_diff_[0], wv_diff_]) + np.hstack([wv_diff_, wv_diff_[-1]])) g_eff = np.sum(wv_diff * fg * wv) / np.sum(wv_diff * fg) ebv = 1 Rg = extinction.ccm89(np.array([float(g_eff)]), 3.1 * ebv, 3.1)[0] if return_type == 'R': return Rg elif return_type == 'more': return g_eff, wv, fg
def deredden_spec(spectrum:xspectrum1d.XSpectrum1D, ebv:float): """ Deredden the input spectrum using the input EBV value Args: spectrum (xspectrum1d.XSpectrum1D): Spectrum ebv (float): Galactic reddening Returns: xspectrum1d.XSpectrum1D: De-reddened spectrum """ # Correct for Galactic extinction AV = ebv * 3.1 # RV Al = extinction.ccm89(spectrum.wavelength.value, AV, 3.1) # New spec new_flux = spectrum.flux * 10**(Al/2.5) new_sig = spectrum.sig * 10**(Al/2.5) new_spec = xspectrum1d.XSpectrum1D.from_tuple((spectrum.wavelength, new_flux, new_sig)) # Return return new_spec
def calc_extinction(E_BV, band, Rv=3.1, E_BV_err=0): ''' Calculate extinction using the Cardelli law E_BV: float E(B-V) value band: str filter corresponding to filter in define_filters dictionary Rv: float R(V) set to 3.1 by default E_BV_err: float 1 sigma error in E(B-V), set to 0 by default ''' Av = Rv * E_BV Av_err = Rv**2 * E_BV_err**2 cenwave = np.array([float(get_cenwave(band))]) A_band = extinction.ccm89(cenwave, Av, Rv) if Av == 0: A_band_err = 0.0 else: A_band_err = np.sqrt(Av_err * A_band / Av) return A_band, A_band_err
def MarginalReddening(m_obs, m_true, sg): dom = min_extinc_usco, max_extinc_usco stp = 100 #------ grid and deltas dtau = (dom[1] - dom[0]) / (stp - 1) tau = np.linspace(dom[0], dom[1], stp) #-------- extinction integral ------------ wls = np.array([7630.0, 10310.0, 12500, 16500, 21500 ]) # Wavelengths in agstroms (i SDSS, Y UKIDSS, JHK 2MASS) pA = p_extinction(tau) ext = np.array(map(lambda x: extinction.ccm89(wls, x, 3.1), tau)) ext[:, 0] = ext[:, 0] - ext[:, 4] extincted = m_true + ext #------------------------------------------------------ #x = m_obs - extincted #p_redden = np.exp(-0.5*(np.dot(x.T,isg.dot(x))+lden)) p_redden = st.multivariate_normal.pdf(extincted, mean=m_obs, cov=sg) # returns the integral over reddening return np.dot(pA, p_redden) * dtau
def test_ccm89(): # NOTE: Test is only to precision of 0.016 because there is a discrepancy # of 0.014 for the B band wavelength of unknown origin (and up to 0.002 in # other bands). # # Note that a and b can be obtained with: # b = ccm89(wave, 0.) # a = ccm89(wave, 1.) - b # # These differ from the values tablulated in the original paper. # Could be due to floating point errors in the original paper? # # U, B, V, R, I, J, H, K band effective wavelengths from CCM '89 table 3 x_inv_microns = np.array([2.78, 2.27, 1.82, 1.43, 1.11, 0.80, 0.63, 0.46]) wave = 1.e4 / x_inv_microns # A(lambda)/A(V) for R_V = 3.1 from Table 3 of CCM '89 ref_values = np.array([1.569, 1.337, 1.000, 0.751, 0.479, 0.282, 0.190, 0.114]) assert_allclose(extinction.ccm89(wave, 1.0, 3.1), ref_values, rtol=0.016, atol=0.)
#!/usr/bin/env python """Plot extinction functions for comparison""" import numpy as np import matplotlib.pyplot as plt from matplotlib import rcParams from mpl_toolkits.axes_grid1 import make_axes_locatable import extinction rcParams['font.family'] = 'serif' wave = np.logspace(np.log10(910.), np.log10(30000.), 2000) a_lambda = {'ccm89': extinction.ccm89(wave, 1.0, 3.1), 'odonnell94': extinction.odonnell94(wave, 1.0, 3.1), 'fitzpatrick99': extinction.fitzpatrick99(wave, 1.0), 'fm07': extinction.fm07(wave, 1.0)} names = list(a_lambda.keys()) # consistent ordering between panels fig = plt.figure(figsize=(8.5, 6.)) ax = plt.axes() for name in names: plt.plot(wave, a_lambda[name], label=name) plt.axvline(x=2700., ls=':', c='k') plt.axvline(x=3030.3030, ls=':', c='k') plt.axvline(x=9090.9091, ls=':', c='k') plt.axvspan(wave[0], 1150., fc='0.8', ec='none', zorder=-1000) plt.axvspan(1150., 1250., fc='0.9', ec='none', zorder=-1000)
def make_a_stack(labels, rootname, norm_region, norm_func, norm_method_text, mage_mode, zchoice, deredden=False, EBV=[], deredden_MW=False, colcont="fnu_cont") : # Note: this is stacking in the rest-frame. plt.close('all') plt.ion() plt.figure(figsize=(20,5)) # specs = jrr.mage.getlist_labels(mage_mode, labels) specs = jrr.mage.wrap_getlist(mage_mode, which_list="labels", labels=labels) Nspectra = len(specs) print("DEBUG, Nspectra is", Nspectra) stacklo = 800. #A # Create a rest-frame wavelength array to stack into stackhi = 3000. #A disp = 0.1 # Angstroms # observed-frame wavelength binning is ~0.3A pper pix for RCS0327. So, want ~0.1A in rest-frame nbins = int((stackhi - stacklo)/disp) wave_stack = np.linspace(stacklo, stackhi, num=nbins) nfnu_stack = np.ma.zeros(shape=(Nspectra, nbins)) # create array that will hold all the spectra nfnu_u_stack = np.ma.zeros(shape=(Nspectra, nbins)) print("Filename label N_pixels rest-frame wavelength range (A)") for ii in range(0, Nspectra) : #nfnu_stack[ii] will be ii spectrum label = specs['short_label'][ii] filename = specs['filename'][ii] if(zchoice == "stars") : # Update 8/2016, enabling either method to to set systemic redshift, selectable as zchoice zz = specs['z_syst'][ii] # using john chisholm's S99 fits to photospheric absorption lines where possible. elif(zchoice == "neb") : zz = specs['z_neb'][ii] # what I used prior to 21 july 2016. else : raise ValueError('Error, I do not recognize input zchoice (choice to set systemic redshift) as stars or neb') # OLD (sp, resoln, dresoln) = jrr.mage.open_spectrum(filename, zz, mage_mode) (sp, resoln, dresoln, LL, zz_syst) = jrr.mage.wrap_open_spectrum(label, mage_mode, addS99=True) # set uncertainties high near skylines [O I] 5577\AA\ and [O I]~6300\AA, skyline = (5577., 6300.) skywidth = 10.0 # flag spectrum +- skywidth of the skyline sp.fnu_u[sp['wave'].between(skyline[0]-skywidth, skyline[0]+skywidth)] = 1.0 # huge uncert near skylines sp.fnu_u[sp['wave'].between(skyline[1]-skywidth, skyline[1]+skywidth)] = 1.0 # huge uncert near skylines sp.fnu_u[sp[colcont].eq(9999)] = 1.0 # Set huge uncertainties where continuum undefined # Mask out known intervening absorbers vmask = 200. # +-200km/s LL['vmask'] = vmask jrr.spec.flag_near_lines(sp, LL, linetype=('INTERVE',)) sp.fnu_u[sp['linemask']] = 1. # Set huge uncertainties at positions of known intervening absorbers if deredden_MW : print("DEBUGGING, dereddening Milky Way extinction") Rv = 3.1 Av = -1 * Rv * specs['EBV_MW'][ii] # Want to deredden, so negative sign sp.fnu = pandas.Series(extinction.apply(extinction.ccm89(sp.wave.as_matrix(), Av, Rv), sp.fnu.as_matrix())) sp.fnu_u = pandas.Series(extinction.apply(extinction.ccm89(sp.wave.as_matrix(), Av, Rv), sp.fnu_u.as_matrix())) sp[colcont] = pandas.Series(extinction.apply(extinction.ccm89(sp.wave.as_matrix(), Av, Rv), sp[colcont].as_matrix())) sp['fnu_cont_u'] = pandas.Series(extinction.apply(extinction.ccm89(sp.wave.as_matrix(), Av, Rv), sp['fnu_cont_u'].as_matrix())) (rest_wave, rest_fnu, rest_fnu_u) = jrr.spec.convert2restframe(sp.wave, sp.fnu, sp.fnu_u, zz, 'fnu') (junk , rest_cont, rest_cont_u) = jrr.spec.convert2restframe(sp.wave, sp[colcont], sp.fnu_cont_u, zz, 'fnu') # should now have arrays of rest wavelength, fnubda, and continuum, as # rest_wave, rest_fnu, rest_fnu_u, rest_cont, rest_cont_u print(filename, label, len(rest_wave), end=' ') print(" %.2f %.2f" % ( rest_wave[0], rest_wave[-1:])) if deredden and len(EBV) : this_ebv = S99.loc[label, 'E(B-V)'] Rv = 4.05 Av = -1 * Rv * this_ebv # stupidity w .Series and .as_matrix() is bc extinction package barfs on pandas. pandas->np->pandas rest_fnu = pandas.Series(extinction.apply(extinction.calzetti00(rest_wave.as_matrix(), Av, Rv), rest_fnu.as_matrix())) rest_fnu_u = pandas.Series(extinction.apply(extinction.calzetti00(rest_wave.as_matrix(), Av, Rv), rest_fnu_u.as_matrix())) rest_cont = pandas.Series(extinction.apply(extinction.calzetti00(rest_wave.as_matrix(), Av, Rv), rest_cont.as_matrix())) rest_cont_u = pandas.Series(extinction.apply(extinction.calzetti00(rest_wave.as_matrix(), Av, Rv), rest_cont_u.as_matrix())) # Normalize the spectrum and error spectrum (temp_norm_fnu, temp_sig) = norm_func(rest_wave, rest_fnu, rest_fnu_u, rest_cont, rest_cont_u, norm_region) nfnu_stack[ii] = np.ma.masked_invalid(jrr.spec.rebin_spec_new(rest_wave, temp_norm_fnu, wave_stack))# normalized fnu, rebinned nfnu_u_stack[ii] = np.ma.masked_invalid(jrr.spec.rebin_spec_new(rest_wave, temp_sig, wave_stack)) # uncertainty on above plt.step(wave_stack, nfnu_stack[ii]) # fnu_u_stack is 1sigma uncertainty spectrum. weight is 1/sigma**2 nfnu_u_stack += 0.00001 # add a very small number to avoid 1/zero errror weight_stack = nfnu_u_stack**-2 sig2clip = 2 # clip at N sigma, in astropy.stats.sigma_clip # Use a masked average to deal with the whole wavelength range. numpy.ma is masking mask1 = np.isnan(nfnu_stack) # interp1d writes NaNs in non-overlap region. Mask these mask2 = np.isnan(nfnu_u_stack) # ditto for uncertainty crazy_high = 1000. mask3 = np.greater(nfnu_stack, crazy_high) + np.less(nfnu_stack, -1*crazy_high) # flag crazy flux values. mask = mask1 + mask2 + mask3 print("DEBUGGING masks", mask1.sum(), mask2.sum(), mask3.sum(), mask.sum(), mask.shape) nfnu_clip = sigma_clip(nfnu_stack, sig=sig2clip, iters=None, axis=0) ## Sigma clipping X_avg, sumweight1 = np.ma.average(nfnu_stack, axis=0, weights=weight_stack, returned=True) # weighted avg of continuum-normalized spectra X_clipavg, sumweight2 = np.ma.average(nfnu_clip, axis=0, weights=weight_stack, returned=True) # weighted avg of cont-normalized spectra, w sig clip X_Ngal = np.sum((1 - mask), axis=0) # Number of galaxies that went into the stack at that wavelength X_sigma = sumweight1**-0.5 X_clipsigma = sumweight2**-0.5 # spiky, dunno why. Presumably legacy of sigma_clip? Don't use it X_median = np.ma.median(nfnu_stack, axis=0) plt.step(wave_stack, X_avg, color="black", linewidth=3) plt.ylim( -1, 3) plt.xlim(1000, 1200) plt.draw() plt.show() #pdb.set_trace() if GOSLOW : plt.pause(4) # Jack-knife: drop one spectrum and make weighted average, repeat. Measure the stdev. jackknife = np.ma.zeros(shape=(Nspectra, nbins)) jack_var = np.ma.zeros(shape=nbins) for ii in range(0, Nspectra) : jnf = nfnu_stack.copy() print("Jackknife, dropping ", specs['short_label'][ii], " from the stack") jnf[ii, :].mask = True # Mask one spectrum jackknife[ii], weight = np.ma.average(jnf, axis=0, weights=weight_stack, returned=True) # all the work is done here. jack_var = jack_var + (jackknife[ii] - X_avg)**2 jack_var *= ((Nspectra -1.0)/float(Nspectra)) X_jack_std = np.sqrt(jack_var) # Jackknife variance estimation, from wikipedia: var = (n-1)/n * sum(i=1 to n) of (xi - x.)**2 #Output the stacked spectrum long_rootname = "magestack_by" + zchoice + "_" + rootname head = '# Stack(s) of the MagE spectral atlas of lensed galaxies, named ' + long_rootname + '\n' head += '# Generated on ' + time.strftime("%d/%m/%Y") + '(dd/mm/yyr)\n' head += '# Generated from ' + str(labels) + "\n" head += '# ' + norm_method_text + "\n" head += '# Columns are: \n' head += '# wave : Rest-frame vacuum wavelength, in Angstroms. Covers ' + str(stacklo) + " to " + str(stackhi) + '\n' head += '# X_avg : Weighted avg of continuum-normalized fnu spectra.\n' head += '# X_clipavg: same as X_avg, but weighted avg done with sigma clipping at sigma=' + str(sig2clip) + '\n' head += '# X_median: median of continuum-normalized fnu spectra. No weighting.\n' head += '# X_sigma : uncertainty on X_avg and X_clipavg, from propagating individual error spectra\n' head += '# X_jack_std : sqrt of variance estimate from jackknife test. \n' head += '# Ngal : Number of galaxies that went into the stack at that wavelength.\n' head += 'restwave X_avg X_clipavg X_median X_sigma X_jack_std Ngal' outfile = long_rootname + "_spectrum.txt" np.savetxt(outfile, np.transpose([wave_stack, X_avg, X_clipavg, X_median, X_sigma, X_jack_std, X_Ngal]), "%.3f %.2E %.2E %.2E %.2E %.2E %d", header=head, comments="") maskout_head = "#This mask shows which galaxies were stacked at each wavelength. 0=gal used. 1=gal masked out.\n" outfile = long_rootname + "_maskused.txt" jack_head = "restwave " + re.sub("\n", "", str(specs.short_label.values)) jack_head = re.sub("'", "", jack_head) jack_head = re.sub("\[", "", jack_head) jack_head = re.sub("\]", "", jack_head) maskout_head += jack_head format_string = "%.3f " + "%.0f " * mask.shape[0] np.savetxt(outfile, np.transpose(np.vstack((wave_stack, mask))), fmt=format_string, header=maskout_head, comments="") # so much pain to figure out this syntax # The above np magic allows us to concatenate wave_stack (which is 1D, and mask, which is 2D, and the 2nd dimension isn't defined. painful" # output the jackknife stacks outfile = long_rootname + "_jackknife.txt" head2 = "# Weighted-averages of MagE spectra, each missing 1 spectrum, for jackknife tests\n#wave(A) weighted_means_w_jackknife\n" head2 += "# Each jackknife is missing the following spectrum:\n" + jack_head np.savetxt(outfile, np.transpose(np.vstack((wave_stack, jackknife))), fmt="%.5E", header=head2, comments="") # plot the stacked spectrum plt.clf() plt.step(wave_stack, X_avg, color="black") plt.step(wave_stack, X_median, color="blue") plt.step(wave_stack, X_sigma, color="orange") plt.step(wave_stack, X_jack_std, color="red") plt.ylabel(r'$f_\nu$') #plt.xlim(stacklo, stackhi) plt.xlim(800,3000) plt.ylim(-1,2) figname = long_rootname + "_quicklook.pdf" plt.savefig(figname) plt.show() if GOSLOW : plt.pause(4) PLOT_NGAL = True if PLOT_NGAL : plt.clf() plt.xlabel(r'wavelength ($\AA$)') plt.ylabel("number of galaxies that went into the stack") plt.plot(wave_stack, X_Ngal, color="red") plt.ylim(0,16) figname = long_rootname + "_Ngals_in_stack.pdf" plt.savefig(figname) plt.show() #raise Exception("I need to see whats happening") return(wave_stack, nfnu_stack, nfnu_u_stack)