Esempio n. 1
0
def get_coord(targ_file, radec=None):
    '''
    radec: int (None)
      None: Read from ASCII file
      1: List of [Name, RA, DEC] with RA/DEC as : separated strings
      2: List of [Name, RA, DEC] with RA/DEC as decimal degrees
    '''

    if not isinstance(targ_file,basestring):
        raise IOError('Bad input to finder.get_coord!')

    from astropy.io import ascii 
    # Import Tables
    if radec == None:
        # Read 
        ra_tab = ascii.read(targ_file) #, names=('Name','RA','DEC','Epoch'))
        # Rename the columns
        ra_tab.rename_column('col1','Name')
        if isinstance(ra_tab['col2'][0],basestring):
            ra_tab.rename_column('col2','RAS')
            ra_tab.rename_column('col3','DECS')
        else:
            ra_tab.rename_column('col2','RA')
            ra_tab.rename_column('col3','DEC')
    elif radec == 1: 
        # Error check
        if len(targ_file) != 3:
            return -1
        # Manipulate
        arr = np.array(targ_file).reshape(1,3)
        # Generate the Table
        ra_tab = QTable( arr, names=('Name','RAS','DECS') )
    elif radec == 2: 
        # Error check
        if len(targ_file) != 3:
            return -1
        # Manipulate
        ras, decs = x_radec.dtos1((targ_file[1], targ_file[2]))
        # Generate the Table
        ra_tab = QTable( [ [targ_file[0]], [ras], [decs] ], names=('Name','RA','DEC') )
    else:
        raise ValueError('get_coord: Bad flag')

    # Add dummy columns for decimal degrees and EPOCH
    nrow = len(ra_tab)
    col_RAD = Column(name='RAD', data=np.zeros(nrow), unit=u.degree)
    col_DECD = Column(name='DECD', data=np.zeros(nrow), unit=u.degree)
    col_EPOCH = Column(name='EPOCH', data=np.zeros(nrow))
    ra_tab.add_columns( [col_RAD, col_DECD, col_EPOCH] )
    # Assume 2000 for now
    ra_tab['EPOCH'] = 2000.
        
    return ra_tab
Esempio n. 2
0
def test_add_column(mixin_cols):
    """
    Test that adding a column preserves values and attributes
    """
    attrs = ('name', 'unit', 'dtype', 'format', 'description', 'meta')
    m = mixin_cols['m']
    assert m.info.name is None

    # Make sure adding column in various ways doesn't touch
    t = QTable([m], names=['a'])
    assert m.info.name is None

    t['new'] = m
    assert m.info.name is None

    m.info.name = 'm'
    m.info.format = '{0}'
    m.info.description = 'd'
    m.info.meta = {'a': 1}
    t = QTable([m])

    # Add columns m2, m3, m4 by two different methods and test expected equality
    t['m2'] = m
    m.info.name = 'm3'
    t.add_columns([m], copy=True)
    m.info.name = 'm4'
    t.add_columns([m], copy=False)
    for name in ('m2', 'm3', 'm4'):
        assert_table_name_col_equal(t, name, m)
        for attr in attrs:
            if attr != 'name':
                assert getattr(t['m'].info, attr) == getattr(t[name].info, attr)
    # Also check that one can set using a scalar.
    s = m[0]
    if type(s) is type(m) and 'info' in s.__dict__:
        # We're not going to worry about testing classes for which scalars
        # are a different class than the real array, or where info is not copied.
        t['s'] = m[0]
        assert_table_name_col_equal(t, 's', m[0])
        for attr in attrs:
            if attr != 'name':
                assert getattr(t['m'].info, attr) == getattr(t['s'].info, attr)

    # While we're add it, also check a length-1 table.
    t = QTable([m[1:2]], names=['m'])
    if type(s) is type(m) and 'info' in s.__dict__:
        t['s'] = m[0]
        assert_table_name_col_equal(t, 's', m[0])
        for attr in attrs:
            if attr != 'name':
                assert getattr(t['m'].info, attr) == getattr(t['s'].info, attr)
Esempio n. 3
0
def test_add_column(mixin_cols):
    """
    Test that adding a column preserves values and attributes
    """
    attrs = ('name', 'unit', 'dtype', 'format', 'description', 'meta')
    m = mixin_cols['m']
    assert m.info.name is None

    # Make sure adding column in various ways doesn't touch
    t = QTable([m], names=['a'])
    assert m.info.name is None

    t['new'] = m
    assert m.info.name is None

    m.info.name = 'm'
    m.info.format = '{0}'
    m.info.description = 'd'
    m.info.meta = {'a': 1}
    t = QTable([m])

    # Add columns m2, m3, m4 by two different methods and test expected equality
    t['m2'] = m
    m.info.name = 'm3'
    t.add_columns([m], copy=True)
    m.info.name = 'm4'
    t.add_columns([m], copy=False)
    for name in ('m2', 'm3', 'm4'):
        assert_table_name_col_equal(t, name, m)
        for attr in attrs:
            if attr != 'name':
                assert getattr(t['m'].info, attr) == getattr(t[name].info, attr)
    # Also check that one can set using a scalar.
    s = m[0]
    if type(s) is type(m):
        # We're not going to worry about testing classes for which scalars
        # are a different class than the real array (and thus loose info, etc.)
        t['s'] = m[0]
        assert_table_name_col_equal(t, 's', m[0])
        for attr in attrs:
            if attr != 'name':
                assert getattr(t['m'].info, attr) == getattr(t['s'].info, attr)

    # While we're add it, also check a length-1 table.
    t = QTable([m[1:2]], names=['m'])
    if type(s) is type(m):
        t['s'] = m[0]
        assert_table_name_col_equal(t, 's', m[0])
        for attr in attrs:
            if attr != 'name':
                assert getattr(t['m'].info, attr) == getattr(t['s'].info, attr)
Esempio n. 4
0
def get_coord(targ_file, radec=None):
    '''
    radec: int (None)
      None: Read from ASCII file
      1: List of [Name, RA, DEC] with RA/DEC as : separated strings
      2: List of [Name, RA, DEC] with RA/DEC as decimal degrees
    '''

    from astropy.io import ascii
    # Import Tables
    if radec == None:
        # Read
        ra_tab = ascii.read(targ_file)  #, names=('Name','RA','DEC','Epoch'))
        # Rename the columns
        ra_tab.rename_column('col1', 'Name')
        ra_tab.rename_column('col2', 'RA')
        ra_tab.rename_column('col3', 'DEC')
    elif radec == 1:
        # Error check
        if len(targ_file) != 3:
            return -1
        # Manipulate
        arr = np.array(targ_file).reshape(1, 3)
        # Generate the Table
        ra_tab = QTable(arr, names=('Name', 'RAS', 'DECS'))
    elif radec == 2:
        # Error check
        if len(targ_file) != 3:
            return -1
        # Manipulate
        ras, decs = x_radec.dtos1((targ_file[1], targ_file[2]))
        # Generate the Table
        ra_tab = QTable([[targ_file[0]], [ras], [decs]],
                        names=('Name', 'RA', 'DEC'))
    else:
        raise ValueError('get_coord: Bad flag')

    # Add dummy columns for decimal degrees and EPOCH
    nrow = len(ra_tab)
    col_RAD = Column(name='RAD', data=np.zeros(nrow), unit=u.degree)
    col_DECD = Column(name='DECD', data=np.zeros(nrow), unit=u.degree)
    col_EPOCH = Column(name='EPOCH', data=np.zeros(nrow))
    ra_tab.add_columns([col_RAD, col_DECD, col_EPOCH])
    # Assume 2000 for now
    ra_tab['EPOCH'] = 2000.

    return ra_tab
Esempio n. 5
0
def mk_summary(dlas, prefix, outfil, specpath=None, htmlfil=None):
    """ Loops through the DLA list and generates a Table

    Also pushes the 1D spectra into the folder

    Parameters
    ----------
    dlas : DLASurvey
    prefix : str
    outfil : str
      Name of the output FITS summary file
    htmlfil : str, optional

    Returns
    -------
    """
    #
    if htmlfil is None:
        htmlfil = 'tmp.html'

    # # Constructing
    # QSO, RA/DEC
    cqso = Column(dlas.qso, name='QSO')
    ra = dlas.coord.ra.degree
    dec = dlas.coord.dec.degree
    jname = []
    for abs_sys in dlas._abs_sys:
        jname.append(survey_name(prefix, abs_sys))

    cjname = Column(jname, name='Name')
    cra = Column(ra, name='RA', unit=u.degree)
    cdec = Column(dec, name='DEC', unit=u.degree)
    czem = Column(dlas.zem, name='Z_QSO')

    # Begin the Table
    dla_table = QTable([cjname, cqso, cra, cdec, czem])

    # LLS properties
    czabs = Column(dlas.zabs, name='ZABS')
    cNHI = Column(dlas.NHI, name='logNHI')
    csigNHI = Column(dlas.sig_NHI, name='sig(logNHI)')

    # Add to Table
    dla_table.add_columns([czabs, cNHI, csigNHI])

    # Spectra files
    all_sfiles = []
    for jj, ills in enumerate(dlas._abs_sys):
        sub_spec = mk_1dspec(ills, name=cjname[jj], outpath=specpath)
        # Pad
        while len(sub_spec) < 5:
            sub_spec.append(str('NULL'))
        # Append
        all_sfiles.append(sub_spec)

    cspec = Column(np.array(all_sfiles), name='SPEC_FILES')
    dla_table.add_column(cspec)

    # Sort
    dla_table.sort('RA')

    # Write
    print('Writing {:s}'.format(outfil))
    xxf.table_to_fits(dla_table, outfil)
    print('Writing {:s}'.format(htmlfil))
    Table(dla_table).write(htmlfil)

    return dla_table
Esempio n. 6
0
def mk_summary(dlas, prefix, outfil, specpath=None, htmlfil=None):
    """ Loops through the DLA list and generates a Table

    Also pushes the 1D spectra into the folder

    Parameters
    ----------
    dlas : DLASurvey
    prefix : str
    outfil : str
      Name of the output FITS summary file
    htmlfil : str, optional

    Returns
    -------
    """
    #
    if htmlfil is None:
        htmlfil = 'tmp.html'

    # # Constructing
    # QSO, RA/DEC
    cqso = Column(dlas.qso, name='QSO')
    ra = dlas.coord.ra.degree[0]
    dec = dlas.coord.dec.degree[0]
    jname = []
    for abs_sys in dlas._abs_sys:
        jname.append(survey_name(prefix, abs_sys))

    cjname = Column(jname, name='Name')
    cra = Column(ra, name='RA', unit=u.degree)
    cdec = Column(dec, name='DEC', unit=u.degree)
    czem = Column(dlas.zem, name='Z_QSO')

    # Begin the Table
    dla_table = QTable( [cjname, cqso, cra, cdec, czem] )

    # LLS properties
    czabs = Column(dlas.zabs, name='ZABS')
    cNHI = Column(dlas.NHI, name='logNHI')
    csigNHI = Column(dlas.sig_NHI, name='sig(logNHI)')

    # Add to Table
    dla_table.add_columns([czabs, cNHI, csigNHI])

    # Spectra files
    all_sfiles = []
    for jj,ills in enumerate(dlas._abs_sys):
        sub_spec = mk_1dspec(ills, name=cjname[jj], outpath=specpath)
        # Pad
        while len(sub_spec) < 5:
            sub_spec.append(str('NULL'))
        # Append
        all_sfiles.append(sub_spec)

    cspec = Column(np.array(all_sfiles), name='SPEC_FILES')
    dla_table.add_column( cspec )

    # Sort
    dla_table.sort('RA')

    # Write
    print('Writing {:s}'.format(outfil))
    xxf.table_to_fits(dla_table,outfil)
    print('Writing {:s}'.format(htmlfil))
    Table(dla_table).write(htmlfil)

    return dla_table
Esempio n. 7
0
    def Load_ExoArchive_Universe(self, composite_table=True, force_new_pull=False, fill_empties=True):
        '''
        A function that reads the Exoplanet Archive data to populate the planet table
        
        Unless force_new_pull=True:
        If the filename provided in constructor is new, new data is pulled from the archive
        If the filename already exists, we try to load that file as an astroquery QTable
        
        Kwargs:
        composite_table  - Bool. True [default]: pull "Planetary Systems Composite
                           Parameters Table". False: pull simple "Planetary Systems" Table
                           NOTE: see Archive website for difference between these tables
                           
        force_new_pull   - Bool. False [default]: loads table from filename if filename
                           file exists. True: pull new archive data and overwrite filename
                           
        fill_empties     - Bool. True [default]: approximate empty table values using
                           other values present in data. Ex: radius, mass, logg, angsep, etc.
                           NOTE: When composite_table=True we do not approximate the planet 
                             radius or mass; we keep the archive-computed approx.
                           
        
        Approximation methods:
        - AngSep     - theta[mas] = SMA[au]/distance[pc] * 1e3
        - logg       - logg [log(cgs)] = log10(G*mass/radius**2)
        - StarLum    - absVmag = Vmag - 5*log10(distance[pc]/10)
                       starlum[L/Lsun] = 10**-(absVmag-4.83)/2.5
        - StarRad    - rad[Rsun] = (5800/Teff[K])**2 *sqrt(starlum)
        - PlanetRad  - ** when composite_table=True, keep archive-computed approx
                       Based on Thorngren 2019 and Chen&Kipping 2016
        - PlanetMass - ^^ Inverse of PlanetRad
        
        
        *** Note: the resulting planet table will have nan's where data is missing/unknown. 
            Ex. if a planet lacks a radius val, the 'PlanetRadius' for will be np.nan        
        '''

        #-- Define columns to read. NOTE: add columns here if needed. 
          # col2pull entries should be matched with colNewNames entries
        col2pull =  "pl_name,hostname,pl_orbsmax,pl_orbeccen,pl_orbincl,pl_bmasse,pl_rade," + \
                    "pl_eqt,ra,dec,sy_dist,st_spectype,st_mass,st_teff," + \
                    "st_rad,st_logg,st_lum,st_age,st_vsin,st_radv," + \
                    "st_met,sy_plx,sy_bmag,sy_vmag,sy_rmag,sy_icmag," + \
                    "sy_jmag,sy_hmag,sy_kmag,discoverymethod"
        colNewNames = ["PlanetName","StarName","SMA","Ecc","Inc","PlanetMass","PlanetRadius",
                       "PlanetTeq","RA","Dec","Distance","StarSpT","StarMass","StarTeff",
                       "StarRad","StarLogg","StarLum","StarAge","StarVsini","StarRadialVelocity",
                       "StarZ","StarParallax","StarBMag","StarVmag","StarRmag","StarImag",
                       "StarJmag","StarHmag","StarKmag","DiscoveryMethod"]

        #-- Load/Pull data depending on provided filename
        import os
        if os.path.isfile(self.filename) and not force_new_pull:
            
            # Existing filename was provided so let's try use that
            
            print("%s already exists:\n    we'll attempt to read this file as an astropy QTable"%self.filename)

            NArx_table = QTable.read(self.filename, format='ascii.ecsv')
            
            # Check that the provided table file matches the requested table type
            if NArx_table.meta['isPSCOMPPARS'] != composite_table:
                err0 = '%s contained the wrong table-type:'%self.filename
                err1 = 'pscomppars' if composite_table else 'ps'
                err2 = 'pscomppars' if NArx_table.meta['isPSCOMPPARS'] else 'ps'
                err3 = " Expected '{}' table but found '{}' table.".format(err1,err2)
                err4 = ' Consider setting force_new_pull=True.'
                raise ValueError(err0+err3+err4)

        else:
            # New filename was provided or a new pull was explicitly requested. Pull new data
            
            if not force_new_pull:
                print("%s does not exist:\n    we'll pull new data from the archive and save it to this filename"%self.filename)
            else:
                print("%s may or may not exist:\n    force_new_pull=True so we'll pull new data regardless and overwrite as needed"%self.filename) 

            # Import pyVO package used to query the Exoplanet Archive
            import pyvo as vo

            # Create a "service" which can be used to access the archive TAP server
            NArx_service = vo.dal.TAPService("https://exoplanetarchive.ipac.caltech.edu/TAP")

            # Create a "query" string formatted per the TAP specifications
              # 'select': specify which columns to pull
              # 'from': specify which table to pull 
              # 'where': (optional) specify parameters to be met when choosing what to pull
                # Add where flag for ps to only pull the best row for each planet
            tab2pull = "pscomppars" if composite_table else "ps where default_flag=1"
            query = "select "+col2pull+" from "+tab2pull

            # Pull the data and convert to astropy masked QTable
            NArx_res = NArx_service.search(query) 
            
            NArx_table = QTable(NArx_res.to_table())

            # Add a flag to the table metadata to denote what kind of table it was
              # This'll prevent trying to read the table as the wrong type later
            NArx_table.meta['isPSCOMPPARS'] = composite_table
            # Save raw table for future use 
            NArx_table.write(self.filename,format='ascii.ecsv',overwrite=force_new_pull)
            # Read table back in to ensure that formatting from a fresh pull matches
              # the formatting from an old pull (as done when filename exists)
            NArx_table = QTable.read(self.filename, format='ascii.ecsv')
            
        #-- Rename columns to psisim-expected names
        NArx_table.rename_columns(col2pull.split(','),colNewNames)
        
        #-- Change fill value from default 1e20 to np.nan
        for col in NArx_table.colnames:
            if isinstance(NArx_table[col],MaskedColumn) and isinstance(NArx_table[col].fill_value,(int,float)):
                # Only change numeric fill values to nan
                NArx_table[col].fill_value = np.nan
        
        #-- Add new columns for values not easily available or computable from table
          # TODO: for now, these are masked but we should find a good way to populate them
        NArx_table.add_columns([MaskedColumn(length=len(NArx_table),mask=True,fill_value=np.nan)]*3,
                               names=['Flux Ratio','ProjAU','Phase'])
        
        if fill_empties:
            #-- Compute missing planet columns
            # Compute missing masses and radii using mass-radius relations
            if not composite_table:
                # NOTE: composite table already has radius-mass approximation so we'll
                  # only repeat them if we don't pull that table
                    
                # Convert masked columns to ndarrays with 0's instead of mask
                  # as needed by the approximate_... functions
                masses   = np.array(NArx_table['PlanetMass'].filled(fill_value=0.0))
                radii    = np.array(NArx_table['PlanetRadius'].filled(fill_value=0.0))
                eqtemps  = np.array(NArx_table['PlanetTeq'].filled(fill_value=0.0))
                # Perform approximations
                radii = self.approximate_radii(masses,radii,eqtemps)
                masses = self.approximate_masses(masses,radii,eqtemps)
                # Create masks for non-zero values (0's are values where data was missing)
                rad_mask = (radii != 0.)
                mss_mask = (masses != 0.)
                # Create mask to only missing values in NArx_table with valid values
                rad_mask = NArx_table['PlanetRadius'].mask & rad_mask
                mss_mask = NArx_table['PlanetMass'].mask & mss_mask
                # Place results back in the table
                NArx_table['PlanetRadius'][rad_mask] = radii[rad_mask]
                NArx_table['PlanetMass'][mss_mask] = masses[mss_mask]
        
            # Angular separation
            NArx_table['AngSep'] = NArx_table['SMA']/NArx_table['Distance'] * 1e3
            # Planet logg
            grav = constants.G * (NArx_table['PlanetMass'].filled()*u.earthMass) / (NArx_table['PlanetRadius'].filled()*u.earthRad)**2
            NArx_table['PlanetLogg'] = np.ma.log10(MaskedColumn(np.ma.masked_invalid(grav.cgs.value),fill_value=np.nan))  # logg cgs

            #-- Guess star luminosity, radius, and gravity for missing (masked) values only
              # The guesses will be questionably reliabile
            # Star Luminosity
            host_MVs = NArx_table['StarVmag'] - 5*np.ma.log10(NArx_table['Distance']/10)  # absolute v mag
            host_lum = -(host_MVs-4.83)/2.5    #log10(L/Lsun)
            NArx_table['StarLum'][NArx_table['StarLum'].mask] = host_lum[NArx_table['StarLum'].mask]

            # Star radius
            host_rad = (5800/NArx_table['StarTeff'])**2 *np.ma.sqrt(10**NArx_table['StarLum'])   # Rsun
            NArx_table['StarRad'][NArx_table['StarRad'].mask] = host_rad[NArx_table['StarRad'].mask]

            # Star logg
            host_grav = constants.G * (NArx_table['StarMass'].filled()*u.solMass) / (NArx_table['StarRad'].filled()*u.solRad)**2
            host_logg = np.ma.log10(np.ma.masked_invalid(host_grav.cgs.value))  # logg cgs
            NArx_table['StarLogg'][NArx_table['StarLogg'].mask] = host_logg[NArx_table['StarLogg'].mask]
        else:
            # Create fully masked columns for AngSep and PlanetLogg
            NArx_table.add_columns([MaskedColumn(length=len(NArx_table),mask=True,fill_value=np.nan)]*2,
                       names=['AngSep','PlanetLogg'])

            
        #-- Deal with units (conversions and Quantity multiplications)
        # Set host luminosity to L/Lsun from log10(L/Lsun)
        NArx_table['StarLum'] = 10**NArx_table['StarLum']    # L/Lsun
        
        # Make sure all number fill_values are np.nan after the column manipulations
        for col in NArx_table.colnames:
            if isinstance(NArx_table[col],MaskedColumn) and isinstance(NArx_table[col].fill_value,(int,float)):
                # Only change numeric fill values to nan
                NArx_table[col].fill_value = np.nan
                
        # Fill in masked values 
        NArx_table = NArx_table.filled()
        # Apply units
        NArx_table['SMA'] *= u.AU
        NArx_table['Inc'] *= u.deg
        NArx_table['PlanetMass'] *= u.earthMass
        NArx_table['PlanetRadius'] *= u.earthRad
        NArx_table['PlanetTeq'] *= u.K
        NArx_table['RA'] *= u.deg
        NArx_table['Dec'] *= u.deg
        NArx_table['Distance'] *= u.pc
        NArx_table['StarMass'] *= u.solMass
        NArx_table['StarTeff'] *= u.K
        NArx_table['StarRad'] *= u.solRad
        NArx_table['StarLogg'] *= u.dex(u.cm/(u.s**2))
        NArx_table['StarLum'] *= u.solLum
        NArx_table['StarAge'] *= u.Gyr
        NArx_table['StarVsini'] *= u.km/u.s
        NArx_table['StarRadialVelocity'] *= u.km/u.s
        #NArx_table['StarZ']  *= u.dex
        NArx_table['StarParallax'] *= u.mas
        NArx_table['ProjAU'] *= u.AU
        NArx_table['Phase'] *= u.rad
        NArx_table['AngSep'] *= u.mas
        NArx_table['PlanetLogg'] *= u.dex(u.cm/(u.s**2))
        
        self.planets = NArx_table