Example #1
0
 def get_vmnx(components):
     zlim_sys = ltu.z_from_dv(self.vlim, self.zabs, rel=False)
     zmin, zmax = zlim_sys
     for component in components:
         zlim_comp = ltu.z_from_dv(component.vlim, component.zcomp, rel=False)
         zmin = min(zmin, zlim_comp[0])
         zmax = max(zmax, zlim_comp[1])
     # Convert back to velocities
     return ltu.dv_from_z([zmin,zmax], self.zabs, rel=False)
Example #2
0
 def get_vmnx(components):
     zlim_sys = ltu.z_from_dv(self.vlim, self.zabs, rel=False)
     zmin, zmax = zlim_sys
     for component in components:
         zlim_comp = ltu.z_from_dv(component.vlim, component.zcomp, rel=False)
         zmin = min(zmin, zlim_comp[0])
         zmax = max(zmax, zlim_comp[1])
     # Convert back to velocities
     return ltu.dv_from_z([zmin,zmax], self.zabs, rel=False)
Example #3
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
Example #4
0
def dla_stat(DLAs, qsos, vprox=None, buff=3000.*u.km/u.s,
             zem_min=0., flg_zsrch=0, vmin=0.*u.km/u.s,
             LLS_CUT=None, partial=False, prox=False,
             zem_tol=0.03):
    """ Identify the statistical DLA in a survey
    Note that this algorithm ignores any existing mask

    Parameters
    ----------
    DLAs : DLASurvey
    qsos : Table
      keys must include RA, DEC, ZEM, Z_START
    vmin : Quantity
    vprox
    maxdz
    zem_min
    buff : Quantity
      Buffer velocity in Proximate analysis [not ready for this]
    NHI_cut
    flg_zsrch
    dz_toler
    partial : bool, optional
      Analyze partial LLS? [pLLS]
    prox : bool, optional
      Proximate LLS? [PLLS]
    zem_tol : float, optional
      Tolerance in zem

    Returns
    -------
    msk_smpl : bool array
      True = statistical
    """
    import warnings
    from astropy.coordinates import SkyCoord, match_coordinates_sky
    # Check for mask
    if DLAs.mask is not None:
        warnings.warn("Resetting mask to None.  Be careful here")
        DLAs.mask = None
    # DLA
    msk_smpl = DLAs.zem != DLAs.zem
    #zmax = ltu.z_from_dv(vprox, qsos['ZEM'])
    zmin = ltu.z_from_dv(vmin*np.ones(len(qsos)), qsos['Z_START'].data) # vmin must be array-like to be applied to each individual qsos['Z_START']

    # Make some lists
    qsos_coord = SkyCoord(ra=qsos['RA'], dec=qsos['DEC'])
    dla_coord = DLAs.coord

    idx, d2d, d3d = match_coordinates_sky(dla_coord, qsos_coord, nthneighbor=1)
    close = d2d < 1.*u.arcsec

    for qq, idla in enumerate(DLAs._abs_sys):
        # In stat?
        if close[qq]:
            if np.abs(idla.zem-qsos['ZEM'][idx[qq]]) < zem_tol:
                if ((idla.zabs >= zmin[idx[qq]]) &
                        (idla.zabs <= qsos['Z_END'][idx[qq]]) & (qsos[idx[qq]]['FLG_BAL'] != 2)):
                        msk_smpl[qq] = True
    # Return
    return msk_smpl
Example #5
0
    def load_HST_ACS(cls, tau_LL=2, sample='stat'):
        """ Load the LLS survey using HST/ACS by O'Meara et al. 2013, ApJ, 765, 137

        Parameters
        ----------
        tau_LL : int, optional
          Sets sample
        sample : str, optional

        Returns
        -------
        lls_survey : IGMSurvey
        """
        if tau_LL == 2:
            NHI_cut = 17.49
        # LLS File
        lls_fil = pyigm_path + '/data/LLS/HST/lls_acs_stat_LLS.fits.gz'
        lls = Table.read(lls_fil)

        # Generate coords
        scoords = [
            lls['QSO_RA'][ii] + ' ' + lls['QSO_DEC'][ii]
            for ii in range(len(lls))
        ]
        coords = SkyCoord(scoords, unit=(u.hourangle, u.deg))
        lls['RA'] = coords.ra.value
        lls['DEC'] = coords.dec.value

        # Read
        lls_survey = cls.from_sfits(lls, coords=coords)
        lls_survey.ref = 'HST-ACS'

        # QSOs file
        qsos_fil = pyigm_path + '/data/LLS/HST/lls_acs_qsos_sn1020.fits.gz'
        qsos = Table.read(qsos_fil)
        lls_survey.sightlines = qsos

        # Z_START, Z_END
        #   Using tau=2
        if tau_LL == 2:
            lls_survey.sightlines['Z_START'] = np.maximum(
                qsos['ZT2'], qsos['ZLLS'][:, 0])
        else:
            pdb.set_trace()
        # zend
        zend = ltu.z_from_dv(-3000 * u.km / u.s * np.ones(len(qsos)),
                             lls_survey.sightlines['ZEM'])
        lls_survey.sightlines['Z_END'] = zend

        # Stat me
        mask = lls_stat(lls_survey, NHI_cut=NHI_cut)
        if sample == 'stat':
            lls_survey.mask = mask
        else:
            lls_survey.mask = ~mask

        # Return
        print('HST-ACS: Loaded')
        return lls_survey
Example #6
0
    def set(self, inp, chk_z=False):#, itype='zlim'):
        """ Set (or reset) limits relative to self._z
        but does not change self._z

        Parameters
        ----------
        inp : tuple, list, or Quantity array
          * If floats -> zlim : Redshift limits
          * If Quantity array with length units  -> wvlim : Wavelength limits
          * If Quantity array with speed units  -> vlim : Velocity limits
        chk_z : bool, optional
          Demand that zlim bound z
          Often not desired as z can be somewhat arbitrary

        Returns
        -------

        """
        # Checks
        if not isinstance(inp, (tuple, list, Quantity)):
            raise IOError("Input must be tuple, list or Quantity.")
        #if np.isclose(self._z, 0.):
        #    warnings.warn("Redshift=0.  If this is unexpected, set _z and reset limits")

        if isinstance(inp[0], float):  # assume zlim
            self._zlim = inp
        elif isinstance(inp[0], Quantity):  # may be wvlim or vlim
            if inp[0].cgs.unit == u.cm:
                self._zlim = (inp/self._wrest).decompose().to(
                        u.dimensionless_unscaled).value - 1.
            elif inp[0].cgs.unit == u.cm/u.s:
                self._zlim = ltu.z_from_dv(inp, self._z)
            else:
                raise IOError("Quantity must be length or speed.")
        else:
            raise IOError("Input must be floats or Quantities.")
        # Check
        if chk_z:
            if (self._zlim[0] > self._z) or (self._zlim[1] < self._z):
                #import pdb; pdb.set_trace()
                raise IOError("Invalid input. `zlim` does not bound `z`.")
        # Reset
        self.reset()
Example #7
0
    def set(self, inp, chk_z=False):#, itype='zlim'):
        """ Over-ride = to re-init values

        Parameters
        ----------
        inp : tuple, list, or Quantity array
          * If floats -> zlim : Redshift limits
          * If Quantity array with length units  -> wvlim : Wavelength limits
          * If Quantity array with speed units  -> vlim : Velocity limits
        chk_z : bool, optional
          Demand that zlim bound z
          Often not desired as z can be somewhat arbitrary

        Returns
        -------

        """
        # Checks
        if not isinstance(inp, (tuple, list, Quantity)):
            raise IOError("Input must be tuple, list or Quantity.")
        if np.isclose(self._z, 0.):
            warnings.warn("Redshift=0.  If this is unexpected, set _z and reset limits")

        if isinstance(inp[0], float):  # assume zlim
            self._zlim = inp
        elif isinstance(inp[0], Quantity):  # may be wvlim or vlim
            try:  # assume wvlim
                self._zlim = (inp/self._wrest).decompose().to(
                        u.dimensionless_unscaled).value - 1.
            except UnitConversionError:
                try:  # assume vlim
                    self._zlim = ltu.z_from_dv(inp, self._z)
                except ValueError:
                    raise IOError("Quantity must be length or speed.")
        else:
            raise IOError("Input must be floats or Quantities.")
        # Check
        if chk_z:
            if (self._zlim[0] > self._z) or (self._zlim[1] < self._z):
                #import pdb; pdb.set_trace()
                raise IOError("Invalid input. `zlim` does not bound `z`.")
        # Reset
        self.reset()
Example #8
0
def test_z_from_dv():
    z = ltu.z_from_dv(1000. * u.km / u.s, 2.)
    np.testing.assert_allclose(z, 2.0100236684175417)
Example #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 = []
Example #10
0
    def load_data(self, **kwargs):
        #
        #q8file = resource_filename('pyigm', 'data/CGM/QPQ/qpq8_all_measured.dat')
        q8file = self.data_file

        if self.from_dict:
            q8file = self.data_file
            qpq8dict = CGMAbsSurvey.from_json(q8file)
            ism = LineList('ISM')
            qpq8dict.build_systems_from_dict(llist=ism)
            self.survey_data = qpq8dict
            #self.cgm_abs = qpq8dict.cgm_abs

        else:

            qpqdata = Table.read(q8file, format='ascii')
            #nmax = len(qpqdata)   # max number of QSOs
            q8filecoord = resource_filename('pyigm',
                                            'data/CGM/QPQ/qpq8_pairs.fits')
            qpqdatacoord = Table.read(q8filecoord)
            if self.nmax is not None:
                nmax = self.nmax
            else:
                nmax = len(qpqdatacoord)  #(qpqdata)

            # match names with qpqdatacoord
            qnames = []
            for i in range(len(qpqdatacoord)):
                qname = qpqdatacoord['QSO'][i].strip()
                qnames.append(qname[-10:])
            qnames2 = []
            for i in range(len(qpqdata)):
                qname = qpqdata['Pair'][i]
                qnames2.append(qname)

            for j in range(nmax):  # i,j
                # match names with qpqdatacoord
                i = np.where(np.asarray(qnames2) == qnames[j])[0]
                # Instantiate the galaxy
                gal = Galaxy((qpqdatacoord['RAD'][j], qpqdatacoord['DECD'][j]),
                             z=qpqdatacoord['Z_FG'][j])
                gal.L_BOL = qpqdatacoord['L_BOL'][j]
                gal.L_912 = qpqdatacoord['L_912'][j]
                gal.G_UV = qpqdatacoord['G_UV'][j]
                gal.zsig = qpqdatacoord['Z_FSIG'][j] * u.km / u.s

                # Instantiate the IGM System
                igm_sys = IGMSystem(
                    (qpqdatacoord['RAD_BG'][j], qpqdatacoord['DECD_BG'][j]),
                    qpqdatacoord['Z_FG'][j], [-5500, 5500.] * u.km / u.s,
                    abs_type='CGM')
                # Redshifts: QSO emission redshifts
                igm_sys.zem = qpqdatacoord['Z_BG'][j]
                igm_sys.NHI = qpqdata['HIcol'][i]
                igm_sys.sig_NHI = [
                    qpqdata['HIcolhierr'][i], qpqdata['HIcolloerr'][i]
                ]
                igm_sys.s2n_lya = qpqdatacoord['S2N_LYA'][j]

                iname = qpqdata['Pair'][i][0]  #+'_'+qpqdata['subsys'][i]
                # Instantiate
                rho = qpqdatacoord['R_PHYS'][j] * u.kpc
                cgabs = CGMAbsSys(gal, igm_sys, name=iname, rho=rho, **kwargs)

                ### add metal lines
                ### not included CII*, SiII*
                lines = [
                    ['CII 1334'],  ## ['CII* 1335'],
                    ['CIV 1548', 'CIV 1550'],
                    ['NI 1134', 'NI 1199'],
                    ['NII 1083'],
                    ['NV 1238', 'NV 1242'],
                    ['OI 1302'],
                    ['OVI 1037'],
                    ['MgI 2852'],
                    ['MgII 2796', 'MgII 2803'],
                    ['AlII 1670'],
                    ['AlIII 1854', 'AlIII 1862'],
                    [
                        'SiII 1190', 'SiII 1193', 'SiII 1304', 'SiII 1260',
                        'SiII 1526', 'SiII 1808'
                    ],  ## ['SiII* 1264'],
                    ['SiIII 1206'],
                    ['SiIV 1393', 'SiIV 1402'],
                    [
                        'FeII 1608', 'FeII 2344', 'FeII 2374', 'FeII 2382',
                        'FeII 2586', 'FeII 2600'
                    ],
                    ['FeIII 1122']
                ]

                for kk in i:

                    for icmp in range(len(lines)):
                        abslines = []
                        for ii in range(len(lines[icmp])):
                            wave0 = float(lines[icmp][ii].split(' ')[1])
                            ewstr = str(lines[icmp][ii].split(' ')[1]) + 'EW'
                            ewerrstr = str(
                                lines[icmp][ii].split(' ')[1]) + 'EWerr'
                            if ewstr == '1808EW':
                                ewstr = '1808E'
                            if ewerrstr == '1122EWerr':
                                ewerrstr = '122EWerr'
                            if qpqdata[ewstr][kk] != '/':
                                # find z
                                v0 = 0.5 * (
                                    qpqdata['v_lobound'][kk] +
                                    qpqdata['v_upbound'][kk]) * u.km / u.s
                                dv = v0
                                zref = igm_sys.zabs
                                z_cmp = ltu.z_from_dv(dv, zref)

                                ## vlim
                                v1 = qpqdata['v_lobound'][kk] * u.km / u.s
                                z1 = ltu.z_from_dv(v1, zref)
                                v1_cmp = ltu.dv_from_z(z1, z_cmp)

                                v2 = qpqdata['v_upbound'][kk] * u.km / u.s
                                z2 = ltu.z_from_dv(v2, zref)
                                v2_cmp = ltu.dv_from_z(z2, z_cmp)

                                # iline
                                iline = AbsLine(wave0 * u.AA,
                                                closest=True,
                                                z=z_cmp)
                                iline.attrib['coord'] = igm_sys.coord

                                ## EW
                                iline.attrib['EW'] = float(
                                    qpqdata[ewstr][kk]) * u.AA  # Rest EW
                                iline.attrib['sig_EW'] = float(
                                    qpqdata[ewerrstr][kk]) * u.AA
                                flgew = 1
                                if iline.attrib[
                                        'EW'] < 3. * iline.attrib['sig_EW']:
                                    flgew = 3
                                iline.attrib['flag_EW'] = flgew

                                ## column densities
                                colstr = str(
                                    lines[icmp][ii].split(' ')[0]) + 'col'
                                colerrstr = str(
                                    lines[icmp][ii].split(' ')[0]) + 'colerr'
                                iline.attrib['logN'] = qpqdata[colstr][kk]
                                iline.attrib['sig_logN'] = qpqdata[colerrstr][
                                    kk]

                                abslines.append(iline)

                        if len(abslines) > 0:
                            comp = AbsComponent.from_abslines(abslines,
                                                              chk_vel=False)
                            comp.limits._vlim = [v1_cmp.value, v2_cmp.value
                                                 ] * u.km / u.s
                            cgabs.igm_sys.add_component(comp)

                # add ang_sep
                qsocoord = SkyCoord(ra=qpqdatacoord['RAD'][j],
                                    dec=qpqdatacoord['DECD'][j],
                                    unit='deg')
                bgcoord = SkyCoord(ra=qpqdatacoord['RAD_BG'][j],
                                   dec=qpqdatacoord['DECD_BG'][j],
                                   unit='deg')
                cgabs.ang_sep = qsocoord.separation(bgcoord).to('arcsec')

                self.cgm_abs.append(cgabs)
Example #11
0
def cgmabssys_from_sightline_field(field,
                                   sightline,
                                   rho_max=300. * u.kpc,
                                   minz=0.001,
                                   maxz=None,
                                   dv_max=400. * u.km / u.s,
                                   embuffer=None,
                                   dummysys=True,
                                   dummyspec=None,
                                   linelist=None,
                                   debug=False,
                                   **kwargs):
    """Instantiate list of CgmAbsSys objects from IgmgGalaxyField and IGMSightline.

    Parameters
    ----------
    field : IgmGalaxyField
    sightline : IGMSightline
    rho_max : Quantity, optional
        Maximum impact parameter for associated galaxies
    minz : float, optional
        Minimum redshift for galaxy/absorber search
    maxz : float, optional
        Maximum redshift for galaxy/absorber search
    dv_max : Quantity, optional
        Maximum galaxy-absorber velocity separation
    embuffer : Quantity, optional
        Velocity buffer between background source (e.g., QSO) and CGMAbsSys
    dummysys : bool, optional
        Passed on to 'cgm_from_galaxy_igmsystems()'.  If True, create CGMAbsSyS
        even if no matching IGMSystem is found in any sightline for some galaxy.
    dummyspec : XSpectrum1D, optional
        Spectrum object to attach to dummy AbsLine/AbsComponent objects when
        adding IGMSystems if dummysys is True
    linelist : LineList, optional
        ListList from which to add dummy line in case of no IGMSystem match

    Returns
    -------
    cgmabslist : list
        List of CgmAbsSys objects
    """
    if dummyspec is None:
        dummyspec = sightline._abssystems[0]._components[0]._abslines[0].analy[
            'spec']

    if linelist is None:
        from linetools.spectralline import AbsLine
        linelist = LineList('ISM')

    if embuffer is not None:
        try:
            bufmax = ltu.z_from_dv(-embuffer, field.zem)
            if maxz is not None:
                zmax = np.max(bufmax, maxz)
            else:
                zmax = bufmax
        except:
            zmax = maxz
    else:
        zmax = maxz

    closegals = get_close_galaxies(field, rho_max, minz, zmax)
    if debug:
        closegals = closegals[0:10]
    cgmabslist = []
    for i, gal in enumerate(closegals):
        #print('i={:d}'.format(i))
        galobj = Galaxy((gal['RA'], gal['DEC']), z=gal['Z'])
        cgmobj = cgm_from_galaxy_igmsystems(galobj,
                                            sightline._abssystems,
                                            dv_max=dv_max,
                                            dummysys=dummysys,
                                            dummyspec=dummyspec,
                                            rho_max=rho_max,
                                            linelist=linelist,
                                            **kwargs)
        cgmabslist.extend(cgmobj)
    return cgmabslist
Example #12
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
Example #13
0
def writelinepars(fitpars,
                  fiterrors,
                  parinfo,
                  specfile,
                  outfilename,
                  linecmts=None):
    '''
	Write fit parameters out to file.

	Parameters
	----------
	fitpars : list of lists
		Parameters for fit ready for fitter!
	fiterrors : array of numpy vectors
		Error array for the fitting initialized to '0' for each param
	parinfo : array of arrays
		Flags to be used in fit
	specfile : str
		Name of the input file containing the spectrum
	outfilename : str
		Parameter output filename
	linecmts : list of lists, optional
		Reliability flags and comments, e.g., from igmguesses

	'''
    import os
    ### Set outputs and open files
    bigfiletowrite = cfg.largeVPparfile
    filetowrite = outfilename
    if os.path.isfile(filetowrite):
        VPparfile = open(filetowrite, 'wb')
        bigparfile = open(bigfiletowrite, 'ab')  # Append to the running list
    else:
        VPparfile = open(filetowrite, 'wb')
        bigparfile = open(bigfiletowrite, 'wb')

    ### Prep header of line parameter file
    if linecmts is not None:
        header = b'specfile|restwave|zsys|col|sigcol|bval|sigbval|vel|sigvel|nflag|bflag|vflag|vlim1|vlim2|wobs1|wobs2|pix1|pix2|z_comp|trans|rely|comment \n'
    else:
        header = b'specfile|restwave|zsys|col|sigcol|bval|sigbval|vel|sigvel|nflag|bflag|vflag|vlim1|vlim2|wobs1|wobs2|pix1|pix2|z_comp|trans \n'
    VPparfile.write(header)
    bigparfile.write(header)

    ### Grab parameters/info for each line
    for i in range(len(fitpars[0])):
        zline = fitpars[3][i]
        vlim1 = fitpars[5][i]
        vlim2 = fitpars[6][i]
        restwave = fitpars[0][i]
        wobs1 = restwave * (1 + zline + vlim1 / 299792.458)
        wobs2 = restwave * (1 + zline + vlim2 / 299792.458)
        pix1 = jbg.closest(cfg.wave, wobs1)
        pix2 = jbg.closest(cfg.wave, wobs2)
        trans = atomicdata.lam2ion(fitpars[0][i])
        z_comp = ltu.z_from_dv(fitpars[4][i] * u.km / u.s, zline)
        if linecmts is not None:
            towrite = jbg.pipedelimrow([
                specfile, restwave,
                round(zline, 5),
                round(fitpars[1][i], 3),
                round(fiterrors[1][i], 3),
                round(fitpars[2][i], 3),
                round(fiterrors[2][i], 3),
                round(fitpars[4][i], 3),
                round(fiterrors[4][i], 3), parinfo[1][i], parinfo[2][i],
                parinfo[4][i], vlim1, vlim2, wobs1, wobs2, pix1, pix2,
                round(z_comp, 5), trans, linecmts[0][i], linecmts[1][i]
            ])
        else:
            towrite = jbg.pipedelimrow([
                specfile, restwave,
                round(zline, 5),
                round(fitpars[1][i], 3),
                round(fiterrors[1][i], 3),
                round(fitpars[2][i], 3),
                round(fiterrors[2][i], 3),
                round(fitpars[4][i], 3),
                round(fiterrors[4][i], 3), parinfo[1][i], parinfo[2][i],
                parinfo[4][i], vlim1, vlim2, wobs1, wobs2, pix1, pix2,
                round(z_comp, 5), trans
            ])
        VPparfile.write(towrite.encode())
        bigparfile.write(towrite.encode())
    VPparfile.close()
    bigparfile.close()
    print('Line parameters written to:')
    print(filetowrite)
Example #14
0
def writelinepars(fitpars,fiterrors,parinfo, specfile, outfilename, linecmts=None):
	'''
	Write fit parameters out to file.

	Parameters
	----------
	fitpars : list of lists
		Parameters for fit ready for fitter!
	fiterrors : array of numpy vectors
		Error array for the fitting initialized to '0' for each param
	parinfo : array of arrays
		Flags to be used in fit
	specfile : str
		Name of the input file containing the spectrum
	outfilename : str
		Parameter output filename
	linecmts : list of lists, optional
		Reliability flags and comments, e.g., from igmguesses

	'''
	import os
	### Set outputs and open files
	bigfiletowrite = cfg.largeVPparfile
	filetowrite = outfilename
	if os.path.isfile(filetowrite):
		VPparfile = open(filetowrite, 'wb')
		bigparfile = open(bigfiletowrite, 'ab') # Append to the running list
	else:
		VPparfile = open(filetowrite, 'wb')
		bigparfile = open(bigfiletowrite, 'wb')

	### Prep header of line parameter file
	if linecmts is not None:
		header = 'specfile|restwave|zsys|col|sigcol|bval|sigbval|vel|sigvel|nflag|bflag|vflag|vlim1|vlim2|wobs1|wobs2|pix1|pix2|z_comp|trans|rely|comment \n'
	else:
		header = 'specfile|restwave|zsys|col|sigcol|bval|sigbval|vel|sigvel|nflag|bflag|vflag|vlim1|vlim2|wobs1|wobs2|pix1|pix2|z_comp|trans \n'
	VPparfile.write(header)
	bigparfile.write(header)

	### Grab parameters/info for each line
	for i in range(len(fitpars[0])):
		zline = fitpars[3][i]
		vlim1 = fitpars[5][i]
		vlim2 = fitpars[6][i]
		restwave = fitpars[0][i]
		wobs1 = restwave * (1 + zline + vlim1 / 299792.458)
		wobs2 = restwave * (1 + zline + vlim2 / 299792.458)
		pix1 = jbg.closest(cfg.wave, wobs1)
		pix2 = jbg.closest(cfg.wave, wobs2)
		trans = atomicdata.lam2ion(fitpars[0][i])
		z_comp = ltu.z_from_dv(fitpars[4][i]*u.km/u.s, zline)
		if linecmts is not None:
			towrite = jbg.pipedelimrow(
				[specfile, restwave, round(zline, 5), round(fitpars[1][i], 3), round(fiterrors[1][i], 3),
				 round(fitpars[2][i], 3), round(fiterrors[2][i], 3), round(fitpars[4][i], 3), round(fiterrors[4][i], 3),
				 parinfo[1][i], parinfo[2][i], parinfo[4][i], vlim1, vlim2, wobs1, wobs2, pix1, pix2,round(z_comp, 5), trans,
				 linecmts[0][i],linecmts[1][i]])
		else:
			towrite = jbg.pipedelimrow(
				[specfile, restwave, round(zline, 5), round(fitpars[1][i], 3), round(fiterrors[1][i], 3),
				 round(fitpars[2][i], 3), round(fiterrors[2][i], 3), round(fitpars[4][i], 3), round(fiterrors[4][i], 3),
				 parinfo[1][i], parinfo[2][i], parinfo[4][i], vlim1, vlim2, wobs1, wobs2, pix1, pix2, round(z_comp, 5),trans])
		VPparfile.write(towrite)
		bigparfile.write(towrite)
	VPparfile.close()
	bigparfile.close()
	print 'Line parameters written to:'
	print filetowrite
Example #15
0
def lls_stat(LLSs,
             qsos,
             vprox=3000. * u.km / u.s,
             maxdz=99.99,
             zem_min=0.,
             NHI_cut=17.5,
             flg_zsrch=0,
             dz_toler=0.04,
             LLS_CUT=None,
             partial=False,
             prox=False):
    """ Identify the statistical LLS in a survey

    Parameters
    ----------
    vprox
    maxdz
    zem_min
    NHI_cut
    flg_zsrch
    dz_toler
    partial : bool, optional
      Analyze partial LLS? [pLLS]
    prox : bool, optional
      Proximate LLS? [PLLS]

    Returns
    -------
    msk_smpl : bool array
      True = statistical
    """

    # Search redshift
    if flg_zsrch == 0:
        zsrch = qsos['ZT2']
    elif flg_zsrch == 1:
        zsrch = qsos['ZT1']
    elif flg_zsrch == 2:
        zsrch = qsos['ZT0']
    # Modify by LLS along QSO sightline as required
    if LLS_CUT is not None:
        pdb.set_trace()
        #zsrch = zsrch > qsos.zlls[LLS_CUT]

    # LLS
    msk_smpl = LLSs.zem != LLSs.zem
    zmax = ltu.z_from_dv(
        vprox * np.ones(len(qsos)), qsos['ZEM'].data
    )  # vprox must be array-like to be applied to each individual qsos['ZEM']

    # Make some lists
    lls_coord = LLSs.coord
    lls_zem = LLSs.zem
    lls_zabs = LLSs.zabs
    qsos_coord = SkyCoord(ra=qsos['RA'] * u.deg, dec=qsos['DEC'] * u.deg)

    for qq, ills in enumerate(LLSs._abs_sys):
        # Two LLS on one sightline?
        small_sep = ills.coord.separation(lls_coord) < 3.6 * u.arcsec
        close_zem = np.abs(ills.zem - lls_zem) < 0.03
        close_zabs = np.abs(ills.zabs - lls_zabs) < dz_toler
        if np.sum(small_sep & close_zem & close_zabs) != 1:
            raise ValueError("LLS are probably too close in z")

        # Cut on NHI
        if partial & (ills.NHI > NHI_cut):
            continue
        if ~partial & (ills.NHI <= NHI_cut):
            continue

        # Match to QSO RA, DEC
        idx = np.where((ills.coord.separation(qsos_coord) < 3.6 * u.arcsec)
                       & (np.abs(qsos['ZEM'] - ills.zem) < 0.03))[0]
        if len(idx) != 1:
            raise ValueError("Problem with matches")

        # Query redshift
        if ((zsrch[idx] > 0.) &
            (ills.zabs > max(zsrch[idx], qsos['ZEM'][idx] - maxdz) - 1e-4) &
            (qsos['ZEM'][idx] > zem_min)):
            if (~prox) & (ills.zabs < zmax[idx]):  #  Intervening
                msk_smpl[qq] = True
            if prox & (ills.zabs >= zmax[idx]):  # Proximate
                msk_smpl[qq] = True

    # Return
    return msk_smpl
Example #16
0
    def load_SDSS_DR7(cls, sample='stat'):
        """ Load the LLS from the SDSS-DR7 survey (Prochaska+10, ApJ, 718, 391)

        Parameters
        ----------
        sample : str, optional
          LLS sample
            stat : Statistical sample
            all : All LLS
            nonstat : Non-statistical sample


        Returns
        -------
        lls_survey : IGMSurvey

        """
        # LLS File
        lls_fil = pyigm_path + '/data/LLS/SDSS/lls_dr7_stat_LLS.fits.gz'
        print('SDSS-DR7: Loading LLS file {:s}'.format(lls_fil))
        lls = Table.read(lls_fil)

        # Rename some columns?
        lls.rename_column('QSO_RA', 'RA')
        lls.rename_column('QSO_DEC', 'DEC')

        # Instantiate
        scoords = [
            lls['RA'][ii] + ' ' + lls['DEC'][ii] for ii in range(len(lls))
        ]
        coords = SkyCoord(scoords, unit=(u.hourangle, u.deg))
        lls_survey = cls.from_sfits(lls, coords=coords)
        lls_survey.ref = 'SDSS-DR7'

        # QSOs file
        qsos_fil = pyigm_path + '/data/LLS/SDSS/lls_dr7_qsos_sn2050.fits.gz'
        print('SDSS-DR7: Loading QSOs file {:s}'.format(qsos_fil))
        qsos = Table.read(qsos_fil)
        lls_survey.sightlines = qsos

        # All?
        if sample == 'all':
            return lls_survey

        # Stat
        # z_em cut
        zem_min = 3.6
        lowz_q = qsos['ZEM'] < zem_min
        qsos['ZT2'][lowz_q] = 99.99
        dz_start = 0.4

        # Survey path
        #   Using tau=2
        lls_survey.sightlines['Z_START'] = np.maximum(qsos['ZT2'],
                                                      qsos['ZLLS'])
        # Maximum search
        lls_survey.sightlines['Z_START'] = np.maximum(qsos['Z_START'],
                                                      qsos['ZEM'] - dz_start)
        # Trim bad ones
        bad_s = np.any([
            lls_survey.sightlines['Z_START'] <= 0.,
            lls_survey.sightlines['FLG_QSO'] != 0
        ],
                       axis=0)
        lls_survey.sightlines['Z_START'][bad_s] = 99.99
        # zend
        zend = ltu.z_from_dv(-3000 * u.km / u.s * np.ones(len(qsos)),
                             lls_survey.sightlines['ZEM'])
        lls_survey.sightlines['Z_END'] = zend

        # Generate mask
        print('SDSS-DR7: Performing stats')
        mask = lls_stat(lls_survey)
        if sample == 'stat':
            lls_survey.mask = mask
        else:
            lls_survey.mask = ~mask
        # Return
        print('SDSS-DR7: Loaded')
        return lls_survey
Example #17
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
Example #18
0
def test_z_from_dv():
    z = ltu.z_from_dv(1000. * u.km / u.s, 2.)
    np.testing.assert_allclose(z, 2.0100236684175417)
Example #19
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 = []
Example #20
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 = []