Restarting a binary

COSMIC allows you to restart a binary from any point in its evolution from a COSMIC generated bpp array.

In [1]: from cosmic.sample.initialbinarytable import InitialBinaryTable

In [2]: from cosmic.evolve import Evolve

Below we provide an example of the same evolutionary track started from the beginning and three different points in the evolution:

  • sometime between the beginning and the first object going supernova

  • between the first and second supernova

  • after both supernova

In [3]: single_binary = InitialBinaryTable.InitialBinaries(m1=25.543645, m2=20.99784, porb=446.795757, ecc=0.448872, tphysf=13700.0, kstar1=1, kstar2=1, metallicity=0.002)

In [4]: BSEDict = {'xi': 1.0, 'bhflag': 1, 'neta': 0.5, 'windflag': 3, 'wdflag': 1, 'alpha1': 1.0, 'pts1': 0.001, 'pts3': 0.02, 'pts2': 0.01, 'epsnov': 0.001, 'hewind': 0.5, 'ck': 1000, 'bwind': 0.0, 'lambdaf': 0.0, 'mxns': 3.0, 'beta': -1.0, 'tflag': 1, 'acc2': 1.5, 'remnantflag': 3, 'ceflag': 0, 'eddfac': 1.0, 'ifflag': 0, 'bconst': 3000, 'sigma': 265.0, 'gamma': -2.0, 'pisn': 45.0, 'natal_kick_array' : [[-100.0,-100.0,-100.0,-100.0,0.0], [-100.0,-100.0,-100.0,-100.0,0.0]], 'bhsigmafrac' : 1.0, 'polar_kick_angle' : 90, 'qcrit_array' : [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0], 'cekickflag' : 2, 'cehestarflag' : 0, 'cemergeflag' : 0, 'ecsn' : 2.5, 'ecsn_mlow' : 1.4, 'aic' : 1, 'ussn' : 0, 'sigmadiv' :-20.0, 'qcflag' : 1, 'eddlimflag' : 0, 'fprimc_array' : [2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0,2.0/21.0], 'bhspinflag' : 0, 'bhspinmag' : 0.0, 'rejuv_fac' : 1.0, 'rejuvflag' : 0, 'htpmb' : 1, 'ST_cr' : 1, 'ST_tide' : 0, 'bdecayfac' : 1, 'randomseed' : -1235453, 'grflag' : 1, 'rembar_massloss' : 0.5, 'kickflag' : 1, 'zsun' : 0.014,  'grflag' : 1, 'bhms_coll_flag' : 0, 'don_lim' : -1, 'acc_lim' : -1, 'rtmsflag' : 0, 'wd_mass_lim': 1}

In [5]: for i in [3, 7, 11]:
   ...:     bpp, bcm, initC, kick_info = Evolve.evolve(initialbinarytable=single_binary, BSEDict=BSEDict)
   ...:     for column in bpp.columns:
   ...:         initC = initC.assign(**{column:bpp.iloc[i][column]})
   ...:     bpp_mid, bcm_mid, initC_mid, kick_info = Evolve.evolve(initialbinarytable=initC, BSEDict={})
   ...:     if i == 3:
   ...:         print("From beginning")
   ...:         print(bpp)
   ...:     print("Started in middle at Index {0}".format(i))
   ...:     print(bpp_mid)
   ...: 
From beginning
       tphys     mass_1     mass_2  ...  bhspin_1  bhspin_2  bin_num
0   0.000000  25.543645  20.997840  ...       0.0       0.0        0
0   7.710210  24.912154  20.771614  ...       0.0       0.0        0
0   7.721745  24.907454  20.771066  ...       0.0       0.0        0
0   8.032373  24.637985  20.771096  ...       0.0       0.0        0
0   8.182496   8.914118  36.245321  ...       0.0       0.0        0
0   8.197726   8.892598  36.248861  ...       0.0       0.0        0
0   8.475201   8.580586  36.159226  ...       0.0       0.0        0
0   8.507068   8.527327  36.148450  ...       0.0       0.0        0
0   8.507068   8.027327  36.148450  ...       0.0       0.0        0
0  11.026336   8.027327  34.999365  ...       0.0       0.0        0
0  11.033156   8.027412  34.984215  ...       0.0       0.0        0
0  11.174855   8.045894  33.800537  ...       0.0       0.0        0
0  11.174855   8.045894  33.800537  ...       0.0       0.0        0
0  11.174855   8.045894  12.597148  ...       0.0       0.0        0
0  11.174855   8.045894  12.597148  ...       0.0       0.0        0
0  11.197226   8.053765  12.597148  ...       0.0       0.0        0

[16 rows x 44 columns]
Started in middle at Index 3
       tphys     mass_1     mass_2  ...  bhspin_1  bhspin_2  bin_num
0   8.032373  24.637985  20.771096  ...       0.0       0.0        0
0   8.182706   8.913234  36.246063  ...       0.0       0.0        0
0   8.197454   8.891835  36.248618  ...       0.0       0.0        0
0   8.475196   8.579641  36.158905  ...       0.0       0.0        0
0   8.507067   8.526389  36.148128  ...       0.0       0.0        0
0   8.507067   8.026389  36.148128  ...       0.0       0.0        0
0  11.026380   8.026389  34.999062  ...       0.0       0.0        0
0  11.033199   8.026474  34.983912  ...       0.0       0.0        0
0  11.174885   8.044952  33.800479  ...       0.0       0.0        0
0  11.174885   8.044952  33.800479  ...       0.0       0.0        0
0  11.174885   8.044952  12.596936  ...       0.0       0.0        0
0  11.174885   8.044952  12.596936  ...       0.0       0.0        0
0  11.197256   8.052822  12.596936  ...       0.0       0.0        0

[13 rows x 44 columns]
Started in middle at Index 7
       tphys    mass_1     mass_2  ...  bhspin_1  bhspin_2  bin_num
0  11.026336  8.027327  34.999365  ...       0.0       0.0        0
0  11.033156  8.027401  34.984215  ...       0.0       0.0        0
0  11.181869  8.046200  33.708076  ...       0.0       0.0        0
0  11.181869  8.046200  33.708076  ...       0.0       0.0        0
0  11.181869  8.046200  12.630507  ...       0.0       0.0        0
0  11.181869  8.046200  12.630507  ...       0.0       0.0        0
0  11.204254  8.054075  12.630507  ...       0.0       0.0        0

[7 rows x 44 columns]
Started in middle at Index 11
       tphys    mass_1     mass_2  ...  bhspin_1  bhspin_2  bin_num
0  11.174855  8.045894  33.800537  ...       0.0       0.0        0
0  11.174855  8.045894  33.800537  ...       0.0       0.0        0
0  11.174855  8.045894  12.597148  ...       0.0       0.0        0
0  11.174855  8.045894  12.597148  ...       0.0       0.0        0
0  11.197226  8.053802  12.597148  ...       0.0       0.0        0

[5 rows x 44 columns]

Natal kick example

One example of where restarting a binary can be extremely helpful is studying how natal kicks affect a binary independently of its previous evolution. This is particularly relevant for Gaia BH1 and Gaia BH2 which are difficult to produce through the standard common envelope channels. We can still study the effect of natal kicks on these binaries if we restart the evolution after the mass transfer would occur. We can do this by using a binary which gets us to the right masses given the metallicity, then overwrite some of the initial conditions to resample the natal kicks and pre-explosion separation.

In [6]: from cosmic import utils
   ...: import pandas as pd
   ...: 

In [7]: single_binary = InitialBinaryTable.InitialBinaries(m1=65.0, m2=0.93, porb=4500, ecc=0.448872,
   ...:                                                    tphysf=13700.0, kstar1=1, kstar2=1, metallicity=0.014*0.6)
   ...: 

In [8]: bpp, bcm, initC, kick_info = Evolve.evolve(initialbinarytable=single_binary, BSEDict=BSEDict)

In [9]: for column in bpp.columns:
   ...:     initC = initC.assign(**{column:bpp.iloc[6][column]})
   ...: 

In [10]: initC = pd.concat([initC]*1000)
   ....: initC['natal_kick_1'] = np.random.uniform(0, 100, 1000)
   ....: initC['phi_1'] = np.random.uniform(-90, 90, 1000)
   ....: initC['theta_1'] = np.random.uniform(0, 360, 1000)
   ....: initC['mean_anomaly_1'] = np.random.uniform(0, 360, 1000)
   ....: initC['porb'] = np.random.uniform(50, 190, 1000)
   ....: initC['sep'] = utils.a_from_p(p=initC.porb.values, m1=initC.mass_1.values, m2=initC.mass_2.values)
   ....: initC['bin_num'] = np.linspace(0, 1000, 1000)
   ....: 

In [11]: bpp_restart, bcm_restart, initC_restart, kick_info_restart = Evolve.evolve(initialbinarytable=initC, BSEDict={})

In [12]: bpp_BH = bpp_restart.loc[(bpp_restart.kstar_1 == 14) & (bpp_restart.kstar_2 == 1) & (bpp_restart.porb > 0)].groupby('bin_num', as_index=False).first()

In [13]: bpp_BH[['tphys', 'mass_1', 'mass_2', 'porb', 'ecc']]
Out[13]: 
Empty DataFrame
Columns: [tphys, mass_1, mass_2, porb, ecc]
Index: []