def get_alpha_beta_L0frame(M, q, chi1, chi2, times, f_ref = 20.): "Wrapper to precession.orbit_vectors()" M_sun = 4.93e-6 #computing alpha, beta q_ = 1./q #using conventions of precession package m1=M/(1.+q_) # Primary mass m2=q_*M/(1.+q_) # Secondary mass (<m1) S1=chi1*m1**2 # Primary spin magnitude S2=chi2*m2**2 # Secondary spin magnitude r_0 = precession.ftor(f_ref,M) L_0 = precession.get_L(r_0, q_) print("q, L0, r_0 ", q_, L_0, r_0) r_f = 1.* M #final separation: time grid is s.t. t = 0 when r = r_f sep = np.linspace(r_0, r_f, 5000) Lx, Ly, Lz, S1x, S1y, S1z, S2x, S2y, S2z, t = precession.orbit_vectors(0,0,L_0, *S1, *S2, sep, q_, time = True) L = np.sqrt(Lx**2 + Ly**2 + Lz**2) alpha = np.unwrap(np.arctan2(Ly,Lx)) beta = np.arccos(Lz/L) t_out = (t-t[-1])*M_sun*M #output grid if times is None: return t_out, alpha, beta return
xi, J, S = precession.from_the_angles(t1, t2, dp, q, S1, S2, sep[0]) print(xi, S, J, q, S1, S2, sep[0]) Jvec, Lvec, S1vec, S2vec, Svec = precession.Jframe_projection( xi, S, J, q, S1, S2, sep[0]) #initial conditions given angles quit() print("Initial conditions: ", Jvec, Lvec, Svec) good_couple = (J >= min(precession.J_allowed(xi, q, S1, S2, sep[0])) and J <= max(precession.J_allowed(xi, q, S1, S2, sep[0]))) if not good_couple: print("Wrong initial conditions") continue Lx_fvals, Ly_fvals, Lz_fvals, S1x_fvals, S1y_fvals, S1z_fvals, S2x_fvals, S2y_fvals, S2z_fvals, t_fvals = precession.orbit_vectors( *Lvec, *S1vec, *S2vec, sep, q, time=True) #precession avg #t1_prec,t2_prec,dp_prec = precession.evolve_angles(t1,t2, sep[0], sep, q,S1,S2) #computing J Jx_fvals = Lx_fvals + S1x_fvals + S2x_fvals Jy_fvals = Ly_fvals + S1y_fvals + S2y_fvals Jz_fvals = Lz_fvals + S1z_fvals + S2z_fvals L_fvals = np.sqrt(Lx_fvals**2 + Ly_fvals**2 + Lz_fvals**2) J_fvals = np.sqrt(Jx_fvals**2 + Jy_fvals**2 + Jz_fvals**2) S1_fvals = np.sqrt(S1x_fvals**2 + S1y_fvals**2 + S1z_fvals**2) print("S1: ", S1_fvals, chi1) print(Jx_fvals, Jy_fvals, Jz_fvals)
def PNwrappers(): ''' Wrappers of the PN integrators. Here we show how to perform orbit-averaged, precession-averaged and hybrid PN inspirals using the various wrappers implemented in the code. We also show how to estimate the final mass, spin and recoil of the BH remnant following a merger. **Run using** import precession.test precession.test.PNwrappers() ''' q = 0.9 # Mass ratio. Must be q<=1. chi1 = 0.5 # Primary spin. Must be chi1<=1 chi2 = 0.5 # Secondary spin. Must be chi2<=1 print "We study a binary with\n\tq=%.3f, chi1=%.3f, chi2=%.3f" % (q, chi1, chi2) M, m1, m2, S1, S2 = precession.get_fixed(q, chi1, chi2) # Total-mass units M=1 ri = 1000 * M # Initial separation. rf = 10. * M # Final separation. rt = 100. * M # Intermediate separation for hybrid evolution. r_vals = numpy.logspace(numpy.log10(ri), numpy.log10(rf), 10) # Output requested t1i = numpy.pi / 4. t2i = numpy.pi / 4. dpi = numpy.pi / 4. # Initial configuration xii, Ji, Si = precession.from_the_angles(t1i, t2i, dpi, q, S1, S2, ri) print "Configuration at ri=%.0f\n\t(xi,J,S)=(%.3f,%.3f,%.3f)\n\t(theta1,theta2,deltaphi)=(%.3f,%.3f,%.3f)" % ( ri, xii, Ji, Si, t1i, t2i, dpi) print " *Orbit-averaged evolution*" print "Evolution ri=%.0f --> rf=%.0f" % (ri, rf) Jf, xif, Sf = precession.orbit_averaged(Ji, xii, Si, r_vals, q, S1, S2) print "\t(xi,J,S)=(%.3f,%.3f,%.3f)" % (xif[-1], Jf[-1], Sf[-1]) t1f, t2f, dpf = precession.orbit_angles(t1i, t2i, dpi, r_vals, q, S1, S2) print "\t(theta1,theta2,deltaphi)=(%.3f,%.3f,%.3f)" % (t1f[-1], t2f[-1], dpf[-1]) Jvec, Lvec, S1vec, S2vec, Svec = precession.Jframe_projection( xii, Si, Ji, q, S1, S2, ri) Lxi, Lyi, Lzi = Lvec S1xi, S1yi, S1zi = S1vec S2xi, S2yi, S2zi = S2vec Lx, Ly, Lz, S1x, S1y, S1z, S2x, S2y, S2z = precession.orbit_vectors( Lxi, Lyi, Lzi, S1xi, S1yi, S1zi, S2xi, S2yi, S2zi, r_vals, q) print "\t(Lx,Ly,Lz)=(%.3f,%.3f,%.3f)\n\t(S1x,S1y,S1z)=(%.3f,%.3f,%.3f)\n\t(S2x,S2y,S2z)=(%.3f,%.3f,%.3f)" % ( Lx[-1], Ly[-1], Lz[-1], S1x[-1], S1y[-1], S1z[-1], S2x[-1], S2y[-1], S2z[-1]) print " *Precession-averaged evolution*" print "Evolution ri=%.0f --> rf=%.0f" % (ri, rf) Jf = precession.evolve_J(xii, Ji, r_vals, q, S1, S2) print "\t(xi,J,S)=(%.3f,%.3f,-)" % (xii, Jf[-1]) t1f, t2f, dpf = precession.evolve_angles(t1i, t2i, dpi, r_vals, q, S1, S2) print "\t(theta1,theta2,deltaphi)=(%.3f,%.3f,%.3f)" % (t1f[-1], t2f[-1], dpf[-1]) print "Evolution ri=%.0f --> infinity" % ri kappainf = precession.evolve_J_backwards(xii, Jf[-1], rf, q, S1, S2) print "\tkappainf=%.3f" % kappainf Jf = precession.evolve_J_infinity(xii, kappainf, r_vals, q, S1, S2) print "Evolution infinity --> rf=%.0f" % rf print "\tJ=%.3f" % Jf[-1] print " *Hybrid evolution*" print "Prec.Av. infinity --> rt=%.0f & Orb.Av. rt=%.0f --> rf=%.0f" % ( rt, rt, rf) t1f, t2f, dpf = precession.hybrid(xii, kappainf, r_vals, q, S1, S2, rt) print "\t(theta1,theta2,deltaphi)=(%.3f,%.3f,%.3f)" % (t1f[-1], t2f[-1], dpf[-1]) print " *Properties of the BH remnant*" Mfin = precession.finalmass(t1f[-1], t2f[-1], dpf[-1], q, S1, S2) print "\tM_f=%.3f" % Mfin chifin = precession.finalspin(t1f[-1], t2f[-1], dpf[-1], q, S1, S2) print "\tchi_f=%.3f, S_f=%.3f" % (chifin, chifin * Mfin**2) vkick = precession.finalkick(t1f[-1], t2f[-1], dpf[-1], q, S1, S2) print "\tvkick=%.5f" % (vkick) # Geometrical units c=1
def get_alpha_beta(q, chi1, chi2, theta1, theta2, delta_phi, times, f_ref = 20., smooth_oscillation = False, verbose = False): """ get_alpha_beta ============== Returns angles alpha and beta by solving PN equations for spins. Uses module precession. Angles are evaluated on a user-given time grid (units: s/M_sun) s.t. the 0 of time is at separation r = M_tot. Inputs: q (N,) mass ratio (>1) chi1 (N,) dimensionless spin magnitude of BH 1 (in [0,1]) chi1 (N,) dimensionless spin magnitude of BH 2 (in [0,1]) theta1 (N,) angle between spin 1 and L theta2 (N,) angle between spin 2 and L delta_phi (N,) angle between in plane projection of the spins times (D,) times at which alpha, beta are evaluated (units s/M_sun) f_ref frequency at which the orbital parameters refer to (and at which the computation starts) smooth_oscillation whether to smooth the oscillation and return the average part and the residuals verbose whether to suppress the output of precession package Outputs: alpha (N,D) alpha angle evaluated at times beta (N,D) beta angle evaluated at times (if not smooth_oscillation) beta (N,D,3) [mean of beta angles, amplitude of the oscillating part, phase of the oscillating part] (if smooth_oscillation) """ #have a loook at precession.evolve_angles: it does exactly what we want.. #https://github.com/dgerosa/precession/blob/precession_v1/precession/precession.py#L3043 M_sun = 4.93e-6 t_min = np.max(np.abs(times)) r_0 = 2. * np.power(t_min/M_sun, .25) #starting point for the r integration #look eq. 4.26 Maggiore #uglyyyyy #print(f_ref, precession.rtof(r_0, 1.)) #print(f_ref) r_0 = precession.ftor(f_ref,1) if isinstance(q,float): q = np.array(q) chi1 = np.array(chi1) chi2 = np.array(chi2) theta1 = np.array(theta1) theta2 = np.array(theta2) delta_phi = np.array(delta_phi) if len(set([q.shape, chi1.shape, chi2.shape, theta1.shape, theta2.shape, delta_phi.shape])) != 1: raise RuntimeError("Inputs are not of the same shape (N,). Unable to continue") if q.ndim == 0: q = q[None] chi1 = chi1[None]; chi2 = chi2[None] theta1 = theta1[None]; theta2 = theta2[None]; delta_phi = delta_phi[None] squeeze = True else: squeeze = False #initializing vectors alpha = np.zeros((q.shape[0],times.shape[0])) if smooth_oscillation: t_cutoff = -0.1 #shall I insert a cutoff here? beta = np.zeros((q.shape[0],times.shape[0], 3)) else: beta = np.zeros((q.shape[0],times.shape[0])) if not verbose: devnull = open(os.devnull, "w") old_stdout = sys.stdout sys.stdout = devnull else: old_stdout = sys.stdout #computing alpha, beta for i in range(q.shape[0]): #computing initial conditions for the time evolution q_ = 1./q[i] #using conventions of precession package M,m1,m2,S1,S2=precession.get_fixed(q_,chi1[i],chi2[i]) #M_tot is always set to 1 #print(q_, chi1[i], chi2[i], theta1[i],theta2[i], delta_phi[i], S1, S2, M) #nice low level os thing print("Generated angle "+str(i)+"\n") #old_stdout.write("Generated angle "+str(i)+"\n") #old_stdout.flush() if np.abs(delta_phi[i]) < 1e-6:#delta Phi cannot be zero(for some reason) delta_phi[i] = 1e-6 xi,J, S = precession.from_the_angles(theta1[i],theta2[i], delta_phi[i], q_, S1,S2, r_0) J_vec,L_vec,S1_vec,S2_vec,S_vec = precession.Jframe_projection(xi, S, J, q_, S1, S2, r_0) #initial conditions given angles r_f = 1.* M #final separation: time grid is s.t. t = 0 when r = r_f sep = np.linspace(r_0, r_f, 5000) Lx, Ly, Lz, S1x, S1y, S1z, S2x, S2y, S2z, t = precession.orbit_vectors(*L_vec, *S1_vec, *S2_vec, sep, q_, time = True) #time evolution of L, S1, S2 L = np.sqrt(Lx**2 + Ly**2 + Lz**2) print(Lx, Ly, Lz, S1x, S1y, S1z, S2x, S2y, S2z, t) #quit() #cos(beta(t)) = L(t).(0,0,1) #this is how I currently do! #cos(beta(t)) = L(t).L_vect #this is the convention that I want temp_alpha = np.unwrap(np.arctan2(Ly,Lx)) temp_beta = np.arccos(Lz/L) #computing beta in the other reference frame L_0 = L_vec /np.linalg.norm(L_vec) L_t = (np.column_stack([Lx,Ly,Lz]).T/L).T #(D,3) temp_beta = np.einsum('ij,j->i', L_t, L_0) #cos beta print(L_t.shape, temp_beta.shape, L_vec) temp_beta = np.arccos(temp_beta) t_out = (t-t[-1])*M_sun #output grid print("\n\nTimes!! ",t_out[0], times[0]) ids = np.where(t_out > np.min(times))[0] t_out = t_out[ids] temp_alpha = temp_alpha[ids] temp_beta = temp_beta[ids] alpha[i,:] = np.interp(times, t_out, temp_alpha) if not smooth_oscillation: #plt.plot(t_out,temp_beta) #plt.show() beta[i,:] = np.interp(times, t_out, temp_beta) if smooth_oscillation: #mean, f_min, f_max = get_spline_mean(t_out, temp_beta[None,:], f_minmax = True) s = smoothener(t_out, temp_beta) #beta[i,:,0] = mean(times) #avg beta beta[i,:,0] = s(times) #beta[i,:,1] = np.interp(times, t_out, temp_beta) - mean(times) #residuals of beta #dealing with amplitude and phase residual = (temp_beta - s(t_out)) if np.mean(np.abs(residual))< 0.001: residual[:] = 0 id_cutoff = np.where(t_out>t_cutoff)[0] not_id_cutoff = np.where(t_out<=t_cutoff)[0] residual[id_cutoff] = 0. m_list, M_list = compute_spline_peaks(t_out, residual[None,:]) amp = lambda t: (M_list[0](t) - m_list[0](t))/2. beta[i,:,1] = amp(times) #amplitude temp_ph = residual / (amp(t_out)+1e-30) temp_ph[id_cutoff] = 0. beta[i,:,2] = np.interp(times, t_out, temp_ph) #phase beta[i,np.where(np.abs(beta[i,:,2])>1)[0],2] = np.sign(beta[i,np.where(np.abs(beta[i,:,2])>1)[0],2]) #plotting if False:# np.max(np.abs(temp_beta-s(t_out))) > 2: #DEBUG plt.figure() plt.title("Alpha") plt.plot(times,alpha[i,:]) plt.figure() plt.title("Mean maxmin") plt.plot(times,beta[i,:,0]) plt.plot(t_out,temp_beta) #plt.figure() #plt.title("Mean grad") #plt.plot(t_out, temp_beta) #plt.plot(t_out, mean_grad[0](t_out)) #plt.figure() #plt.title("Gradient") #plt.plot(t_out,np.gradient(temp_beta, t_out)) #plt.ylim([-0.6,0.6]) plt.figure() plt.title("Amplitude") #plt.plot(t_out, amp(t_out)) plt.plot(times, beta[i,:,1]) plt.plot(t_out,np.squeeze(temp_beta - s(t_out) )) #plt.figure() #plt.plot(times,beta[i,:,1]) plt.figure() plt.title("ph") plt.plot(times,beta[i,:,2]) plt.show() if not verbose: sys.stdout = old_stdout devnull.close() if squeeze: return np.squeeze(alpha), np.squeeze(beta) return alpha, beta
def get_alpha_beta_M(M, q, chi1, chi2, theta1, theta2, delta_phi, f_ref = 20., smooth_oscillation = False, verbose = False): """ get_alpha_beta ============== Returns angles alpha and beta by solving PN equations for spins. Uses module precession. Angles are evaluated on a user-given time grid (units: s/M_sun) s.t. the 0 of time is at separation r = M_tot. Inputs: M (N,) total mass q (N,) mass ratio (>1) chi1 (N,) dimensionless spin magnitude of BH 1 (in [0,1]) chi1 (N,) dimensionless spin magnitude of BH 2 (in [0,1]) theta1 (N,) angle between spin 1 and L theta2 (N,) angle between spin 2 and L delta_phi (N,) angle between in plane projection of the spins f_ref frequency at which the orbital parameters refer to (and at which the computation starts) verbose whether to suppress the output of precession package Outputs: times (D,) times at which alpha, beta are evaluated (units s) alpha (N,D) alpha angle evaluated at times beta (N,D) beta angle evaluated at times (if not smooth_oscillation) """ M_sun = 4.93e-6 if isinstance(q,np.ndarray): q = q[0] chi1 = chi1[0] chi2 = chi2[0] theta1 = theta1[0] theta2 = theta2[0] delta_phi = delta_phi[0] #initializing vectors if not verbose: devnull = open(os.devnull, "w") old_stdout = sys.stdout sys.stdout = devnull else: old_stdout = sys.stdout #computing alpha, beta q_ = 1./q #using conventions of precession package m1=M/(1.+q_) # Primary mass m2=q_*M/(1.+q_) # Secondary mass S1=chi1*m1**2 # Primary spin magnitude S2=chi2*m2**2 # Secondary spin magnitude r_0 = precession.ftor(f_ref,M) xi,J, S = precession.from_the_angles(theta1,theta2, delta_phi, q_, S1,S2, r_0) J_vec,L_vec,S1_vec,S2_vec,S_vec = precession.Jframe_projection(xi, S, J, q_, S1, S2, r_0) #initial conditions given angles r_f = 1.* M #final separation: time grid is s.t. t = 0 when r = r_f sep = np.linspace(r_0, r_f, 5000) Lx, Ly, Lz, S1x, S1y, S1z, S2x, S2y, S2z, t = precession.orbit_vectors(*L_vec, *S1_vec, *S2_vec, sep, q_, time = True) #time evolution of L, S1, S2 L = np.sqrt(Lx**2 + Ly**2 + Lz**2) L_0 = np.array([Lx[0], Ly[0], Lz[0]])/L[0] #in L0 frame Ln = (np.array([Lx, Ly, Lz])/L).T L0_y = np.array([1.,0.,0.]) L0_y = L0_y - np.dot(L0_y,L_0) * L_0 L0_x = np.cross(L0_y,L_0) alpha = np.unwrap(np.arctan2(np.dot(Ln,L0_y),np.dot(Ln,L0_x))) beta = np.arccos(np.dot(Ln,L_0)) #in J frame #alpha = np.unwrap(np.arctan2(Ly,Lx)) #beta = np.arccos(Lz/L) t_out = (t-t[-1])*M_sun*M #output grid if not verbose: sys.stdout = old_stdout devnull.close() return t_out, alpha, beta