Esempio n. 1
0
def test_dist_to_dm():
    """ Test that astropy units / angles work with dist_to_dm """
    a = pygedm.dist_to_dm(204, -6.5, 200, method='ne2001')
    b = pygedm.dist_to_dm(Angle(204, unit='degree'), Angle(-6.5, unit='degree'), 200, method='ne2001')
    c = pygedm.dist_to_dm(204, -6.5, 200 * Unit('pc'), method='ne2001')
    assert a[0] == b[0] == c[0]
    assert a[1] == b[1] == c[1]
Esempio n. 2
0
def test_tau_sc_nu():
    """ Test that tau_sc changes with nu """
    dm, tau_sc = pygedm.dist_to_dm(0, 0, 100, method='ymw16', nu=1)
    dm_, tau_sc_ = pygedm.dist_to_dm(0, 0, 100, method='ymw16', nu=1000*u.MHz)
    assert dm == dm_
    assert tau_sc == tau_sc_

    dm, tau_sc = pygedm.dist_to_dm(0, 0, 100, method='ne2001', nu=1)
    dm_, tau_sc_ = pygedm.dist_to_dm(0, 0, 100, method='ne2001', nu=1000*u.MHz)
    assert dm == dm_
    assert tau_sc == tau_sc_    
    
    dist, tau_sc = pygedm.dist_to_dm(0, 0, 100, method='ymw16', nu=1)
    dist_, tau_sc_ = pygedm.dist_to_dm(0, 0, 100, method='ymw16', nu=1000*u.MHz)
    assert dist == dist_
    assert tau_sc == tau_sc_        

    dist, tau_sc = pygedm.dist_to_dm(0, 0, 100, method='ne2001', nu=1)
    dist_, tau_sc_ = pygedm.dist_to_dm(0, 0, 100, method='ne2001', nu=1000*u.MHz)
    assert dist == dist_
    assert tau_sc == tau_sc_     
    
    dm, tau_sc_1GHz = pygedm.dm_to_dist(0, 0, 1000, method='ymw16', nu=1.0)
    dm, tau_sc_100MHz = pygedm.dm_to_dist(0, 0, 1000, method='ymw16', nu=0.1)
    assert np.isclose(tau_sc_1GHz.value, 0.31681767)
    assert np.isclose(tau_sc_100MHz.value, 3168.17671061)
    
    assert np.isclose((0.1/1.0)**(-4) * tau_sc_1GHz.value, tau_sc_100MHz.value)
    
    dm, tau_sc_1GHz = pygedm.dm_to_dist(0, 0, 1000, method='ne2001', nu=1.0)
    dm, tau_sc_100MHz = pygedm.dm_to_dist(0, 0, 1000, method='ne2001', nu=0.1)
    assert np.isclose(tau_sc_1GHz.value, 198.57881596)
    assert np.isclose(tau_sc_100MHz.value, 4988074.33385041)    
Esempio n. 3
0
def test_raises():
    """ Test that IGM mode FAILS as expected """
    with pytest.raises(RuntimeError):
        pygedm.dm_to_dist(100, 10, 100, method='ymw1066')
    with pytest.raises(RuntimeError):
        pygedm.dist_to_dm(100, 10, 100, method='ne2020')
    with pytest.raises(RuntimeError):
        pygedm.calculate_electron_density_xyz(100, 10, 100, method='tc93')
    with pytest.raises(RuntimeError):
        pygedm.calculate_electron_density_lbr(100,
                                              10,
                                              100,
                                              method='ymwPaleolithic')
    with pytest.raises(RuntimeError):
        pygedm.dist_to_dm(100, 10, 100, mode='igm', method='ne2001')
    with pytest.raises(RuntimeError):
        pygedm.convert_lbr_to_xyz(0, 0, 0, method='chicken')
Esempio n. 4
0
def test_igm():
    """ Test that IGM mode works as expected

    Note: tested against YMW16 code with:
    # CMD:    ./ ymw16 -d data -v IGM 204 -6.5 2000 100 1
    # OUTPUT: DM_Gal:  252.05 DM_MC:    0.00 DM_IGM: 1647.95 DM_Host:  100.00
    #         z:  2.311   Dist:  5336.4   log(tau_sc): -2.218
    """

    dist, tau = pygedm.dm_to_dist(204, -6.5, 2000, dm_host=100, mode='igm')
    assert np.isclose(dist.value, 5336.4, rtol=0.1)
    assert np.isclose(np.log10(tau.value), -2.218, rtol=0.1)

    dm, tau = pygedm.dist_to_dm(204, -6.5, 5336.4, mode='igm')
    dm_total = dm.value + 252.05 + 100  # Add galactic and host contribution
    assert np.isclose(dm_total, 2000, rtol=0.1)

    dm, tau = pygedm.dist_to_dm(204, -6.5, 5336.4 * u.Mpc, mode='igm')
    dm_total = dm.value + 252.05 + 100  # Add galactic and host contribution
    assert np.isclose(dm_total, 2000, rtol=0.1)
Esempio n. 5
0
    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", "ne2001"]

        if model.lower() in YMW16_options:
            # Since the GEDMs only give a dispersion measure out to a
            # distance within the galaxy, to get the entire DM contribution of the
            # galaxy we need to integrate across the full Galaxy
            max_galaxy_dist = 30 * u.kpc  # 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 = pygedm.dist_to_dm(self._skycoords.galactic.l,
                                                  self._skycoords.galactic.b,
                                                  max_galaxy_dist,
                                                  method=model)

        self.dm_galaxy = dm_galaxy.value
        self.calc_dm_excess()
        return self.dm_galaxy
Esempio n. 6
0
def test_magellanic_cloud():
    """ Test that MC mode agrees with YMW16

    Note: tested against YMW16 code with:
    CMD:        ./ymw16 -d data -v MC 280.46 -32.88 50000 2
    OUTPUT:     MC: gl= 280.460 gb= -32.880 Dist=  50000.0
                dtest=50000.000000, nstep=10000.000000, dstep=5.000000
                DM_Gal:   58.03 DM_MC:   78.87 DM:  136.90 log(tau_sc): -5.399
    """
    dm, tau = pygedm.dist_to_dm(280.46, -32.88, 50000, mode='mc')
    assert np.isclose(dm.value, 136.90)
    assert np.isclose(np.log10(tau.value), -5.399, rtol=0.1)
Esempio n. 7
0
def test_basic():
    """ Basic tests of YMW16 model

    Note: tested against online NE2001 interface
    https://www.nrl.navy.mil/rsd/RORF/ne2001/
    """

    # No access to actual model via web interface
    #a = pygedm.calculate_electron_density_xyz(1, 2, 3)
    #assert np.isclose(a.value, 5.220655, atol=0.0001)

    # FRB180301 value
    dm, tau = pygedm.dist_to_dm(204, -6.5, 25*u.kpc, method='ne2001')
    assert np.isclose(dm.value, 150.80, atol=0.01)

    # Loop through distances and check round trip
    for dist in (10.*u.pc, 100.*u.pc, 1000.*u.pc):
        dm, tau = pygedm.dist_to_dm(0, 0, dist, method='ne2001')
        dist_out, tau = pygedm.dm_to_dist(0, 0, dm, method='ne2001')
        print(dist, dm, dist_out)
        assert np.isclose(dist_out.to('pc').value, dist.to('pc').value, rtol=0.1)
Esempio n. 8
0
def test_basic():
    """ Basic tests of YMW16 model

    Note: tested against online YMW16 interface
    http://www.atnf.csiro.au/research/pulsar/ymw16/index.php
    """

    a = pygedm.calculate_electron_density_xyz(1, 2, 3)
    assert np.isclose(a.value, 5.220655, atol=0.0001)

    a = pygedm.calculate_electron_density_lbr(0, 0, 4000)
    assert np.isclose(a.value, 0.388407, atol=0.0001)

    # FRB180301 value
    dm, tau = pygedm.dist_to_dm(204, -6.5, 25000)
    assert np.isclose(dm.value, 252.0501, atol=0.01)

    # Loop through distances and check round trip
    for dist in (10., 100., 1000.):
        dm, tau = pygedm.dist_to_dm(0, 0, dist)
        dist_out, tau = pygedm.dm_to_dist(0, 0, dm.value)
        assert np.isclose(dist_out.value, dist, rtol=0.1)
Esempio n. 9
0
    def test_frb_calc_dm_galaxy(self):
        dm_galaxy = self.frb_raj_decj.calc_dm_galaxy()
        dm_pymw16, t_sc_pymw16 = pygedm.dist_to_dm(
            self.frb_raj_decj.skycoords.galactic.l,
            self.frb_raj_decj.skycoords.galactic.b, 30 * u.kpc)
        assert np.isclose(dm_galaxy.value, dm_pymw16.value)

        dm_galaxy = self.frb_raj_decj.calc_dm_galaxy(model='ne2001')
        dm_ne2001, t_sc_ne2001 = pygedm.dist_to_dm(
            self.frb_raj_decj.skycoords.galactic.l,
            self.frb_raj_decj.skycoords.galactic.b,
            30 * u.kpc,
            method='ne2001')
        assert np.isclose(dm_galaxy.value, dm_ne2001.value)

        dm_galaxy = self.frb_raj_decj.calc_dm_galaxy(model='ymw16')
        dm_pymw16, t_sc_pymw16 = pygedm.dist_to_dm(
            self.frb_raj_decj.skycoords.galactic.l,
            self.frb_raj_decj.skycoords.galactic.b,
            30 * u.kpc,
            method='ymw16')
        assert np.isclose(dm_galaxy.value, dm_pymw16.value)
Esempio n. 10
0
import pygedm

print("\n--- DM to dist ---")
print("YMW16:", pygedm.dm_to_dist(100, 0, 250, dm_host=0, method='ymw16'))
print("NE2001:", pygedm.dm_to_dist(100, 0, 250, dm_host=0, method='ne2001'))

print("\n--- dist to DM ---")
print("YMW16:", pygedm.dist_to_dm(100, 0, 250, method='ymw16'))
print("NE2001:", pygedm.dist_to_dm(100, 0, 250, method='ne2001'))

print("\n--- Electron density ---")
print("YMW16:", pygedm.calculate_electron_density_xyz(0, 0, 0, method='ymw16'))
print("NE2001:", pygedm.calculate_electron_density_xyz(0, 0, 0, method='ne2001'))
Esempio n. 11
0
    def calc_dm_galaxy(self,
                       model='ymw16',
                       include_halo=False,
                       return_tau_sc=False):
        """
        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'

        include_halo : bool, optional
            Include the DM of the galactic halo which isn't included
            in NE2001 or YMW16. This used the YT2020 halo model. Default: False

        return_tau_sc : bool, optional
            Return the scattering timescale in addition to the DM.
            Default: False

        Returns
        -------
        dm_galaxy: :obj:`astropy.units.Quantity`
            The dispersion measure contribution from the Milky Way of
            the FRB.

        tau_sc: :obj:`astropy.units.Quantity`, optional
            The scattering timescale at 1 GHz (s). Only returns if
            :attr:`return_tau_sc` is `True`.

        """
        YMW16_options = ["ymw16", "YMW16"]
        NE2001_options = ["ne2001", "NE2001"]

        if model in YMW16_options:
            model = 'YMW16'
        elif model in NE2001_options:
            model = 'NE2001'
        else:
            raise ValueError(
                "'{}' is not a valid galactic DM model".format(model))

        # 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 = pygedm.dist_to_dm(gl=self._skycoords.galactic.l,
                                              gb=self._skycoords.galactic.b,
                                              dist=25000.0,
                                              method=model)

        if include_halo:
            self.galaxy_halo = pygedm.calculate_halo_dm(
                gl=self._skycoords.galactic.l,
                gb=self._skycoords.galactic.b,
                method='yt2020')

        else:
            self.galaxy_halo = 0 * u.pc * u.cm**(-3)

        self.dm_galaxy_model = model
        self.dm_galaxy = dm_galaxy.value + self.galaxy_halo.value
        self.tau_sc = tau_sc.value
        self.calc_dm_excess()

        if return_tau_sc:
            return self.dm_galaxy, self.tau_sc
        else:
            return self.dm_galaxy
Esempio n. 12
0
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'.
        transient_data (str):
            Path to data (in .csv format).
        ism_model (str):
            Model used to calculated the MW halo DM.
            Accepts 'ymw16'  [Yao et al. 2017] or 'ne2001' [Cordes & Lazio 2003].
        b_val (int):
            Galactic latitude considered (b>b_val, b<-b_val).
        mc_deg (int):
            Number of degrees from Magellanic clouds within which transients are removed.
        save_df (str, optional):
            Save transient DMs and coords to csv.
    
    Outputs:
    """
    # Sort data and get coords
    if transient_type == 'frb':
        transcat_df = pd.read_csv(transient_data,
                                  skiprows=1,
                                  usecols=[0, 5, 6, 7],
                                  names=['Name', 'l', 'b', 'dm'])
        transcat_df['dm'] = transcat_df['dm'].str.split('&').str[0].astype(
            float).values
        coords = SkyCoord(l=transcat_df['l'],
                          b=transcat_df['b'],
                          unit=(u.degree),
                          frame=Galactic)
    elif transient_type == 'pulsar':
        transcat_df = pd.read_csv(
            transient_data,
            skiprows=2,
            usecols=[1, 2, 3, 9, 10],
            names=['Name', 'Pref', 'dm', 'RAJD', 'DECJD'])
        transcat_df = transcat_df[~transcat_df['dm'].str.
                                  contains('*', regex=False)].reset_index(
                                      drop=True)
        transcat_df['dm'] = transcat_df['dm'].astype(float)
        c_icrs = SkyCoord(ra=transcat_df['RAJD'],
                          dec=transcat_df['DECJD'],
                          unit=(u.degree),
                          frame='icrs')
        transcat_df['l'] = pd.DataFrame(c_icrs.galactic.l.value)
        transcat_df['b'] = pd.DataFrame(c_icrs.galactic.b.value)
        coords = SkyCoord(l=transcat_df['l'],
                          b=transcat_df['b'],
                          unit=(u.degree),
                          frame=Galactic)

    # Find transients in line of sight of MCs
    logging.info('Removing transients near Magellanic clouds...')
    # LMC
    lmc_distance = 50 * u.kpc
    lmc_coord = SkyCoord('J052334.6-694522',
                         unit=(u.hourangle, u.deg),
                         distance=lmc_distance)
    close_to_lmc = lmc_coord.separation(coords) < mc_deg * u.deg
    lmc_trans = list(transcat_df[close_to_lmc]['Name'])
    # SMC
    smc_distance = 61 * u.kpc
    smc_coord = SkyCoord('J005238.0-724801',
                         unit=(u.hourangle, u.deg),
                         distance=smc_distance)
    close_to_smc = smc_coord.separation(coords) < mc_deg * u.deg
    smc_trans = list(transcat_df[close_to_smc]['Name'])

    transcat_df = transcat_df[~transcat_df['Name'].
                              isin(lmc_trans)].reset_index(drop=True)
    transcat_df = transcat_df[~transcat_df['Name'].
                              isin(smc_trans)].reset_index(drop=True)
    if transient_type == 'pulsar':
        transcat_df = transcat_df[~transcat_df['Pref'].str.
                                  contains('mfl+06', regex=False)].reset_index(
                                      drop=True)
    elif transient_type == 'frb':
        pass

    # Remove transients with low Galactic lattitudes
    logging.info('Removing transients with low Galactic lattitudes...')
    transcat_df = pd.concat([
        transcat_df[transcat_df.b > b_val], transcat_df[transcat_df.b < -b_val]
    ],
                            ignore_index=True)

    # ISM model
    logging.info('Correcting transient DMs for ISM...')
    trans_ism = []
    if ism_model == 'ymw16':
        for i in range(len(transcat_df['dm'])):
            trans_ism_ = pygedm.dist_to_dm(transcat_df['l'].iloc[i],
                                           transcat_df['b'].iloc[i],
                                           100000)[0].value
            trans_ism = np.append(trans_ism, trans_ism_)
    elif ism_model == 'ne2001':
        for i in range(len(transcat_df['dm'])):
            trans_ism_ = ne.DM(transcat_df['l'].iloc[i],
                               transcat_df['b'].iloc[i], 100.).value
            trans_ism = np.append(trans_ism, trans_ism_)

    transcat_df['trans_ism'] = pd.DataFrame(trans_ism)
    transcat_df['deltaDM'] = pd.DataFrame(transcat_df['dm'] -
                                          transcat_df['trans_ism'])

    if save_df == True:
        transcat_df.to_csv('transient_data/' + transient_type + 'cat_df_' +
                           ism_model + '_' + str(int(b_val)) + '.csv')
        logging.info('Transient data saved to csv.')
    else:
        pass

    return np.array(transcat_df['deltaDM'])