def func_get_time(M1, M2, t_obs): """ Get the adjusted time for a secondary that accreted the primary's envelope in thermal timescale MT parameters ---------- M1 : float Primary mass before mass transfer (Msun) M2 : float Secondary mass before mass transfer (Msun) t_obs : float Observation time (Myr) Returns ------- Effective observed time: float Time to be fed into load_sse.py function func_get_sse_star() (Myr) """ t_lifetime_1 = load_sse.func_sse_ms_time(M1) he_mass_1 = load_sse.func_sse_he_mass(M1) t_lifetime_2 = load_sse.func_sse_ms_time(M2) he_mass_2 = load_sse.func_sse_he_mass(M2) # Relative lifetime through star 2 at mass gain he_mass = t_lifetime_1/t_lifetime_2 * he_mass_2 # Get new secondary parameters mass_new = M2 + M1 - he_mass_1 t_lifetime_new = load_sse.func_sse_ms_time(mass_new) he_mass_new = load_sse.func_sse_he_mass(mass_new) # New, effective lifetime t_eff = he_mass / he_mass_new * t_lifetime_new # Now, we obtain the "effective observed time" return t_eff + t_obs - t_lifetime_1
def full_forward(M1, M2, A, ecc, v_k, theta, phi, t_obs): """ Evolve a binary forward from its initial conditions Parameters ---------- M1 : float Initial primary mass (Msun) M2 : float Initial secondary mass (Msun) A : float Initial orbital separation (Rsun) ecc : float Initial orbital eccentricity (unitless) v_k : float SN kick velocity theta : float SN kick polar angle phi : float SN kick azimuthal angle t_obs : float observation time Returns ------- M_NS : float or ndarray Array of final primary masses (Currently set to the NS mass, c.M_NS) M_2 : float or ndarray Array of final secondary masses (Msun) L_x : float or ndarray X-ray luminosity (erg/s) v_sys : float or ndarray Systemic velocity (km/s) M2_dot : float or ndarray Mass accretion rate (Msun/yr) A : float or ndarray Orbital separation (Rsun) ecc : float or ndarray Orbital eccentricity (unitless) theta : float or ndarray Projected angular distance traveled from birth location (radians) k_type : int k-type of HMXB donor """ if load_sse.func_sse_mass is None: load_sse.load_sse() if isinstance(M1, np.ndarray): dtypes = [('M_NS','<f8'), \ ('M_2','<f8'), \ ('L_x','<f8'), \ ('v_sys','<f8'), \ ('M2_dot','<f8'), \ ('A','<f8'), \ ('ecc','<f8'), \ ('theta','<f8'), \ ('k_type','<i8')] HMXB = np.recarray(len(M1), dtype=dtypes) for i in np.arange(len(M1)): if isinstance(t_obs, np.ndarray): if t_obs[i] < load_sse.func_sse_ms_time(M1[i]): HMXB["M_NS"][i] = M1[i] HMXB["M_2"][i] = M2[i] HMXB["A"][i] = A[i] continue else: if t_obs < load_sse.func_sse_ms_time(M1[i]): HMXB["M_NS"][i] = M1[i] HMXB["M_2"][i] = M2[i] HMXB["A"][i] = A[i] continue # First MT phase M_1_b, M_2_b, A_b = binary_evolve.func_MT_forward(M1[i], M2[i], A[i], ecc[i]) if isinstance(t_obs, np.ndarray): if t_obs[i] < load_sse.func_sse_tmax(M1[i]): HMXB["M_NS"][i] = M_1_b HMXB["M_2"][i] = M_2_b HMXB["A"][i] = A_b continue else: if t_obs < load_sse.func_sse_tmax(M1[i]): HMXB["M_NS"][i] = M_1_b HMXB["M_2"][i] = M_2_b HMXB["A"][i] = A_b continue # SN A_tmp, v_sys_tmp, e_tmp = binary_evolve.func_SN_forward(M_1_b, M_2_b, A_b, v_k[i], theta[i], phi[i]) # XRB if isinstance(t_obs, np.ndarray): M_2_tmp, L_x_tmp, M2_dot_out, A_out = binary_evolve.func_Lx_forward(M1[i], M2[i], M_2_b, A_tmp, e_tmp, t_obs[i]) theta_out = (t_obs[i] - load_sse.func_sse_tmax(M1[i])) * v_sys_tmp / c.dist_SMC * c.yr_to_sec * 1.0e6 * np.sin(get_theta(1)) tobs_eff = binary_evolve.func_get_time(M1[i], M2[i], t_obs[i]) else: M_2_tmp, L_x_tmp, M2_dot_out, A_out = binary_evolve.func_Lx_forward(M1[i], M2[i], M_2_b, A_tmp, e_tmp, t_obs) theta_out = (t_obs - load_sse.func_sse_tmax(M1[i])) * v_sys_tmp / c.dist_SMC * c.yr_to_sec * 1.0e6 * np.sin(get_theta(1)) tobs_eff = binary_evolve.func_get_time(M1[i], M2[i], t_obs) # To get k-type of HMXB donor if M_2_b > c.max_mass: k_type = -999 else: M_tmp, M_dot_tmp, R_tmp, k_type = load_sse.func_get_sse_star(M_2_b, tobs_eff) HMXB["M_NS"][i] = c.M_NS HMXB["M_2"][i] = M_2_tmp HMXB["L_x"][i] = L_x_tmp HMXB["v_sys"][i] = v_sys_tmp HMXB["M2_dot"][i] = M2_dot_out HMXB["A"][i] = A_out HMXB["ecc"][i] = e_tmp HMXB["theta"][i] = theta_out HMXB["k_type"][i] = int(k_type) return HMXB["M_NS"], HMXB["M_2"], HMXB["L_x"], HMXB["v_sys"], HMXB["M2_dot"], HMXB["A"], HMXB["ecc"], HMXB["theta"], HMXB["k_type"] else: # Star does not make it to MT phase if t_obs < load_sse.func_sse_ms_time(M1): return M1, M2, 0.0, 0.0, 0.0, A, ecc, 0.0 # MT phase M_1_b, M_2_b, A_b = binary_evolve.func_MT_forward(M1, M2, A, ecc) # Star does not make it to SN if t_obs < load_sse.func_sse_tmax(M1): return M_1_b, M_2_b, 0.0, 0.0, 0.0, A_b, ecc, 0.0 # SN A_tmp, v_sys_tmp, e_tmp = binary_evolve.func_SN_forward(M_1_b, M_2_b, A_b, v_k, theta, phi) # XRB M_2_tmp, L_x_tmp, M2_dot_out, A_out = binary_evolve.func_Lx_forward(M1, M2, M_2_b, A_tmp, e_tmp, t_obs) theta_out = (t_obs - load_sse.func_sse_tmax(M1)) * v_sys_tmp / c.dist_SMC * c.yr_to_sec * 1.0e6 * np.sin(get_theta(1)) # To get k-type of HMXB donor tobs_eff = binary_evolve.func_get_time(M1, M2, t_obs) M_tmp, M_dot_tmp, R_tmp, k_type = load_sse.func_get_sse_star(M_2_b, tobs_eff) return c.M_NS, M_2_tmp, L_x_tmp, v_sys_tmp, M2_dot_out, A_out, e_tmp, theta_out, int(k_type)