Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
AST 303 Fall 2018 Homework #7 Solutions
Note: all python code copied below uses the following preamble:
import matplotlib.pyplot as pltimport numpy as np
1. Fitting a real exoplanet.
(a) The RV data is shown in the figure below:
2450000 2450500 2451000 2451500 2452000
HJD (days)
−75
−50
−25
0
25
50
75
rad
ial
velo
city
(m/s
)
RV data for 51 Peg b
The Lomb-Scargle periodogram is as follows:
101 102 103 104
period (days)
0.0
0.2
0.4
0.6
0.8
1.0
pow
er
Lomb-Scargle periodogram for 51 Peg b
The peak period appears to be P = 4.23107 days. The fit RV curve corresponding tothis period has K = 55.60534 m/s and vr0 = −2.65528 m/s. The RV data phased byP and the sinusoidal fit are displayed in the figure below:
0 1 2 3 4
time (days)
−75
−50
−25
0
25
50
75
rad
ial
velo
city
(m/s
)
phased RV data for 51 Peg b
(b) I set my guesses for the orbital parameters to be vr0 = −2.65528 m/s, K = 55.60534 m/s,P = 4.23107 days, e = 0, $ = 0, and τ = 2, 450, 068.67 days. With e = 0, Kepler’sequation is θ = E = 2π(t− τ)/P . Inserting these values into the radial-velocity fit
vr,fit(t) = vr0 +K[cos(θ(t) +$) + e cos$
],
and comparing this to the data, results in a χ2 = 1263.0843, or a reduced chi-squareχ2/(N − 6) = 5.0523. Could be better.
(c) My code for solve kepler is as follows:
from scipy.optimize import fsolve
def solve kepler(M,e):eanom = np.zeros(M.shape)for i,mi in enumerate(M):
# do iterative root solve with e=0 giving E=M as guesstmp,=fsolve(lambda E: E-e*np.sin(E)-mi,mi)eanom[i] = tmp
return eanom
This goes into the provided curve fit with keplerian fit:
guess = (K,P,e,w,tau,vr0)popt,pcov = curve fit(keplerian fit,jd,rv,sigma=er,
absolute sigma=True,p0=guess)(K,P,e,w,tau,vr0) = poptrvfit = keplerian fit(jd,K,P,e,w,tau,vr0)
chisq = np.sum(((rv-rvfit)/er)**2)print("Chi-squared of least-squares fit is %10.5f" % chisq)
if e<0:w -= np.pie *= -1
w deg = w*180/np.pi
print(K,P,e,w,w deg,tau,vr0)
This returns χ2 = 330.5969, or χ2/(N − 6) = 1.3224. Not too bad! Parameters areK = 55.88694 m/s, P = 4.230731 days, e = 0.01253384, $ = 0.979342 = 56.112135◦,τ = 2, 450, 071.29 days, and vr0 = −1.904959 m/s. All the numbers shifted slightly frompart (b), but perhaps the most important is the introduction of non-zero eccentricity.Using m? = (1.12±0.06) M�, the following code gives a = 0.05316538 au and mp sin i =0.48 MJ:
P yr = P/365.2422 # period in yearsa au = (ms*P yr**2)**(1./3) # semi-major axis in auK auyr = K*2.1096256684e-4 # K in au/yr
# compute planet mass and convert to Jupiter-mass unitsmp = (2*np.pi)**(-1)*K auyr*np.sqrt(1-e**2)*(ms**2*P yr)**(1/3)mp mjup = mp*1047.59421
The resulting fit is shown in the figure below on top of the RV data phased with P .
0 1 2 3 4
time (days)
−75
−50
−25
0
25
50
75
rad
ial
velo
city
(m/s
)
phased RV data for 51 Peg b
(d) The errors may be obtained using
ms = 1.12ms error = 0.06
K error = np.sqrt(pcov[0,0])P error = np.sqrt(pcov[1,1])e error = np.sqrt(pcov[2,2])w error = np.sqrt(pcov[3,3])tau error = np.sqrt(pcov[4,4])a error = a au * np.sqrt( (2*P/(3*P error))**2
+ (ms error/(3*ms))**2 )mp error = mp mjup * np.sqrt( (2*ms error/(3*ms))**2
+ (K error/K)**2 + (P error/(3*P))**2+ (e*e error/np.sqrt(1-e*e))**2 )
Combining the resulting numbers with the fit parameters, I find
K = (55.89± 1.26) m/s
P = (4.230731± 0.000037) days
e = 0.01253± 0.0098
$ = 56.11◦ ± 10.02◦
τ = (2450071.29± 0.50) days
a = (0.05317± 0.00095) au
mp sin i = (0.480± 0.020) MJ
All of these appear to be within the error bars declared on the NASA exoplanet archive.
2. Integrating a real exoplanet. I used mp = 0.48 MJ, e = 0.01253, and a = 0.05317 au.All of the routines for this problem use the same preamble:
# gravitational constant in units where yr = au = Msun = 1gconst = (2*np.pi)**2
# computes grav acceleration of mass i due to all masses j != idef compute gravity(i,x,y,z):
ax = 0 ; ay = 0 ; az = 0jlist = [k for k in range(nbody) if k != i]for j in jlist: # loop over all masses j != i
xsep = x[j]-x[i] # x ij = x j - x iysep = y[j]-y[i] # y ij = y j - y izsep = z[j]-z[i] # z ij = z j - z igrav = m[j]*(xsep**2+ysep**2+zsep**2)**(-1.5)
# gravity on mass i due to mass jax += grav*xsep # x-component of gravityay += grav*ysep # y-component of gravityaz += grav*zsep # z-component of gravity
return (ax,ay,az)
# computes total (kinetic + potential) energy of all massesdef compute energy(x,y,z,u,v,w):
ke = 0. ; pe = 0.for i in range(nbody):
ke += 0.5*m[i]*(u[i]**2+v[i]**2+w[i]**2)jlist = [k for k in range(nbody) if k > i]for j in jlist:
xsep = x[j]-x[i]ysep = y[j]-y[i]zsep = z[j]-z[i]pe -= m[i]*m[j]*(xsep**2+ysep**2+zsep**2)**(-0.5)
return (ke+pe)/gconst
# computes total angular momentum of all massesdef compute angmom(x,y,z,u,v,w):
L = 0.for i in range(nbody):
L += m[i]*np.sqrt( (y[i]*w[i]-z[i]*v[i])**2+ (z[i]*u[i]-x[i]*w[i])**2+ (x[i]*v[i]-y[i]*u[i])**2)
return L/gconst
#######################################
nbody = 2 # number of bodiesdt = 0.0001 # time step [yr]tfinal = 2**14*dt # final time [yr]
# pre-declare arrays for speedtsize = int(tfinal/dt)t = np.zeros(tsize) ; enrg = np.zeros(tsize) ; angm = np.zeros(tsize)x = np.zeros((tsize,nbody)) ; u = np.zeros((tsize,nbody))y = np.zeros((tsize,nbody)) ; v = np.zeros((tsize,nbody))z = np.zeros((tsize,nbody)) ; w = np.zeros((tsize,nbody))
# 51 Peg planetary systemms = 1.12 # stellar mass [Msun]mp = 0.48*9.54568e-4 # planetary mass [Msun]m = gconst*np.array([ms,mp]) # array of masses * grav constante = 0.01253 # eccentricitya = 0.05317 # semi-major axis [au]r0 = a*(1-e*e)/(1+e) # initial position [au]v0 = np.sqrt((m[0]+m[1])*(2/r0-1/a)) # initial speed [au]
# initial positions and velocities for each massi = 0x[0,i] = 0. ; y[0,i] = 0. ; z[0,i] = 0.u[0,i] = 0. ; v[0,i] = 0. ; w[0,i] = 0.
i += 1x[0,i] = r0 ; y[0,i] = 0. ; z[0,i] = 0.u[0,i] = 0. ; v[0,i] = v0 ; w[0,i] = 0.
# compute initial total energy of systemenrg[0] = compute energy(x[0,:],y[0,:],z[0,:],u[0,:],v[0,:],w[0,:])
# compute initial angular momentum of systemangm[0] = compute angmom(x[0,:],y[0,:],z[0,:],u[0,:],v[0,:],w[0,:])
(a) The following code performs a forward-Euler integration of the system:
# begin Euler integrationfor n in range(tsize-1): # loop over times
for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)# compute grav acceleration for mass i using current positions(ax,ay,az) = compute gravity(i,x[n,:],y[n,:],z[n,:])# update position and velocity of mass ix[n+1,i] = x[n,i] + dt*u[n,i]y[n+1,i] = y[n,i] + dt*v[n,i]z[n+1,i] = z[n,i] + dt*w[n,i]u[n+1,i] = u[n,i] + dt*axv[n+1,i] = v[n,i] + dt*ayw[n+1,i] = w[n,i] + dt*az
# increment timet[n+1] = t[n] + dt
# compute total energy of systemenrg[n+1] = compute energy(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
# compute angular momentum of systemangm[n+1] = compute angmom(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
The following orbit (centered on the star) is found:
−0.4 −0.2 0.0 0.2 0.4
x (au)
−0.4
−0.2
0.0
0.2
0.4
y(a
u)
Euler method
The errors in the total energy and angular momentum are as follows:
0.0 0.5 1.0 1.5
t (yr)
10−2
10−1
100
|E/E
(0)−
1|
Euler method
0.0 0.5 1.0 1.5
t (yr)
10−2
10−1
100
|L/L
(0)−
1|
Euler method
Looks pretty bad. Energy isn’t conserved and the orbit spirals outwards.
(b) The following code performs an RK2 integration of the system:
# begin RK2 integrationfor n in range(tsize-1): # loop over times
# stage 1
for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)# compute grav acceleration for mass i using current positions(ax,ay,az) = compute gravity(i,x[n,:],y[n,:],z[n,:])# store k1k1[i,ix] = dt*u[n,i]k1[i,iy] = dt*v[n,i]k1[i,iz] = dt*w[n,i]k1[i,iu] = dt*axk1[i,iv] = dt*ayk1[i,iw] = dt*az
# stage 2for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using advanced positions(ax,ay,az) = compute gravity(i,x[n,:]+0.5*k1[:,ix],
y[n,:]+0.5*k1[:,iy],z[n,:]+0.5*k1[:,iz])
# store k2k2[i,ix] = dt*(u[n,i]+0.5*k1[i,iu])k2[i,iy] = dt*(v[n,i]+0.5*k1[i,iv])k2[i,iz] = dt*(w[n,i]+0.5*k1[i,iw])k2[i,iu] = dt*axk2[i,iv] = dt*ayk2[i,iw] = dt*az
# update position and velocity of mass ifor i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
x[n+1,i] = x[n,i] + k2[i,ix]y[n+1,i] = y[n,i] + k2[i,iy]z[n+1,i] = z[n,i] + k2[i,iz]u[n+1,i] = u[n,i] + k2[i,iu]v[n+1,i] = v[n,i] + k2[i,iv]w[n+1,i] = w[n,i] + k2[i,iw]
# increment timet[n+1] = t[n] + dt
# compute total energy of systemenrg[n+1] = compute energy(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
# compute angular momentum of systemangm[n+1] = compute angmom(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
The following orbit (centered on the star) is found:
−6 −4 −2 0 2 4 6
x (10−2 au)
−6
−4
−2
0
2
4
6
y(1
0−
2au
)
RK2 method
The errors in the total energy and angular momentum are as follows:
0.0 0.5 1.0 1.5
t (yr)
10−8
10−7
10−6
10−5
10−4
10−3
10−2
|E/E
(0)−
1|
RK2 method
0.0 0.5 1.0 1.5
t (yr)
10−7
10−5
10−3
10−1
|L/L
(0)−
1|
RK2 method
This is better. . . the orbits bleeds just a little bit. The error in the energy went downby two orders of magnitude.
(c) The following code performs an RK4 integration of the system:
# declare temporary storage arrays for RK4 integrationk1 = np.zeros((nbody,6)) ; k2 = np.zeros((nbody,6))
k3 = np.zeros((nbody,6)) ; k4 = np.zeros((nbody,6))ix = 0 ; iy = 1 ; iz = 2 ; iu = 3 ; iv = 4 ; iw = 5
# begin RK4 integrationfor n in range(tsize-1): # loop over times
# stage 1for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using current positions(ax,ay,az) = compute gravity(i,x[n,:],y[n,:],z[n,:])# store k1k1[i,ix] = dt*u[n,i]k1[i,iy] = dt*v[n,i]k1[i,iz] = dt*w[n,i]k1[i,iu] = dt*axk1[i,iv] = dt*ayk1[i,iw] = dt*az
# stage 2for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using advanced positions(ax,ay,az) = compute gravity(i,x[n,:]+0.5*k1[:,ix],
y[n,:]+0.5*k1[:,iy],z[n,:]+0.5*k1[:,iz])
# store k2k2[i,ix] = dt*(u[n,i]+0.5*k1[i,iu])k2[i,iy] = dt*(v[n,i]+0.5*k1[i,iv])k2[i,iz] = dt*(w[n,i]+0.5*k1[i,iw])k2[i,iu] = dt*axk2[i,iv] = dt*ayk2[i,iw] = dt*az
# stage 3for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using advanced positions(ax,ay,az) = compute gravity(i,x[n,:]+0.5*k2[:,ix],
y[n,:]+0.5*k2[:,iy],z[n,:]+0.5*k2[:,iz])
# store k3k3[i,ix] = dt*(u[n,i]+0.5*k2[i,iu])k3[i,iy] = dt*(v[n,i]+0.5*k2[i,iv])k3[i,iz] = dt*(w[n,i]+0.5*k2[i,iw])k3[i,iu] = dt*axk3[i,iv] = dt*ayk3[i,iw] = dt*az
# stage 4
for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)# compute grav acceleration for mass i using advanced positions(ax,ay,az) = compute gravity(i,x[n,:]+k3[:,ix],
y[n,:]+k3[:,iy],z[n,:]+k3[:,iz])
# store k4k4[i,ix] = dt*(u[n,i]+k3[i,iu])k4[i,iy] = dt*(v[n,i]+k3[i,iv])k4[i,iz] = dt*(w[n,i]+k3[i,iw])k4[i,iu] = dt*axk4[i,iv] = dt*ayk4[i,iw] = dt*az
# update position and velocity of mass ifor i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
x[n+1,i] = x[n,i] + oo6*(k1[i,ix]+2*k2[i,ix]+2*k3[i,ix]+k4[i,ix])y[n+1,i] = y[n,i] + oo6*(k1[i,iy]+2*k2[i,iy]+2*k3[i,iy]+k4[i,iy])z[n+1,i] = z[n,i] + oo6*(k1[i,iz]+2*k2[i,iz]+2*k3[i,iz]+k4[i,iz])u[n+1,i] = u[n,i] + oo6*(k1[i,iu]+2*k2[i,iu]+2*k3[i,iu]+k4[i,iu])v[n+1,i] = v[n,i] + oo6*(k1[i,iv]+2*k2[i,iv]+2*k3[i,iv]+k4[i,iv])w[n+1,i] = w[n,i] + oo6*(k1[i,iw]+2*k2[i,iw]+2*k3[i,iw]+k4[i,iw])
# increment timet[n+1] = t[n] + dt
# compute total energy of systemenrg[n+1] = compute energy(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
# compute angular momentum of systemangm[n+1] = compute angmom(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
The following orbit (centered on the star) is found:
−6 −4 −2 0 2 4 6
x (10−2 au)
−6
−4
−2
0
2
4
6
y(1
0−
2au
)
RK4 method
The errors in the total energy and angular momentum are as follows:
0.0 0.5 1.0 1.5
t (yr)
10−8
10−7
10−6
10−5
10−4
10−3
10−2
|E/E(
0)−
1|
RK4 method
0.0 0.5 1.0 1.5
t (yr)
10−7
10−5
10−3
10−1
|L/L
(0)−
1|
RK4 method
Nice! Orbit looks much better and the error in the energy went down by another threeorders of magnitude. The energy in the angular momentum is pretty much the samethough.
(d) The following code performs a leapfrog integration of the system with an initial backward-RK2 half-step to obtain v−1/2:
# use RK2 to get "initial" velocity at t[n-1/2]k1 = np.zeros((nbody,3))ix = 0 ; iy = 1 ; iz = 2
# stage 1for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using current positions(ax,ay,az) = compute gravity(i,x[0,:],y[0,:],z[0,:])# store k1k1[i,ix] = -halfdt*u[0,i]k1[i,iy] = -halfdt*v[0,i]k1[i,iz] = -halfdt*w[0,i]
# stage 2for i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using advanced positions(ax,ay,az) = compute gravity(i,x[n,:]+0.5*k1[:,ix],
y[n,:]+0.5*k1[:,iy],z[n,:]+0.5*k1[:,iz])
# compute velocity of mass i at t[-1/2]u[0,i] -= halfdt*axv[0,i] -= halfdt*ayw[0,i] -= halfdt*az
# begin leapfrog integrationfor n in range(tsize-1):
# update velocities from n-1/2 to n+1/2 using positions at nfor i in range(nbody): # loop over masses i=0,1,...,(nbody-1)
# compute grav acceleration for mass i using current positions(ax,ay,az) = compute gravity(i,x[n,:],y[n,:],z[n,:])u[n+1,i] = u[n,i] + dt*axv[n+1,i] = v[n,i] + dt*ayw[n+1,i] = w[n,i] + dt*az# update positions from n to n+1/2 using velocities at n+1/2x[n+1,i] = x[n,i] + halfdt*u[n+1,i]y[n+1,i] = y[n,i] + halfdt*v[n+1,i]z[n+1,i] = z[n,i] + halfdt*w[n+1,i]
# compute total energy of systemenrg[n+1] = compute energy(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
# compute angular momentum of systemangm[n+1] = compute angmom(x[n+1,:],y[n+1,:],z[n+1,:],
u[n+1,:],v[n+1,:],w[n+1,:])
# finish updating positions to n+1 using velocities at n+1/2for i in range(nbody):
x[n+1,i] += halfdt*u[n+1,i]y[n+1,i] += halfdt*v[n+1,i]z[n+1,i] += halfdt*w[n+1,i]
# increment timet[n+1] = t[n] + dt
The following orbit (centered on the star) is found:
−6 −4 −2 0 2 4 6
x (10−2 au)
−6
−4
−2
0
2
4
6
y(1
0−
2au
)
leapfrog method
The errors in the total energy and angular momentum are as follows:
0.0 0.5 1.0 1.5
t (yr)
10−8
10−7
10−6
10−5
10−4
10−3
10−2
|E/E
(0)−
1|
leapfrog method
0.0 0.5 1.0 1.5
t (yr)
10−7
10−5
10−3
10−1
|L/L
(0)−
1|
leapfrog method
Beautiful (and cheaper than RK4)! Orbit looks perfect and the error in the energy isconstant in time. Remember that leapfrog still makes a truncation error in the phaseof the orbit.
3. FFT’ing numerical planets.
(a) Taking the time series of vx(t) from #2(d), I calculated its power spectrum using
yr = 365.25f = np.fft.fftfreq(tsize,dt)f = np.abs(f[0:(tsize//2+1)])/yruf = np.fft.rfft(u[:,1])sp = 2*abs(uf)/tsize
10−2 10−1 100 101
f (days−1)
10−6
10−4
10−2
100
102
|v̂ x(f
)|2
The peak frequency is at 4.244153 yr−1, which is just slightly different than found inProblem 1. Numerical artifacts are: (i) the constant power at small frequencies and(ii) the spikes rightward of the peak. The former is due to the finite signal that isnot periodic at its ends. The latter is due to the fact that the orbit is not preciselysinusoidal (since e 6= 0), and thus cannot be describe by a single Fourier harmonic.
(b) Below are plots of the inner and outer solar system from the data:
−2 −1 0 1 2
x (au)
−2.0
−1.5
−1.0
−0.5
0.0
0.5
1.0
1.5
2.0y
(au
)inner solar system
−30 −20 −10 0 10 20 30
x (au)
−30
−20
−10
0
10
20
30
y(a
u)
outer solar system
−2 −1 0 1 2
x (au)
−0.06
−0.04
−0.02
0.00
0.02
0.04
0.06
z(a
u)
inner solar system
−30 −20 −10 0 10 20 30
x (au)
−1.0
−0.5
0.0
0.5
1.0
z(a
u)
outer solar system
Doing the following procedure on each planet’s data set:
dt = planet[0,1]-planet[0,0]dsize = planet.shape[1]f = np.fft.fftfreq(dsize,dt)f = np.abs(f[0:(dsize//2+1)])vf = np.fft.rfft(planet[4,:])s planet = (2*abs(vf)/dsize)**2
gives the following power spectra and periods:
10−3 10−2 10−1 100 101 102
f (yr−1)
10−8
10−6
10−4
10−2
100
102
|v̂ x(f
)|2
Pmercury = 0.24719634595550327 yr,
Pvenus = 0.6132023391812869 yr,
Pearth = 0.9892226415094344 yr,
Pmars = 1.880853811659194 yr,
Pjupiter = 11.814940845070428 yr,
Psaturn = 29.433712280701773 yr,
Puranus = 83.88608000000005 yr,
Pneptune = 167.7721600000001 yr.
Not too bad considering that leapfrog makes an error in the orbital phase.