Beispiel #1
2
    def get_measured_temperature(self, starname, date, Tmax, instrument=None, N=7, addmode='simple', feh=None, vsini=None):
        """
        Get the measured temperature by doing a weighted sum over temperatures near the given one (which I find by hand)
        :param starname: The name of the star
        :param Tmax: The temperature to search near
        :param date: The date the observation was taken
        :param instrument: The instrument used (this function automatically finds it if not given)
        :param N:  The number of temperature points to take
        :param addmode: The way the individual order CCFs were co-added.
        :param feh: The metallicity to use. If not given, it finds whatever gives the highest ccf peak.
        :param vsini: The vsini to use. If not given, it finds whatever gives the highest ccf peak.
        :return: A pandas DataFrame with the starname, date, instrument, and model parameters for the
                 temperatures near the requested one
        """
        if instrument is None:
            # Find this star/date in all of the interfaces
            found = False
            df_list = []
            for inst in self._interfaces.keys():
                interface = self._interfaces[inst]
                if starname in interface.list_stars() and date in interface.list_dates(starname):
                    found = True
                    df = self.get_measured_temperature(starname, date, Tmax, instrument=inst, N=N)
                    df_list.append(df)
            if not found:
                warnings.warn('Star ({}) not found for date ({}) in any CCF interfaces!'.format(starname, date))
                return None
            return pd.concat(df_list, ignore_index=True)

        # Check that the star/date combination are in the requested interface
        if starname not in self._interfaces[instrument].list_stars():
            raise KeyError('Star ({}) not in instrument ({})'.format(starname, instrument))
        if date not in self._interfaces[instrument].list_dates(starname):
            # Try date +/- 1 before failing (in case of civil/UT date mismatch or something)
            from datetime import datetime, timedelta
            year, month, day = [int(s) for s in date.split('-')]
            for inc in [-1, 1]:
                t = datetime(year, month, day) + timedelta(inc)
                test_date = '{}-{:02d}-{:02d}'.format(t.year, t.month, t.day)
                if test_date in self._interfaces[instrument].list_dates(starname):
                    return self.get_measured_temperature(starname, test_date, Tmax,
                                                         instrument=instrument, N=N, addmode=addmode)
            raise KeyError(
                'Date ({}) not in CCF interface for star {} and instrument {}'.format(date, starname, instrument))

        # Get CCF information from the requested instrument/star/date combo
        interface = self._interfaces[instrument]
        logging.info('{}, {}, {}, {}'.format(starname, date, instrument, addmode))
        df = interface._compile_data(starname=starname, date=date, addmode=addmode, read_ccf=True)
        #df['ccf_max'] = df.ccf.map(np.max) Already done now

        # Get the parameters and RV of the CCF with the highest peak (which has temperature = Tmax)
        #print(df)
        requested = df.loc[df['T'] == Tmax]
        if feh is not None:
            requested = requested.loc[requested['[Fe/H]'] == feh]
        if vsini is not  None:
            requested = requested.loc[requested['vsini'] == vsini]
        i = np.argmax(requested.ccf_max)
        vsini = requested.loc[i, 'vsini'].item()
        metal = requested.loc[i, '[Fe/H]'].item()
        logg = requested.loc[i, 'logg'].item()
        idx = requested.loc[i, 'ccf'].argmax()
        rv = interface.velocities[idx]

        # Now, get the CCF height for the N/2 temperatures on either side of Tmax
        N = roundodd(N)
        d = defaultdict(list)
        for T in np.arange(Tmax - 100 * (N - 1) / 2, Tmax + 100 * (N - 1) / 2 + 1, 100):
            requested = df.loc[(df['T'] == T) & (df.vsini == vsini) &
                               (df['[Fe/H]'] == metal) & (df.logg == logg)]
            if len(requested) == 0:
                warnings.warn('No matches for T = {} with star/date = {}/{}!'.format(T, starname, date))
                d['Star'].append(starname)
                d['Date'].append(date)
                d['Instrument'].append(instrument)
                d['Temperature'].append(T)
                d['vsini'].append(vsini)
                d['logg'].append(logg)
                d['[Fe/H]'].append(metal)
                d['rv'].append(rv)
                d['CCF'].append(np.nan)
                d['significance'].append(np.nan)
                continue
           
            if len(requested) > 1:
                requested = requested.sort_values(by='ccf_max').tail(1)
            # Save the best parameters for this temperature
            d['Star'].append(starname)
            d['Date'].append(date)
            d['Instrument'].append(instrument)
            d['Temperature'].append(T)
            d['vsini'].append(requested['vsini'].item())
            d['logg'].append(requested['logg'].item())
            d['[Fe/H]'].append(requested['[Fe/H]'].item())
            idx = np.argmin(np.abs(interface.velocities - rv))
            d['rv'].append(rv)
            ccf = requested['ccf'].item()
            d['CCF'].append(ccf[idx])

            # Measure the detection significance
            std = mad(ccf)
            mean = np.median(ccf)
            d['significance'].append((d['CCF'][-1] - mean) / std)

        # Do the weighted sum.
        summary = CCF_Systematics.get_Tmeas(pd.DataFrame(data=d), include_actual=False)

        # Put the star, date, and instrument back in the dataframe before returning
        summary['Star'] = starname
        summary['Date'] = date
        summary['Instrument'] = instrument
        summary['addmode'] = addmode

        return summary
def find_best_pars(df, velocity='highest', vel_arr=np.arange(-900.0, 900.0, 0.1), N=1):
    """
    Find the 'best-fit' parameters for each combination of primary and secondary star
    :param df: the dataframe to search in
    :keyword velocity: The velocity to measure the CCF at. The default is 'highest', and uses the maximum of the ccf
    :keyword vel_arr: The velocities to interpolate each ccf at
    :keyword N: The number of parameters to return
    :return: a dataframe with keys of primary, secondary, and the parameters
    """
    # Make sure N is odd
    if N % 2 == 0:
        logging.warn('N must be an odd number. Changing N from {} --> {}'.format(N, N + 1))
        N += 1


    # Get the names of the primary and secondary stars
    primary_names = pd.unique(df.Primary)
    secondary_names = pd.unique(df.Secondary)

    # Find the ccf value at the given velocity
    def val_fcn(ccf, idx=None, search_indices=None):
        if idx is None:
            if search_indices is None:
                idx = np.argmax(ccf)
            else:
                idx = np.argmax(ccf[search_indices])
                idx = search_indices[idx]
        rv = vel_arr[idx]
        sigma = np.std(ccf[np.abs(vel_arr - rv) > 200])
        return ccf[idx], ccf[idx] / sigma, rv
    if velocity == 'highest':
        vals = df['CCF'].map(val_fcn)
        df['ccf_max'] = vals.map(lambda l: l[0])
        df['significance'] = vals.map(lambda l: l[1])
        df['rv'] = vals.map(lambda l: l[2])
    else:
        # idx = np.argmin(np.abs(vel_arr - velocity))
        idx = np.where(np.abs(vel_arr - velocity) <= 5)[0]
        vals = df['CCF'].map(lambda c: val_fcn(c, search_indices=idx))
        df['ccf_max'] = vals.map(lambda l: l[0])
        df['significance'] = vals.map(lambda l: l[1])
        df['rv'] = vals.map(lambda l: l[2])
        #print(df[['Secondary', 'rv']])

    # Find the best parameter for each combination
    d = defaultdict(list)
    groups = df.groupby(('Primary', 'Secondary'))
    for group in groups.groups.keys():
        primary = group[0]
        secondary = group[1]
        g = groups.get_group(group)
        best = g.loc[g.ccf_max == g.ccf_max.max()]
        T = best['Temperature'].item()
        vsini = best['vsini'].item()
        logg = best['logg'].item()
        metal = best['[Fe/H]'].item()
        rv = best['rv'].item()
        Tmin = T - (N - 1) * 50
        Tmax = T + (N - 1) * 50
        for Ti in range(Tmin, Tmax + 1, 100):
            good = g.loc[
                (g['Temperature'] == Ti) & (g['vsini'] == vsini) & (g['logg'] == logg) & (g['[Fe/H]'] == metal)]
            if len(good) == 0:
                logging.warn('No matches for T = {} with primary/secondary = {}/{}!'.format(Ti, primary, secondary))
                d['Primary'].append(primary)
                d['Secondary'].append(secondary)
                d['Temperature'].append(Ti)
                d['vsini'].append(vsini)
                d['logg'].append(logg)
                d['[Fe/H]'].append(metal)
                d['rv'].append(rv)
                d['CCF'].append(np.nan)
                d['significance'].append(np.nan)
                continue
            # print len(good)
            best = good.loc[good.ccf_max == good.ccf_max.max()]
            #best = good
            if len(best) != 1 or any(np.isnan(best['CCF'].item())):
                print best
                print good
                print good.ccf_max
                print good.ccf_max.max()
                continue

            # Save the best parameters for this temperature
            d['Primary'].append(primary)
            d['Secondary'].append(secondary)
            d['Temperature'].append(best['Temperature'].item())
            d['vsini'].append(best['vsini'].item())
            d['logg'].append(best['logg'].item())
            d['[Fe/H]'].append(best['[Fe/H]'].item())
            idx = np.argmin(np.abs(vel_arr - rv))
            d['rv'].append(rv)
            d['CCF'].append(best['CCF'].item()[idx])
            # d['rv'].append(best['rv'].item())
            #d['CCF'].append(best.ccf_max.item())

            # Measure the detection significance
            std = mad(best.CCF.item())
            mean = np.median(best.CCF.item())
            d['significance'].append((d['CCF'][-1] - mean) / std)

    return pd.DataFrame(data=d)