Example #1
0
    print("Take a BH binary with q={}, chi1={} and chi2={}".format(
        q, chi1, chi2))

    M, m1, m2, S1, S2 = precession.get_fixed(q, chi1, chi2)
    print("Masses and spins: ", M, m1, m2, S1, S2)

    #separations
    ri = 500 * M  # Initial separation.
    rf = 1. * M  # Final separation.
    sep = np.linspace(ri, rf, 10000)  # Output separations

    #random angles
    t1 = np.random.uniform(0, np.pi)  # theta 1
    t2 = np.random.uniform(0, np.pi)  # theta 2
    dp = np.random.uniform(-np.pi, np.pi)  #delta phi
    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(
Example #2
0
def parameter_selection():
    '''
    Selection of consistent parameters to describe the BH spin orientations, both at finite and infinitely large separation. Compute some quantities which characterize the spin-precession dynamics, such as morphology, precessional period and resonant angles.
    All quantities are given in total-mass units c=G=M=1.

    **Run using**

        import precession.test
        precession.test.parameter_selection()
    '''

    print "\n *Parameter selection at finite separations*"
    q = 0.8  # Must be q<=1. Check documentation for q=1.
    chi1 = 1.  # Must be chi1<=1
    chi2 = 1.  # Must be chi2<=1
    M, m1, m2, S1, S2 = precession.get_fixed(q, chi1,
                                             chi2)  # Total-mass units M=1
    print "We study a binary with\n\tq=%.3f  m1=%.3f  m2=%.3f\n\tchi1=%.3f  S1=%.3f\n\tchi2=%.3f  S2=%.3f" % (
        q, m1, m2, chi1, S1, chi2, S2)
    r = 100 * M  # Must be r>10M for PN to be valid
    print "at separation\n\tr=%.3f" % r
    xi_min, xi_max = precession.xi_lim(q, S1, S2)
    Jmin, Jmax = precession.J_lim(q, S1, S2, r)
    Sso_min, Sso_max = precession.Sso_limits(S1, S2)
    print "The geometrical limits on xi,J and S are\n\t%.3f<=xi<=%.3f\n\t%.3f<=J<=%.3f\n\t%.3f<=S<=%.3f" % (
        xi_min, xi_max, Jmin, Jmax, Sso_min, Sso_max)
    J = (Jmin + Jmax) / 2.
    print "We select a value of J\n\tJ=%.3f " % J
    St_min, St_max = precession.St_limits(J, q, S1, S2, r)
    print "This constrains the range of S to\n\t%.3f<=S<=%.3f" % (St_min,
                                                                  St_max)
    xi_low, xi_up = precession.xi_allowed(J, q, S1, S2, r)
    print "The allowed range of xi is\n\t%.3f<=xi<=%.3f" % (xi_low, xi_up)
    xi = (xi_low + xi_up) / 2.
    print "We select a value of xi\n\txi=%.3f" % xi
    test = (J >= min(precession.J_allowed(xi, q, S1, S2, r))
            and J <= max(precession.J_allowed(xi, q, S1, S2, r)))
    print "Is our couple (xi,J) consistent?", test
    Sb_min, Sb_max = precession.Sb_limits(xi, J, q, S1, S2, r)
    print "S oscillates between\n\tS-=%.3f\n\tS+=%.3f" % (Sb_min, Sb_max)
    S = (Sb_min + Sb_max) / 2.
    print "We select a value of S between S- and S+\n\tS=%.3f" % S
    t1, t2, dp, t12 = precession.parametric_angles(S, J, xi, q, S1, S2, r)
    print "The angles describing the spin orientations are\n\t(theta1,theta2,DeltaPhi)=(%.3f,%.3f,%.3f)" % (
        t1, t2, dp)
    xi, J, S = precession.from_the_angles(t1, t2, dp, q, S1, S2, r)
    print "From the angles one can recovery\n\t(xi,J,S)=(%.3f,%.3f,%.3f)" % (
        xi, J, S)

    print "\n *Features of spin precession*"
    t1_dp0, t2_dp0, t1_dp180, t2_dp180 = precession.resonant_finder(
        xi, q, S1, S2, r)
    print "The spin-orbit resonances for these values of J and xi are\n\t(theta1,theta2)=(%.3f,%.3f) for DeltaPhi=0\n\t(theta1,theta2)=(%.3f,%.3f) for DeltaPhi=pi" % (
        t1_dp0, t2_dp0, t1_dp180, t2_dp180)
    tau = precession.precession_period(xi, J, q, S1, S2, r)
    print "We integrate dt/dS to calculate the precessional period\n\ttau=%.3f" % tau
    alpha = precession.alphaz(xi, J, q, S1, S2, r)
    print "We integrate Omega*dt/dS to find\n\talpha=%.3f" % alpha
    morphology = precession.find_morphology(xi, J, q, S1, S2, r)
    if morphology == -1: labelm = "Librating about DeltaPhi=0"
    elif morphology == 1: labelm = "Librating about DeltaPhi=pi"
    elif morphology == 0: labelm = "Circulating"
    print "The precessional morphology is: " + labelm
    sys.stdout = os.devnull  # Ignore warnings
    phase, xi_transit_low, xi_transit_up = precession.phase_xi(J, q, S1, S2, r)
    sys.stdout = sys.__stdout__  # Restore warnings
    if phase == -1: labelp = "a single DeltaPhi~pi phase"
    elif phase == 2: labelp = "two DeltaPhi~pi phases, a Circulating phase"
    elif phase == 3:
        labelp = "a DeltaPhi~0, a Circulating, a DeltaPhi~pi phase"
    print "The coexisting phases are: " + labelp

    print "\n *Parameter selection at infinitely large separation*"
    print "We study a binary with\n\tq=%.3f  m1=%.3f  m2=%.3f\n\tchi1=%.3f  S1=%.3f\n\tchi2=%.3f  S2=%.3f" % (
        q, m1, m2, chi1, S1, chi2, S2)
    print "at infinitely large separation"
    kappainf_min, kappainf_max = precession.kappainf_lim(S1, S2)
    print "The geometrical limits on xi and kappa_inf are\n\t%.3f<=xi<=%.3f\n\t %.3f<=kappa_inf<=%.3f" % (
        xi_min, xi_max, kappainf_min, kappainf_max)
    print "We select a value of xi\n\txi=%.3f" % xi
    kappainf_low, kappainf_up = precession.kappainf_allowed(xi, q, S1, S2)
    print "This constrains the range of kappa_inf to\n\t%.3f<=kappa_inf<=%.3f" % (
        kappainf_low, kappainf_up)
    kappainf = (kappainf_low + kappainf_up) / 2.
    print "We select a value of kappa_inf\n\tkappa_inf=%.3f" % kappainf
    test = (xi >= min(precession.xiinf_allowed(kappainf, q, S1, S2))
            and xi <= max(precession.xiinf_allowed(kappainf, q, S1, S2)))
    print "Is our couple (xi,kappa_inf) consistent?", test
    t1_inf, t2_inf = precession.thetas_inf(xi, kappainf, q, S1, S2)
    print "The asymptotic (constant) values of theta1 and theta2 are\n\t(theta1_inf,theta2_inf)=(%.3f,%.3f)" % (
        t1_inf, t2_inf)
    xi, kappainf = precession.from_the_angles_inf(t1_inf, t2_inf, q, S1, S2)
    print "From the angles one can recovery\n\t(xi,kappa_inf)=(%.3f,%.3f)" % (
        xi, kappainf)
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
Example #4
0
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_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