Beispiel #1
0
def test_use():
    # Init
    llim = zLimits(1., (0.999, 1.001), wrest=1215.67 * u.AA)
    # Use
    np.testing.assert_allclose(llim.zlim, (0.999, 1.001))
    np.testing.assert_allclose(llim.wvlim.value, [2430.12433, 2432.55567])
    np.testing.assert_allclose(llim.vlim.value, [-149.93370, 149.858755])
    assert llim.vlim.unit == u.km / u.s
    # Print
    print(llim)
Beispiel #2
0
def test_set():
    # Init
    zlim = (0.999, 1.001)
    llim = zLimits(1., zlim, wrest=1215.67 * u.AA)
    # Set
    llim.set(zlim)
    np.testing.assert_allclose(llim.wvlim.value, [2430.12433, 2432.55567])
    llim.set([2430., 2433.] * u.AA)
    np.testing.assert_allclose(llim.vlim.value, [-165.27207033, 204.61374917])
    llim.set([-160., 200] * u.km / u.s)
Beispiel #3
0
def test_init():
    # Init
    zlim = (0.999, 1.001)
    llim = zLimits(1., zlim)
    # Init
    zlim = (0.999, 1.001)
    llim = zLimits(1., zlim, wrest=1215.67 * u.AA)
    # Test
    with pytest.raises(AttributeError):
        llim.zlim = 3
    # AbsLine
    lya = AbsLine('HI 1215')
    z = 1.
    zlim = (0.999, 1.001)
    llim = zLimits.from_specline(lya, z, zlim)
    # Bad zlim
    with pytest.raises(IOError):
        llim = zLimits(1., (1.1, 1.2), wrest=1215.67 * u.AA, chk_z=True)
    # Null zlim
    llim = zLimits(1., (1., 1), wrest=1215.67 * u.AA)
    assert llim.is_set() is False
Beispiel #4
0
    def update_component_vel(self):
        """Change the velocities of each component to rest frame of zsys
        """
        from linetools.analysis.zlimits import zLimits

        for i, comp in enumerate(self._components):
            dv = ltu.dv_from_z(comp.zcomp, self.zabs)
            zmin = ltu.z_from_dv(comp.limits.vlim[0] + dv, self.zabs)
            zmax = ltu.z_from_dv(comp.limits.vlim[1] + dv, self.zabs)
            newzlim = zLimits(self.zabs, (zmin, zmax))
            comp.limits = newzlim
            comp.attrib['vel'] = comp.attrib['vel'] + dv
Beispiel #5
0
    def __init__(self,
                 radec,
                 Zion,
                 zcomp,
                 vlim,
                 Ej=0. / u.cm,
                 A=None,
                 Ntup=None,
                 comment='',
                 name=None,
                 stars=None,
                 reliability='none'):
        """  Initiator

        Parameters
        ----------
        radec : tuple or SkyCoord
            (RA,DEC) in deg or astropy.coordinate.SkyCoord
        Zion : tuple
            Atomic number, ion -- (int,int)
            e.g. (8,1) for OI
            Note: (-1, -1) is special and is meant for moleculer (e.g. H2)
                  This notation will most likely change in the future.
        zcomp : float
            Absorption component redshift
        vlim : Quantity array
            Velocity limits of the component w/r to `z`
            e.g.  [-300,300]*u.km/u.s
        A : int, optional
            Atomic mass -- used to distinguish isotopes
        Ntup : tuple
            (int,float,two-element list,tuple or array)
            (flag_N, logN, sig_logN)
            flag_N : Flag describing N measurement  (0: no info; 1: detection; 2: saturated; 3: non-detection)
            logN : log10 N column density
            sig_logN : Error in log10 N.  Two elements are expected but not required
        Ej : Quantity, optional
            Energy of lower level (1/cm)
        stars : str, optional
            asterisks to add to name, e.g. '**' for CI**
            Required if name=None and Ej>0.
        reliability : str, optional
            Reliability of AbsComponent
                'a' - reliable
                'b' - possible
                'c' - uncertain
                'none' - not defined (default)
        comment : str, optional
            A comment, default is ``
        """

        # Required
        self.coord = ltu.radec_to_coord(radec)
        self.Zion = Zion
        # Limits
        zlim = ltu.z_from_dv(vlim, zcomp)
        self.limits = zLimits(zcomp, zlim.tolist())

        # Attributes
        self.attrib = init_attrib.copy()

        # Optional
        self.A = A
        self.Ej = Ej
        self.stars = stars
        self.comment = comment
        if Ntup is not None:
            self.attrib['flag_N'] = Ntup[0]
            self.attrib['logN'] = Ntup[1]
            if isiterable(Ntup[2]):
                self.attrib['sig_logN'] = np.array(Ntup[2])
            else:
                self.attrib['sig_logN'] = np.array([Ntup[2]] * 2)
            _, _ = ltaa.linear_clm(self.attrib)  # Set linear quantities

        # Name
        if (name is None) and (self.Zion != (-1, -1)):
            iname = ions.ion_to_name(self.Zion, nspace=0)
            if self.Ej.value > 0:  # Need to put *'s in name
                if stars is not None:
                    iname += stars
                else:
                    warnings.warn(
                        "No stars provided.  Adding one because Ej > 0.")
                    iname += '*'
            self.name = '{:s}_z{:0.5f}'.format(iname, self.zcomp)
        elif (name is None) and (self.Zion == (-1, -1)):
            self.name = 'mol_z{:0.5f}'.format(self.zcomp)
        else:
            self.name = name

        # reliability
        if reliability not in ['a', 'b', 'c', 'none']:
            raise ValueError(
                "Input reliability `{}` not valid.".format(reliability))
        self.reliability = reliability

        # AbsLines
        self._abslines = []
Beispiel #6
0
def test_to_dict():
    # Init
    llim = zLimits(1., (0.999, 1.001), wrest=1215.67 * u.AA)
    ldict = llim.to_dict()
    for key in ['vlim', 'wrest', 'wvlim', 'z', 'zlim']:
        assert key in ldict.keys()
Beispiel #7
0
    def from_dict(cls, idict, coord=None, warn_only=False, chk_data=True, **kwargs):
        """ Initialize from a dict (usually read from disk)

        Parameters
        ----------
        idict : dict
          dict with the Line parameters
        chk_data : bool, optional
          Check atomic data in dict against current values in LineList
        warn_only : bool, optional
          If the chk_data is performed and the values do not match, only
          throw a Warning as opposed to crashing

        Returns
        -------
        sline : SpectralLine
         SpectralLine of the proper type

        """
        # Init
        if idict['ltype'] == 'Abs':
            # TODO: remove this try/except eventually
            try:
                sline = AbsLine(idict['name'], **kwargs)
            except KeyError: #  This is to be compatible JSON files already written with old notation (e.g. DLA H100)
                sline = AbsLine(idict['trans'], **kwargs)
        elif idict['ltype'] == 'Em':
            sline = EmLine(idict['name'], **kwargs)
        else:
            raise ValueError("Not prepared for type {:s}.".format(idict['ltype']))
        # Check data
        if chk_data:
            #for key in idict['data']:
            for key in sline.data.keys():
                if key not in idict['data'].keys():
                    warnings.warn("Key {:s} not in your input dict".format(key))
                    continue
                if isinstance(idict['data'][key], dict):  # Assume Quantity
                    val = idict['data'][key]['value']
                else:
                    val = idict['data'][key]
                try:
                    assert sline.data[key] == val
                except AssertionError:
                    if warn_only:
                        warnings.warn("Different data value for {:s}: {}, {}".format(key,sline.data[key],val))
        # Set analy
        for key in idict['analy'].keys():
            if isinstance(idict['analy'][key], dict):  # Assume Quantity
                #sline.analy[key] = Quantity(idict['analy'][key]['value'],
                #                             unit=idict['analy'][key]['unit'])
                #pdb.set_trace()
                sline.analy[key] = ltu.convert_quantity_in_dict(idict['analy'][key])
            elif key == 'spec_file':
                # spec_file is intended to be the name of the spectrum file
                # spec is intended to hold an XSpectrum1D object
                #warnings.warn("You will need to load {:s} into analy['spec'] yourself".format(
                #        idict['analy'][key]))
                sline.analy[key] = idict['analy'][key]
            else:
                sline.analy[key] = idict['analy'][key]

        # Set attrib
        for key in idict['attrib'].keys():
            if isinstance(idict['attrib'][key], dict):
                sline.attrib[key] = ltu.convert_quantity_in_dict(idict['attrib'][key])
            elif key in ['RA','DEC']:
                if coord is None:
                    sline.attrib['coord'] = SkyCoord(ra=idict['attrib']['RA']*u.deg,
                                                  dec=idict['attrib']['DEC']*u.deg)
                else:
                    sline.attrib['coord'] = coord
            else:
                sline.attrib[key] = idict['attrib'][key]

        # Set z and limits
        if 'z' in sline.attrib.keys():  # Backwards compatability
            z = sline.attrib.pop('z')
        else:
            z = 0.
        if 'limits' in idict.keys():
            if 'wrest' not in idict['limits'].keys(): # compatibility with IGMGuesses
                # import pdb; pdb.set_trace()
                idict['limits']['wrest'] = ltu.jsonify(sline.wrest)
                idict['limits']['z'] = z
            sline.limits = zLimits.from_dict(idict['limits'])
        else:
            sline.limits = zLimits(z, [z,z], wrest=sline.wrest)
            if 'vlim' in sline.analy.keys():  # Backwards compatability
                if sline.analy['vlim'][1] > sline.analy['vlim'][0]:
                    sline.limits.set(sline.analy['vlim'])
            elif 'wvlim' in sline.analy.keys():  # Backwards compatability
                if sline.analy['wvlim'][1] > sline.analy['wvlim'][0]:
                    sline.limits.set(sline.analy['wvlim'])
        return sline
Beispiel #8
0
def cgm_from_galaxy_igmsystems(galaxy,
                               igmsystems,
                               rho_max=300 * u.kpc,
                               dv_max=400 * u.km / u.s,
                               cosmo=None,
                               dummysys=False,
                               dummyspec=None,
                               verbose=True,
                               **kwargs):
    """ Generate a list of CGMAbsSys objects given an input galaxy and a list of IGMSystems

    Parameters
    ----------
    galaxy : Galaxy
    igmsystems : list
      list of IGMSystems
    rho_max : Quantity
      Maximum projected separation from sightline to galaxy
    dv_max
      Maximum velocity offset between system and galaxy
    dummysys: bool, optional
        If True, instantiate CGMAbsSys even if no match is found in igmsystems
    dummyspec : XSpectrum1D, optional
        Spectrum object to attach to dummy AbsLine/AbsComponent objects when
        adding IGMSystems if dummysys is True.

    Returns
    -------
    cgm_list : list
      list of CGM objects generated

    """
    from pyigm.cgm.cgm import CGMAbsSys
    # Cosmology
    if cosmo is None:
        cosmo = cosmology.Planck15

    if dummysys is True:
        if dummyspec is None:
            dummyspec = igmsystems[0]._components[0]._abslines[0].analy['spec']
        dummycoords = igmsystems[0].coord

    # R -- speed things up
    rho, angles = calc_cgm_rho(galaxy, igmsystems, cosmo, **kwargs)
    if len(igmsystems) == 1:  # Kludge
        rho = u.Quantity([rho])
        angles = u.Quantity([angles])

    # dv
    igm_z = np.array([igmsystem.zabs for igmsystem in igmsystems])
    dv = ltu.dv_from_z(igm_z, galaxy.z)

    # Rules
    match = np.where((rho < rho_max) & (np.abs(dv) < dv_max))[0]

    ### If none, see if some system has a component that's actually within dv_max
    if (len(match) == 0) & (rho[0] < rho_max):
        zcomps = []
        sysidxs = []
        for i, csys in enumerate(igmsystems):
            thesezs = [comp.zcomp for comp in csys._components]
            sysidxs.extend([i] * len(thesezs))
            zcomps.extend(thesezs)
        zcomps = np.array(zcomps)
        sysidxs = np.array(sysidxs)
        dv_comps = ltu.dv_from_z(zcomps, galaxy.z)
        match = np.unique(sysidxs[np.where(np.abs(dv_comps) < dv_max)[0]])

    if len(match) == 0:
        if dummysys is False:
            print(
                "No IGMSystem paired to this galaxy. CGM object not created.")
            return []
        else:
            if verbose:
                print("No IGMSystem match found. Attaching dummy IGMSystem.")
            dummysystem = IGMSystem(dummycoords, galaxy.z, vlim=None)
            dummycomp = AbsComponent(dummycoords, (1, 1), galaxy.z,
                                     [-100., 100.] * u.km / u.s)
            dummycomp.flag_N = 3
            dummyline = AbsLine(
                'HI 1215',
                **kwargs)  # Need an actual transition for comp check
            dummyline.analy['spec'] = dummyspec
            dummyline.attrib['coord'] = dummycoords
            dummycomp.add_absline(dummyline, chk_vel=False, chk_sep=False)
            dummysystem.add_component(dummycomp, chk_vel=False, chk_sep=False)
            cgm = CGMAbsSys(galaxy, dummysystem, cosmo=cosmo, **kwargs)
            cgm_list = [cgm]
    else:
        # Loop to generate
        cgm_list = []
        for imatch in match:
            # Instantiate new IGMSystem
            # Otherwise, updates to the IGMSystem cross-pollinate other CGMs
            sysmatch = igmsystems[imatch]
            newisys = sysmatch.copy()
            # Handle z limits
            zlim = ltu.z_from_dv((-dv_max.value, dv_max.value) * u.km / u.s,
                                 galaxy.z)
            newlims = zLimits(galaxy.z, zlim.tolist())
            newisys.limits = newlims
            # Allow for components extending beyond dv_max
            newisys.update_vlim()
            newisys.update_component_vel()
            # Finish
            cgm = CGMAbsSys(galaxy,
                            newisys,
                            cosmo=cosmo,
                            rho=rho[imatch],
                            ang_sep=angles[imatch],
                            **kwargs)
            cgm_list.append(cgm)

    # Return
    return cgm_list
Beispiel #9
0
    def from_dict(cls,
                  idict,
                  coord=None,
                  warn_only=False,
                  chk_data=True,
                  **kwargs):
        """ Initialize from a dict (usually read from disk)

        Parameters
        ----------
        idict : dict
          dict with the Line parameters
        chk_data : bool, optional
          Check atomic data in dict against current values in LineList
        warn_only : bool, optional
          If the chk_data is performed and the values do not match, only
          throw a Warning as opposed to crashing

        Returns
        -------
        sline : SpectralLine
         SpectralLine of the proper type

        """
        # Init
        if idict['ltype'] == 'Abs':
            # TODO: remove this try/except eventually
            try:
                sline = AbsLine(idict['name'], **kwargs)
            except KeyError:  #  This is to be compatible JSON files already written with old notation (e.g. DLA H100)
                sline = AbsLine(idict['trans'], **kwargs)
        elif idict['ltype'] == 'Em':
            sline = EmLine(idict['name'], **kwargs)
        else:
            raise ValueError("Not prepared for type {:s}.".format(
                idict['ltype']))
        # Check data
        if chk_data:
            #for key in idict['data']:
            for key in sline.data.keys():
                if key not in idict['data'].keys():
                    warnings.warn(
                        "Key {:s} not in your input dict".format(key))
                    continue
                if isinstance(idict['data'][key], dict):  # Assume Quantity
                    val = idict['data'][key]['value']
                else:
                    val = idict['data'][key]
                try:
                    assert sline.data[key] == val
                except AssertionError:
                    if warn_only:
                        warnings.warn(
                            "Different data value for {:s}: {}, {}".format(
                                key, sline.data[key], val))
        # Set analy
        for key in idict['analy'].keys():
            if isinstance(idict['analy'][key], dict):  # Assume Quantity
                #sline.analy[key] = Quantity(idict['analy'][key]['value'],
                #                             unit=idict['analy'][key]['unit'])
                #pdb.set_trace()
                sline.analy[key] = ltu.convert_quantity_in_dict(
                    idict['analy'][key])
            elif key == 'spec_file':
                # spec_file is intended to be the name of the spectrum file
                # spec is intendended to hold an XSpectrum1D object
                warnings.warn(
                    "You will need to load {:s} into analy['spec'] yourself".
                    format(idict['analy'][key]))
                sline.analy[key] = idict['analy'][key]
            else:
                sline.analy[key] = idict['analy'][key]

        # Set attrib
        for key in idict['attrib'].keys():
            if isinstance(idict['attrib'][key], dict):
                sline.attrib[key] = ltu.convert_quantity_in_dict(
                    idict['attrib'][key])
            elif key in ['RA', 'DEC']:
                if coord is None:
                    sline.attrib['coord'] = SkyCoord(
                        ra=idict['attrib']['RA'] * u.deg,
                        dec=idict['attrib']['DEC'] * u.deg)
                else:
                    sline.attrib['coord'] = coord
            else:
                sline.attrib[key] = idict['attrib'][key]

        # Set z and limits
        if 'z' in sline.attrib.keys():  # Backwards compatability
            z = sline.attrib.pop('z')
        else:
            z = 0.
        if 'limits' in idict.keys():
            if 'wrest' not in idict['limits'].keys(
            ):  # compatibility with IGMGuesses
                # import pdb; pdb.set_trace()
                idict['limits']['wrest'] = ltu.jsonify(sline.wrest)
                idict['limits']['z'] = z
            sline.limits = zLimits.from_dict(idict['limits'])
        else:
            sline.limits = zLimits(z, [z, z], wrest=sline.wrest)
            if 'vlim' in sline.analy.keys():  # Backwards compatability
                if sline.analy['vlim'][1] > sline.analy['vlim'][0]:
                    sline.limits.set(sline.analy['vlim'])
            elif 'wvlim' in sline.analy.keys():  # Backwards compatability
                if sline.analy['wvlim'][1] > sline.analy['wvlim'][0]:
                    sline.limits.set(sline.analy['wvlim'])
        return sline
Beispiel #10
0
    def __init__(self,
                 radec,
                 zabs,
                 vlim,
                 zem=0.,
                 abs_type=None,
                 NHI=0.,
                 sig_NHI=np.zeros(2),
                 flag_NHI=None,
                 name=None,
                 **kwargs):

        self.zem = zem
        # Limits
        zlim = ltu.z_from_dv(vlim, zabs)
        self.limits = zLimits(zabs, zlim.tolist())
        # NHI
        self.NHI = NHI
        self.sig_NHI = sig_NHI
        # Special handling for the flag as this is often not input with NHI
        if flag_NHI is None:
            if NHI > 0.:
                self.flag_NHI = 1
            else:
                self.flag_NHI = 0
        else:
            self.flag_NHI = flag_NHI
        self.coord = ltu.radec_to_coord(radec)
        if name is None:
            self.name = 'J{:s}{:s}_z{:.6f}'.format(  # Should be unique
                self.coord.icrs.ra.to_string(unit=u.hour, sep='', pad=True),
                self.coord.icrs.dec.to_string(sep='',
                                              pad=True,
                                              alwayssign=True), self.zabs)
        else:
            self.name = name

        # Abs type
        if abs_type is None:
            self.abs_type = 'NONE'
        else:
            self.abs_type = abs_type

        # Components
        self._components = []  # List of AbsComponent objects

        # Kinematics
        self.kin = {}

        # Metallicity
        self.ZH = 0.
        self.sig_ZH = 0.
        self.flag_ZH = 0

        # Abundances and Tables
        self._EW = Table()
        self._ionN = None  # Needs to be None for fill_ion
        self._trans = Table()
        self._ionstate = {}
        self._abund = Table()

        # Refs (list of references)
        self.Refs = []
Beispiel #11
0
    def __init__(self, radec, Zion, zcomp, vlim, Ej=0./u.cm, A=None,
                 Ntup=None, comment='', name=None, stars=None, reliability='none'):
        """  Initiator

        Parameters
        ----------
        radec : tuple or SkyCoord
            (RA,DEC) in deg or astropy.coordinate.SkyCoord
        Zion : tuple
            Atomic number, ion -- (int,int)
            e.g. (8,1) for OI
            Note: (-1, -1) is special and is meant for moleculer (e.g. H2)
                  This notation will most likely change in the future.
        zcomp : float
            Absorption component redshift
        vlim : Quantity array
            Velocity limits of the component w/r to `z`
            e.g.  [-300,300]*u.km/u.s
        A : int, optional
            Atomic mass -- used to distinguish isotopes
        Ntup : tuple
            (int,float,two-element list,tuple or array)
            (flag_N, logN, sig_logN)
            flag_N : Flag describing N measurement  (0: no info; 1: detection; 2: saturated; 3: non-detection)
            logN : log10 N column density
            sig_logN : Error in log10 N.  Two elements are expected but not required
        Ej : Quantity, optional
            Energy of lower level (1/cm)
        stars : str, optional
            asterisks to add to name, e.g. '**' for CI**
            Required if name=None and Ej>0.
        reliability : str, optional
            Reliability of AbsComponent
                'a' - reliable
                'b' - possible
                'c' - uncertain
                'none' - not defined (default)
        comment : str, optional
            A comment, default is ``
        """

        # Required
        self.coord = ltu.radec_to_coord(radec)
        self.Zion = Zion
        # Limits
        zlim = ltu.z_from_dv(vlim, zcomp)
        self.limits = zLimits(zcomp, zlim.tolist())

        # Attributes
        self.attrib = init_attrib.copy()

        # Optional
        self.A = A
        self.Ej = Ej
        self.stars = stars
        self.comment = comment
        if Ntup is not None:
            self.attrib['flag_N'] = Ntup[0]
            self.attrib['logN'] = Ntup[1]
            if isiterable(Ntup[2]):
                self.attrib['sig_logN'] = np.array(Ntup[2])
            else:
                self.attrib['sig_logN'] = np.array([Ntup[2]]*2)
            _, _ = ltaa.linear_clm(self.attrib)  # Set linear quantities

        # Name
        if (name is None) and (self.Zion != (-1, -1)):
            iname = ions.ion_to_name(self.Zion, nspace=0)
            if self.Ej.value > 0:  # Need to put *'s in name
                if stars is not None:
                    iname += stars
                else:
                    warnings.warn("No stars provided.  Adding one because Ej > 0.")
                    iname += '*'
            self.name = '{:s}_z{:0.5f}'.format(iname, self.zcomp)
        elif (name is None) and (self.Zion == (-1, -1)):
            self.name = 'mol_z{:0.5f}'.format(self.zcomp)
        else:
            self.name = name

        # reliability
        if reliability not in ['a', 'b', 'c', 'none']:
            raise ValueError("Input reliability `{}` not valid.".format(reliability))
        self.reliability = reliability

        # AbsLines
        self._abslines = []