Note
Go to the end to download the full example code
Motion of a charged particle in a combined magnetic and electric field#
A charged particle follows a curved path in a magnetic field. In an electric field, the particle tends to accelerate in a direction parallel/antiparallel to the electric field depending on the nature of charge on the particle. In a combined electric and magnetic field, the particle moves along a helical path.
In this animation, there’s a magnetic and an electric field present in +x direction under whose influence the positively charged particle follows a helical path.
Importing necessary modules
import itertools
import numpy as np
import fury
Let’s define some variable and their description:
radius_particle: radius of the point that will represent the particle (default = 0.08)
initial_velocity: initial velocity of the particle along +x (default = 0.09)
acc: acceleration of the particle along +x (due to the electric field) (default = 0.004)
time: time (default time i.e. time at beginning of the animation = 0)
incre_time: value by which time is incremented for each call of timer_callback (default = 0.09)
angular_frq: angular frequency (default = 0.1)
phase_angle: phase angle (default = 0.002)
radius_particle = 0.08
initial_velocity = 0.09
acc = 0.004
time = 0
incre_time = 0.09
angular_frq = 0.1
phase_angle = 0.002
Creating a scene object and configuring the camera’s position
scene = fury.window.Scene()
scene.zoom(1.2)
scene.set_camera(
position=(10, 12.5, 19), focal_point=(3.0, 0.0, 0.0), view_up=(0.0, 0.0, 0.0)
)
showm = fury.window.ShowManager(
scene, size=(800, 600), reset_camera=True, order_transparent=True
)
/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/sphinx_gallery/gen_rst.py:722: UserWarning: We'll no longer accept the way you call the __init__ function in future versions of FURY.
Here's how to call the Function __init__: __init__(self_value, scene='value', title='value', size='value', png_magnify='value', reset_camera='value', order_transparent='value', interactor_style='value', stereo='value', multi_samples='value', max_peels='value', occlusion_ratio='value')
exec(self.code, self.fake_main.__dict__)
Creating a blue colored arrow which shows the direction of magnetic field and electric field.
color_arrow = fury.window.colors.blue # color of the arrow can be manipulated
centers = np.array([[0, 0, 0]])
directions = np.array([[1, 0, 0]])
heights = np.array([8])
arrow_actor = fury.actor.arrow(
centers,
directions,
color_arrow,
heights,
resolution=20,
tip_length=0.06,
tip_radius=0.012,
shaft_radius=0.005,
)
scene.add(arrow_actor)
/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/sphinx_gallery/gen_rst.py:722: UserWarning: We'll no longer accept the way you call the arrow function in future versions of FURY.
Here's how to call the Function arrow: arrow(centers_value, directions_value, colors_value, heights='value', resolution='value', tip_length='value', tip_radius='value', shaft_radius='value', scales='value', vertices='value', faces='value', repeat_primitive='value')
exec(self.code, self.fake_main.__dict__)
Initializing the initial coordinates of the particle
x = initial_velocity * time + 0.5 * acc * (time**2)
y = np.sin(angular_frq * time + phase_angle)
z = np.cos(angular_frq * time + phase_angle)
Initializing point actor which will represent the charged particle
color_particle = fury.window.colors.red # color of particle can be manipulated
pts = np.array([[x, y, z]])
charge_actor = fury.actor.point(pts, color_particle, point_radius=radius_particle)
scene.add(charge_actor)
vertices = fury.utils.vertices_from_actor(charge_actor)
vcolors = fury.utils.colors_from_actor(charge_actor, "colors")
no_vertices_per_point = len(vertices)
initial_vertices = vertices.copy() - np.repeat(pts, no_vertices_per_point, axis=0)
/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/sphinx_gallery/gen_rst.py:722: UserWarning: We'll no longer accept the way you call the colors_from_actor function in future versions of FURY.
Here's how to call the Function colors_from_actor: colors_from_actor(actor_value, array_name='value', as_vtk='value')
exec(self.code, self.fake_main.__dict__)
Initializing text box to display the name of the animation
Initializing counter
end is used to decide when to end the animation
end = 200
This will be useful for plotting path of the particle
Coordinates to be plotted are changed every time timer_callback is called by using the update_coordinates function. The wave is rendered here.
def timer_callback(_obj, _event):
global pts, time, incre_time, coor_1
time += incre_time
cnt = next(counter)
x = initial_velocity * time + 0.5 * acc * (time**2)
y = np.sin(10 * angular_frq * time + phase_angle)
z = np.cos(10 * angular_frq * time + phase_angle)
pts = np.array([[x, y, z]])
vertices[:] = initial_vertices + np.repeat(pts, no_vertices_per_point, axis=0)
fury.utils.update_actor(charge_actor)
# Plotting the path followed by the particle
coor_2 = np.array([x, y, z])
coors = np.array([coor_1, coor_2])
coors = [coors]
line_actor = fury.actor.line(coors, fury.window.colors.cyan, linewidth=3)
scene.add(line_actor)
coor_1 = coor_2
showm.render()
# to end the animation
if cnt == end:
showm.exit()
Run every 15 milliseconds
showm.add_timer_callback(True, 15, timer_callback)
showm.start()
fury.window.record(showm.scene, size=(800, 600), out_path="viz_helical_motion.png")
/Users/skoudoro/devel/fury/fury/window.py:561: UserWarning: We'll no longer accept the way you call the line function in future versions of FURY.
Here's how to call the Function line: line(lines_value, colors='value', opacity='value', linewidth='value', spline_subdiv='value', lod='value', lod_points='value', lod_points_size='value', lookup_colormap='value', depth_cue='value', fake_tube='value')
self.iren.Start()
/opt/homebrew/Caskroom/miniforge/base/envs/py311-fury/lib/python3.11/site-packages/sphinx_gallery/gen_rst.py:722: UserWarning: We'll no longer accept the way you call the record function in future versions of FURY.
Here's how to call the Function record: record(scene='value', cam_pos='value', cam_focal='value', cam_view='value', out_path='value', path_numbering='value', n_frames='value', az_ang='value', magnification='value', size='value', reset_camera='value', screen_clip='value', stereo='value', verbose='value')
exec(self.code, self.fake_main.__dict__)
Total running time of the script: (1 minutes 9.878 seconds)