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 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 deredUV = ex.remove(Av, 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 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 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 Spec_mags(Models, pbs, av=0, Rv=3.1, Conversion=1.029): """ Generate synthetic magnitudes from the models and passbands added. Conversion converts between Ebv and Egr, the Green value is 0.981, but the best fit value was found to be 1.029. """ #a_v = 3.1*(Conversion * ex ) # ex = extinction from Bayestar19 = Egr keys = list(pbs.keys()) mags = {} for key in keys: mags[key] = [] pb, zp = pbs[key] # construct mags ind = [] red = {} for model in Models: if av > 0: model = S.ArraySpectrum(model.wave, apply( fitzpatrick99(model.wave, av, Rv), model.flux), waveunits=model.waveunits, fluxunits=model.fluxunits) if av < 0: model = S.ArraySpectrum(model.wave, remove( fitzpatrick99(model.wave, -av, Rv), model.flux), waveunits=model.waveunits, fluxunits=model.fluxunits) mags[key] += [source_synphot.passband.synphot(model, pb, zp)] for key in keys: mags[key] = np.array(mags[key]) #good = np.ones(len(mags[key])) > 0 #for key in keys: # good = good *np.isfinite(mags[key]) #for key in keys: # mags[key] = mags[key][good] return mags
def deredden(wave, flux, ra, dec, scaling=0.86, reddening_law='fitzpatrick99', dustmaps_dir=None, r_v=3.1, ebv=None): """Dereddens the given spectrum, given a right ascension and declination or :math:`E(B-V)`. Parameters ---------- wave : array Wavelength values. flux : array Flux density values. ra : float Right ascension in degrees. dec : float Declination in degrees. scaling: float, default ``0.86`` Calibration of the Milky Way dust maps. Either ``0.86`` for the Schlafly & Finkbeiner (2011) recalibration or ``1.0`` for the original dust map of Schlegel, Fikbeiner & Davis (1998). reddening_law: str, default ``fitzpatrick99`` Reddening law. The options are: ``ccm89`` (Cardelli, Clayton & Mathis 1989), ``odonnell94`` (O’Donnell 1994), ``fitzpatrick99`` (Fitzpatrick 1999), ``calzetti00`` (Calzetti 2000) and ``fm07`` (Fitzpatrick & Massa 2007 with :math:`R_V` = 3.1.) dustmaps_dir : str, default ``None`` Directory where the dust maps of Schlegel, Fikbeiner & Davis (1998) are found. r_v : float, default ``3.1`` Total-to-selective extinction ratio (:math:`R_V`) ebv : float, default ``None`` Colour excess (:math:`E(B-V)`). If given, this is used instead of the dust map value. Returns ------- deredden_flux : array Deredden flux values. """ pisco_path = piscola.__path__[0] if dustmaps_dir is None: dustmaps_dir = os.path.join(pisco_path, 'sfddata-master') if ebv is None: m = sfdmap.SFDMap(mapdir=dustmaps_dir, scaling=scaling) ebv = m.ebv(ra, dec) # RA and DEC in degrees a_v = r_v * ebv rl_list = ['ccm89', 'odonnell94', 'fitzpatrick99', 'calzetti00', 'fm07'] assert reddening_law in rl_list, f'Choose one of the available reddening laws: {rl_list}' if reddening_law == 'ccm89': ext = extinction.ccm89(wave, a_v, r_v) elif reddening_law == 'odonnell94': ext = extinction.odonnell94(wave, a_v, r_v) elif reddening_law == 'fitzpatrick99': ext = extinction.fitzpatrick99(wave, a_v, r_v) elif reddening_law == 'calzetti00': ext = extinction.calzetti00(wave, a_v, r_v) elif reddening_law == 'fm07': ext = extinction.fm07(wave, a_v) deredden_flux = extinction.remove(ext, flux) return deredden_flux
def lineflux_to_Mdot(flux, dist, mass, radius, Av, Rin=5, line=None, A=None, B=None): ''' This function will turn a line flux into a mass accretion rate estimate using the Lacc-Lline fits derived by Alcala et al 2017. Inputs: flux (float) : line flux [erg/(s*cm^2)]? dist (float) : distance to object [pc] mass (float) : mass of object [Msun] radius (float) : radius of object [Rsun] Optional: Rin (float) : magnetospheric radius (default 5 [Rsun]) line (str) : type of line. for now acceptable inputs are H-alpha: 'Ha', Pa-beta: 'Pab', and Br-gamma: 'Brg' A (float) : If you want to input the parameters for your own line flux vs Lacc relationship B (float) : If you want to input the parameters for your own line flux vs Lacc relationship Outputs: Mdot (float) : mass accretion rate [Msun/yr] ''' #a & b values pulled directly from the paper if line == None: a = A b = B elif line == 'Ha': a = 1.13 #+/- 0.05 b = 1.74 #+/- 0.19 elif line == 'Pab': a = 1.06 #+/- 0.07 b = 2.76 #+/- 0.34 elif line == 'Brg': a = 1.19 #+/- 0.10 b = 4.02 #+/- 0.51 else: print('Line not found.') return #extinction correction deredflux = ex.remove(Av, flux) #find Lline in erg/s Lline = deredflux * (4 * np.pi * (dist * const.pc.to('cm').value)**2) #convert to solar luminosity Lline = Lline / const.L_sun.to('erg/s').value #Find Lacc using Alcala relationships logLacc = a * np.log10(Lline) + b #solar luminosity Lacc = unlog(logLacc) Mdot = Lacc_to_Mdot(Lacc, mass, radius, Rin=Rin) return Mdot
def deredden(self,R_v=3.1): """Deredden the spectrum, based on the estimated A_v, using the Fitzpatrick (1999) curve, as used in Schlafy & Finkbeiner (2012)""" self.data = self.data.T self.data[1] = remove(f99(self.data[0],self.A_v,R_v),self.data[1]) self.data[2] = remove(f99(self.data[0],self.A_v,R_v),self.data[2]) self.data = self.data.T
# "integrated" over the filter filter_bandwidth flux_bp = "int_flux(%s)" % (photflam.unit * rect_width.unit) phot_source[flux_bp] = phot_source[aperture_keyword] * photflam * rect_width phot_source["int_flux_err"] = phot_source_conf_pos * photflam * rect_width - phot_source[flux_bp] # more appropiate for emission lines line_flux = "monochromatic_flux(%s)" % (photflam.unit) phot_source[line_flux] = phot_source[aperture_keyword] * bp.emflx(bp.area) phot_source["monochromatic_flux_err"] = phot_source_conf_pos * bp.emflx(bp.area) - phot_source[line_flux] #https://www.stsci.edu/hst/instrumentation/acs/data-analysis/zeropoints phot_source["mag"] = -2.5 * log10(phot_source[aperture_keyword]) - zero_point phot_source["mag_err_neg"] = -2.5 * log10(phot_source_conf_pos) - zero_point - phot_source["mag"] phot_source["mag_err_pos"] = -2.5 * log10(phot_source_conf_neg) - zero_point - phot_source["mag"] if args.av is not None: waves = np.array([pivot_wavelength]) phot_source["der_flux"] = remove(ccm89(waves, args.av, 3.1, unit="aa"), phot_source[flux_header]) phot_source["der_flux_err"] = remove(ccm89(waves, args.av, 3.1, unit="aa"), phot_source_conf_pos* photflam ) - phot_source["der_flux"] # formatting phot_source["xcenter"].info.format = '%.2f' phot_source["ycenter"].info.format = '%.2f' phot_source["aperture_sum"].info.format = '%.3f' phot_source[aperture_keyword].info.format = '%.2f' phot_source["corrected_aperture_err"].info.format = '%.2f' phot_source[flux_header].info.format = '%.3E' phot_source['flux_err'].info.format = '%.2E' phot_source["mag"].info.format = "%.2f" phot_source["mag_err_neg"].info.format = "%.2f" phot_source["mag_err_pos"].info.format = "%.3f" reg_basename = os.path.basename(args.regions[0]).replace('.reg', '') out_data_file = "aperture_phot_%s_%s.csv" % (hst_filter, reg_basename)
def test_sdss_halpha(fname, fluxkey, magkey, magerrprefix, bands, scatter_density=True, zkey="z", xmin=-17, xmax=-13, output=None, bands_ebv=None, wline=6562.8 * u.AA): bands_ebv = ["G", "I"] if bands_ebv is None else bands_ebv ############################################################################ # Reading transmission curves for S-PLUS filters_dir = os.path.join(os.getcwd(), "filter_curves-master") filenames = sorted([os.path.join(filters_dir, _) for _ in os.listdir( \ filters_dir)]) filternames = [os.path.split(_)[1].replace(".dat", "") for _ in filenames] filternames = [ _.replace("F0", "F").replace("JAVA", "") for _ in filternames ] filternames = [_.replace("SDSS", "").upper() for _ in filternames] fcurves = [np.loadtxt(f) for f in filenames] wcurves = [curve[:, 0] * u.AA for curve in fcurves] trans = [curve[:, 1] for curve in fcurves] wcurves = dict(zip(filternames, wcurves)) trans = dict(zip(filternames, trans)) halpha = EmLine3Filters(wline, [_.upper() for _ in bands], wcurves, trans) ############################################################################ # Reading catalog and remove objects out of z-range wdir = os.path.join(context.home_dir, "catalogs") filename = os.path.join(wdir, fname) table = Table.read(filename) if zkey in table.colnames: table = table[table[zkey] < 0.02] ############################################################################ # Cleaning table against large errors in mgnitudes magerrs = np.array([ table["{}{}{}".format(magerrprefix, band, magkey)].data for band in bands ]) idx = np.where(np.nanmax(magerrs, axis=0) < 0.2)[0] table = table[idx] ############################################################################ # Estimating the extinction gi = np.array( [table["{}{}".format(band, magkey)].data for band in bands_ebv]) g_i = gi[0] - gi[1] ebvs = np.clip(0.206 * np.power(g_i, 1.68) - 0.0457, 0, np.infty) Rv = 4.1 Avs = Rv * ebvs corr = np.array([ extinction.remove( extinction.calzetti00(np.atleast_1d(wline), Av, Rv)[0], 1) for Av in Avs ]) ############################################################################ # Correcting observations for Galactic extinction coords = SkyCoord(table["ra"] * u.degree, table["dec"] * u.degree) sfd = SFDQuery() ebv_mw = sfd(coords) Rv_mw = 3.1 Av_mw = Rv_mw * ebv_mw corr_mw = np.array([ extinction.remove( extinction.ccm89(halpha.wpiv, Av, Rv_mw)[0], np.ones(3)) for Av in Av_mw ]).T ############################################################################ # Calculating H-alpha mags = np.array( [table["{}{}".format(band, magkey)].data for band in bands]) flam = mag2flux(mags, halpha.wpiv) * corr_mw flux_halpha_nii = halpha.flux_3F(flam) log_halpha = np.where(g_i <= 0.5, 0.989 * np.log10(flux_halpha_nii.value) - 0.193, 0.954 * np.log10(flux_halpha_nii.value) - 0.753) halpha_sdss = np.log10((table[fluxkey]) * np.power(10., -17)) halpha_splus = log_halpha + np.log10(corr) ############################################################################ # Selecting only regions within limits of flux idx = np.where( np.isfinite(halpha_sdss * halpha_splus) & (halpha_sdss > xmin) & (halpha_splus < xmax)) halpha_sdss = halpha_sdss[idx] halpha_splus = halpha_splus[idx] ############################################################################ fig = plt.figure() if scatter_density: ax = fig.add_subplot(1, 1, 1, projection='scatter_density') density = ax.scatter_density(halpha_sdss, halpha_splus, cmap="magma_r") fig.colorbar(density, label='Number of points per pixel') else: ax = fig.add_subplot(1, 1, 1) label = "mag_key={}".format(magkey) counts, xedges, yedges, im = ax.hist2d(halpha_sdss, halpha_splus, bins=(50, 50), cmap="bone_r") plt.legend(title=label) fig.colorbar(im, ax=ax) ax.set_aspect("equal") plt.xlim(xmin, xmax) plt.ylim(xmin, xmax) plt.plot(np.linspace(xmin, xmax, 100), np.linspace(xmin, xmax, 100), "--r") plt.xlabel(r"$\log$ H$\alpha$ (erg / s / cm$^2$) -- SDSS") plt.ylabel(r"$\log$ H$\alpha$ (erg / s / cm$^2$) -- SPLUS") axins = inset_axes(ax, width="80%", height="80%", bbox_to_anchor=(.65, .05, .38, .38), bbox_transform=ax.transAxes, loc=3) diff = halpha_splus - halpha_sdss median = np.nanmedian(diff) std = np.nanstd(diff) title = "med: {:.2f} std: {:.2f}".format(median, std) axins.hist(diff, bins=20) axins.set_title(title) plt.tight_layout() if "output" is not None: plt.savefig( output, dpi=250, ) plt.show()