def to_dict(self): """ Convert component data to a dict Returns ------- cdict : dict """ cdict = dict( Zion=self.Zion, zcomp=self.zcomp, vlim=self.vlim.to('km/s').value, Name=self.name, RA=self.coord.icrs.ra.value, DEC=self.coord.icrs.dec.value, A=self.A, Ej=self.Ej.to('1/cm').value, comment=self.comment, attrib=self.attrib.copy()) # Avoids changing the dict in place cdict['class'] = self.__class__.__name__ # AbsLines cdict['lines'] = {} for iline in self._abslines: cdict['lines'][iline.wrest.value] = iline.to_dict() # set linear quantities in column density _, _ = ltaa.linear_clm(cdict['attrib']) # Polish cdict = ltu.jsonify(cdict) # Return return cdict
def mk_comp(ctype,vlim=[-300.,300]*u.km/u.s,add_spec=False, use_rand=True, add_trans=False, zcomp=2.92939, b=20*u.km/u.s): # Read a spectrum Spec if add_spec: xspec = lsio.readspec(lt_path+'/spectra/tests/files/UM184_nF.fits') else: xspec = None # AbsLines if ctype == 'HI': all_trans = ['HI 1215', 'HI 1025'] elif ctype == 'SiII': all_trans = ['SiII 1260', 'SiII 1304', 'SiII 1526', 'SiII 1808'] if add_trans: all_trans += ['SiII 1193'] abslines = [] for trans in all_trans: iline = AbsLine(trans, z=zcomp) if use_rand: rnd = np.random.rand() else: rnd = 0. iline.attrib['logN'] = 13.3 + rnd iline.attrib['sig_logN'] = 0.15 iline.attrib['flag_N'] = 1 iline.attrib['b'] = b iline.analy['spec'] = xspec iline.limits.set(vlim) _,_ = ltaa.linear_clm(iline.attrib) # Loads N, sig_N abslines.append(iline) # Component abscomp = AbsComponent.from_abslines(abslines) return abscomp, abslines
def test_linearclm(): obj = type(str('Dummy'), (object, ), { str('logN'): 13, str('sig_logN'): 0.2 }) # N, sig_N = linear_clm(obj) np.testing.assert_allclose(N.value, 1e13)
def mk_comp(ctype, vlim=[-300., 300] * u.km / u.s, add_spec=False, use_rand=True, add_trans=False, zcomp=2.92939, b=20 * u.km / u.s, **kwargs): # Read a spectrum Spec if add_spec: spec_file = resource_filename('linetools', '/spectra/tests/files/UM184_nF.fits') xspec = lsio.readspec(spec_file) else: xspec = None # AbsLines if ctype == 'HI': all_trans = ['HI 1215', 'HI 1025'] elif ctype == 'SiII': all_trans = ['SiII 1260', 'SiII 1304', 'SiII 1526', 'SiII 1808'] if add_trans: all_trans += ['SiII 1193'] elif ctype == 'SiII*': all_trans = ['SiII* 1264', 'SiII* 1533'] elif ctype == 'SiIII': all_trans = ['SiIII 1206'] abslines = [] for trans in all_trans: iline = AbsLine(trans, z=zcomp, linelist=ism) if use_rand: rnd = np.random.rand() else: rnd = 0. iline.attrib['logN'] = 13.3 + rnd iline.attrib['sig_logN'] = 0.15 iline.attrib['flag_N'] = 1 iline.attrib['b'] = b iline.analy['spec'] = xspec iline.limits.set(vlim) _, _ = ltaa.linear_clm(iline.attrib) # Loads N, sig_N abslines.append(iline) # Component abscomp = AbsComponent.from_abslines(abslines, **kwargs) return abscomp, abslines
def test_linearclm(): obj = type(str('Dummy'), (object,), { str('logN'): 13, str('sig_logN'): 0.2 }) # N, sig_N = linear_clm(obj) np.testing.assert_allclose(N.value, 1e13)
def abslines_from_VPfile(parfile, specfile=None, ra=None, dec=None, linelist=None): ''' Takes a joebvp parameter file and builds a list of linetools AbsLines from the measurements therein. Parameters ---------- parfile : str Name of the parameter file in the joebvp format ra : float, optional Right Ascension of the QSO in decimal degrees dec : float, optional Declination of the QSO in decimal degress Returns ------- abslinelist: list List of AbsLine objects ''' from linetools.spectralline import AbsLine from linetools.analysis import absline as ltaa import astropy.units as u if linelist is None: llist = LineList('ISM') else: llist = linelist if specfile != None: spec = readspec(specfile) # Allow spectrum file to be declared in call linetab = ascii.read(parfile) # Read parameters from file linetab['restwave'] = linetab['restwave'] * u.AA abslinelist = [] # Initiate list to populate for i, row in enumerate(linetab): ### Check to see if errors for this line are defined colerr, berr, velerr = get_errors(linetab, i) ### Adjust velocity limits according to centroid errors and limits from file vcentmin = row['vel'] - velerr vcentmax = row['vel'] + velerr v1 = vcentmin + row['vlim1'] v2 = vcentmax + row['vlim2'] line = AbsLine(row['restwave'] * u.AA, z=row['zsys'], closest=True, linelist=llist) vlims = [v1, v2] * u.km / u.s line.limits.set(vlims) ### Set other parameters line.attrib['logN'] = row['col'] line.attrib['sig_logN'] = colerr line.attrib['flag_N'] = 1 lincol = ltaa.linear_clm(line.attrib) line.attrib['N'] = lincol[0] line.attrib['sig_N'] = lincol[1] line.attrib['b'] = row['bval'] * u.km / u.s line.attrib['sig_b'] = berr * u.km / u.s line.attrib['vel'] = row['vel'] * u.km / u.s ### Attach the spectrum to this AbsLine but check first to see if this one is same as previous if specfile == None: if i == 0: spec = readspec(row['specfile']) elif row['specfile'] != linetab['specfile'][i - 1]: spec = readspec(row['specfile']) else: pass line.analy['spec'] = spec ### Add it to the list and go on abslinelist.append(line) return abslinelist
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
def load_coolgas(self): """ Load data on cool gas (CII, CIV, SiII, SiIII) Richter+17 """ llist = LineList('ISM') # Ricther+17 print('Loading Richter+17 for CII, CIV, SiII, SiIII') r17_a1_file = resource_filename('pyigm', '/data/CGM/Galaxy/richter17_A1.fits') r17_a1 = Table.read(r17_a1_file) r17_a2_file = resource_filename('pyigm', '/data/CGM/Galaxy/richter17_A2.fits') r17_a2 = Table.read(r17_a2_file) # Coords coords = SkyCoord(ra=r17_a1['_RAJ2000'], dec=r17_a1['_DEJ2000'], unit='deg') gc = coords.transform_to('galactic') ra = np.zeros((len(r17_a2))) dec = np.zeros((len(r17_a2))) # Loop on Sightlines for kk, row in enumerate(r17_a1): if self.debug and (kk == 5): break a2_idx = np.where(r17_a2['Name'] == row['Name'])[0] if len(a2_idx) == 0: continue ra[a2_idx] = row['_RAJ2000'] dec[a2_idx] = row['_DEJ2000'] # Generate the components icoord = gc[kk] alines = [] for jj, idx in enumerate(a2_idx): # Transition trans = '{:s} {:d}'.format(r17_a2['Ion'][idx].strip(), int(r17_a2['lambda0'][idx])) try: aline = AbsLine(trans, linelist=llist) except ValueError: pdb.set_trace() aline.attrib['coord'] = icoord # Skip EW=0 lines if r17_a2['e_W'][idx] == 0: continue # Velocity z = 0. aline.setz(z) vlim = np.array([r17_a2['vmin'][idx], r17_a2['vmax'][idx] ]) * u.km / u.s aline.limits.set(vlim) # These are v_LSR # EW aline.attrib['flag_EW'] = 1 aline.attrib['EW'] = r17_a2['W'][idx] / 1e3 * u.AA aline.attrib['sig_EW'] = r17_a2['e_W'][idx] / 1e3 * u.AA # Column if np.isnan( r17_a2['logN'] [idx]): # Odd that some lines had an error but no value aline.attrib['flag_N'] = 0 elif r17_a2['l_logN'][idx] == '>': aline.attrib['flag_N'] = 2 aline.attrib['sig_logN'] = 99.99 else: aline.attrib['flag_N'] = 1 aline.attrib['sig_logN'] = r17_a2['e_logN'][idx] aline.attrib['logN'] = r17_a2['logN'][idx] # Fill linear _, _ = linear_clm(aline.attrib) alines.append(aline) # Generate components from abslines comps = ltiu.build_components_from_abslines(alines, chk_sep=False, chk_vel=False) # Limits vmin = np.min([icomp.limits.vmin.value for icomp in comps]) vmax = np.max([icomp.limits.vmax.value for icomp in comps]) # Instantiate s_kwargs = dict(name=row['Name'] + '_z0') c_kwargs = dict(chk_sep=False, chk_z=False) abssys = IGMSystem.from_components(comps, vlim=[vmin, vmax] * u.km / u.s, s_kwargs=s_kwargs, c_kwargs=c_kwargs) # CGM Abs rho, ang_sep = calc_Galactic_rho(abssys.coord) cgmabs = CGMAbsSys(self.galaxy, abssys, rho=rho, ang_sep=ang_sep, cosmo=self.cosmo) # Add to cgm_abs self.abs.cgm_abs.append(cgmabs) # Finish r17_a2['RA'] = ra r17_a2['DEC'] = dec self.richter17 = r17_a2 # Reference if len(self.refs) > 0: self.refs += ',' self.refs += 'Richter+17'
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 = []
def from_dict(cls, idict, coord=None, skip_abslines=False, **kwargs): """ Instantiate from a dict Parameters ---------- idict : dict skip_abslines : bool, optional Skip loading up the AbsLine objects. Speeds up performance when one only needs the component object Returns ------- AbsComponent """ if coord is not None: radec = coord else: radec = SkyCoord(ra=idict['RA'], dec=idict['DEC'], unit='deg') # Init # slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], Quantity(idict['vlim'], unit='km/s'), # For IGMGuesses for key in ['reliability', 'Reliability']: if key in idict.keys(): reliability = idict[key] break else: reliability = 'none' # Deprecated column density attributes if 'logN' in idict.keys(): warnings.warn('Column density attributes are now Deprecated', DeprecationWarning) #print("We will use yours for now..") Ntup = tuple([idict[key] for key in ['flag_N', 'logN', 'sig_logN']]) else: Ntup = None # Instantiate slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], idict['vlim']*u.km/u.s, Ej=idict['Ej']/u.cm, A=idict['A'], Ntup=Ntup, comment=idict['comment'], name=idict['Name'], reliability=reliability) # Attributes if 'attrib' in idict.keys(): attrkeys = idict['attrib'].keys() for ak in attrkeys: if isinstance(idict['attrib'][ak],dict): slf.attrib[ak] = ltu.convert_quantity_in_dict(idict['attrib'][ak]) else: slf.attrib[ak] = idict['attrib'][ak] # Insist that error values are 2-elements :: Mainly for older saved files if ak == 'sig_N': if slf.attrib[ak].size == 1: slf.attrib[ak] = Quantity([slf.attrib[ak].value]*2) * slf.attrib[ak].unit if ak == 'sig_logN': if isinstance(slf.attrib[ak], (float,int)): slf.attrib[ak] = np.array([slf.attrib[ak]]*2) elif isinstance(slf.attrib[ak], (list)): slf.attrib[ak] = np.array(slf.attrib[ak]) # Deprecated column (again) if Ntup is not None: warnings.warn('Overwriting column density attributes (if they existed).', DeprecationWarning) slf.attrib['flag_N'] = Ntup[0] slf.attrib['logN'] = Ntup[1] if isiterable(Ntup[2]): slf.attrib['sig_logN'] = np.array(Ntup[2]) else: slf.attrib['sig_logN'] = np.array([Ntup[2]]*2) _, _ = ltaa.linear_clm(slf.attrib) # Set linear quantities # Add AbsLine objects if not skip_abslines: for key in idict['lines'].keys(): iline = AbsLine.from_dict(idict['lines'][key], coord=coord, **kwargs) slf.add_absline(iline, **kwargs) # Return return slf
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)
def __init__(self, radec, Zion, zcomp, vlim, Ej=0. / u.cm, A=None, Ntup=None, comment='', name=None, stars=None): """ Initiator Parameters ---------- radec : tuple or SkyCoord (RA,DEC) in deg or astropy.coordinate.SkyCoord Zion : tuple Atomic number, ion -- (int,int) e.g. (8,1) for OI Note: (-1, -1) is special and is meant for moleculer (e.g. H2) This notation will most likely change in the future. zcomp : float Absorption component redshift vlim : Quantity array Velocity limits of the component w/r to `z` e.g. [-300,300]*u.km/u.s A : int, optional Atomic mass -- used to distinguish isotopes Ntup : tuple (int,float,float) (flag_N,logN,sig_logN) flag_N : Flag describing N measurement (0: no info; 1: detection; 2: saturated; 3: non-detection) logN : log10 N column density sig_logN : Error in log10 N Ej : Quantity, optional Energy of lower level (1/cm) stars : str, optional asterisks to add to name, e.g. '**' for CI** Required if name=None and Ej>0. comment : str, optional A comment, default is `` """ # Required self.coord = ltu.radec_to_coord(radec) self.Zion = Zion self.zcomp = zcomp self.vlim = vlim # Optional self.A = A self.Ej = Ej self.comment = comment if Ntup is not None: self.flag_N = Ntup[0] self.logN = Ntup[1] self.sig_logN = Ntup[2] _, _ = ltaa.linear_clm(self) # Set linear quantities else: self.flag_N = 0 self.logN = 0. self.sig_logN = 0. # Name if (name is None) and (self.Zion != (-1, -1)): iname = ions.ion_name(self.Zion, nspace=0) if self.Ej.value > 0: # Need to put *'s in name try: iname += stars except: raise IOError("Need to provide 'stars' parameter.") self.name = '{:s}_z{:0.5f}'.format(iname, self.zcomp) elif (name is None) and (self.Zion == (-1, -1)): self.name = 'mol_z{:0.5f}'.format(self.zcomp) else: self.name = name # Potential for attributes self.attrib = dict() # Other self._abslines = []
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
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
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 = []
def from_dict(cls, idict, coord=None, skip_abslines=False, **kwargs): """ Instantiate from a dict Parameters ---------- idict : dict skip_abslines : bool, optional Skip loading up the AbsLine objects. Speeds up performance when one only needs the component object Returns ------- AbsComponent """ if coord is not None: radec = coord else: radec = SkyCoord(ra=idict['RA'], dec=idict['DEC'], unit='deg') # Init # slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], Quantity(idict['vlim'], unit='km/s'), # For IGMGuesses for key in ['reliability', 'Reliability']: if key in idict.keys(): reliability = idict[key] break else: reliability = 'none' # Deprecated column density attributes if 'logN' in idict.keys(): warnings.warn('Column density attributes are now Deprecated', DeprecationWarning) #print("We will use yours for now..") Ntup = tuple( [idict[key] for key in ['flag_N', 'logN', 'sig_logN']]) else: Ntup = None # Instantiate slf = cls(radec, tuple(idict['Zion']), idict['zcomp'], idict['vlim'] * u.km / u.s, Ej=idict['Ej'] / u.cm, A=idict['A'], Ntup=Ntup, comment=idict['comment'], name=idict['Name'], reliability=reliability) # Attributes if 'attrib' in idict.keys(): attrkeys = idict['attrib'].keys() for ak in attrkeys: if isinstance(idict['attrib'][ak], dict): slf.attrib[ak] = ltu.convert_quantity_in_dict( idict['attrib'][ak]) else: slf.attrib[ak] = idict['attrib'][ak] # Insist that error values are 2-elements :: Mainly for older saved files if ak == 'sig_N': if slf.attrib[ak].size == 1: slf.attrib[ak] = Quantity( [slf.attrib[ak].value] * 2) * slf.attrib[ak].unit if ak == 'sig_logN': if isinstance(slf.attrib[ak], (float, int)): slf.attrib[ak] = np.array([slf.attrib[ak]] * 2) elif isinstance(slf.attrib[ak], (list)): slf.attrib[ak] = np.array(slf.attrib[ak]) # Deprecated column (again) if Ntup is not None: warnings.warn( 'Overwriting column density attributes (if they existed).', DeprecationWarning) slf.attrib['flag_N'] = Ntup[0] slf.attrib['logN'] = Ntup[1] if isiterable(Ntup[2]): slf.attrib['sig_logN'] = np.array(Ntup[2]) else: slf.attrib['sig_logN'] = np.array([Ntup[2]] * 2) _, _ = ltaa.linear_clm(slf.attrib) # Set linear quantities # Add AbsLine objects if not skip_abslines: for key in idict['lines'].keys(): iline = AbsLine.from_dict(idict['lines'][key], coord=coord, **kwargs) slf.add_absline(iline, **kwargs) # Return return slf
def __init__(self, radec, Zion, zcomp, vlim, Ej=0./u.cm, A=None, Ntup=None, comment='', name=None, stars=None): """ Initiator Parameters ---------- radec : tuple or SkyCoord (RA,DEC) in deg or astropy.coordinate.SkyCoord Zion : tuple Atomic number, ion -- (int,int) e.g. (8,1) for OI Note: (-1, -1) is special and is meant for moleculer (e.g. H2) This notation will most likely change in the future. zcomp : float Absorption component redshift vlim : Quantity array Velocity limits of the component w/r to `z` e.g. [-300,300]*u.km/u.s A : int, optional Atomic mass -- used to distinguish isotopes Ntup : tuple (int,float,float) (flag_N,logN,sig_logN) flag_N : Flag describing N measurement (0: no info; 1: detection; 2: saturated; 3: non-detection) logN : log10 N column density sig_logN : Error in log10 N # TODO FUTURE IMPLEMENTATION WILL ALLOW FOR 2-element ndarray for sig_logN Ej : Quantity, optional Energy of lower level (1/cm) stars : str, optional asterisks to add to name, e.g. '**' for CI** Required if name=None and Ej>0. comment : str, optional A comment, default is `` """ # Required self.coord = ltu.radec_to_coord(radec) self.Zion = Zion self.zcomp = zcomp self.vlim = vlim # Optional self.A = A self.Ej = Ej self.comment = comment if Ntup is not None: self.flag_N = Ntup[0] self.logN = Ntup[1] self.sig_logN = Ntup[2] _, _ = ltaa.linear_clm(self) # Set linear quantities else: self.flag_N = 0 self.logN = 0. self.sig_logN = 0. # Name if (name is None) and (self.Zion != (-1, -1)): iname = ions.ion_name(self.Zion, nspace=0) if self.Ej.value > 0: # Need to put *'s in name try: iname += stars except: raise IOError("Need to provide 'stars' parameter.") self.name = '{:s}_z{:0.5f}'.format(iname, self.zcomp) elif (name is None) and (self.Zion == (-1, -1)): self.name = 'mol_z{:0.5f}'.format(self.zcomp) else: self.name = name # Potential for attributes self.attrib = dict() # Other self._abslines = []
def __init__(self, radec, Zion, zcomp, vlim, Ej=0./u.cm, A=None, Ntup=None, comment='', name=None, stars=None): """ Initiator Parameters ---------- radec : tuple or SkyCoord (RA,DEC) in deg or astropy.coordinate Zion : tuple Atomic number, ion -- (int,int) e.g. (8,1) for OI zcomp : float Absorption component redshift vlim : Quantity array Velocity limits of the component w/r to `z` e.g. [-300,300]*u.km/u.s A : int, optional Atomic mass -- used to distinguish isotopes Ntup : tuple (int,float,float) (flag_N,logN,sig_N) flag_N : Flag describing N measurement logN : log10 N column density sig_logN : Error in log10 N Ej : Quantity, optional Energy of lower level (1/cm) stars : str, optional asterisks to add to name, e.g. '**' for CI** Required if name=None and Ej>0. comment : str, optional A comment, default is `` """ # Required if isinstance(radec, (tuple)): self.coord = SkyCoord(ra=radec[0], dec=radec[1]) elif isinstance(radec, SkyCoord): self.coord = radec self.Zion = Zion self.zcomp = zcomp self.vlim = vlim # Optional self.A = A self.Ej = Ej self.comment = comment if Ntup is not None: self.flag_N = Ntup[0] self.logN = Ntup[1] self.sig_logN = Ntup[2] _, _ = ltaa.linear_clm(self) # Set linear quantities else: self.flag_N = 0 self.logN = 0. self.sig_logN = 0. # Name if name is None: iname = ions.ion_name(self.Zion, nspace=0) if self.Ej.value > 0: # Need to put *'s in name try: iname += stars except: raise IOError("Need to provide 'stars' parameter.") self.name = '{:s}_z{:0.5f}'.format(iname, self.zcomp) else: self.name = name # Other self._abslines = []
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)