def compute_pair_separations_hill_radii(pairs): ''' d = {'pair_inner_radius':[], 'pair_outer_radius':[], 's_mass':[], 's_met':[], 's_logage':[], 'pair_inner_sma': [], 'pair_outer_sma': [], 'n_planet_in_sys':[], 'pair_ind':[]} ''' inner_masses, outer_masses = [], [] for inner_rad, outer_rad in zip(arr(pairs['pair_inner_radius']), arr(pairs['pair_outer_radius'])): inner_masses.append(_get_WM14_mass(inner_rad)) outer_masses.append(_get_WM14_mass(outer_rad)) pairs['pair_inner_mass'] = arr(inner_masses) pairs['pair_outer_mass'] = arr(outer_masses) m_j = arr(pairs['pair_inner_mass']) * u.Mearth m_jp1 = arr(pairs['pair_outer_mass']) * u.Mearth M_star = arr(pairs['s_mass']) * u.Msun a_j = arr(pairs['pair_inner_sma']) * u.au a_jp1 = arr(pairs['pair_outer_sma']) * u.au R_H = 0.5 * ((m_j + m_jp1) / (3 * M_star))**(1 / 3) * (a_j + a_jp1) sep = (a_jp1 - a_j) / R_H pairs['R_H'] = R_H.to(u.au).value pairs['sep_by_RH'] = sep.cgs.value return pairs
def scatter_p2byp1_vs_p1(pairs): # the period ratio P2/P1 tends to be larger than average when P1 is less # than about 2-3 days a1 = arr(pairs['pair_inner_sma']) a2 = arr(pairs['pair_outer_sma']) P1 = arr(pairs['pair_inner_period']) P2 = arr(pairs['pair_outer_period']) aByRstar1 = arr(pairs['pair_inner_abyRstar']) aByRstar2 = arr(pairs['pair_outer_abyRstar']) plt.close('all') f, ax = plt.subplots(figsize=(8, 6)) ax.scatter(P1, P2 / P1, marker='o', s=5, c='#1f77b4', zorder=2) ax.get_yaxis().set_tick_params(which='both', direction='in') ax.get_xaxis().set_tick_params(which='both', direction='in') ax.set_xlabel('$P_1$, inner period of planet pair [days]', fontsize='medium') ax.set_ylabel('$P_2/P_1$, ratio of planet pair periods', fontsize='medium') ax.set_xscale('log') ax.set_yscale('log') savpath = '../results/cks_multis_vs_age/scatter_p2byp1_vs_p1.pdf' f.tight_layout(h_pad=0, w_pad=0) f.savefig(savpath, bbox_inches='tight') print('made {:s}'.format(savpath))
def hill_radius_pairs_vs_age(pairs, aByRstar_cut=20): plt.close('all') f, ax = plt.subplots(nrows=1, ncols=1, figsize=(8, 6)) a1 = arr(pairs['pair_inner_sma']) a2 = arr(pairs['pair_outer_sma']) P1 = arr(pairs['pair_inner_period']) P2 = arr(pairs['pair_outer_period']) aByRstar1 = arr(pairs['pair_inner_abyRstar']) aByRstar2 = arr(pairs['pair_outer_abyRstar']) sep_by_RH = arr(pairs['sep_by_RH']) s_logage = arr(pairs['s_logage']) # really giso_slogage sel = (aByRstar1 < aByRstar_cut) & (aByRstar2 < aByRstar_cut) ax.scatter(sep_by_RH[sel], 10**(s_logage[sel]) / 1e9) ax.set_xlabel('separation in mutual hill radii') ax.set_ylabel('age [Gyr]') from matplotlib.ticker import MultipleLocator, FormatStrFormatter ax.xaxis.set_major_locator(MultipleLocator(10)) ax.xaxis.set_major_formatter(FormatStrFormatter('%d')) #ax.yaxis.set_major_locator(MultipleLocator(10)) #ax.yaxis.set_major_formatter(FormatStrFormatter('%d')) ax.get_yaxis().set_tick_params(which='both', direction='in') ax.get_xaxis().set_tick_params(which='both', direction='in') ax.grid(True, zorder=-2, which='major', alpha=0.2) ax.set_title('{:d} pairs where both planets have ' '$a/R_\star<${:d}'.format(len(pairs[sel]), aByRstar_cut)) f.tight_layout(h_pad=0, w_pad=0) savname = ( '../results/cks_age_plots_old_short_period/' + 'hill_radius_pairs_vs_age_aByRstar_cut_{:d}.pdf'.format(aByRstar_cut)) f.savefig(savname, bbox_inches='tight') print('saved %s' % savname) savname = ( '../results/cks_age_plots_old_short_period/' + 'hill_radius_pairs_vs_age_aByRstar_cut_{:d}.png'.format(aByRstar_cut)) f.savefig(savname, bbox_inches='tight', dpi=350) print('saved %s' % savname)
def _apply_cks_VI_metallicity_study_filters(df): ''' given df from _get_cks_data, return the boolean indices for the subset of interest. See Weiss+ 2018, CKS VI, table 1. Here we reproduce the "full CKS-Gaia multis sample". We don't make the magnitude-limited cut, because we're gonna compare multis to multis. ''' # row zero, `r0` tuple containing stats rows = [] rows.append(_get_Weiss18_table1_stats(df)) # not a false positive is_fp = arr(df['cks_fp']) sel = ~is_fp rows.append(_get_Weiss18_table1_stats(df[sel])) # radius correction factor <5%, logical or not given in Furlan+2017 table. sel &= ((arr(df['fur17_rcorr_avg']) < 1.05) | (~np.isfinite(df['fur17_rcorr_avg']))) rows.append(_get_Weiss18_table1_stats(df[sel])) # not grazing (b<0.9) sel &= np.isfinite(arr(df['koi_impact'])) sel &= arr(df['koi_impact']) < 0.9 rows.append(_get_Weiss18_table1_stats(df[sel])) # SNR>10 sel &= np.isfinite(arr(df['koi_model_snr'])) sel &= arr(df['koi_model_snr']) > 10. rows.append(_get_Weiss18_table1_stats(df[sel])) # Rp < 22.4 Re sel &= np.isfinite(arr(df['giso_prad'])) sel &= arr(df['giso_prad']) < 22.4 rows.append(_get_Weiss18_table1_stats(df[sel])) # You need finite ages, too sel &= np.isfinite(arr(df['giso_slogage'])) rows.append(_get_Weiss18_table1_stats(df[sel])) for row in rows: print(row) weiss_18_table_1 = [ (1944, 1222, 1176), (1788, 1118, 1092), (1700, 1060, 1042), (1563, 990, 940), (1495, 952, 908), (1491, 948, 892), ] for rowind, wrow in enumerate(weiss_18_table_1): if wrow == rows[rowind]: print('row {:d} matches Weiss+18 Table 1'.format(rowind)) elif np.abs(np.sum(wrow) - np.sum(rows[rowind])) < 10: print('row {:d} is close (w/in 10 planets) of Weiss+18 Table 1'. format(rowind)) else: print('row {:d} is quite different from Weiss+18 Table 1'.format( rowind)) return sel
def scatter_p2byp1_vs_p1_age_percentiles(pairs): P1 = arr(pairs['pair_inner_period']) P2 = arr(pairs['pair_outer_period']) smet = arr(pairs['s_met']) slogage = arr(pairs['s_logage']) sep = 25 smet_pctls = [ np.percentile(smet, pct) for pct in np.arange(0, 100 + sep, sep) ] slogage_pctls = [ np.percentile(slogage, pct) for pct in np.arange(0, 100 + 25, 25) ] # plot pairs by stellar age percentiles plt.close('all') f, axs = plt.subplots(nrows=2, ncols=2, figsize=(8, 6), sharex=True, sharey=True) axs = axs.flatten() for ix, ax in enumerate(axs): ax.scatter(P1, P2 / P1, marker='o', s=5, c='lightgray', zorder=1) if ix == 0: sel = slogage < slogage_pctls[ix + 1] textstr = 'logage$<${:.2f}\ntot={:d},blue={:d}'.format( slogage_pctls[ix + 1], len(pairs), int(len(pairs) * sep / 100)) elif ix == len(axs) - 1: sel = slogage > slogage_pctls[ix] textstr = 'logage$>${:.2f}\ntot={:d},blue={:d}'.format( slogage_pctls[ix], len(pairs), int(len(pairs) * sep / 100)) else: sel = slogage >= slogage_pctls[ix] sel &= slogage < slogage_pctls[ix + 1] textstr = 'logage=({:.2f},{:.2f})\ntot={:d},blue={:d}'.format( slogage_pctls[ix], slogage_pctls[ix + 1], len(pairs), int(len(pairs) * sep / 100)) ax.scatter(P1[sel], P2[sel] / P1[sel], marker='o', s=3, c='#1f77b4', zorder=2) ax.text(0.95, 0.95, textstr, horizontalalignment='right', verticalalignment='top', transform=ax.transAxes, fontsize='xx-small') ax.set_xscale('log') ax.set_yscale('log') ax.set_xlim([0.4, 300]) ax.set_xlim([0.9, 102]) ax.get_yaxis().set_tick_params(which='both', direction='in') ax.get_xaxis().set_tick_params(which='both', direction='in') f.tight_layout(h_pad=0, w_pad=0) # set labels f.add_subplot(111, frameon=False) plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False) plt.grid(False) plt.xlabel('$P_1$, inner period of planet pair [days]', fontsize='medium') plt.ylabel('$P_2/P_1$, ratio of planet pair periods', fontsize='medium') savpath = '../results/cks_multis_vs_age/scatter_p2byp1_vs_p1_age_percentiles.pdf' f.tight_layout(h_pad=0, w_pad=0) f.savefig(savpath, bbox_inches='tight') print('made {:s}'.format(savpath))
def split_weiss18_fig1_high_low_met(df, sel): # reproduce Weiss+18 CKS VI's Figure 1, the detected system multiplicity # function, for high and low metallicity CKS systems. u, u_inds, inv_inds, counts = np.unique(df[sel]['id_starname'], return_index=True, return_inverse=True, return_counts=True) multiplicity_function = counts # length: number of systems df_multiplicity = counts[inv_inds] # length: number of transiting planets multis = df[sel][df_multiplicity != 1] # length: number of planets in multi systems system_df = df[sel].iloc[ u_inds] # length: number of systems. unique stellar properties here! # get metallicities for systems with at least two planets smet_VII = arr(system_df['cks_smet'])[(counts >= 2)] med_smet = np.median(smet_VII) sel_highmet = (smet_VII > med_smet) bins = np.arange(0.5, 7.5, 1) n_highmet, _ = np.histogram(counts[(counts >= 2)][sel_highmet], bins) sel_lowmet = (smet_VII <= med_smet) n_lowmet, _ = np.histogram(counts[(counts >= 2)][sel_lowmet], bins) N = int(np.max(counts)) plt.close('all') f, ax = plt.subplots(figsize=(4, 3)) ind = np.arange(1, N, 1) width = 0.35 rects1 = ax.bar(ind, n_highmet, width) rects2 = ax.bar(ind + width, n_lowmet, width) ax.set_xlabel('Number of Transiting Planets', fontsize='large') ax.set_xlim([0.5, 7.5]) ax.set_ylabel('Number of Stars', fontsize='large') ax.set_xticks(ind + width / 2) ax.set_xticklabels(('1', '2', '3', '4', '5', '6')) ax.legend((rects1[0], rects2[0]), ('[Fe/H]$>${:.3f}'.format(med_smet), '[Fe/H]$\le${:.3f}'.format(med_smet)), fontsize='xx-small') ax.set_title('split CKS+Gaia multis by host star metallicity', fontsize='xx-small') def autolabel(rects): #Attach a text label above each bar displaying its height for rect in rects: height = rect.get_height() ax.text(rect.get_x() + rect.get_width() / 2., 1.01 * height, '%d' % int(height), ha='center', va='bottom', fontsize='xx-small') autolabel(rects1) autolabel(rects2) f.tight_layout() f.savefig( '../results/cks_multis_vs_age/cks_gaia_multis_multiplicity_highvlowmet.pdf' )