def test_electron_density_trapz(): tol = 1e-3 ne = density.ElectronDensity() l, b, d = -2, 12, 1 DM = 23.98557 assert abs(ne.DM(l, b, d, integrator=integrate.trapz).value - DM) / DM < tol
def best_dm_from_z(frbc, DM_host=50., DM_MW=80.): """ Calculate an estimated DM_FRB provided the candidate info Calls ne2001 for Galactic ISM estimate in the given direction Args: frbc: FRBCandidate object Must include coord and z DM_host: float, optional WAG for the host DM in pc/cm^3 DM_MW: WAG for the MW halo DM in pc/cm^3 Returns: DM_FRB: float Estimated DM in pc/cm^3 """ # NE2001 ne = density.ElectronDensity() DM_ISM = ne.DM(frbc['coord'].galactic.l, frbc['coord'].galactic.b, 100.) # Cosmic DM_cosmic = average_DM(frbc['z']).value # Add em up DM_FRB = DM_ISM.value + DM_MW + DM_cosmic + DM_host # Return return DM_FRB
def ismDM(coord): gcoord = coord.transform_to('galactic') l, b = gcoord.l.value, gcoord.b.value ne = density.ElectronDensity()#**PARAMS) ismDM = ne.DM(l, b, 100.) # Return return ismDM
def mwdm(ra, dec, distance): co = coordinates.SkyCoord(ra, dec, unit='deg') # or pass sexagesimal # co = coordinates.SkyCoord(rastr, decstr, unit=(units.hourangle, units.deg)) ne = density.ElectronDensity(**ne_io.Params()) dm = ne.DM(co.galactic.l, co.galactic.b, distance) print(f'For (RA, Dec) = ({ra}, {dec}), (l, b) = ({co.galactic.l}, {co.galactic.b}), DM={dm} pc/cm3')
def test_dist(): seed(123) for i in range(1): tol = 0.1 ne = density.ElectronDensity() l = rand() * 360 b = np.arccos(1 - 2 * rand()) / np.pi * 180 d = rand() * 5 DM = ne.DM(l, b, d) d_DM = ne.dist(l, b, DM) err = abs(d_DM.value - d) / d print(err, l, b, d, d_DM) assert err < tol, (l, b, d)
def main(pargs, **kwargs): """ Run """ # init ne = density.ElectronDensity() # DM DM = ne.DM(pargs.l, pargs.b, pargs.d) print("----------------------------------------------") print("DM:") print(" Along l={:g} deg and b={:g} deg to d={:g} kpc".format( pargs.l, pargs.b, pargs.d)) print(" DM = {:g}".format(DM)) print("----------------------------------------------")
def sub_cartoon(ax1, ax2, coord, zFRB, halos=False, host_DM=50., ymax=None, IGM_only=True, smin=0.1, show_M31=None, fg_halos=None, dsmx=0.05, FRB_DM=None, yscl=0.97): """ Cartoon of DM cumulative Plot of increasing DM from Earth to the FRB Args: ax1 (matplotlib.Axis): First axis. Used for Milky Way and local group ax2 (matplotlib.Axis): Second axis. Used for Cosmic and Host coord (astropy.coord.SkyCoord): Coordinate of the FRB used with ne2001 zFRB (float): Redshift of the FRB halos (?, optional): Not implemented! host_DM (float): DM to use for the Host ymax (tuple or list): ymin, ymax values for the y-axis IGM_only (bool, optional): Use only the IGM for DM_Cosmic, i.e. ignore the presumed average halo contribution show_M31 (bool, optional): Include M31 in the calculation? NOT IMPLEMENTED RIGHT NOW fg_halos (dict or Table): Used to add to DM_IGM Keys must include 'z' 'DM' 'lbl' smin (float, optional): Minimum value in axis2 (Gpc) dsmx (float, optional): Padding on the x-axis; Gpc Allows for host. Set to 0 to ignore host FRB_DM (float): Observed value; sets ymax = FRB_DM+50 yscl (float, optional): Controls placement of labels """ if halos: embed() gcoord = coord.transform_to('galactic') l, b = gcoord.l.value, gcoord.b.value ds = [] # kpc DM_cumul = [] # ISM ne = density.ElectronDensity() # **PARAMS) for ss in np.linspace(2., 4, 5): # log pc idd = 10.**ss / 1e3 # kpc iDM = ne.DM(l, b, idd) # Append ds.append(idd) # kpc DM_cumul.append(iDM.value) # print(idd, iDM) max_ISM = DM_cumul[-1] # MW Mhalo = np.log10(1.5e12) # Boylan-Kolchin et al. 2013 f_hot = 0.75 # Allows for disk + ISM c = 7.7 mnfw_2 = ModifiedNFW(log_Mhalo=Mhalo, f_hot=f_hot, y0=2, alpha=2, c=c) # Zero out inner 10kpc mnfw_2.zero_inner_ne = 10. # kpc params = dict(F=1., e_density=1.) model_ne = density.NEobject(mnfw_2.ne, **params) for ss in np.linspace(1., np.log10(mnfw_2.r200.value), 5): # log kpc idd = 10.**ss # kpc iDM = model_ne.DM(l, b, idd).value # Add it in if idd == ds[-1]: DM_cumul[-1] = DM_cumul[-1] + iDM else: ds.append(idd) DM_cumul.append(max_ISM + iDM) DM_ISM_Halo = DM_cumul[-1] if show_M31: raise NotImplemented # M31 m31 = M31() a, c = 1, 0 x0, y0 = m31.distance.to( 'kpc' ).value, 0. # kpc (Riess, A.G., Fliri, J., & Valls - Gabaud, D. 2012, ApJ, 745, 156) sep = m31.coord.separation(coord) atan = np.arctan(sep.radian) b = -1 * a / atan M31_Rperp = np.abs(a * x0 + b * y0 + c) / np.sqrt(a**2 + b**2) # kpc zval, M31_DM_cumul = m31.Ne_Rperp(M31_Rperp * u.kpc, rmax=1., cumul=True) # Add em in ds += (zval + x0).tolist() DM_cumul += (M31_DM_cumul + DM_ISM_Halo).tolist() #DM_LG = 0. DM_LG = DM_cumul[-1] # IGM z0 = z_at_value(cosmo.comoving_distance, 1 * units.Mpc) zvals = np.linspace(z0, 0.5, 50) dz_vals = zvals[1] - zvals[0] # DM_cosmic_cumul, zeval = frb_igm.average_DM(zvals[-1], cumul=True) dzeval = zeval[1] - zeval[0] dDM_cosmic = DM_cosmic_cumul - np.roll(DM_cosmic_cumul, 1) dDM_cosmic[0] = dDM_cosmic[1] # DM_interp = IUS(zeval, dDM_cosmic) dDM_cosm = DM_interp(zvals) * dz_vals / dzeval sub_DM_cosm = np.cumsum(dDM_cosm) f_cosm = IUS(zvals, sub_DM_cosm) zvals2 = np.linspace(z0, zFRB, 1000) DM_cosmic = f_cosm(zvals2) # Ignore halos? if IGM_only: # fhalos = frb_halos.frac_in_halos(zvals, 3e10, 1e16, rmax=1.) fIGM = 1. - fhalos # dDM_IGM = DM_interp(zvals) * fIGM * dz_vals / dzeval sub_DM_IGM = np.cumsum(dDM_IGM) f_IGM = IUS(zvals, sub_DM_IGM) DM_IGM = f_IGM(zvals2) # DM_cosmic = DM_IGM.copy() # Halos at last if fg_halos is not None: for z, halo_DM, lbl in zip(fg_halos['z'], fg_halos['DM'], fg_halos['lbl']): iz = np.argmin(np.abs(zvals2 - z)) DM_cosmic[iz:] += halo_DM # Label d = cosmo.comoving_distance(z) ax1.text(d.to('Gpc').value, DM_cosmic[iz], lbl, color='black', fontsize=13, ha='left', va='top') Dc = cosmo.comoving_distance(zvals2).to('kpc') ds += Dc.value.tolist() DM_cumul += (DM_cosmic + DM_LG).tolist() # Host if host_DM > 0.: ds.append(ds[-1]) DM_cumul.append(DM_cumul[-1] + host_DM) # Plot the DM curve ax1.plot(ds, DM_cumul, 'k') # max_y = np.max(DM_cumul) if FRB_DM is not None: ymax = FRB_DM + 50. if ymax is not None: max_y = ymax # Shade me lsz = 14. ax1.fill_between((0.1, 10.), 0, max_y, color='green', alpha=0.4) # ISM ax1.text(0.15, max_y * yscl, r'\textbf{Galactic}' + '\n' + r'\textbf{ISM}', color='black', fontsize=lsz, ha='left', va='top') ax1.fill_between((10., mnfw_2.r200.value), 0, max_y, color='blue', alpha=0.4) # Galactic Halo ax1.text(12., max_y * yscl, r'\textbf{Galactic}' + '\n' + r'\textbf{Halo}', color='black', fontsize=lsz, ha='left', va='top') if show_M31: ax1.fill_between((mnfw_2.r200.value, 2e3), 0, max_y, color='red', alpha=0.4) # Galactic Halo ax1.text(300., max_y * yscl, r'\texgbf{M31}', color='black', fontsize=lsz, ha='left', va='top') ax1.set_xscale("log", nonposx='clip') # ax.set_yscale("log", nonposy='clip') if show_M31: ax1.set_xlim(0.1, 2e3) # kpc else: ax1.set_xlim(0.1, mnfw_2.r200.value) # kpc ax1.set_ylim(0., max_y) ax1.spines['right'].set_visible(False) ax1.set_xlabel(r'\textbf{Distance (kpc)}') ax1.set_ylabel(r'\textbf{Cumulative DM (pc cm$^{-3}$)}') # IGM Gds = np.array(ds) / 1e6 ax2.plot(Gds, DM_cumul, 'k') ax2.spines['left'].set_visible(False) ax2.yaxis.tick_right() ax2.tick_params(labelright='off') ax2.minorticks_on() ax2.set_xlabel(r'\textbf{Distance (Gpc)}') smax = cosmo.comoving_distance(zFRB).to('Gpc').value #ax2.fill_between((0.1, smax-dsmx), 0, max_y, color='gray', alpha=0.4) # Galactic Halo ax2.fill_between((smin, smax - dsmx), 0, max_y, color='gray', alpha=0.4) # Cosmic ilbl = r'\textbf{Cosmic}' ax2.text(0.2, max_y * yscl, ilbl, color='black', fontsize=lsz, ha='left', va='top') # Host if host_DM > 0.: ax2.fill_between((smax - dsmx, smax + dsmx), 0, max_y, color='red', alpha=0.4) # Host ax2.set_xlim(smin, smax + dsmx) # Gpc else: ax2.set_xlim(smin, smax) # Gpc if FRB_DM is not None: ax1.axhline(y=FRB_DM, ls='--', color='black', lw=3) ax2.axhline(y=FRB_DM, ls='--', color='black', lw=3)
def calc_dm_galaxy(self, model='ymw16'): """ Calculates the dispersion measure contribution of the Milky Way from either (:attr:`raj`, :attr:`decj`) or (:attr:`gl`, :attr:`gb`). Uses the YMW16 model of the Milky Way free electron column density. Parameters ---------- model : 'ymw16' or 'ne2001', optional The Milky Way dispersion measure model. To use 'ne2001' you will need to install the python port. See https://fruitbat.readthedocs.io/en/latest/user_guide/ne2001_installation.html Default: 'ymw16' Returns ------- :obj:`astropy.units.Quantity` The dispersion measure contribution from the Milky Way of the FRB. """ YMW16_options = ["ymw16", "YMW16"] NE2001_options = ["ne2001", "NE2001"] if model in YMW16_options: # Since the YMW16 model only gives you a dispersion measure out to a # distance within the galaxy, to get the entire DM contribution of the # galaxy we need to specify the furthest distance in the YMW16 model. max_galaxy_dist = 25000 # units: pc # Check to make sure some of the keyword are not None coord_list = [ self.skycoords, self.raj, self.decj, self.gl, self.gb ] if all(val is None for val in coord_list): raise ValueError( """Can not calculate dm_galaxy since coordinates for FRB burst were not provided. Please provide (raj, decj) or (gl, gb) coordinates.""") # Calculate skycoords position if it elif (self.skycoords is None and (self.raj is not None and self.decj is not None) or (self.gl is not None and self.gb is not None)): self._skycoords = self.calc_skycoords() dm_galaxy, tau_sc = ymw16.dist_to_dm(self._skycoords.galactic.l, self._skycoords.galactic.b, max_galaxy_dist) elif model in NE2001_options: try: from ne2001 import density except ModuleNotFoundError: msg = (""" By default only the YMW16 Milky Way electron density model is installed with Fruitbat. However Fruitbat due support using the NE2001 model via a python port from JXP and Ben Baror. To install the ne2001 model compatible with Fruitbat download and install it from github: >>> git clone https://github.com/FRBs/ne2001 >>> cd ne2001 >>> pip install . Once you have installed it you should be able to use Fruitbat in exactly the same way by passing 'ne2001' instead of 'ymw16'. """) raise ModuleNotFoundError(msg) # This is the same max distanc e that we used for the YMW16 model # However the NE2001 model specifies distance in kpc not pc. max_galaxy_dist = 25 # units kpc # NE2001 models needs gl and gb in floats gl = float(self._skycoords.galactic.l.value) gb = float(self._skycoords.galactic.b.value) ne = density.ElectronDensity() dm_galaxy = ne.DM(gl, gb, max_galaxy_dist) self.dm_galaxy = dm_galaxy.value self.calc_dm_excess() return self.dm_galaxy
""" Module to correct pulsar and FRB DMs for the MW ISM """ from ne2001 import ne_io, density #ne2001 ism model import pygedm #ymw ism model import numpy as np import pandas as pd from astropy import units as u from astropy.coordinates import SkyCoord, Galactic import logging logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=logging.INFO) ne = density.ElectronDensity() def find_delta_dm(transient_type, transient_data, ism_model, b_val, mc_deg=5, save_df=True): """ Find pulsar/FRB DMs corrected for by the MW ISM DM and remove observations in complex DM regions. Returns array of DMs FRB data is available as a csv in the FRBs/FRB/frb/data/FRBs repo (FRB catalogue [Petroff et al. 2017]) Pulsar data is avaiable as a csv in the FRBs/pulsars/pulsars/data/atnf_cat repo (v1.61 ATNF pulsar catalogue [Manchester et al. 2005]) Arguments: transient_type (str): Accepts 'frb' or 'pulsar'.
def test_electron_density_quad(): tol = 1e-3 ne = density.ElectronDensity() l, b, d = -2, 12, 1 DM = 23.98557 assert abs(ne.DM(l, b, d).value - DM) / DM < tol
import time import numpy as np from numpy.random import rand from numpy.random import randint from ne2001 import density sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/../../src/') PARAMS = density.PARAMS density.set_xyz_sun(np.array([0, 8.5, 0])) if __name__ == '__main__': tol = 1e-3 ne = density.ElectronDensity(**PARAMS) l, b, d = -2, 12, 1 DM = 23.98557 start = time.time() DMc = ne.DM(l, b, d) t1 = time.time() - start start = time.time() DMc = ne.DM(l, b, d) t2 = time.time() - start assert abs(DMc - DM)/DM < tol cProfile.run('ne.DM(l, b, d)', 'restats') print(t1,t2) p = pstats.Stats('restats') p.strip_dirs().sort_stats('cumulative').print_stats(50)