Hands-on Tutorials

Simple Physics Animations Using VPython

Create a 3D physics simulation with Python and GlowScript to model the helical motion of a charged particle in a magnetic field

Zhiheng Jiang
Towards Data Science
8 min readMay 2, 2021

--

Photo by FLY:D on Unsplash

Performing physics experiments can be challenging in real life, often involving expensive yet noisy equipment. As experiments today become more complex, simulation and modelling has become an attractive new domain to generate and intepret data. This article is aimed to get you started on modelling physical systems using VPython, a 3D Python environment for simulations!

Simulating movements of charged particles in a magnetic field

Today, we are going to look at how charged particles move in a magnetic field. Electromagnetism is the study of how electric and magnetic fields interact. When charged particles move with a velocity perpendicular to the external magnetic field, it performs circular motion, as the magnetic force which is constantly perpendicular to velocity acts as the centripetal force for circular motion.

What if the velocity was not exactly perpendicular to the magnetic field? Well, that would mean that the component of velocity perpendicular to the magnetic field will continue providing centrepetal force for the charged particle to be in circular motion. On the other hand, the component of velocity parallel to the magnetic field would not experience any centrepetal acceleration nor any change in direction. Hence we would observe a helical path as shown below.

Helical motion of a charged particle in a magnetic field (Image by author)

Introduction to VPython

We are going to use VPython to recreate this physics phenomenon. VPython allows us to perform 3D visualisations of this phenomenon. We are going to be using GlowScript, which is an online code editor for VPython. You can access it here:

After you have clicked on the link, click on “Sign In” and log in using your Google Account. Then click the “here” button on the GlowScript page, and then click “Create New Program” to get started! Alternatively, you may wish to run VPython locally, in which case you will have to import the VPython module. The full VPython / Glowscript documentation can be found here.

Creating environments

Before we start dealing with any moving particles, we first have to define our workspace. The following code below shows how we can create a scene in VPython by defining the size of a canvas.

scene = display(width=1500, height=600)

Firstly, we are going to start defining the boundaries of our experiment. We will perform our experiment in an enclosed container, made of the sides of a cube. In other words, we are going to draw our own container.

xlen, ylen , zlen = 100, 100, 100
boundaries = [
box(pos = vector(0,-ylen/2,0), size = vector(xlen, .2, zlen)),
box(pos = vector(0,ylen/2,0), size = vector(xlen, .2, zlen)),
box(pos = vector(-xlen/2,0,0), size = vector(.2, ylen, zlen)),
box(pos = vector(xlen/2,0,0), size = vector(.2, ylen, zlen)),
box(pos = vector(0,0,-zlen/2), size = vector(xlen, ylen, .2))
]

Here, we standardised the length of our cube container to be 100 units. We also defined a list of boxes (i.e. cuboids) to form the sides of our container. Let’s take a look at what each of the arguments in “box” does:

  • The pos argument takes in a vector, which represents the position vector of the centers of the boxes.
  • The size argument takes in another vector, which takes in 3 values, the lengths of the box in the x, y, and z axis respectively. Note that for each box, one of the axes have a side of length 0.2 units, which represents the thickness of our container.

Hooray! Now we have a container to conduct our experiment. Before we move on to actually creating objects, let’s define a few physics constants. The meaning behind these constants will be elaborated in later sections, but it would suffice to have a rough idea of what these values do at this point.

dt = .001 #time step
Bfield = 5 #strength of magnetic field
v_mag = 20 # magnitude of velocity of proton
Q = 0.5 #charge of proton in arbitrary units
theta = pi/4 #angle of launch of proton
v = vector(v_mag*cos(theta), v_mag*sin(theta), 0) #velocity vector
B = vector(0,-Bfield,0) #vector of magnetic field
starting_point = vector(0,-ylen/2 + 1,0) #starting position vector of proton

Defining objects using Python Classes

In this next segment, we are going to use a Python Class to represent our proton travelling in a magnetic field.

class create_proton:
def __init__(self, v): #v is a vector representing velocity
self.v = v
self.proton = sphere(pos = starting_point, color = color.red, radius = 1, make_trail=True, trail_type="curve")
self.a = vector(0,0,0)

def move(self): #moves proton by small step
self.a = Q * cross(self.v, B) # F = ma = q v x B
self.v += self.a * dt #a = dv/dt
self.proton.pos += self.v * dt #v = dx/dt

def reset_proton(self): #resets proton position and path
self.proton.pos = starting_point
self.v = v
self.proton.clear_trail()
self.a = vector(0,0,0)

def check_collision(self): #checks for boundaries
if self.proton.pos.y < ylen / 2 and self.proton.pos.x < xlen/2 and self.proton.pos.y > -ylen/2 and self.proton.pos.x > -xlen/2 and self.proton.pos.z > -zlen/2 and self.proton.pos.z < zlen/2:
return True
else:
return False
proton = create_proton(v) #creates the variable 'proton'

There are 4 functions in our create_proton class above. Here are their functions:

  • __init__

This function will be called when the class is created. This sets the default velocity vector for the proton to self.v. We also create the proton, which is modelled as a sphere in VPython. We defined the radius of the proton, as well as turned on the setting to draw a trail behind the path of the proton.

  • move

This function moves the proton by a small increment at a specific point in time. The acceleration (self.a) is calculated based on the Lorentz Force Law, which states that F = Q (v x B). Hence we use the cross product of vectors v and B calculate the resultant acceleration as well as its direction. There is no need to resolve the individual components of the velocities. This is also where our time steps come into play, as we are moving the proton with a small step at a time, and we are updating the velocity and displacement gradually. Thus we multiply the small time step, dt, to the displacement and velocity of the proton.

The magnetic field is assumed to be directed downwards, based on the vector B as defined above. The initial velocity v is determined by the angle θ (theta) defined earlier as well.

  • reset_proton

This function resets all the parameters so that we can run the experiment multiple times later.

  • check_collision

If there is no collision with the walls of the container, the function returns True. If not, it returns False and the program terminates.

At this point, if you click on “Run this program”, you will see the following layout:

3D box with proton as red sphere at the bottom of the box (Image by author)

You can hold the right click of your mouse to drag the box around.

The launch function

Below we define the main launch function, which performs one instance of our experiment. First, we reset all the variables in the system, and while the proton does not collide with any of the walls of the container, we move the proton after waiting for each small time step dt. The time step is put in place to improve the efficiency of the algorithm.

def launch():
proton.reset_proton()
while proton.check_collision():
rate(1/dt) #basically a delay function
proton.move()

After that, we create a launch button so that we can press it to start the experiment. The code for the button is as follows:

button(text="Launch!", bind=launch) #link the button and function

Adjusting parameters using sliders

In any experiment, we want to be able to vary our parameters to observe trends when we do so. Sliders are extremely useful in achieving this function. For example, below is the code to adjust the magnetic field strength (B).

scene.append_to_caption("\n\n") #newlines for aesthetics
def adjustBfield():
global Bfield #to update global value
Bfield = BfieldSlider.value
B = (0,-Bfield,0) #B directed downwards
BfieldSliderReadout.text = BfieldSlider.value + " Tesla"
BfieldSlider = slider(min=0, max=10, step=.5, value=5,
bind=adjustBfield)
scene.append_to_caption(" B-field Strength = ")
BfieldSliderReadout = wtext(text="5 Tesla")

The function takes in the input from the slider and updates the magnetic field strength values in the code. When the slider is adjusted, the function adjustBfield will be called, and all the values in the code will be updated. The display of the value of B will also be updated on the screen. When creating the slider, you can also specify the range and intervals of your slider. If you wish to change any of these parameters, you can refer to the documentation for sliders here: https://www.glowscript.org/docs/VPythonDocs/controls.html.

Similar sliders can be used for the amount of charge (Q) and the angle of launch (θ), and the relevant code has been provided below.

#Adjust charge Q
scene.append_to_caption("\n\n")
def adjustQ():
global Q
Q = QSlider.value
QSliderReadout.text = QSlider.value + " Coulumbs"
QSlider = slider(min=0, max=1, step=.1, value=.5,
bind=adjustQ)
scene.append_to_caption(" Q = ")
QSliderReadout = wtext(text="0.5 Coulumbs")
#Adjust angle theta
scene.append_to_caption("\n\n")
def adjustAngle():
global theta
theta = angleSlider.value * pi / 180 #degree - radian conversion
angleSliderReadout.text = angleSlider.value + " degrees"
proton.v = vector(v_mag*cos(theta), v_mag*sin(theta), 0)


angleSlider = slider(min=0, max=90, step=1, value=45,
bind=adjustAngle)
scene.append_to_caption(" Angle = ")
angleSliderReadout = wtext(text="45 degrees")

After you have constructed the sliders, they should appear below the canvas like this:

Launch button and sliders to adjust experimental parameters (Image by author)

You can drag the sliders around to modify the parameters to vary the path of the proton.

Running the simulation

And now, you are ready to launch the proton! Click on “Run this program” and then click on the launch button that you have created. You will notice that the proton travels in a helical path, just as we have learnt earlier!

Helical path of proton (Image by author)

You can even experiment with different values using the sliders and create helixes of different radii and pitches! To try out the simulation, click here.

LEFT: Helical path with large pitch and radius; RIGHT: Helical path with small pitch and radius (Images by author)

Conclusion

That’s it for now! The 3D interface of VPython allows us to do all sorts of cool experiments and animations and is widely used in Physics simulations. VPython has many exciting applications, and this is just one of them.

Next up, you can read more on how to plot graphs using VPython (https://www.glowscript.org/docs/VPythonDocs/graph.html), which are extremely useful in generating data and observing trends from your experiments.

--

--