Ejemplo n.º 1
0
    def to_dict(self):
        """ Convert component data to a dict
        
        Returns
        -------
        cdict : dict
        """
        cdict = dict(
            Zion=self.Zion,
            zcomp=self.zcomp,
            vlim=self.vlim.to('km/s').value,
            Name=self.name,
            RA=self.coord.icrs.ra.value,
            DEC=self.coord.icrs.dec.value,
            A=self.A,
            Ej=self.Ej.to('1/cm').value,
            comment=self.comment,
            attrib=self.attrib.copy())  # Avoids changing the dict in place
        cdict['class'] = self.__class__.__name__
        # AbsLines
        cdict['lines'] = {}
        for iline in self._abslines:
            cdict['lines'][iline.wrest.value] = iline.to_dict()
        # set linear quantities in column density
        _, _ = ltaa.linear_clm(cdict['attrib'])

        # Polish
        cdict = ltu.jsonify(cdict)
        # Return
        return cdict
Ejemplo n.º 2
0
def mk_comp(ctype,vlim=[-300.,300]*u.km/u.s,add_spec=False, use_rand=True,
            add_trans=False, zcomp=2.92939, b=20*u.km/u.s):
    # Read a spectrum Spec
    if add_spec:
        xspec = lsio.readspec(lt_path+'/spectra/tests/files/UM184_nF.fits')
    else:
        xspec = None
    # AbsLines
    if ctype == 'HI':
        all_trans = ['HI 1215', 'HI 1025']
    elif ctype == 'SiII':
        all_trans = ['SiII 1260', 'SiII 1304', 'SiII 1526', 'SiII 1808']
        if add_trans:
            all_trans += ['SiII 1193']
    abslines = []
    for trans in all_trans:
        iline = AbsLine(trans, z=zcomp)
        if use_rand:
            rnd = np.random.rand()
        else:
            rnd = 0.
        iline.attrib['logN'] = 13.3 + rnd
        iline.attrib['sig_logN'] = 0.15
        iline.attrib['flag_N'] = 1
        iline.attrib['b'] = b
        iline.analy['spec'] = xspec
        iline.limits.set(vlim)
        _,_ = ltaa.linear_clm(iline.attrib)  # Loads N, sig_N
        abslines.append(iline)
    # Component
    abscomp = AbsComponent.from_abslines(abslines)
    return abscomp, abslines
Ejemplo n.º 3
0
def test_linearclm():
    obj = type(str('Dummy'), (object, ), {
        str('logN'): 13,
        str('sig_logN'): 0.2
    })
    #
    N, sig_N = linear_clm(obj)
    np.testing.assert_allclose(N.value, 1e13)
Ejemplo n.º 4
0
def mk_comp(ctype,
            vlim=[-300., 300] * u.km / u.s,
            add_spec=False,
            use_rand=True,
            add_trans=False,
            zcomp=2.92939,
            b=20 * u.km / u.s,
            **kwargs):
    # Read a spectrum Spec
    if add_spec:
        spec_file = resource_filename('linetools',
                                      '/spectra/tests/files/UM184_nF.fits')
        xspec = lsio.readspec(spec_file)
    else:
        xspec = None
    # AbsLines
    if ctype == 'HI':
        all_trans = ['HI 1215', 'HI 1025']
    elif ctype == 'SiII':
        all_trans = ['SiII 1260', 'SiII 1304', 'SiII 1526', 'SiII 1808']
        if add_trans:
            all_trans += ['SiII 1193']
    elif ctype == 'SiII*':
        all_trans = ['SiII* 1264', 'SiII* 1533']
    elif ctype == 'SiIII':
        all_trans = ['SiIII 1206']
    abslines = []
    for trans in all_trans:
        iline = AbsLine(trans, z=zcomp, linelist=ism)
        if use_rand:
            rnd = np.random.rand()
        else:
            rnd = 0.
        iline.attrib['logN'] = 13.3 + rnd
        iline.attrib['sig_logN'] = 0.15
        iline.attrib['flag_N'] = 1
        iline.attrib['b'] = b
        iline.analy['spec'] = xspec
        iline.limits.set(vlim)
        _, _ = ltaa.linear_clm(iline.attrib)  # Loads N, sig_N
        abslines.append(iline)
    # Component
    abscomp = AbsComponent.from_abslines(abslines, **kwargs)
    return abscomp, abslines
Ejemplo n.º 5
0
def test_linearclm():
    obj = type(str('Dummy'), (object,), { str('logN'): 13, str('sig_logN'): 0.2 })
    #
    N, sig_N = linear_clm(obj)
    np.testing.assert_allclose(N.value, 1e13)
Ejemplo n.º 6
0
def abslines_from_VPfile(parfile,
                         specfile=None,
                         ra=None,
                         dec=None,
                         linelist=None):
    '''
    Takes a joebvp parameter file and builds a list of linetools AbsLines from the measurements therein.

    Parameters
    ----------
    parfile : str
        Name of the parameter file in the joebvp format
    ra : float, optional
        Right Ascension of the QSO in decimal degrees
    dec : float, optional
        Declination of the QSO in decimal degress

    Returns
    -------
    abslinelist: list
        List of AbsLine objects
    '''
    from linetools.spectralline import AbsLine
    from linetools.analysis import absline as ltaa
    import astropy.units as u
    if linelist is None:
        llist = LineList('ISM')
    else:
        llist = linelist
    if specfile != None:
        spec = readspec(specfile)  # Allow spectrum file to be declared in call
    linetab = ascii.read(parfile)  # Read parameters from file
    linetab['restwave'] = linetab['restwave'] * u.AA
    abslinelist = []  # Initiate list to populate
    for i, row in enumerate(linetab):
        ### Check to see if errors for this line are defined
        colerr, berr, velerr = get_errors(linetab, i)
        ### Adjust velocity limits according to centroid errors and limits from file
        vcentmin = row['vel'] - velerr
        vcentmax = row['vel'] + velerr
        v1 = vcentmin + row['vlim1']
        v2 = vcentmax + row['vlim2']
        line = AbsLine(row['restwave'] * u.AA,
                       z=row['zsys'],
                       closest=True,
                       linelist=llist)
        vlims = [v1, v2] * u.km / u.s
        line.limits.set(vlims)
        ### Set other parameters
        line.attrib['logN'] = row['col']
        line.attrib['sig_logN'] = colerr
        line.attrib['flag_N'] = 1
        lincol = ltaa.linear_clm(line.attrib)
        line.attrib['N'] = lincol[0]
        line.attrib['sig_N'] = lincol[1]
        line.attrib['b'] = row['bval'] * u.km / u.s
        line.attrib['sig_b'] = berr * u.km / u.s
        line.attrib['vel'] = row['vel'] * u.km / u.s
        ### Attach the spectrum to this AbsLine but check first to see if this one is same as previous
        if specfile == None:
            if i == 0:
                spec = readspec(row['specfile'])
            elif row['specfile'] != linetab['specfile'][i - 1]:
                spec = readspec(row['specfile'])
            else:
                pass
        line.analy['spec'] = spec
        ### Add it to the list and go on
        abslinelist.append(line)
    return abslinelist
Ejemplo n.º 7
0
def read_joebvp_to_components(filename,
                              coord,
                              llist=None,
                              specfile=None,
                              chk_vel=False):
    """ Generate a list of AbsComponent objects from a JoeB VP output file

    Parameters
    ----------
    filename : str
      joeB VP filename
    coord : SkyCoord
      QSO sightline
    llist : LineList, optional
      Used to construct AbsLine objects
    specfile : str, optional
    chk_vel : bool, optional
      Demand that the velocities of a given ion all be the same

    Returns
    -------
    comps : list
      list of AbsComponent objects
    """
    # init
    if llist is None:
        llist = LineList('ISM')
    comps = []
    # Read
    vp_data = Table.read(filename, format='ascii')

    # Subset by zsys + trans
    lbls = []
    for izsys, itrans in zip(vp_data['zsys'], vp_data['trans']):
        lbls.append('{:.6f}_{:s}'.format(izsys, itrans))
    lbls = np.array(lbls)
    ulbls = np.unique(lbls)

    # Subset by nflag; Build components
    for lbl in ulbls:
        mt_lines = np.where(lbls == lbl)[0]
        if chk_vel:
            if len(np.unique(vp_data['vel'][mt_lines])) != 1:
                pdb.set_trace()
        z_fit = ltu.z_from_dv(vp_data['vel'][mt_lines[0]] * u.km / u.s,
                              vp_data['zsys'][mt_lines[0]])
        # Loop on abs lines
        alines = []
        for idx in mt_lines:
            zlim = [
                vp_data['zsys'][idx] + vp_data[vkey][idx] *
                (1 + vp_data['zsys'][idx]) / ckms
                for vkey in ['vlim1', 'vlim2']
            ]
            absline = AbsLine(vp_data['restwave'][idx] * u.AA,
                              z=z_fit,
                              zlim=zlim,
                              linelist=llist)
            # Add measurements [JB -- Want to capture anything else??]
            absline.attrib['coord'] = coord
            absline.attrib['flag_N'] = 1
            absline.attrib['logN'] = vp_data['col'][idx]
            absline.attrib['sig_logN'] = vp_data['sigcol'][idx]
            absline.attrib['b'] = vp_data['bval'][idx]
            absline.attrib['sig_b'] = vp_data['sigbval'][idx]
            absline.attrib['z'] = z_fit
            absline.attrib['sig_z'] = ltu.dz_from_dv(
                vp_data['sigvel'][idx] * u.km / u.s, vp_data['z_comp'][idx])
            if specfile is None:
                absline.attrib['specfile'] = vp_data['specfile'][idx]
            else:
                absline.attrib['specfile'] = specfile
            # Fill N, sig_N
            _, _, = linear_clm(absline.attrib)
            alines.append(absline)

        # AbsComponent
        stars = '*' * alines[0].ion_name.count('*')
        if 'comment' in vp_data.keys():
            comment = vp_data['comment'][mt_lines[0]]
        else:
            comment = ''
        if 'rely' in vp_data.keys():
            reliability = vp_data['rely'][mt_lines[0]]
        else:
            reliability = 'none'
        abscomp = AbsComponent.from_abslines(alines,
                                             stars=stars,
                                             comment=comment,
                                             reliability=reliability)

        # Add measurements [JB -- Want to capture anything else??]
        abscomp.attrib = alines[0].attrib.copy()
        # Remove undesired keys
        for key in ['EW', 'sig_EW', 'flag_EW', 'N', 'sig_N']:
            abscomp.attrib.pop(key)
        # And more required
        for key in ['flag_N', 'logN', 'sig_logN']:
            setattr(abscomp, key, abscomp.attrib[key])
        # Errors must be in first line!
        assert abscomp.sig_logN > 0.
        comps.append(abscomp)
    # Finish
    return comps
Ejemplo n.º 8
0
    def load_coolgas(self):
        """ Load data on cool gas (CII, CIV, SiII, SiIII)
        Richter+17
        """
        llist = LineList('ISM')
        # Ricther+17
        print('Loading Richter+17 for CII, CIV, SiII, SiIII')
        r17_a1_file = resource_filename('pyigm',
                                        '/data/CGM/Galaxy/richter17_A1.fits')
        r17_a1 = Table.read(r17_a1_file)
        r17_a2_file = resource_filename('pyigm',
                                        '/data/CGM/Galaxy/richter17_A2.fits')
        r17_a2 = Table.read(r17_a2_file)
        # Coords
        coords = SkyCoord(ra=r17_a1['_RAJ2000'],
                          dec=r17_a1['_DEJ2000'],
                          unit='deg')
        gc = coords.transform_to('galactic')
        ra = np.zeros((len(r17_a2)))
        dec = np.zeros((len(r17_a2)))

        # Loop on Sightlines
        for kk, row in enumerate(r17_a1):
            if self.debug and (kk == 5):
                break
            a2_idx = np.where(r17_a2['Name'] == row['Name'])[0]
            if len(a2_idx) == 0:
                continue
            ra[a2_idx] = row['_RAJ2000']
            dec[a2_idx] = row['_DEJ2000']
            # Generate the components
            icoord = gc[kk]
            alines = []
            for jj, idx in enumerate(a2_idx):
                # Transition
                trans = '{:s} {:d}'.format(r17_a2['Ion'][idx].strip(),
                                           int(r17_a2['lambda0'][idx]))
                try:
                    aline = AbsLine(trans, linelist=llist)
                except ValueError:
                    pdb.set_trace()
                aline.attrib['coord'] = icoord

                # Skip EW=0 lines
                if r17_a2['e_W'][idx] == 0:
                    continue
                # Velocity
                z = 0.
                aline.setz(z)
                vlim = np.array([r17_a2['vmin'][idx], r17_a2['vmax'][idx]
                                 ]) * u.km / u.s

                aline.limits.set(vlim)  # These are v_LSR
                # EW
                aline.attrib['flag_EW'] = 1
                aline.attrib['EW'] = r17_a2['W'][idx] / 1e3 * u.AA
                aline.attrib['sig_EW'] = r17_a2['e_W'][idx] / 1e3 * u.AA
                # Column

                if np.isnan(
                        r17_a2['logN']
                    [idx]):  # Odd that some lines had an error but no value
                    aline.attrib['flag_N'] = 0
                elif r17_a2['l_logN'][idx] == '>':
                    aline.attrib['flag_N'] = 2
                    aline.attrib['sig_logN'] = 99.99
                else:
                    aline.attrib['flag_N'] = 1
                    aline.attrib['sig_logN'] = r17_a2['e_logN'][idx]
                aline.attrib['logN'] = r17_a2['logN'][idx]
                # Fill linear
                _, _ = linear_clm(aline.attrib)
                alines.append(aline)
            # Generate components from abslines
            comps = ltiu.build_components_from_abslines(alines,
                                                        chk_sep=False,
                                                        chk_vel=False)
            # Limits
            vmin = np.min([icomp.limits.vmin.value for icomp in comps])
            vmax = np.max([icomp.limits.vmax.value for icomp in comps])
            # Instantiate
            s_kwargs = dict(name=row['Name'] + '_z0')
            c_kwargs = dict(chk_sep=False, chk_z=False)
            abssys = IGMSystem.from_components(comps,
                                               vlim=[vmin, vmax] * u.km / u.s,
                                               s_kwargs=s_kwargs,
                                               c_kwargs=c_kwargs)
            # CGM Abs
            rho, ang_sep = calc_Galactic_rho(abssys.coord)
            cgmabs = CGMAbsSys(self.galaxy,
                               abssys,
                               rho=rho,
                               ang_sep=ang_sep,
                               cosmo=self.cosmo)
            # Add to cgm_abs
            self.abs.cgm_abs.append(cgmabs)
        # Finish
        r17_a2['RA'] = ra
        r17_a2['DEC'] = dec
        self.richter17 = r17_a2
        # Reference
        if len(self.refs) > 0:
            self.refs += ','
        self.refs += 'Richter+17'
Ejemplo n.º 9
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 = []
Ejemplo n.º 10
0
    def from_dict(cls, idict, coord=None, skip_abslines=False, **kwargs):
        """ Instantiate from a dict

        Parameters
        ----------
        idict : dict
        skip_abslines : bool, optional
          Skip loading up the AbsLine objects.
          Speeds up performance when one only needs the component object

        Returns
        -------
        AbsComponent

        """
        if coord is not None:
            radec = coord
        else:
            radec = SkyCoord(ra=idict['RA'], dec=idict['DEC'], unit='deg')
        # Init
        # slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], Quantity(idict['vlim'], unit='km/s'),

        # For IGMGuesses
        for key in ['reliability', 'Reliability']:
            if key in idict.keys():
                reliability = idict[key]
                break
            else:
                reliability = 'none'

        # Deprecated column density attributes
        if 'logN' in idict.keys():
            warnings.warn('Column density attributes are now Deprecated', DeprecationWarning)
            #print("We will use yours for now..")
            Ntup = tuple([idict[key] for key in ['flag_N', 'logN', 'sig_logN']])
        else:
            Ntup = None
        # Instantiate
        slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], idict['vlim']*u.km/u.s,
                  Ej=idict['Ej']/u.cm, A=idict['A'], Ntup=Ntup,
                  comment=idict['comment'], name=idict['Name'], reliability=reliability)
        # Attributes
        if 'attrib' in idict.keys():
            attrkeys = idict['attrib'].keys()
            for ak in attrkeys:
                if isinstance(idict['attrib'][ak],dict):
                    slf.attrib[ak] = ltu.convert_quantity_in_dict(idict['attrib'][ak])
                else:
                    slf.attrib[ak] = idict['attrib'][ak]
                # Insist that error values are 2-elements :: Mainly for older saved files
                if ak == 'sig_N':
                    if slf.attrib[ak].size == 1:
                        slf.attrib[ak] = Quantity([slf.attrib[ak].value]*2) * slf.attrib[ak].unit
                if ak == 'sig_logN':
                    if isinstance(slf.attrib[ak], (float,int)):
                        slf.attrib[ak] = np.array([slf.attrib[ak]]*2)
                    elif isinstance(slf.attrib[ak], (list)):
                        slf.attrib[ak] = np.array(slf.attrib[ak])

        # Deprecated column (again)
        if Ntup is not None:
            warnings.warn('Overwriting column density attributes (if they existed).', DeprecationWarning)
            slf.attrib['flag_N'] = Ntup[0]
            slf.attrib['logN'] = Ntup[1]
            if isiterable(Ntup[2]):
                slf.attrib['sig_logN'] = np.array(Ntup[2])
            else:
                slf.attrib['sig_logN'] = np.array([Ntup[2]]*2)
            _, _ = ltaa.linear_clm(slf.attrib)  # Set linear quantities

        # Add AbsLine objects
        if not skip_abslines:
            for key in idict['lines'].keys():
                iline = AbsLine.from_dict(idict['lines'][key], coord=coord, **kwargs)
                slf.add_absline(iline, **kwargs)
        # Return
        return slf
Ejemplo n.º 11
0
    def load_hotgas(self):
        """ Load data on hot gas (e.g. OVII, OVIII)
        Fang+15
        """
        from linetools.lists.linelist import LineList
        from linetools.analysis.absline import linear_clm

        llist = LineList('EUV',use_ISM_table=False)
        ovii = AbsLine('OVII 21', linelist=llist)

        # Fang+15  Table 1  [OVII]
        self.fang15 = Table.read(pyigm.__path__[0]+'/data/CGM/Galaxy/fang15_table1.dat', format='cds')
        print('Loading Fang+15 for OVII')
        # Reference
        if len(self.refs) > 0:
            self.refs += ','
        self.refs += 'Fang+15'
        # Generate the systems
        # # (should check to see if low-ion ones exist already)
        for row in self.fang15:
            # Coordinates
            gc = SkyCoord(l=row['GLON']*u.degree, b=row['GLAT']*u.degree, frame='galactic')
            # Limits
            # OVII line
            aline = ovii.copy()
            aline.attrib['coord'] = gc
            z = row['Vel']/c_kms
            try:
                aline.setz(z)
            except IOError:
                z = 0.
                vlim = np.array([-300,300]) * u.km/u.s
                aline.attrib['flag_EW'] = 3
                aline.attrib['flag_N'] = 0  # Might be able to set an upper limit
                aline.attrib['EW'] = row['EW1'] / 1e3 * u.AA
                aline.attrib['sig_EW'] = 99. * u.AA
            else:
                aline.attrib['b'] = row['b'] * u.km / u.s
                aline.attrib['flag_EW'] = 1
                aline.attrib['EW'] = row['EW1'] / 1e3 * u.AA
                aline.attrib['sig_EW'] = row['e_EW1'] / 1e3 * u.AA
                vlim = np.array([-1,1]) * (2 * row['b'] + 2 * row['E_b']) * u.km/u.s
                # N_OVII
                aline.attrib['flag_N'] = 1
                aline.attrib['logN'] = row['logNO']
                aline.attrib['sig_logN'] = np.array([row['e_logNO'], row['E_logNO']])
                # Fill linear
                _,_ = linear_clm(aline.attrib)
            # OVII
            aline.limits.set(vlim)
            # Generate component and add
            comp = AbsComponent.from_abslines([aline])
            comp.synthesize_colm()
            # Instantiate
            abssys = IGMSystem(gc, z, vlim, name=row['Name']+'_z0', zem=row['z'])
            abssys.add_component(comp, chk_sep=False)
            # CGM Abs
            cgmabs = CGMAbsSys(self.galaxy, abssys, Galactic=True)
            # Add to cgm_abs
            self.abs.cgm_abs.append(cgmabs)

        scoord = self.abs.scoord  # Sightline coordiantes
        # Savage+03  Table 2  [OVI] -- Thick disk/halo only??
        print('Loading Savage+03 for OVI')
        self.savage03 = Table.read(pyigm.__path__[0] + '/data/CGM/Galaxy/savage03_table2.fits')
        # Reference
        if len(self.refs) > 0:
            self.refs += ','
        self.refs += 'Savage+03'
        # Generate the systems
        # # (should check to see if low-ion ones exist already)
        for row in self.savage03:
            # Coordinates
            coord = SkyCoord(ra=row['_RA']*u.deg, dec=row['_DE']*u.deg, frame='fk5')
            gc = coord.transform_to('galactic')
            # Build the component
            vlim = np.array([row['V-'],row['V_']])*u.km/u.s
            comp = AbsComponent(gc, (8,6), 0., vlim)
            # Add attributes
            if row['b'] > 0.:
                comp.attrib['vcen'] = row['__v_obs']*u.km/u.s
                comp.attrib['sig_vcen'] = row['e__v_obs']*u.km/u.s
                comp.attrib['b'] = row['b']*u.km/u.s
                comp.attrib['sig_b'] = row['e_b']*u.km/u.s
                # Column
                comp.flag_N = 1
                comp.logN = row['logN_OVI_']
                comp.sig_logN = np.sqrt(row['e_sc']**2 + row['e_sys']**2)
            else: # Upper limit
                comp.flag_N = 3
                comp.logN = row['logN_OVI_']
                comp.sig_logN = 99.
            # Check for existing system
            minsep = np.min(comp.coord.separation(scoord).to('arcsec'))
            if minsep < 30*u.arcsec:
                idx = np.argmin(comp.coord.separation(scoord).to('arcsec'))
                self.abs.cgm_abs[idx].igm_sys.add_component(comp, chk_sep=False, debug=True)
            else:  # New
                if row['RV'] > 0:
                    zem = row['RV']/c_kms
                else:
                    zem = row['z']
                abssys = IGMSystem(gc, comp.zcomp, vlim, name=row['Name']+'_z0', zem=zem)
                abssys.add_component(comp, chk_sep=False, debug=True)
                # CGM Abs
                cgmabs = CGMAbsSys(self.galaxy, abssys, Galactic=True)
                # Add to cgm_abs
                self.abs.cgm_abs.append(cgmabs)
Ejemplo n.º 12
0
    def __init__(self,
                 radec,
                 Zion,
                 zcomp,
                 vlim,
                 Ej=0. / u.cm,
                 A=None,
                 Ntup=None,
                 comment='',
                 name=None,
                 stars=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,float)
            (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
        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.
        comment : str, optional
            A comment, default is ``
        """

        # Required
        self.coord = ltu.radec_to_coord(radec)
        self.Zion = Zion
        self.zcomp = zcomp
        self.vlim = vlim

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

        # Name
        if (name is None) and (self.Zion != (-1, -1)):
            iname = ions.ion_name(self.Zion, nspace=0)
            if self.Ej.value > 0:  # Need to put *'s in name
                try:
                    iname += stars
                except:
                    raise IOError("Need to provide 'stars' parameter.")
            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

        # Potential for attributes
        self.attrib = dict()

        # Other
        self._abslines = []
Ejemplo n.º 13
0
    def load_single_fits(self, inp, skip_ions=False, verbose=True, **kwargs):
        """ Load a single COS-Halos sightline
        Appends to cgm_abs list

        Parameters
        ----------
        inp : tuple or str
          if tuple -- (field,gal_id)
            field: str 
              Name of field (e.g. 'J0226+0015')
            gal_id: str 
              Name of galaxy (e.g. '268_22')
        skip_ions : bool, optional
          Avoid loading the ions (not recommended)
        verbose : bool, optional
        """
        # Parse input
        if isinstance(inp, basestring):
            fil = inp
        elif isinstance(inp, tuple):
            field, gal_id = inp
            tmp = self.fits_path + '/' + field + '.' + gal_id + '.fits.gz'
            fils = glob.glob(tmp)
            if len(fils) != 1:
                raise IOError('Bad field, gal_id: {:s}'.format(tmp))
            fil = fils[0]
        else:
            raise IOError('Bad input to load_single')

        # Read COS-Halos file
        if verbose:
            print('cos_halos: Reading {:s}'.format(fil))
        hdu = fits.open(fil)
        summ = Table(hdu[1].data)
        galx = Table(hdu[2].data)
        # Instantiate the galaxy
        gal = Galaxy((galx['RA'][0], galx['DEC'][0]), z=summ['ZFINAL'][0])
        gal.field = galx['FIELD'][0]
        gal.gal_id = galx['GALID'][0]
        # Galaxy properties
        gal.halo_mass = summ['LOGMHALO'][0]
        gal.stellar_mass = summ['LOGMFINAL'][0]
        gal.rvir = galx['RVIR'][0]
        gal.MH = galx['ABUN'][0]
        gal.flag_MH = galx['ABUN_FLAG'][0]
        gal.sdss_phot = [
            galx[key][0]
            for key in ['SDSSU', 'SDSSG', 'SDSSR', 'SDSSI', 'SDSSZ']
        ]
        gal.sdss_phot_sig = [
            galx[key][0] for key in
            ['SDSSU_ERR', 'SDSSG_ERR', 'SDSSR_ERR', 'SDSSI_ERR', 'SDSSZ_ERR']
        ]
        gal.sfr = (galx['SFR_UPLIM'][0], galx['SFR'][0], galx['SFR_FLAG'][0]
                   )  # FLAG actually gives method used
        gal.ssfr = galx['SSFR'][0]
        # Instantiate the IGM System
        igm_sys = IGMSystem((galx['QSORA'][0], galx['QSODEC'][0]),
                            summ['ZFINAL'][0], [-600, 600.] * u.km / u.s,
                            abs_type='CGM')
        igm_sys.zqso = galx['ZQSO'][0]
        # Instantiate
        cgabs = CGMAbsSys(gal,
                          igm_sys,
                          name=gal.field + '_' + gal.gal_id,
                          **kwargs)
        # EBV
        cgabs.ebv = galx['EBV'][0]
        # Ions
        if skip_ions is True:
            # NHI
            dat_tab = Table(hdu[3].data)
            #if dat_tab['Z'] != 1:
            #    raise ValueError("Uh oh")
            cgabs.igm_sys.NHI = dat_tab['CLM'][0]
            cgabs.igm_sys.sig_NHI = dat_tab['SIG_CLM'][0]
            cgabs.igm_sys.flag_NHI = dat_tab['FLG_CLM'][0]
            self.cgm_abs.append(cgabs)
            return
        all_Z = []
        all_ion = []
        for jj in range(summ['NION'][0]):
            iont = hdu[3 + jj].data
            if jj == 0:  # Generate new Table
                dat_tab = Table(iont)
            else:
                try:
                    dat_tab.add_row(Table(iont)[0])
                except:
                    pdb.set_trace()
            all_Z.append(iont['ZION'][0][0])
            all_ion.append(iont['ZION'][0][1])
            # AbsLines
            abslines = []
            ntrans = len(np.where(iont['LAMBDA'][0] > 1.)[0])
            for kk in range(ntrans):
                flg = iont['FLG'][0][kk]
                # Fill in
                aline = AbsLine(iont['LAMBDA'][0][kk] * u.AA, closest=True)
                aline.attrib['flag_origCH'] = int(flg)
                aline.attrib[
                    'EW'] = iont['WOBS'][0][kk] * u.AA / 1e3  # Observed
                aline.attrib['sig_EW'] = iont['SIGWOBS'][0][kk] * u.AA / 1e3
                if aline.attrib['EW'] > 3. * aline.attrib['sig_EW']:
                    aline.attrib['flag_EW'] = 1
                else:
                    aline.attrib['flag_EW'] = 3
                # Force an upper limit (i.e. from a blend)
                if (flg == 2) or (flg == 4) or (flg == 6):
                    aline.attrib['flag_EW'] = 3
                #
                aline.analy['vlim'] = [
                    iont['VMIN'][0][kk], iont['VMAX'][0][kk]
                ] * u.km / u.s
                aline.attrib['z'] = igm_sys.zabs
                aline.attrib['coord'] = igm_sys.coord
                # Check f
                if (np.abs(aline.data['f'] - iont['FVAL'][0][kk]) /
                        aline.data['f']) > 0.001:
                    Nscl = iont['FVAL'][0][kk] / aline.data['f']
                    flag_f = True
                else:
                    Nscl = 1.
                    flag_f = False
                # Colm
                if ((flg % 2) == 0) or (flg == 15) or (flg == 13):
                    flgN = 0
                    print(
                        'Skipping column contribution from {:g} as NG for a line; flg={:d}'
                        .format(iont['LAMBDA'][0][kk], flg))
                elif (flg == 1) or (flg == 3):
                    flgN = 1
                elif (flg == 5) or (flg == 7):
                    flgN = 3
                elif (flg == 9) or (flg == 11):
                    flgN = 2
                else:
                    pdb.set_trace()
                    raise ValueError("Bad flag!")
                if flgN == 3:
                    aline.attrib['logN'] = iont['LOGN2SIG'][0][kk] + np.log10(
                        Nscl)
                    aline.attrib['sig_logN'] = 9.
                elif flgN == 0:  # Not for N measurement
                    pass
                else:
                    aline.attrib['logN'] = iont['LOGN'][0][kk] + np.log10(Nscl)
                    aline.attrib['sig_logN'] = iont['SIGLOGN'][0][kk]
                aline.attrib['flag_N'] = int(flgN)
                #pdb.set_trace()
                if flgN != 0:
                    _, _ = ltaa.linear_clm(aline.attrib)
                # Append
                abslines.append(aline)
            # Component
            if len(abslines) == 0:
                comp = AbsComponent(cgabs.igm_sys.coord,
                                    (iont['ZION'][0][0], iont['ZION'][0][1]),
                                    igm_sys.zabs, igm_sys.vlim)

            else:
                comp = AbsComponent.from_abslines(abslines, chk_vel=False)
                if comp.Zion != (1, 1):
                    comp.synthesize_colm()  # Combine the abs lines
                    if np.abs(comp.logN - float(iont['CLM'][0])) > 0.15:
                        print(
                            "New colm for ({:d},{:d}) and sys {:s} is {:g} different from old"
                            .format(comp.Zion[0], comp.Zion[1], cgabs.name,
                                    comp.logN - float(iont['CLM'][0])))
                    if comp.flag_N != iont['FLG_CLM'][0]:
                        if comp.flag_N == 0:
                            pass
                        else:
                            print(
                                "New flag for ({:d},{:d}) and sys {:s} is different from old"
                                .format(comp.Zion[0], comp.Zion[1],
                                        cgabs.name))
                            pdb.set_trace()
            #_,_ = ltaa.linear_clm(comp)
            cgabs.igm_sys.add_component(comp)
        self.cgm_abs.append(cgabs)

        # Add Z,ion
        dat_tab.add_column(Column(all_Z, name='Z'))
        dat_tab.add_column(Column(all_ion, name='ion'))
        # Rename
        dat_tab.rename_column('LOGN', 'indiv_logN')
        dat_tab.rename_column('SIGLOGN', 'indiv_sig_logN')
        dat_tab.rename_column('CLM', 'logN')
        dat_tab.rename_column('SIG_CLM', 'sig_logN')
        dat_tab.rename_column('FLG_CLM', 'flag_N')
        # Set
        self.cgm_abs[-1].igm_sys._ionN = dat_tab
        # NHI
        HI = (dat_tab['Z'] == 1) & (dat_tab['ion'] == 1)
        if np.sum(HI) > 0:
            self.cgm_abs[-1].igm_sys.NHI = dat_tab[HI]['logN'][0]
            self.cgm_abs[-1].igm_sys.sig_NHI = dat_tab[HI]['sig_logN'][0]
            self.cgm_abs[-1].igm_sys.flag_NHI = dat_tab[HI]['flag_N'][0]
        else:
            warnings.warn("No HI measurement for {}".format(self.cgm_abs[-1]))
            self.cgm_abs[-1].igm_sys.flag_NHI = 0
Ejemplo n.º 14
0
    def load_single_fits(self, inp, skip_ions=False, verbose=True, **kwargs):
        """ Load a single COS-Halos sightline
        Appends to cgm_abs list

        Parameters
        ----------
        inp : tuple or str
          if tuple -- (field,gal_id)
            field: str 
              Name of field (e.g. 'J0226+0015')
            gal_id: str 
              Name of galaxy (e.g. '268_22')
        skip_ions : bool, optional
          Avoid loading the ions (not recommended)
        verbose : bool, optional
        """
        # Parse input
        if isinstance(inp, basestring):
            fil = inp
        elif isinstance(inp, tuple):
            field, gal_id = inp
            tmp = self.fits_path+'/'+field+'.'+gal_id+'.fits.gz'
            fils = glob.glob(tmp)
            if len(fils) != 1:
                raise IOError('Bad field, gal_id: {:s}'.format(tmp))
            fil = fils[0]
        else:
            raise IOError('Bad input to load_single')

        # Read COS-Halos file
        if verbose:
            print('cos_halos: Reading {:s}'.format(fil))
        hdu = fits.open(fil)
        summ = Table(hdu[1].data)
        galx = Table(hdu[2].data)
        # Instantiate the galaxy
        gal = Galaxy((galx['RA'][0], galx['DEC'][0]), z=summ['ZFINAL'][0])
        gal.field = galx['FIELD'][0]
        gal.gal_id = galx['GALID'][0]
        # Galaxy properties
        gal.halo_mass = summ['LOGMHALO'][0]
        gal.stellar_mass = summ['LOGMFINAL'][0]
        gal.rvir = galx['RVIR'][0]
        gal.MH = galx['ABUN'][0]
        gal.flag_MH = galx['ABUN_FLAG'][0]
        gal.sdss_phot = [galx[key][0] for key in ['SDSSU','SDSSG','SDSSR','SDSSI','SDSSZ']]
        gal.sdss_phot_sig = [galx[key][0] for key in ['SDSSU_ERR','SDSSG_ERR','SDSSR_ERR','SDSSI_ERR','SDSSZ_ERR']]
        gal.sfr = (galx['SFR_UPLIM'][0], galx['SFR'][0],
                                       galx['SFR_FLAG'][0]) # FLAG actually gives method used
        gal.ssfr = galx['SSFR'][0]
        # Instantiate the IGM System
        igm_sys = IGMSystem((galx['QSORA'][0], galx['QSODEC'][0]),
                            summ['ZFINAL'][0], [-600, 600.]*u.km/u.s,
                            abs_type='CGM')
        igm_sys.zqso = galx['ZQSO'][0]
        # Instantiate
        cgabs = CGMAbsSys(gal, igm_sys, name=gal.field+'_'+gal.gal_id, **kwargs)
        # EBV
        cgabs.ebv = galx['EBV'][0]
        # Ions
        if skip_ions is True:
            # NHI
            dat_tab = Table(hdu[3].data)
            #if dat_tab['Z'] != 1:
            #    raise ValueError("Uh oh")
            cgabs.igm_sys.NHI = dat_tab['CLM'][0]
            cgabs.igm_sys.sig_NHI = dat_tab['SIG_CLM'][0]
            cgabs.igm_sys.flag_NHI = dat_tab['FLG_CLM'][0]
            self.cgm_abs.append(cgabs)
            return
        all_Z = []
        all_ion = []
        for jj in range(summ['NION'][0]):
            iont = hdu[3+jj].data
            if jj == 0: # Generate new Table
                dat_tab = Table(iont)
            else:
                try:
                    dat_tab.add_row(Table(iont)[0])
                except:
                    pdb.set_trace()
            all_Z.append(iont['ZION'][0][0])
            all_ion.append(iont['ZION'][0][1])
            # AbsLines
            abslines = []
            ntrans = len(np.where(iont['LAMBDA'][0] > 1.)[0])
            for kk in range(ntrans):
                flg = iont['FLG'][0][kk]
                # Fill in
                aline = AbsLine(iont['LAMBDA'][0][kk]*u.AA, closest=True)
                aline.attrib['flag_origCH'] = int(flg)
                aline.attrib['EW'] = iont['WOBS'][0][kk]*u.AA/1e3  # Observed
                aline.attrib['sig_EW'] = iont['SIGWOBS'][0][kk]*u.AA/1e3
                if aline.attrib['EW'] > 3.*aline.attrib['sig_EW']:
                    aline.attrib['flag_EW'] = 1
                else:
                    aline.attrib['flag_EW'] = 3
                # Force an upper limit (i.e. from a blend)
                if (flg == 2) or (flg == 4) or (flg == 6):
                    aline.attrib['flag_EW'] = 3
                #
                aline.analy['vlim'] = [iont['VMIN'][0][kk],iont['VMAX'][0][kk]]*u.km/u.s
                aline.attrib['z'] = igm_sys.zabs
                aline.attrib['coord'] = igm_sys.coord
                # Check f
                if (np.abs(aline.data['f']-iont['FVAL'][0][kk])/aline.data['f']) > 0.001:
                    Nscl = iont['FVAL'][0][kk] / aline.data['f']
                    flag_f = True
                else:
                    Nscl = 1.
                    flag_f = False
                # Colm
                if ((flg % 2) == 0) or (flg == 15) or (flg == 13):
                    flgN = 0
                    print('Skipping column contribution from {:g} as NG for a line; flg={:d}'.format(iont['LAMBDA'][0][kk],flg))
                elif (flg == 1) or (flg == 3):
                    flgN = 1
                elif (flg == 5) or (flg == 7):
                    flgN = 3
                elif (flg == 9) or (flg == 11):
                    flgN = 2
                else:
                    pdb.set_trace()
                    raise ValueError("Bad flag!")
                if flgN == 3:
                    aline.attrib['logN'] = iont['LOGN2SIG'][0][kk] + np.log10(Nscl)
                    aline.attrib['sig_logN'] = 9.
                elif flgN == 0:  # Not for N measurement
                    pass
                else:
                    aline.attrib['logN'] = iont['LOGN'][0][kk] + np.log10(Nscl)
                    aline.attrib['sig_logN'] = iont['SIGLOGN'][0][kk]
                aline.attrib['flag_N'] = int(flgN)
                #pdb.set_trace()
                if flgN != 0:
                    _,_ = ltaa.linear_clm(aline.attrib)
                # Append
                abslines.append(aline)
            # Component
            if len(abslines) == 0:
                comp = AbsComponent(cgabs.igm_sys.coord,
                                    (iont['ZION'][0][0],iont['ZION'][0][1]),
                                    igm_sys.zabs, igm_sys.vlim)

            else:
                comp = AbsComponent.from_abslines(abslines, chk_vel=False)
                if comp.Zion != (1,1):
                    comp.synthesize_colm()  # Combine the abs lines
                    if np.abs(comp.logN - float(iont['CLM'][0])) > 0.15:
                        print("New colm for ({:d},{:d}) and sys {:s} is {:g} different from old".format(
                            comp.Zion[0], comp.Zion[1], cgabs.name, comp.logN - float(iont['CLM'][0])))
                    if comp.flag_N != iont['FLG_CLM'][0]:
                        if comp.flag_N == 0:
                            pass
                        else:
                            print("New flag for ({:d},{:d}) and sys {:s} is different from old".format(
                                comp.Zion[0], comp.Zion[1], cgabs.name))
                            pdb.set_trace()
            #_,_ = ltaa.linear_clm(comp)
            cgabs.igm_sys.add_component(comp)
        self.cgm_abs.append(cgabs)

        # Add Z,ion
        dat_tab.add_column(Column(all_Z,name='Z'))
        dat_tab.add_column(Column(all_ion,name='ion'))
        # Rename
        dat_tab.rename_column('LOGN','indiv_logN')
        dat_tab.rename_column('SIGLOGN','indiv_sig_logN')
        dat_tab.rename_column('CLM','logN')
        dat_tab.rename_column('SIG_CLM','sig_logN')
        dat_tab.rename_column('FLG_CLM','flag_N')
        # Set
        self.cgm_abs[-1].igm_sys._ionN = dat_tab
        # NHI
        HI = (dat_tab['Z'] == 1) & (dat_tab['ion'] == 1)
        if np.sum(HI) > 0:
            self.cgm_abs[-1].igm_sys.NHI = dat_tab[HI]['logN'][0]
            self.cgm_abs[-1].igm_sys.sig_NHI = dat_tab[HI]['sig_logN'][0]
            self.cgm_abs[-1].igm_sys.flag_NHI = dat_tab[HI]['flag_N'][0]
        else:
            warnings.warn("No HI measurement for {}".format(self.cgm_abs[-1]))
            self.cgm_abs[-1].igm_sys.flag_NHI = 0
Ejemplo n.º 15
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 = []
Ejemplo n.º 16
0
    def from_dict(cls, idict, coord=None, skip_abslines=False, **kwargs):
        """ Instantiate from a dict

        Parameters
        ----------
        idict : dict
        skip_abslines : bool, optional
          Skip loading up the AbsLine objects.
          Speeds up performance when one only needs the component object

        Returns
        -------
        AbsComponent

        """
        if coord is not None:
            radec = coord
        else:
            radec = SkyCoord(ra=idict['RA'], dec=idict['DEC'], unit='deg')
        # Init
        # slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], Quantity(idict['vlim'], unit='km/s'),

        # For IGMGuesses
        for key in ['reliability', 'Reliability']:
            if key in idict.keys():
                reliability = idict[key]
                break
            else:
                reliability = 'none'

        # Deprecated column density attributes
        if 'logN' in idict.keys():
            warnings.warn('Column density attributes are now Deprecated',
                          DeprecationWarning)
            #print("We will use yours for now..")
            Ntup = tuple(
                [idict[key] for key in ['flag_N', 'logN', 'sig_logN']])
        else:
            Ntup = None
        # Instantiate
        slf = cls(radec,
                  tuple(idict['Zion']),
                  idict['zcomp'],
                  idict['vlim'] * u.km / u.s,
                  Ej=idict['Ej'] / u.cm,
                  A=idict['A'],
                  Ntup=Ntup,
                  comment=idict['comment'],
                  name=idict['Name'],
                  reliability=reliability)
        # Attributes
        if 'attrib' in idict.keys():
            attrkeys = idict['attrib'].keys()
            for ak in attrkeys:
                if isinstance(idict['attrib'][ak], dict):
                    slf.attrib[ak] = ltu.convert_quantity_in_dict(
                        idict['attrib'][ak])
                else:
                    slf.attrib[ak] = idict['attrib'][ak]
                # Insist that error values are 2-elements :: Mainly for older saved files
                if ak == 'sig_N':
                    if slf.attrib[ak].size == 1:
                        slf.attrib[ak] = Quantity(
                            [slf.attrib[ak].value] * 2) * slf.attrib[ak].unit
                if ak == 'sig_logN':
                    if isinstance(slf.attrib[ak], (float, int)):
                        slf.attrib[ak] = np.array([slf.attrib[ak]] * 2)
                    elif isinstance(slf.attrib[ak], (list)):
                        slf.attrib[ak] = np.array(slf.attrib[ak])

        # Deprecated column (again)
        if Ntup is not None:
            warnings.warn(
                'Overwriting column density attributes (if they existed).',
                DeprecationWarning)
            slf.attrib['flag_N'] = Ntup[0]
            slf.attrib['logN'] = Ntup[1]
            if isiterable(Ntup[2]):
                slf.attrib['sig_logN'] = np.array(Ntup[2])
            else:
                slf.attrib['sig_logN'] = np.array([Ntup[2]] * 2)
            _, _ = ltaa.linear_clm(slf.attrib)  # Set linear quantities

        # Add AbsLine objects
        if not skip_abslines:
            for key in idict['lines'].keys():
                iline = AbsLine.from_dict(idict['lines'][key],
                                          coord=coord,
                                          **kwargs)
                slf.add_absline(iline, **kwargs)
        # Return
        return slf
Ejemplo n.º 17
0
    def __init__(self, radec, Zion, zcomp, vlim, Ej=0./u.cm, A=None,
                 Ntup=None, comment='', name=None, stars=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,float)
            (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
              # TODO FUTURE IMPLEMENTATION WILL ALLOW FOR 2-element ndarray for sig_logN
        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.
        comment : str, optional
            A comment, default is ``
        """

        # Required
        self.coord = ltu.radec_to_coord(radec)
        self.Zion = Zion
        self.zcomp = zcomp
        self.vlim = vlim

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

        # Name
        if (name is None) and (self.Zion != (-1, -1)):
            iname = ions.ion_name(self.Zion, nspace=0)
            if self.Ej.value > 0:  # Need to put *'s in name
                try:
                    iname += stars
                except:
                    raise IOError("Need to provide 'stars' parameter.")
            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

        # Potential for attributes
        self.attrib = dict()

        # Other
        self._abslines = []
Ejemplo n.º 18
0
    def __init__(self, radec, Zion, zcomp, vlim, Ej=0./u.cm, A=None,
                 Ntup=None, comment='', name=None, stars=None):
        """  Initiator

        Parameters
        ----------
        radec : tuple or SkyCoord
            (RA,DEC) in deg or astropy.coordinate
        Zion : tuple 
            Atomic number, ion -- (int,int)
            e.g. (8,1) for OI
        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,float)
            (flag_N,logN,sig_N)
            flag_N : Flag describing N measurement
            logN : log10 N column density
            sig_logN : Error in log10 N
        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.
        comment : str, optional
            A comment, default is ``
        """

        # Required
        if isinstance(radec, (tuple)):
            self.coord = SkyCoord(ra=radec[0], dec=radec[1])
        elif isinstance(radec, SkyCoord):
            self.coord = radec
        self.Zion = Zion
        self.zcomp = zcomp
        self.vlim = vlim

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

        # Name
        if name is None:
            iname = ions.ion_name(self.Zion, nspace=0)
            if self.Ej.value > 0:  # Need to put *'s in name
                try:
                    iname += stars
                except:
                    raise IOError("Need to provide 'stars' parameter.")
            self.name = '{:s}_z{:0.5f}'.format(iname, self.zcomp)
        else:
            self.name = name
        # Other
        self._abslines = []
Ejemplo n.º 19
0
    def load_hotgas(self):
        """ Load data on hot gas (e.g. OVII, OVIII)
        Fang+15
        """

        # Init
        llist = LineList('EUV')
        ovii = AbsLine('OVII 21', linelist=llist)
        scoord = self.abs.scoord  # Sightline coordiantes

        # Fang+15  Table 1  [OVII]
        fang15_file = resource_filename('pyigm',
                                        '/data/CGM/Galaxy/fang15_table1.dat')
        self.fang15 = Table.read(fang15_file, format='cds')
        print('Loading Fang+15 for OVII')
        # Reference
        if len(self.refs) > 0:
            self.refs += ','
        self.refs += 'Fang+15'
        # Generate the systems
        # # (should check to see if low-ion ones exist already)
        for row in self.fang15:
            # Coordinates
            gc = SkyCoord(l=row['GLON'] * u.degree,
                          b=row['GLAT'] * u.degree,
                          frame='galactic')
            # Limits
            # OVII line
            aline = ovii.copy()
            aline.attrib['coord'] = gc
            z = row['Vel'] / c_kms
            try:
                aline.setz(z)
            except IOError:
                z = 0.
                vlim = np.array([-300, 300]) * u.km / u.s
                aline.attrib['flag_EW'] = 3
                aline.attrib['EW'] = row['EW1'] / 1e3 * u.AA
                aline.attrib['sig_EW'] = 99. * u.AA
                #
                aline.attrib[
                    'flag_N'] = 0  # Might be able to set an upper limit
            else:
                aline.attrib['b'] = row['b'] * u.km / u.s
                aline.attrib['flag_EW'] = 1
                aline.attrib['EW'] = row['EW1'] / 1e3 * u.AA
                aline.attrib['sig_EW'] = row['e_EW1'] / 1e3 * u.AA
                vlim = np.array(
                    [-1, 1]) * (2 * row['b'] + 2 * row['E_b']) * u.km / u.s
                # N_OVII
                aline.attrib['flag_N'] = 1
                aline.attrib['logN'] = row['logNO']
                aline.attrib['sig_logN'] = np.array(
                    [row['e_logNO'], row['E_logNO']])
                # Fill linear
                _, _ = linear_clm(aline.attrib)
            # OVII
            aline.limits.set(vlim)
            # Generate component and add
            comp = AbsComponent.from_abslines([aline])
            if aline.attrib['flag_N'] == 0:  # Hack to merge later
                comp.attrib['sig_logN'] = np.array([0., 0.])
            else:
                pass
            # Check for existing system
            minsep = np.min(comp.coord.separation(scoord).to('arcsec'))
            if minsep < 30 * u.arcsec:  # Add component to existing system
                idx = np.argmin(comp.coord.separation(scoord).to('arcsec'))
                if self.verbose:
                    print("Adding OVII system to {}".format(
                        self.abs.cgm_abs[idx].igm_sys))
                self.abs.cgm_abs[idx].igm_sys.add_component(comp,
                                                            chk_sep=False,
                                                            debug=True)
            else:  # Instantiate
                abssys = IGMSystem(gc,
                                   z,
                                   vlim,
                                   name=row['Name'] + '_z0',
                                   zem=row['z'])
                abssys.add_component(comp, chk_sep=False)
                # CGM Abs
                rho, ang_sep = calc_Galactic_rho(abssys.coord)
                cgmabs = CGMAbsSys(self.galaxy,
                                   abssys,
                                   rho=rho,
                                   ang_sep=ang_sep,
                                   cosmo=self.cosmo)
                # Add to cgm_abs
                self.abs.cgm_abs.append(cgmabs)

        scoord = self.abs.scoord  # Sightline coordiantes
        # Savage+03  Table 2  [OVI] -- Thick disk/halo only??
        print('Loading Savage+03 for OVI')
        savage03_file = resource_filename(
            'pyigm', '/data/CGM/Galaxy/savage03_table2.fits')
        self.savage03 = Table.read(savage03_file)
        # Reference
        if len(self.refs) > 0:
            self.refs += ','
        self.refs += 'Savage+03'
        # Generate the systems
        # # (should check to see if low-ion ones exist already)
        for row in self.savage03:
            # Coordinates
            coord = SkyCoord(ra=row['_RA'] * u.deg,
                             dec=row['_DE'] * u.deg,
                             frame='icrs')
            gc = coord.transform_to('galactic')
            # Build the component
            vlim = np.array([row['V-'], row['V_']]) * u.km / u.s
            comp = AbsComponent(gc, (8, 6), 0., vlim)
            # Add attributes
            if row['b'] > 0.:
                comp.attrib['vcen'] = row['__v_obs'] * u.km / u.s
                comp.attrib['sig_vcen'] = row['e__v_obs'] * u.km / u.s
                comp.attrib['b'] = row['b'] * u.km / u.s
                comp.attrib['sig_b'] = row['e_b'] * u.km / u.s
                # Column
                comp.attrib['flag_N'] = 1
                comp.attrib['logN'] = row['logN_OVI_']
                comp.attrib['sig_logN'] = np.array(
                    [np.sqrt(row['e_sc']**2 + row['e_sys']**2)] * 2)
            else:  # Upper limit
                comp.attrib['flag_N'] = 3
                comp.attrib['logN'] = row['logN_OVI_']
                comp.attrib['sig_logN'] = np.array([99.] * 2)
            # Set linear quantities
            _, _ = linear_clm(comp.attrib)
            # Check for existing system
            minsep = np.min(comp.coord.separation(scoord).to('arcsec'))
            if minsep < 30 * u.arcsec:
                idx = np.argmin(comp.coord.separation(scoord).to('arcsec'))
                self.abs.cgm_abs[idx].igm_sys.add_component(comp,
                                                            chk_sep=False,
                                                            debug=True,
                                                            update_vlim=True)
            else:  # New
                if row['RV'] > 0:
                    zem = row['RV'] / c_kms
                else:
                    zem = row['z']
                abssys = IGMSystem(gc,
                                   comp.zcomp,
                                   vlim,
                                   name=row['Name'] + '_z0',
                                   zem=zem)
                abssys.add_component(comp, chk_sep=False, debug=True)
                # CGM Abs
                rho, ang_sep = calc_Galactic_rho(abssys.coord)
                cgmabs = CGMAbsSys(self.galaxy,
                                   abssys,
                                   rho=rho,
                                   ang_sep=ang_sep,
                                   cosmo=self.cosmo)
                # Add to cgm_abs
                self.abs.cgm_abs.append(cgmabs)