class ball:
def __init__(self, m=1, r=np.array([0,0,0]), v=np.array([0,0,0]), a=np.array([0,0,0])):
self.m = m
self.r = r
self.v = v
self.a = a
self.r_array = np.array([])
self.v_array = np.array([])
self.a_array = np.array([])
# Gravitational constant
G = 6.674e-11 # N m^2 / kg^2
# Force function: inputs are ball_1 and ball_2
def force(ball_1, ball_2):
'''
This is the force that ball_1 feels due to ball_2. This is dependent
only on the position and mass of the balls, and the gravitational constant (G).
The order in which we put the balls matters for calcualting the correct direction of the force.
'''
output_force = np.zeros(3) # Initialze the returned force array with zeros
r = ball_1.r - ball_2.r # Position vector from ball_2 to ball_1
# Quick check if r^2 is zero to avoid division by zero
if np.sqrt(r.dot(r)) == 0:
return output_force
r_hat = r / np.sqrt(r.dot(r)) # Unit vector pointing from ball_2 to ball_1
##### Begin Editing #####
# YOUR CODE HERE
#note if you wish to use the magnitude of r^2, use r.dot(r)
output_force = ???
##### End Editing #####
return output_force
#Insert the initial velocity for the Earth
##### Begin Editing #####
v_initial_earth = ??? # Your answer here
##### End Editing #####
# Physical constants: mass of the Sun, mass of the Earth, and average distance between the two
M_Sun = 1.988e30 # kg
M_Earth = 5.972e24 # kg
R_Earth = 1.496e11 # m
# Create instances of the ball class for the earth and sun
earth = ball(m=M_Earth, r=np.array([R_Earth,0,0]),
v=np.array([0, v_initial_earth, 0]))
sun = ball(m=M_Sun)
##### Begin Editing #####
T = ???# Your answer here
dt = ???# Your answer here
##### End Editing #####
times = np.arange(0, T+dt, dt)
N = times.size
earth.a_array = np.empty((N,3))
earth.a_array[0] = earth.a
earth.v_array = np.empty((N,3))
earth.v_array[0] = earth.v
earth.r_array = np.empty((N,3))
earth.r_array[0] = earth.r
sun.a_array = np.empty((N,3))
sun.a_array[0] = sun.a
sun.v_array = np.empty((N,3))
sun.v_array[0] = sun.v
sun.r_array = np.empty((N,3))
sun.r_array[0] = sun.r
i = 1
for t in times[1:]:
# first update the accelerations
earth.a = force(earth, sun)/earth.m
sun.a = np.zeros(3) # Here we assume no force on the sun (stays static)
# then append the new value to the list
earth.a_array[i] = earth.a
sun.a_array[i] = sun.a
# second update the velocities
earth.v = earth.v + earth.a * dt
sun.v = sun.v + sun.a * dt
# then append the new value to the list
earth.v_array[i] = earth.v
sun.v_array[i] = sun.v
# third update the positions
earth.r = earth.r + earth.v * dt
sun.r = sun.r + sun.v * dt
# then append the new value to the list
earth.r_array[i] = earth.r
sun.r_array[i] = sun.r
# update iteration count
i = i + 1
plt.plot(earth.r_array[:,0], earth.r_array[:,1], '.')
plt.plot(sun.r_array[:,0], sun.r_array[:,1], '.')
plt.gca().set_aspect('equal')
plt.show()
#Use this code cell to calculate the eccentricty of your orbit.
#Here we use earth.r_array to determine the aphelion and perihelion distances of the orbit
rMag = np.sqrt(earth.r_array[:,0]**2 + earth.r_array[:,1]**2) #turns earth.r_array to list of distances (magnitudes)
A = max(rMag) #aphelion is maximum distance
P = min(rMag) #perihelion is minimum distance
##### Begin Editing #####
#Code in the formula for eccentricity here in terms of A and P, then run the code cell to print out result
ecc = ??? #Look at paragraph above for formula
##### End Editing #####
print('The eccentricity of our simulated orbit is {:.4f}.'.format(ecc))
def init():
line.set_data([], [])
return(line)
def animate_ball_list(ball_list):
def animation_function(i):
x = []
y = []
for j in range(0,len(ball_list)):
x.append(ball_list[j].r_array[i, 0])
y.append(ball_list[j].r_array[i, 1])
line.set_data(x, y)
return (line)
return animation_function
fig3, axs3 = plt.subplots()
axs3.set_xlim((np.min(earth.r_array[:,0]) - 0.1*np.abs(np.min(earth.r_array[:,0])),
np.max(earth.r_array[:,0]) + 0.1*np.abs(np.max(earth.r_array[:,0]))))
axs3.set_ylim((np.min(earth.r_array[:,1]) - 0.1*np.abs(np.min(earth.r_array[:,1])),
np.max(earth.r_array[:,1]) + 0.1*np.abs(np.max(earth.r_array[:,1])))
)
axs3.set_aspect('equal')
axs3.plot([-1,1], [0,0], color='C1', lw=2)
line, = axs3.plot([], [], '.', markersize=24, lw=2)
plt.close()
anim_2 = animation.FuncAnimation(fig3, animate_ball_list([sun, earth]), init_func=init, frames=N, interval=40)
anim_2
rMag = np.sqrt(earth.r_array[:,0]**2 + earth.r_array[:,1]**2)
rMaxIndex = np.argmax(rMag)
rMinIndex = np.argmin(rMag)
vMag = np.sqrt(earth.v_array[:,0]**2 + earth.v_array[:,1]**2)
print('At its maximum distance, the speed of earth is {:.3f} m/s'.format(vMag[rMaxIndex]))
print('At its minimum distance, the speed of earth is {:.3f} m/s'.format(vMag[rMinIndex]))
def initialize_planet(planet, N):
'''
This takes in a planet and initializes it with
empty arrays for the position, velocity, and
acceleration histories. N denotes the total number
of time steps these histories will contain.
'''
planet.a_array = np.empty((N,3))
planet.a_array[0] = planet.a
planet.v_array = np.empty((N,3))
planet.v_array[0] = planet.v
planet.r_array = np.empty((N,3))
planet.r_array[0] = planet.r
def update_planet(planet, force_felt, dt):
'''
This takes in a planet and the force it felt and
updates the planet by one time step.
'''
# first update the acceleration
planet.a = force_felt/planet.m
# then append the new value to the list
planet.a_array[i] = planet.a
# second update the velocities
planet.v = planet.v + planet.a * dt
# then append the new value to the list
planet.v_array[i] = planet.v
# third update the positions
planet.r = planet.r + planet.v * dt
# then append the new value to the list
planet.r_array[i] = planet.r
#Insert the initial speed, T, and dt for the simulation
##### Begin Editing #####
v_initial_earth = ??? # Your answer here
T = ???# Your answer here
dt = ???# Your answer here
##### End Editing #####
times = np.arange(0, T+dt, dt)
N = times.size
earth = ball(m=M_Earth, r=np.array([R_Earth,0,0]),
v=np.array([0, v_initial_earth, 0]))
sun = ball(m=M_Sun)
initialize_planet(earth, N)
initialize_planet(sun, N)
i = 1
for t in times[1:]:
# First find the force
earth_force = force(earth, sun)
sun_force = np.zeros(3) # Here we assume no force on the sun still (stays static)
# Update the planet(s)
update_planet(earth, earth_force, dt)
update_planet(sun, sun_force, dt)
i = i + 1
# Plotting
plt.plot(earth.r_array[:,0], earth.r_array[:,1], '.')
plt.plot(sun.r_array[:,0], sun.r_array[:,1], '.')
plt.gca().set_aspect('equal')
plt.show()
def length_of_year(planet, dt, tolerance=R_Earth*0.01):
'''
This takes in a planet after it has orbitted and calculates
the length of the year based on how long it takes for it to
return back to its starting point. Because our simulation
is not perfect, some tolerance is allowed in case it misses
its starting point by a little
'''
def distance_from_start(index):
'''
This calculates the distance at a given time the planet
is from its start location
'''
start_loc = planet.r_array[0]
curr_loc = planet.r_array[index]
distance = curr_loc - start_loc
return np.sqrt(distance.dot(distance))
# This loop seems a little complicated, but really it is just first
# checking that the planet got away from start and then came back,
# so it doesn't just think it has finished a loop immediately
near_start = True
for i in range(len(planet.r_array)):
if near_start and distance_from_start(i) > tolerance:
near_start = False
if not near_start and distance_from_start(i) < tolerance:
return i*dt
return 0 # If something went wrong, it will say the year was instant
v_initial_earth = 29800 # m/s
earth = ball(m=M_Earth, r=np.array([R_Earth,0,0]),
v=np.array([0, v_initial_earth, 0]))
sun = ball(m=M_Sun)
planets = [earth, sun]
for planet in planets:
initialize_planet(planet, N)
i = 1
for t in times[1:]:
# first find the force
for planet in planets:
planet.force = 0
for second_planet in planets:
planet.force += force(planet, second_planet)
# Update the planet(s)
for planet in planets:
update_planet(planet, planet.force, dt)
i = i + 1
print('The length of one year is ~'+str(length_of_year(earth, dt))+' s.')
plt.plot(earth.r_array[:,0], earth.r_array[:,1], '.')
plt.plot(sun.r_array[:,0], sun.r_array[:,1], '.')
plt.gca().set_aspect('equal')
plt.show()
#Code cell provided for calculations of the force. Show your work to recieve credit.
#Code cell provided for calculations of the accelerations. Show your work to recieve credit.
#Use this code cell to determine the ratio of Sun's distance traveled during the simulation to
#the radius of the Sun
#If you are redoing this section after tackling the CAT, re-run all code cells from Part 3 to ensure
#your values are updated properly for this code.
R_Sun = 6.957e8 #[m]
FinalPositionSun = sun.r_array[-1,:]
#This indexes the position of the sun at the last time step (i.e. -1 first index)
##### Begin Editing #####
#Determine the magnitude of the position to be the norm of the final position of the Sun
#Hint: Use np.linalg.norm()
DisplacementSun = ???
# Calculate Ratio here
RatioDistoRadius = ???
##### End Editing #####
print('Ratio of the displacement of the Sun to the radius of the Sun is '+str(RatioDistoRadius))
T = 4e7
dt = 1e5
#Insert the above conditions into the arrays below
##### Begin Editing #####
suns = [ball(m=?, r=np.array([?, ?, ?]), v=np.array([?, ?, ?])),
ball(m=?, r=np.array([?, ?, ?]), v=np.array([?, ?, ?])),
ball(m=?, r=np.array([?, ?, ?]), v=np.array([?, ?, ?]))]
##### End Editing #####
times = np.arange(0, T+dt, dt)
N = times.size
for sun in suns:
initialize_planet(sun, N)
i = 1
for t in times[1:]:
# first find the force
for planet in suns:
planet.force = 0
for second_planet in suns:
planet.force += force(planet, second_planet)
# Update the planet(s)
for planet in suns:
update_planet(planet, planet.force, dt)
i = i + 1
print('The length of one year is ~'+str(length_of_year(suns[2], dt, tolerance=R_Earth*0.1))+' s.')
for sun in suns:
plt.plot(sun.r_array[:,0], sun.r_array[:,1], '.')
plt.xlim(-1.5*R_Earth, 1.5*R_Earth)
plt.ylim(-R_Earth, R_Earth)
plt.gca().set_aspect('equal')
plt.show()
fig, axs = plt.subplots()
xMin = 0
xMax = 0
yMin = 0
yMax = 0
for sun in suns:
xMin = min(xMin, np.min(sun.r_array[:,0]))
yMin = min(yMin, np.min(sun.r_array[:,1]))
xMax = max(xMax, np.max(sun.r_array[:,0]))
yMax = max(yMax, np.max(sun.r_array[:,1]))
axs.set_xlim(xMin, xMax)
axs.set_ylim(yMin, yMax)
plt.gca().set_aspect('equal')
axs.plot([-1,1], [0,0], color='C1', lw=2)
line, = axs.plot([], [], '.', markersize=24, lw=2)
plt.close()
anim_many = animation.FuncAnimation(fig, animate_ball_list(suns), init_func=init, frames=N, interval=20)
anim_many
# Code cell provided for calculations with values recopied from above to use.
R_Earth = 6.38e6 # m Earth's radius
M_Sun = 1.988e30 # kg
M_Earth = 5.972e24 # kg
D_avg_Earth_Sun = 1.496e11 # m The average distance between Earth and Sun
# Code cell provided for calculations with values recopied from above to use.
R_Earth = 6.38e6 # m Earth's radius
M_Sun = 1.988e30 # kg
M_Earth = 5.972e24 # kg
D_avg_Earth_Sun = 1.496e11 # m The average distance between Earth and Sun
# Code cell provided for calculations with values recopied from above to use.
R_Earth = 6.38e6 # m Earth's radius
M_Sun = 1.988e30 # kg
M_Earth = 5.972e24 # kg
M_Moon = 7.346e22 #kg
# Code cell provided for calculations with values recopied from above to use.
R_Earth = 6.38e6 # m Earth's radius
M_Sun = 1.988e30 # kg
M_Earth = 5.972e24 # kg