def ln_priors(y): """ Priors on the model parameters Parameters ---------- y : ra, dec, M1, M2, A, ecc, v_k, theta, phi, ra_b, dec_b, t_b Current HMXB location (ra, dec) and 10 model parameters Returns ------- lp : float Natural log of the prior """ # M1, M2, A, v_k, theta, phi, ra_b, dec_b, t_b = y ra, dec, M1, M2, A, ecc, v_k, theta, phi, ra_b, dec_b, t_b = y lp = 0.0 # P(M1) if M1 < c.min_mass or M1 > c.max_mass: return -np.inf norm_const = (c.alpha+1.0) / (np.power(c.max_mass, c.alpha+1.0) - np.power(c.min_mass, c.alpha+1.0)) lp += np.log( norm_const * np.power(M1, c.alpha) ) # M1 must be massive enough to evolve off the MS by t_obs if load_sse.func_sse_tmax(M1) > t_b: return -np.inf # P(M2) # Normalization is over full q in (0,1.0) q = M2 / M1 if q < 0.3 or q > 1.0: return -np.inf lp += np.log( (1.0 / M1 ) ) # P(ecc) if ecc < 0.0 or ecc > 1.0: return -np.inf lp += np.log(2.0 * ecc) # P(A) if A*(1.0-ecc) < c.min_A or A*(1.0+ecc) > c.max_A: return -np.inf norm_const = np.log(c.max_A) - np.log(c.min_A) lp += np.log( norm_const / A ) # A must avoid RLOF at ZAMS, by a factor of 2 r_1_roche = binary_evolve.func_Roche_radius(M1, M2, A*(1.0-ecc)) if 2.0 * load_sse.func_sse_r_ZAMS(M1) > r_1_roche: return -np.inf # P(v_k) if v_k < 0.0: return -np.inf lp += np.log( maxwell.pdf(v_k, scale=c.v_k_sigma) ) # P(theta) if theta <= 0.0 or theta >= np.pi: return -np.inf lp += np.log(np.sin(theta) / 2.0) # P(phi) if phi < 0.0 or phi > np.pi: return -np.inf lp += -np.log( np.pi ) # Get star formation history sf_history.load_sf_history() sfh = sf_history.get_SFH(ra_b, dec_b, t_b, sf_history.smc_coor, sf_history.smc_sfh) if sfh <= 0.0: return -np.inf # P(alpha, delta) # From spherical geometric effect, we need to care about cos(declination) lp += np.log(np.cos(c.deg_to_rad * dec_b) / 2.0) ################################################################## # We add an additional prior that scales the RA and Dec by the # area available to it, i.e. pi theta^2, where theta is the angle # of the maximum projected separation over the distance. # # Still under construction ################################################################## M1_b, M2_b, A_b = binary_evolve.func_MT_forward(M1, M2, A, ecc) A_c, v_sys, ecc = binary_evolve.func_SN_forward(M1_b, M2_b, A_b, v_k, theta, phi) if ecc < 0.0 or ecc > 1.0 or np.isnan(ecc): return -np.inf # Ensure that we only get non-compact object companions tobs_eff = binary_evolve.func_get_time(M1, M2, t_b) M_tmp, M_dot_tmp, R_tmp, k_type = load_sse.func_get_sse_star(M2_b, tobs_eff) if int(k_type) > 9: return -np.inf # t_sn = (t_b - func_sse_tmax(M1)) * 1.0e6 * yr_to_sec # The time since the primary's core collapse # theta_max = (v_sys * t_sn) / dist_LMC # Unitless # area = np.pi * rad_to_dec(theta_max)**2 # lp += np.log(1.0 / area) ################################################################## # Instead, let's estimate the number of stars formed within a cone # around the observed position, over solid angle and time. # Prior is in Msun/Myr/steradian ################################################################## t_min = load_sse.func_sse_tmax(M1) * 1.0e6 * c.yr_to_sec t_max = (load_sse.func_sse_tmax(M2_b) - binary_evolve.func_get_time(M1, M2, 0.0)) * 1.0e6 * c.yr_to_sec if t_max-t_min < 0.0: return -np.inf theta_C = (v_sys * (t_max - t_min)) / c.dist_SMC stars_formed = get_stars_formed(ra, dec, t_min, t_max, v_sys, c.dist_SMC) if stars_formed == 0.0: return -np.inf volume_cone = (np.pi/3.0 * theta_C**2 * (t_max - t_min) / c.yr_to_sec / 1.0e6) lp += np.log(sfh / stars_formed / volume_cone) ################################################################## # # P(t_b | alpha, delta) # sfh_normalization = 1.0e-6 # lp += np.log(sfh_normalization * sfh) # Add a prior so that the post-MT secondary is within the correct bounds M2_c = M1 + M2 - load_sse.func_sse_he_mass(M1) if M2_c > c.max_mass or M2_c < c.min_mass: return -np.inf # Add a prior so the effective time remains bounded t_eff_obs = binary_evolve.func_get_time(M1, M2, t_b) if t_eff_obs < 0.0: return -np.inf if t_b * 1.0e6 * c.yr_to_sec < t_min: return -np.inf if t_b * 1.0e6 * c.yr_to_sec > t_max: return -np.inf return lp
def ln_priors_population(y): """ Priors on the model parameters Parameters ---------- y : M1, M2, A, ecc, v_k, theta, phi, ra_b, dec_b, t_b 10 model parameters Returns ------- lp : float Natural log of the prior """ M1, M2, A, ecc, v_k, theta, phi, ra_b, dec_b, t_b = y lp = 0.0 # P(M1) if M1 < c.min_mass or M1 > c.max_mass: return -np.inf norm_const = (c.alpha+1.0) / (np.power(c.max_mass, c.alpha+1.0) - np.power(c.min_mass, c.alpha+1.0)) lp += np.log( norm_const * np.power(M1, c.alpha) ) # M1 must be massive enough to evolve off the MS by t_obs if load_sse.func_sse_tmax(M1) > t_b: return -np.inf # P(M2) # Normalization is over full q in (0,1.0) q = M2 / M1 if q < 0.3 or q > 1.0: return -np.inf lp += np.log( (1.0 / M1 ) ) # P(ecc) if ecc < 0.0 or ecc > 1.0: return -np.inf lp += np.log(2.0 * ecc) # P(A) if A*(1.0-ecc) < c.min_A or A*(1.0+ecc) > c.max_A: return -np.inf norm_const = np.log(c.max_A) - np.log(c.min_A) lp += np.log( norm_const / A ) # A must avoid RLOF at ZAMS, by a factor of 2 r_1_roche = binary_evolve.func_Roche_radius(M1, M2, A*(1.0-ecc)) if 2.0 * load_sse.func_sse_r_ZAMS(M1) > r_1_roche: return -np.inf # P(v_k) if v_k < 0.0: return -np.inf lp += np.log( maxwell.pdf(v_k, scale=c.v_k_sigma) ) # P(theta) if theta <= 0.0 or theta >= np.pi: return -np.inf lp += np.log(np.sin(theta) / 2.0) # P(phi) if phi < 0.0 or phi > np.pi: return -np.inf lp += -np.log( np.pi ) # Get star formation history sfh = sf_history.get_SFH(ra_b, dec_b, t_b, sf_history.smc_coor, sf_history.smc_sfh) if sfh <= 0.0: return -np.inf lp += np.log(sfh) # P(alpha, delta) # From spherical geometric effect, scale by cos(declination) lp += np.log(np.cos(c.deg_to_rad*dec_b) / 2.0) M1_b, M2_b, A_b = binary_evolve.func_MT_forward(M1, M2, A, ecc) A_c, v_sys, ecc = binary_evolve.func_SN_forward(M1_b, M2_b, A_b, v_k, theta, phi) if ecc < 0.0 or ecc > 1.0 or np.isnan(ecc): return -np.inf # Ensure that we only get non-compact object companions tobs_eff = binary_evolve.func_get_time(M1, M2, t_b) M_tmp, M_dot_tmp, R_tmp, k_type = load_sse.func_get_sse_star(M2_b, tobs_eff) if int(k_type) > 9: return -np.inf # Add a prior so that the post-MT secondary is within the correct bounds M2_c = M1 + M2 - load_sse.func_sse_he_mass(M1) if M2_c > c.max_mass or M2_c < c.min_mass: return -np.inf # Add a prior so the effective time remains bounded t_eff_obs = binary_evolve.func_get_time(M1, M2, t_b) if t_eff_obs < 0.0: return -np.inf t_max = (load_sse.func_sse_tmax(M2_b) - binary_evolve.func_get_time(M1, M2, 0.0)) if t_b > t_max: return -np.inf return lp