Esempio n. 1
0
def test_cgmsurvey_from_fields_sightlines():
    # Instantiate fields and add galaxies
    field1 = ('PG1407+265', 212.349634 * u.deg, 26.3058650 * u.deg)
    fieldobj1 = IgmGalaxyField((field1[1], field1[2]),
                               name=field1[0],
                               verbose=False)
    field2 = ('PG1148+549', 177.83526042 * u.deg, 54.625855 * u.deg)
    fieldobj2 = IgmGalaxyField((field2[1], field2[2]),
                               name=field2[0],
                               verbose=False)
    f1ras = [212.33310891, 212.329875] * u.deg
    f1decs = [26.3722716934, 26.3084391667] * u.deg
    f1zs = [0.974413514137, 0.22016787529]
    f1gals = Table([f1ras, f1decs, f1zs], names=['RA', 'DEC', 'Z'])
    f2ras = [177.835229336, 178.536958333] * u.deg
    f2decs = [54.625851084, 54.6176108333] * u.deg
    f2zs = [0.0595485754311, 0.00385531364009]
    f2gals = Table([f2ras, f2decs, f2zs], names=['RA', 'DEC', 'Z'])
    fieldobj1.galaxies = f1gals
    fieldobj2.galaxies = f2gals
    fields = [fieldobj1, fieldobj2]

    # Instantiate sightlines
    sl1coord = SkyCoord(field1[1], field1[2], unit='deg')
    sl2coord = SkyCoord(field2[1], field2[2], unit='deg')
    comp11 = AbsComponent(sl1coord, (8, 6), 0.9743, [-200, 200] * u.km / u.s)
    comp12 = AbsComponent(sl1coord, (1, 1), 0.9743, [-200, 200] * u.km / u.s)
    al11 = AbsLine('OVI 1031')
    al11.attrib['coord'] = sl1coord
    al11.analy['spec'] = 'files/J0042-1037.358_9.fits.gz'
    al12 = AbsLine('HI 1215')
    al12.attrib['coord'] = sl1coord
    al12.analy['spec'] = 'files/J0042-1037.358_9.fits.gz'
    comp11.add_absline(al11, chk_sep=False, chk_vel=False)
    comp12.add_absline(al12, chk_sep=False, chk_vel=False)
    sys1 = IGMSystem.from_components([comp11, comp12])
    sl1 = IGMSightline.from_systems([sys1])
    comp21 = AbsComponent(sl2coord, (6, 4), 0.0037, [-200, 200] * u.km / u.s)
    comp22 = AbsComponent(sl2coord, (1, 1), 0.0037, [-200, 200] * u.km / u.s)
    al21 = AbsLine('CIV 1548')
    al21.attrib['coord'] = sl1coord
    al21.analy['spec'] = 'files/J0042-1037.358_9.fits.gz'
    al22 = AbsLine('HI 1215')
    al22.attrib['coord'] = sl1coord
    al22.analy['spec'] = 'files/J0042-1037.358_9.fits.gz'
    comp21.add_absline(al21, chk_sep=False, chk_vel=False)
    comp22.add_absline(al22, chk_sep=False, chk_vel=False)
    sys2 = IGMSystem.from_components([comp21, comp22])
    sl2 = IGMSightline.from_systems([sys2])
    sightlines = [sl1, sl2]

    # Run function
    csurvey = cgmsurvey_from_sightlines_fields(fields, sightlines)
    assert isinstance(csurvey, CGMAbsSurvey)
Esempio n. 2
0
def test_init():
    # Simple properties
    abscomp = AbsComponent((10.0 * u.deg, 45 * u.deg), (14, 2), 1.0,
                           [-300, 300] * u.km / u.s)
    # Test
    assert abscomp.Zion[0] == 14
    np.testing.assert_allclose(abscomp.zcomp, 1.0)
    print(abscomp)
    # Fine structure
    comp = AbsComponent((10.0 * u.deg, 45 * u.deg), (14, 2),
                        1.0, [-300, 300] * u.km / u.s,
                        Ej=0.1 / u.cm)  # need stars!
    assert comp.name.count('*') == 1
Esempio n. 3
0
def synthesize_components(components, zcomp=None, vbuff=0 * u.km / u.s):
    """Synthesize a list of components into one

    Requires consistent RA/DEC, Zion, Ej, (A; future)
    Is agnostic about z+vlim
    Melds column densities
    Melds velocities with an optional buffer

    Note: Could make this a way to instantiate AbsComponent

    Parameters
    ----------
    components : list
      list of AbsComponent objects
    zcomp : float, optional
      Input z to reference the synthesized component
      If not input, the mean of the input components is used
    vbuff : Quantity, optional
      Buffer for synthesizing velocities.  Deals with round off, c, etc.
    """
    # Checks
    assert chk_components(components, chk_A_none=True, chk_match=True)

    # Meld column densities
    obj = dict(flag_N=components[0].flag_N,
               logN=components[0].logN,
               sig_logN=components[0].sig_logN)
    for comp in components[1:]:
        if comp.flag_N != 0:
            obj['flag_N'], obj['logN'], obj['sig_logN'] = ltaa.sum_logN(
                obj, comp)

    # zcomp
    if zcomp is None:
        zcomp = np.mean([comp.zcomp for comp in components])

    # Set vlim by min/max  [Using non-relativistic + buffer]
    vmin = u.Quantity([
        (comp.zcomp - zcomp) / (1 + zcomp) * const.c.to('km/s') + comp.vlim[0]
        for comp in components
    ])
    vmax = u.Quantity([
        (comp.zcomp - zcomp) / (1 + zcomp) * const.c.to('km/s') + comp.vlim[1]
        for comp in components
    ])
    vlim = u.Quantity([np.min(vmin) - vbuff, np.max(vmax) + vbuff])

    # Init final component
    synth_comp = AbsComponent(
        components[0].coord,
        components[0].Zion,
        zcomp,
        vlim,
        Ej=components[0].Ej,
        stars=components[0].stars,
        Ntup=(obj['flag_N'], obj['logN'],
              obj['sig_logN']))  # Should probably set attrib instead

    # Return
    return synth_comp
Esempio n. 4
0
def test_init():
    # Simple properties
    abscomp = AbsComponent((10.0 * u.deg, 45 * u.deg), (14, 2), 1.0,
                           [-300, 300] * u.km / u.s)
    # Test
    assert abscomp.Zion[0] == 14
    np.testing.assert_allclose(abscomp.zcomp, 1.0)
    print(abscomp)
Esempio n. 5
0
def test_init_failures():
    with pytest.raises(IOError):
        AbsComponent.from_abslines('blah')
    with pytest.raises(IOError):
        AbsComponent.from_abslines(['blah'])
    with pytest.raises(IOError):
        AbsComponent.from_component('blah')
    with pytest.raises(IOError):
        AbsComponent((10.0 * u.deg, 45 * u.deg), (14, 2),
                     1.0, [-300, 300] * u.km / u.s,
                     Ej=0.1 / u.cm)  # need stars!
Esempio n. 6
0
def test_abscomp_H2():
    Zion = (-1, -1)  # temporary code for molecules
    Ntuple = (
        1, 17, -1
    )  # initial guess for Ntuple (needs to be given for adding lines from linelist)
    coord = SkyCoord(0, 0, unit='deg')
    z = 0.212
    vlim = [-100., 100.] * u.km / u.s
    comp = AbsComponent(coord, Zion, z, vlim, Ntup=Ntuple)
    comp.add_abslines_from_linelist(llist='H2',
                                    init_name="B19-0P(1)",
                                    wvlim=[1100, 5000] * u.AA)
    assert len(comp._abslines) == 7
Esempio n. 7
0
def p11():
    """ Ingest Prochaska et al. 2011 CGM survey
    """
    # Low z OVI summary
    ovi_file = pyigm.__path__[0] + '/data/CGM/P11/lowovidat.fits'
    ovidat = Table.read(ovi_file)
    qso_radec = SkyCoord(ra=ovidat['QSO_RA'],
                         dec=ovidat['QSO_DEC'],
                         unit=(u.hourangle, u.deg))
    qso_nms = np.array([row['QSO'].strip() for row in ovidat])

    # CGM Survey
    p11 = CGMAbsSurvey(survey='P11', ref='Prochaska+11')

    # Dwarfs
    cgm_dwarf_file = pyigm.__path__[0] + '/data/CGM/P11/dwarf_galabs_strct.fits'
    cgm_dwarfs = Table.read(cgm_dwarf_file)
    # sub L*
    cgm_subls_file = pyigm.__path__[0] + '/data/CGM/P11/subls_galabs_strct.fits'
    cgm_subls = Table.read(cgm_subls_file)
    # L*
    cgm_lstar_file = pyigm.__path__[0] + '/data/CGM/P11/lstar_galabs_strct.fits'
    cgm_lstar = Table.read(cgm_lstar_file)

    # Loop on subsets
    for subset in [cgm_dwarfs, cgm_subls, cgm_lstar]:
        for row in subset:
            # RA, DEC
            # Galaxy
            gal = Galaxy((row['RA'], row['DEC']), z=row['Z'])
            gal.Lstar = row['DDEC']
            gal.type = row['GAL_TYPE']
            # IGMSys
            mtqso = np.where(qso_nms == row['FIELD'].strip())[0]
            if len(mtqso) != 1:
                pdb.set_trace()
                raise ValueError("No Field match")
            igmsys = IGMSystem(qso_radec[mtqso[0]], row['Z'],
                               (-400., 400.) * u.km / u.s)
            # HI
            if row['MAG'][2] > 0.:
                # Lya
                lya = AbsLine(1215.67 * u.AA, z=float(row['MAG'][3]))
                lya.attrib['EW'] = row['MAG'][4] / 1e3 * u.AA
                if row['MAG'][5] >= 99.:
                    lya.attrib['flag_EW'] = 3
                else:
                    lya.attrib['flag_EW'] = 1
                lya.attrib['sig_EW'] = row['MAG'][5] / 1e3 * u.AA
                # Ref
                lya.attrib['Ref'] = int(row['MAG'][2])
                # HI component
                if row['MAG'][9] <= 0.:
                    flagN = 3
                elif row['MAG'][9] > 9.:
                    flagN = 2
                else:
                    flagN = 1
                HIcomp = AbsComponent(qso_radec[mtqso[0]], (1, 1),
                                      float(row['MAG'][3]),
                                      (-400, 400) * u.km / u.s,
                                      Ntup=(flagN, row['MAG'][8],
                                            row['MAG'][9]))
                HIcomp._abslines.append(lya)
                igmsys._components.append(HIcomp)
                # NHI
                igmsys.NHI = HIcomp.logN
                igmsys.flag_NHI = HIcomp.flag_N
                igmsys.sig_NHI = HIcomp.sig_N
            # OVI
            if row['MAGERR'][2] > 0.:
                # OVI 1031
                ovi1031 = None
                if row['MAGERR'][4] > 0.:
                    ovi1031 = AbsLine(1031.9261 * u.AA,
                                      z=float(row['MAGERR'][3]))
                    if row['MAGERR'][5] >= 99.:
                        ovi1031.attrib['flag_EW'] = 3
                    else:
                        ovi1031.attrib['flag_EW'] = 1
                    ovi1031.attrib['EW'] = row['MAGERR'][4] / 1e3 * u.AA
                    ovi1031.attrib['sig_EW'] = row['MAGERR'][5] / 1e3 * u.AA
                # OVI component
                if row['MAGERR'][9] <= 0.:
                    flagN = 3
                elif row['MAGERR'][9] > 9.:
                    flagN = 2
                else:
                    flagN = 1
                OVIcomp = AbsComponent(qso_radec[mtqso[0]], (8, 6),
                                       float(row['MAGERR'][3]),
                                       (-400, 400) * u.km / u.s,
                                       Ntup=(flagN, row['MAGERR'][8],
                                             row['MAGERR'][9]))
                if ovi1031 is not None:
                    OVIcomp._abslines.append(ovi1031)
                # Ref
                OVIcomp.Ref = int(row['MAG'][2])
                igmsys._components.append(OVIcomp)
            # CGM
            cgmabs = CGMAbsSys(gal, igmsys, chk_lowz=False)
            p11.cgm_abs.append(cgmabs)
    # Write tarball
    out_file = pyigm.__path__[0] + '/data/CGM/P11/P11_sys.tar'
    p11.to_json_tarball(out_file)
Esempio n. 8
0
def ingest_johnson15():
    """ Ingest Johnson+15
    """
    # Dict for QSO coords
    qsos = {}
    qsos['1ES1028+511'] = ltu.radec_to_coord('J103118.52517+505335.8193')
    qsos['FBQS1010+3003'] = ltu.radec_to_coord((152.5029167, 30.056111))
    qsos['HE0226-4110'] = ltu.radec_to_coord('J022815.252-405714.62')
    qsos['HS1102+3441'] = ltu.radec_to_coord('J110539.8189+342534.672')
    qsos['LBQS1435-0134'] = ltu.radec_to_coord((219.451183, -1.786328))
    qsos['PG0832+251'] = ltu.radec_to_coord('J083535.8048+245940.146')
    qsos['PG1522+101'] = ltu.radec_to_coord((231.1023075, 9.9749372))
    qsos['PKS0405-123'] = ltu.radec_to_coord('J040748.4376-121136.662')
    qsos['SBS1108+560'] = ltu.radec_to_coord((167.8841667, 55.790556))
    qsos['SBS1122+594'] = ltu.radec_to_coord((171.4741250, 59.172667))
    qsos['Ton236'] = ltu.radec_to_coord((232.1691746, 28.424928))

    # Virial matching
    j15_file = resource_filename('pyigm',
                                 'data/CGM/z0/johnson2015_table1.fits')
    j15_tbl = Table.read(j15_file)

    # Clip COS-Halos
    keep = j15_tbl['Survey'] != 'COS-Halos'
    j15_tbl = j15_tbl[keep]

    # CGM Survey
    j15 = CGMAbsSurvey(survey='J15', ref='Johnson+15')

    # Linelist
    llist = LineList('ISM')

    for row in j15_tbl:
        # RA, DEC
        # Galaxy
        gal = Galaxy((row['RAJ2000'], row['DEJ2000']), z=float(row['zgal']))
        gal.Class = row['Class']
        gal.Mstar = row['logM_']
        gal.field = row['Name']
        gal.Env = row['Env']
        gal.d_Rh = row['d_Rh']
        #
        igmsys = IGMSystem(qsos[row['Name']], float(row['zgal']),
                           (-400., 400.) * u.km / u.s)
        # HI
        if np.isnan(row['logNHI']):
            pass
        else:
            # HI component
            if row['l_logNHI'] == '<':
                flagN = 3
                sigNHI = 99.
            elif np.isnan(row['e_logNHI']):
                flagN = 2
                sigNHI = 99.
            else:
                flagN = 1
                sigNHI = row['e_logNHI']
            HIcomp = AbsComponent(qsos[row['Name']], (1, 1),
                                  float(row['zgal']), (-400, 400) * u.km / u.s,
                                  Ntup=(flagN, row['logNHI'], sigNHI))
            igmsys._components.append(HIcomp)
            # NHI
            igmsys.NHI = HIcomp.logN
            igmsys.flag_NHI = HIcomp.flag_N
            igmsys.sig_NHI = HIcomp.sig_N
        # OVI
        if np.isnan(row['logNHOVI']):
            pass
        else:
            # OVI component
            if row['l_logNHOVI'] == '<':
                flagN = 3
                sigNHOVI = 99.
            elif np.isnan(row['e_logNHOVI']):
                flagN = 2
                sigNHOVI = 99.
            else:
                flagN = 1
                sigNHOVI = row['e_logNHOVI']
            OVIcomp = AbsComponent(qsos[row['Name']], (8, 6),
                                   float(row['zgal']),
                                   (-400, 400) * u.km / u.s,
                                   Ntup=(flagN, row['logNHOVI'], sigNHOVI))
            igmsys._components.append(OVIcomp)
        # CGM
        cgmabs = CGMAbsSys(gal, igmsys, chk_lowz=False)
        j15.cgm_abs.append(cgmabs)
    # Write tarball
    out_file = resource_filename('pyigm', '/data/CGM/z0/J15_sys.tar')
    j15.to_json_tarball(out_file)
Esempio n. 9
0
def ingest_burchett16(smthd='vir'):
    """ Ingest Burchett+16
    """
    # Virial matching
    if smthd == 'vir':
        b16_file = resource_filename(
            'pyigm', 'data/CGM/z0/Burchett2016_CIV_HI_virselect.fits')
    else:
        b16_file = resource_filename(
            'pyigm', 'data/CGM/z0/Burchett2016_CIV_HI_kpcselect.fits')
    b16_tbl = Table.read(b16_file)

    # CGM Survey
    b16 = CGMAbsSurvey(survey='B16', ref='Burchett+16')

    # Linelist
    llist = LineList('ISM')

    for row in b16_tbl:
        # RA, DEC
        # Galaxy
        gal = Galaxy((row['ra_gal'], row['dec_gal']), z=row['zgal'])
        gal.SFR = row['SFR']
        gal.sig_SFR = row['SFR_err']
        gal.Mstar = row['mstars']
        gal.field = row['field']
        gal.RRvir = row['rrvir']
        gal.NSAidx = row['NSAidx']
        #
        igmsys = IGMSystem((row['ra_qso'], row['dec_qso']), row['zgal'],
                           (-400., 400.) * u.km / u.s)
        # HI
        if row['flag_h1'] > 0:
            # Lya
            lya = AbsLine(1215.67 * u.AA, z=row['zgal'], linelist=llist)
            lya.attrib['EW'] = row['EW_h1'] * u.AA
            lya.attrib['logN'] = row['col_h1']
            lya.attrib['N'] = 10**row['col_h1'] * u.cm**-2
            if row['flag_h1'] == 3:
                lya.attrib['flag_EW'] = 3
                lya.attrib['flag_N'] = 3
                lya.attrib['sig_N'] = (10**(row['col_h1'])) / 3. * u.cm**-2
            elif row['flag_h1'] == 2:
                lya.attrib['flag_EW'] = 1
                lya.attrib['flag_N'] = 2
            else:
                lya.attrib['flag_EW'] = 1
                lya.attrib['flag_N'] = 1
                lya.attrib['sig_N'] = (10**(row['col_h1'] + row['colsig_h1']) -
                                       10**row['col_h1']) * u.cm**-2
            lya.attrib['sig_EW'] = row['EWsig_h1'] * u.AA
            # Ref
            lya.attrib['Ref'] = 'Burchett+16'
            # HI component
            if row['colsig_h1'] >= 99.:
                flagN = 2
            elif row['colsig_h1'] <= 0.:
                flagN = 3
            else:
                flagN = 1
            HIcomp = AbsComponent(
                (row['ra_qso'], row['dec_qso']), (1, 1),
                row['zgal'], (-400, 400) * u.km / u.s,
                Ntup=(flagN, row['col_h1'], row['colsig_h1']))
            HIcomp._abslines.append(lya)
            igmsys._components.append(HIcomp)
            # NHI
            igmsys.NHI = HIcomp.logN
            igmsys.flag_NHI = HIcomp.flag_N
            igmsys.sig_NHI = HIcomp.sig_N
        # CIV
        if row['flag_c4'] > 0:
            # CIV 1548
            civ1548 = AbsLine(1548.195 * u.AA, z=row['zgal'], linelist=llist)
            civ1548.attrib['EW'] = row['EW_c4'] * u.AA
            civ1548.attrib['logN'] = row['col_c4']
            civ1548.attrib['N'] = 10**row['col_c4'] * u.cm**-2
            if row['flag_c4'] == 3:
                civ1548.attrib['flag_EW'] = 3
                civ1548.attrib['flag_N'] = 3
                civ1548.attrib['sig_N'] = (10**(row['col_c4'])) / 3. * u.cm**-2
            elif row['flag_c4'] == 2:
                civ1548.attrib['flag_EW'] = 1
                civ1548.attrib['flag_N'] = 2
            else:
                civ1548.attrib['flag_EW'] = 1
                civ1548.attrib['flag_N'] = 1
                civ1548.attrib['sig_N'] = (10**
                                           (row['col_c4'] + row['colsig_c4']) -
                                           10**row['col_c4']) * u.cm**-2
            civ1548.attrib['sig_EW'] = row['EWsig_c4'] * u.AA
            # Ref
            civ1548.attrib['Ref'] = 'Burchett+16'
            # CIV component
            if row['colsig_c4'] >= 99.:
                flagN = 2
            elif row['colsig_c4'] <= 0.:
                flagN = 3
            else:
                flagN = 1
            CIVcomp = AbsComponent(
                (row['ra_qso'], row['dec_qso']), (6, 4),
                row['zgal'], (-400, 400) * u.km / u.s,
                Ntup=(flagN, row['col_c4'], row['colsig_c4']))
            CIVcomp._abslines.append(civ1548)
            igmsys._components.append(CIVcomp)
        # CGM
        cgmabs = CGMAbsSys(gal, igmsys, correct_lowz=False)
        b16.cgm_abs.append(cgmabs)
    # Write tarball
    if smthd == 'vir':
        out_file = resource_filename('pyigm', '/data/CGM/z0/B16_vir_sys.tar')
    else:
        out_file = resource_filename('pyigm', '/data/CGM/z0/B16_kpc_sys.tar')
    b16.to_json_tarball(out_file)
Esempio n. 10
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
Esempio n. 11
0
def complist_from_table(table):
    """
    Returns a list of AbsComponents from an input astropy.Table.

    Parameters
    ----------
    table : Table
        Table with component information (each row must correspond
        to a component).
        Each column is expecting a unit when appropriate.
           Units for vmin, vmax are assumed km/s if not given
           Units for Ej are assumed cm^-1 if not given

    Returns
    -------
    complist : list
        List of AbsComponents defined from the input table.

    Notes
    -----
    Mandatory column names: 'RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax'
        These column are required.
    Special column names: 'name', 'comment', 'logN', 'sig_logN', 'flag_logN'
        These columns will fill internal attributes when corresponding.
        In order to fill in the Ntuple attribute all three 'logN', 'sig_logN', 'flag_logN'
        must be present. For convenience 'logN' and 'sig_logN' are expected to be floats
        corresponding to their values in np.log10(1/cm^2).

    Other columns: 'any_column_name'
        These will be added as attributes within the AbsComponent.attrib dictionary,
        with their respective units if given.

    """
    # Convert to QTable to handle units in individual entries more easily
    tkeys = table.keys()

    # mandatory and optional columns
    min_columns = ['RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax', 'Z', 'ion', 'Ej']
    special_columns = ['name', 'comment', 'logN', 'sig_logN', 'flag_logN']
    for colname in min_columns:
        if colname not in table.keys():
            raise IOError('{} is a mandatory column. Please make sure your input table has it.'.format(colname))

    # Generate components -- Should add to linetools.isgm.utils
    complist = []
    coords = SkyCoord(ra=table['RA'], dec=table['DEC'], unit='deg')
    for kk,row in enumerate(table):
        # Setup
        if 'flag_logN' in tkeys:
            Ntuple = (row['flag_logN'], row['logN'], row['sig_logN'])
        else:
            Ntuple = None
        # Units
        vmnx = [row['vmin'], row['vmax']]
        vmnx *= u.km/u.s if table['vmin'].unit is None else table['vmin'].unit
        Ej = row['Ej'] * (1/u.cm if table['Ej'].unit is None else table['Ej'].unit)
        #
        abscomp = AbsComponent(coords[kk], (row['Z'], row['ion']),
                               row['z_comp'], vmnx, Ej=Ej, Ntup=Ntuple)
        # Extra attrib
        for key in ['comment', 'name']:
            if key in tkeys:
                setattr(abscomp, key, row[key])
        # Other
        for key in ['sig_z', 'b','sig_b','specfile']:
            try:
                abscomp.attrib[key] = row[key]
            except KeyError:
                pass
            else:
                if table[key].unit is not None:
                    abscomp.attrib[key] *= table[key].unit
                else:
                    if key in ['b', 'sig_b']:
                        warnings.warn("No units for 'b'.  Will assume km/s")
                        abscomp.attrib[key] *= u.km/u.s
        complist.append(abscomp)
    return complist
Esempio n. 12
0
    def write_to_igmguesses(self,
                            outfile,
                            fwhm=3.,
                            specfilename=None,
                            creator=None,
                            instrument='unknown',
                            altname='unknown',
                            date=None,
                            overwrite=False):
        import json
        """
        Writes an IGMGuesses formatted JSON file

        Parameters
        ----------
        outfile : str
            Name of the IGMGuesses JSON file to write to.
        fwhm : int
            FWHM for IGMguesses
        specfilename : str
            Name of the spectrum file these guesses are associated to.
        altname : str
            Alternative name for the sightline. e.g. 3C273
        creator : str
            Name of the person who is creating the file. Important for tracking.
        instrument : str
            String indicating the instrument and its configuration associated to the specfilename.
            e.g. HST/COS/G130M+G160M/LP2
        overwrite : bool
            Wthether to overwrite output


        Returns
        -------

        """
        import datetime
        # Slurp IGMGuesses component attributes
        from pyigm.guis.igmguesses import comp_init_attrib
        from linetools.isgm.abscomponent import AbsComponent
        tmp = AbsComponent((10.0 * u.deg, 45 * u.deg), (14, 2), 1.0,
                           [-300, 300] * u.km / u.s)
        comp_init_attrib(tmp)
        igmg_akeys = list(tmp.attrib.keys())
        # components
        comp_list = self._components
        coord_ref = comp_list[0].coord
        if date is None:
            date = str(datetime.date.today().strftime('%Y-%b-%d'))

        # spec_file, meta
        if hasattr(self, 'igmg_dict'):
            spec_file = self.igmg_dict['spec_file']
            meta = self.igmg_dict['meta']
            # Updates
            meta['Date'] = date
            if creator is not None:
                meta['Creator'] = creator
            #
            fwhm = self.igmg_dict['fwhm']
        else:
            spec_file = specfilename
            # coordinates and meta
            RA = coord_ref.ra.to('deg').value
            DEC = coord_ref.dec.to('deg').value
            jname = ltu.name_from_coord(coord_ref, precision=(2, 1))
            if self.zem is None:
                zem = 0.  # IGMGuesses rules
            else:
                zem = self.zem
            if creator is None:
                creator = 'unknown'
            meta = {
                'RA': RA,
                'DEC': DEC,
                'ALTNAME': altname,
                'zem': zem,
                'Creator': creator,
                'Instrument': instrument,
                'Date': date,
                'JNAME': jname
            }

        # Create dict of the components
        out_dict = dict(cmps={},
                        spec_file=spec_file,
                        fwhm=fwhm,
                        bad_pixels=[],
                        meta=meta)

        for comp in comp_list:
            key = comp.name
            out_dict['cmps'][key] = comp.to_dict()
            # import pdb; pdb.set_trace()
            # check coordinate
            if comp.coord != coord_ref:
                raise ValueError(
                    "All AbsComponent objects must have the same coordinates!")
            out_dict['cmps'][key]['zcomp'] = comp.zcomp
            # IGMGuesses specific component attr
            for igm_key in [
                    'zfit', 'Nfit', 'bfit', 'wrest', 'mask_abslines', 'vlim'
            ]:
                out_dict['cmps'][key][igm_key] = comp.igmg_attrib['top_level'][
                    igm_key]
            # IGMGuesses attribute dict
            out_dict['cmps'][key]['attrib'] = {}
            for igm_key in igmg_akeys:
                try:
                    out_dict['cmps'][key]['attrib'][
                        igm_key] = comp.igmg_attrib[igm_key]
                except KeyError:
                    out_dict['cmps'][key]['attrib'][igm_key] = comp.attrib[
                        igm_key]
            #out_dict['cmps'][key]['vlim'] = list(comp.vlim.value)
            out_dict['cmps'][key]['reliability'] = str(comp.reliability)
            out_dict['cmps'][key]['comment'] = str(comp.comment)
            # Compatability on sig_logN
            out_dict['cmps'][key]['attrib']['sig_logN'] = comp.attrib[
                'sig_logN'][0]

        # JSONify
        gd_dict = ltu.jsonify(out_dict)

        # Write file
        ltu.savejson(outfile,
                     gd_dict,
                     overwrite=overwrite,
                     sort_keys=True,
                     indent=4,
                     separators=(',', ': '))
        print('Wrote: {:s}'.format(outfile))
Esempio n. 13
0
def complist_from_table(table):
    """
    Returns a list of AbsComponents from an input astropy.Table.

    Parameters
    ----------
    table : Table
        Table with component information (each row must correspond
        to a component). Each column is expecting a unit when
        appropriate.

    Returns
    -------
    complist : list
        List of AbsComponents defined from the input table.

    Notes
    -----
    Mandatory column names: 'RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax'
        These column are required.
    Special column names: 'name', 'comment', 'logN', 'sig_logN', 'flag_logN'
        These columns will fill internal attributes when corresponding.
        In order to fill in the Ntuple attribute all three 'logN', 'sig_logN', 'flag_logN'
        must be present. For convenience 'logN' and 'sig_logN' are expected to be floats
        corresponding to their values in np.log10(1/cm^2).

    Other columns: 'any_column_name'
        These will be added as attributes within the AbsComponent.attrib dictionary,
        with their respective units if given.

    """
    # Convert to QTable to handle units in individual entries more easily
    table = QTable(table)

    # mandatory and optional columns
    min_columns = ['RA', 'DEC', 'ion_name', 'z_comp', 'vmin', 'vmax']
    special_columns = ['name', 'comment', 'logN', 'sig_logN', 'flag_logN']
    for colname in min_columns:
        if colname not in table.keys():
            raise IOError(
                '{} is a mandatory column. Please make sure your input table has it.'
                .format(colname))

    #loop over rows
    complist = []
    for row in table:
        # mandatory
        coord = SkyCoord(row['RA'].to('deg').value,
                         row['DEC'].to('deg').value,
                         unit='deg')  # RA y DEC must both come with units
        Zion = name_to_ion(row['ion_name'])
        zcomp = row['z_comp']
        vlim = [row['vmin'].to('km/s').value, row['vmax'].to('km/s').value
                ] * u.km / u.s  # units are expected here too

        # special columns
        try:
            Ntuple = (row['flag_logN'], row['logN'], row['sig_logN']
                      )  # no units expected
        except KeyError:
            Ntuple = None
        try:
            comment = row['comment']
        except KeyError:
            comment = ''
        try:
            name = row['name']
        except KeyError:
            name = None

        # define the component
        comp = AbsComponent(coord,
                            Zion,
                            zcomp,
                            vlim,
                            Ntup=Ntuple,
                            comment=comment,
                            name=name)

        # other columns will be filled in comp.attrib dict
        for colname in table.keys():
            if (colname not in special_columns) and (colname
                                                     not in min_columns):
                kms_cols = ['b', 'sig_b']
                if colname in kms_cols:  # check units for parameters expected in velocity units
                    try:
                        val_aux = row[colname].to('km/s').value * u.km / u.s
                    except u.UnitConversionError:
                        raise IOError(
                            'If `{}` column is present, it must have velocity units.'
                            .format(colname))
                    comp.attrib[colname] = val_aux
                # parameters we do not care about units much
                else:
                    comp.attrib[colname] = row[colname]

        # append
        complist += [comp]
    return complist
Esempio n. 14
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)
Esempio n. 15
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
Esempio n. 16
0
    def stack_plot(self,
                   to_plot,
                   pvlim=None,
                   maxtrans=3,
                   return_fig=True,
                   add_missing_lines=False,
                   spec=None,
                   **kwargs):
        '''Show a stack plot of the CGM absorption system

        Parameters
        ----------
        to_plot : List of AbsLines, AbsComponents, tuples, or strs
           If AbsLines, pass list on to linetools.analysis.plots.stack_plot()
           If not Abslines, will plot up to maxtrans of strongest transitions
           covered by spectra for components of some species.
             If tuples or strs, should be Zion value or ion name: (8,6) or 'OVI'
        pvlim : Quantities, optional
           Override system vlim for plotting
        maxtrans : int, optional
           Maximum number of lines per transition to plot
        add_missing_lines : bool, optional
           If True, plot transitions that do not have associated AbsLine objects
        spec : XSpectrum1D, optional
           Spectrum to plot in regions of requested lines; required if assoc.
           AbsLine objects do not have their analy['specfile'] attributes set

        Returns
        -------
        fig : matplotlib Figure, optional
           Figure instance containing stack plot with subplots, axes, etc.
        '''

        from linetools.analysis import plots as ltap
        from linetools.spectralline import AbsLine
        from linetools.isgm.abscomponent import AbsComponent
        from linetools.spectra.io import readspec
        from linetools.lists.linelist import LineList
        from linetools.abund import ions as ltai
        from pyigm import utils as pu

        ilist = LineList('ISM')

        if not isinstance(to_plot[0], AbsLine):
            lines2plot = []  # Master list of lines to plot
            for i, tp in enumerate(to_plot):
                if isinstance(tp, AbsComponent):
                    comp = to_plot
                else:  # Pick components in system closest to z_cgm
                    thesecomps = pu.get_components(self, tp)
                    if len(thesecomps) == 0:
                        if add_missing_lines is True:
                            # Add components
                            if isinstance(tp, str):
                                tup = ltai.name_to_ion(tp)
                            else:
                                tup = tp
                            comp = AbsComponent(self.coord,
                                                tup,
                                                zcomp=self.z,
                                                vlim=[-100., 100.] * u.km /
                                                u.s)
                            comp.add_abslines_from_linelist()
                            if spec is not None:
                                for al in comp._abslines:
                                    al.analy['spec'] = spec
                            else:
                                raise ValueError('spec must be provided if '
                                                 'requesting species without'
                                                 ' existing components.')
                        else:
                            continue
                    else:
                        # Find component with redshift closest to systemic
                        compvels = np.array(
                            [np.median(tc.vlim.value) for tc in thesecomps])
                        comp = thesecomps[np.argmin(np.abs(compvels))]

                    ### Get strongest transitions covered
                    wmins = []
                    wmaxs = []
                    for j, al in enumerate(comp._abslines):
                        # Load spectrum if not already loaded
                        if al.analy['spec'] is None:
                            try:
                                if spec is not None:
                                    al.analy['spec'] = spec
                                else:
                                    al.analy['spec'] = readspec(
                                        al.analy['spec_file'])
                            except:
                                raise LookupError("spec must be defined or "
                                                  "analy['specfile'] must be "
                                                  "declared for AbsLines")
                        # Get wavelength limits to know where to look
                        wmins.append(al.analy['spec'].wvmin.value)
                        wmaxs.append(al.analy['spec'].wvmax.value)
                    wlims = (np.min(np.array(wmins)), np.max(
                        np.array(wmaxs))) * u.Angstrom
                    # ID the strong transitions
                    strong = ilist.strongest_transitions(tp,
                                                         wvlims=wlims /
                                                         (1. + comp.zcomp),
                                                         n_max=maxtrans)
                    if strong is None:  #  No lines covered in the spectra
                        warnings.warn(
                            'No lines for {} are covered by the spectra'
                            'provided.'.format(tp))
                        continue
                    # Grab the AbsLines from this AbsComponent and their names
                    complines = comp._abslines
                    complines = np.array(complines)  # For the indexing
                    compnames = np.array([ll.name for ll in complines])
                    ### Add the lines found to the master list
                    if isinstance(strong, dict):  # Only one line covered
                        lines2plot.append(
                            complines[compnames == strong['name']][0])
                    else:  # Multiple lines covered
                        for i, sn in enumerate(strong['name']):
                            # Handle case where relevant components are defined
                            if sn in compnames:
                                tokeep = [complines[compnames == sn][0]]
                                lines2plot.extend(tokeep)
                            # Now case where components were not attached to sys
                            elif add_missing_lines is True:
                                # Add line to the existing comp to preserve z, etc.
                                compcopy = comp.copy(
                                )  #Copy to add dummy lines
                                # Set up observed wavelength range
                                obswave = strong['wrest'][i] * (1. +
                                                                compcopy.zcomp)
                                wvrange = [obswave - 0.1, obswave + 0.1
                                           ] * u.Angstrom
                                # Add this line to the component
                                compcopy.add_abslines_from_linelist(
                                    wvlim=wvrange)
                                al = compcopy._abslines[-1]
                                # Set the spectrum
                                if spec is not None:
                                    al.analy['spec'] = spec
                                else:
                                    al.analy['spec'] = comp._abslines[0].analy[
                                        'spec']
                                # Add the line
                                lines2plot.append(al)
                            else:
                                warnings.warn(
                                    '{} covered by spectra but not in'
                                    'components list'.format(sn))
        else:
            lines2plot = to_plot

        # Deal with velocity limits
        if pvlim is not None:
            vlim = pvlim
        else:
            vlim = self.vlim
        ### Make the plot!
        fig = ltap.stack_plot(lines2plot,
                              vlim=vlim,
                              return_fig=return_fig,
                              zref=self.z,
                              **kwargs)
        fig.subplots_adjust(bottom=0.,
                            left=0.1,
                            right=0.95,
                            hspace=0.,
                            wspace=0.35)
        return fig
Esempio n. 17
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)