Gravity simulation

Let's now simulate gravity. We will simulate the movement of four planets (Mercury, Venus, Earth, and Mars), and our very own Moon, using Newton's law of universal gravitation.

Our simulation assumes the Sun at the center, but it does not draw an oval for the Sun as that would make our planets invisible at that scale. Our simulation programs shows the four planets and moon revolving in circular orbits (8.07_gravity_simulation.py):

While the system could be extended to include other planets from the solar system - putting them all on the rectangular window of our screen would not be possible as the differences in planet sizes and distances are so disproportionate that making one planet, such as Jupiter, show up would make sizes and distances of planets such as Earth  smaller than a pixel, making them invisible. So our visualization sticks to just the four relatively nearby planets and our Moon. A very insightful interactive visualization of the entire solar system, titled If the moon were only 1 pixel, can be found here: http://joshworth.com/dev/pixelspace/pixelspace_solarsystem.html.

Newton's law of gravitation established the fact that gravitation is universal and that all objects attract each other with a force of gravity that is related to the mass of the two bodies and the distance between them, using this formula:

Where:

  • F = Force of attraction between two objects 
  • m1 = Mass of object 1
  • m2 = Mass of object 2
  • d = Distance between the two objects
  • G = 6.673 x 10-11 N m2/kg2

Once the preceding equation yields us the gravitational force, we can then find the angular velocity of the object using this formula:  

The preceding formula holds true for motion in circular paths, which is somewhat an approximation of the actual motion of planets in an elliptical orbit. With angular velocity in hand, we can get the angular position (θ):

With the distance from the Sun (center) and θ in hand, we can convert it from a polar coordinate to a Cartesian coordinate as we have done in previous examples. Next, it's just a matter of drawing spheres on the Tkinter canvas at various locations.

With the formulas in hand, we define a Planet class (8.07_gravity_simulation.py):

class Planet:
sun_mass = 1.989 * math.pow(10, 30)
G = 6.67 * math.pow(10, -11)

def __init__(self, name, mass, distance, radius, color, canvas):
self.name = name
self.mass = mass
self.distance = distance
self.radius = radius
self.canvas = canvas
self.color = color
self.angular_velocity = -math.sqrt(self.gravitational_force() /
(self.mass * self.distance))
self.oval_id = self.draw_initial_planet()
self.scaled_radius = self.radius_scaler(self.radius)
self.scaled_distance = self.distance_scaler(self.distance)

While most of the preceding code is a simple instantiation of variables, note that it takes in a canvas as an input on which it will draw the planet.

We also need to scale down the planet distances and radii to fit into our window screen, so we have defined two methods in the class to scale distance and radius (8.07_gravity_simulation.py):

def distance_scaler(self, value):
#[57.91, 4497.1] scaled to [0, self.canvas.winfo_width()/2]
return (self.canvas.winfo_width() / 2 - 1) * (value - 1e10) /
(2.27e11 - 1e10) + 1

def radius_scaler(self, value):
#[2439, 6051.8] scaled to [0, self.canvas.winfo_width()/2]
return (16 * (value - 2439) / (6052 - 2439)) + 2

For scaling the distance, we take the maximum distance and scale it to fit in half of the canvas width. For scaling radius, we take the maximum and minimum radii from the first four planets and multiply them with the arbitrary number 16, so that the planets' scales look acceptable on the screen. Most of the preceding code was obtained by experimenting with what looks best on the screen, and the numbers were chosen purely arbitrarily.

The constructor then calls a method, draw_initial_planet, which creates an oval of a scaled radius and at a scaled distance on the canvas. It also returns the unique ID of the created oval so that the oval's position can be updated using the id as a handle.

We then define two helper methods using the formulas we discussed earlier:

def gravitational_force(self):
force = self.G * (self.mass * self.sun_mass) / math.pow(self.distance, 2)
return force

def angular_position(self, t):
theta = self.angular_velocity * t
return theta

Now we calculate the angular position (theta), convert it from polar to Cartesian coordinates, and update the x, y position for the oval pertaining to the planet. We also leave a 1-pixel trail for the planet's position using create_rectangle:

def update_location(self, t):
theta = self.angular_position(t)
x, y = self.coordinates(theta)
scaled_radius = self.scaled_radius
self.canvas.create_rectangle(x, y, x, y, outline="grey")
self.canvas.coords(self.oval_id, x - scaled_radius, y - scaled_radius,
x + scaled_radius, y + scaled_radius)

The code to convert from polar to Cartesian coordinates is as follows:

def coordinates(self, theta):
screen_dim = self.canvas.winfo_width()
y = self.scaled_distance * math.sin(theta) + screen_dim / 2
x = self.scaled_distance * math.cos(theta) + screen_dim / 2
return (x, y)

Next, we define a Moon class, which is similar in all aspects to the Planet class, so it inherits from the Planet class. However, the most important difference is that instead of taking distance from the Sun and the mass of the Sun as a reference, it takes distance from Earth and the mass of Earth as a reference. As scaling on actual values would have made the Moon's size smaller than 1 pixel, we have also hardcoded the scaled distance and scaled radius values for Moon to make it visible on the screen. Since Moon needs to go round Earth, we also need to pass Earth as an extra argument to the __init__ method of the Moon class (8.07_gravity_simulation.py).

Finally, we create the four planets and the Moon, passing in their actual values taken from Wikipedia:

#name,mass,distance,radius, color, canvas
mercury = Planet("Mercury", 3.302e23, 5.7e10, 2439.7, 'red2', canvas)
venus = Planet("Venus", 4.8685e24, 1.08e11, 6051.8, 'CadetBlue1', canvas)
earth = Planet("Earth", 5.973e24, 1.49e11, 6378, 'RoyalBlue1', canvas)
mars = Planet("Mars", 6.4185e23, 2.27e11, 3396, 'tomato2', canvas)
planets = [mercury, venus, earth, mars]
moon = Moon("Moon", 7.347e22, 3.844e5, 173, 'white', canvas, earth)

Then we create a Tkinter canvas and define an update_bodies_positions method that runs every 100 ms, as follows:

time = 0
time_step = 100000

def update_bodies_position():
global time, time_step
for planet in planets:
planet.update_location(time)
moon.update_location(time)
time = time + time_step
root.after(100, update_bodies_position)

That concludes the gravity simulation project. If you now go and run 8.07_gravity_simulation.py, you can see the planets and our Moon responding to gravitational force.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.7.131