BorisStepper
Electromagnetic particle stepper method implementing the Boris Algorithm.
Results of the verification of the BorisStepper can be found in Gall et al. (2024).
In magnetized (or electromagnetic) PIC simulations, the de facto standard particle stepping algorithm is commonly known as the Boris algorithm Boris and others (1970), Birdsall and Langdon (1991), and Qin et al. (2013). This algorithm is similar to a Leap Frog method and has second order accuracy in time when solving the equations of motion for a charged particle, given by
(1)
and
(2)
where is the particle's charge, is the particle's mass, and and are the electric and magnetic fields that the particle is subject to, respectively.
In the Boris algorithm, \cref{eq:pos,eq:vel} are discretized with a central difference scheme and the acceleration due to the electric field and magnetic field are separated. First, half of the impulse due to the electric field is applied to the particle, as
(3)
where is an intermediate particle velocity, is the particle velocity at step , and is the electric field at step . The velocity of the particle after rotation due to the magnetic field is derived as
(4)
with
(5)
where
(6)
which accounts for the effect of , the magnetic field at step . is defined as
(7)
Finally, the rotation due to the presence of the magnetic field is then applied with
(8)
and the final impulse due to the electric field is then applied to the particle using
(9)
The implementation of the Boris algorithm was verified using several single particle motion tests: constant electric field ((test/tests/userobjects/particle_stepper/boris_stepper/boris_parallel_acceleration.i), (test/tests/userobjects/particle_stepper/boris_stepper/boris_projectile_motion.i)), cyclotron motion ((test/tests/userobjects/particle_stepper/boris_stepper/cyclotron_motion.i)), and drift motion ((test/tests/userobjects/particle_stepper/boris_stepper/e_cross_b.i)).
[UserObjects<<<{"href": "../../syntax/UserObjects/index.html"}>>>]
[stepper]
type = BorisStepper<<<{"description": "Electromagnetic particle stepper method implementing the Boris Algorithm.", "href": "BorisStepper.html"}>>>
efield_components<<<{"description": "A list of 3 variables which represent the 3 components of the electric field"}>>> = 'Ex Ey Ez'
bfield_components<<<{"description": "A list of 3 variables which represent the 3 components of the electric field"}>>> = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 1 0'
start_velocities = '1 0 0'
mass = 1
weight = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
(test/tests/userobjects/particle_stepper/boris_stepper/cyclotron_motion.i)(test/tests/userobjects/particle_stepper/boris_stepper/boris_parallel_acceleration.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 120
ny = 20
xmax = 120
ymax = 20
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '5e-7'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '0'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 10.5 0'
start_velocities = '0 0 0'
mass = 9.1093837015e-31
charge = 1.602176634e-19
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-4
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
file_base = 'parallel_acceleration_rays'
[]
(test/tests/userobjects/particle_stepper/boris_stepper/boris_projectile_motion.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 25
ny = 7
xmax = 22
ymax = 7
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0'
[]
[E_y_ic]
type = ParsedFunction
expression = '-9.81'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '0'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 0 0'
start_velocities = '10 10 0'
mass = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-2
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check = false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
file_base = 'projectile_motion_rays'
[]
(test/tests/userobjects/particle_stepper/boris_stepper/cyclotron_motion.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 5
ny = 5
xmin = -2
xmax = 2
ymin = -2
ymax = 2
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '1'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 1 0'
start_velocities = '1 0 0'
mass = 1
weight = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-1
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
[]
(test/tests/userobjects/particle_stepper/boris_stepper/e_cross_b.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 20
ny = 20
xmin = -2
xmax = 30
ymin = -20
ymax = 20
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0.05'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '1'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 1 0'
start_velocities = '1 0 0'
mass = 1
weight = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-1
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
[]
(test/tests/userobjects/particle_stepper/boris_stepper/cyclotron_motion.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 5
ny = 5
xmin = -2
xmax = 2
ymin = -2
ymax = 2
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '1'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 1 0'
start_velocities = '1 0 0'
mass = 1
weight = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-1
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
[]
(test/tests/userobjects/particle_stepper/boris_stepper/cyclotron_motion.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 5
ny = 5
xmin = -2
xmax = 2
ymin = -2
ymax = 2
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '1'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 1 0'
start_velocities = '1 0 0'
mass = 1
weight = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-1
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
[]
(test/tests/userobjects/particle_stepper/boris_stepper/boris_parallel_acceleration.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 120
ny = 20
xmax = 120
ymax = 20
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '5e-7'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '0'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 10.5 0'
start_velocities = '0 0 0'
mass = 9.1093837015e-31
charge = 1.602176634e-19
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-4
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
file_base = 'parallel_acceleration_rays'
[]
(test/tests/userobjects/particle_stepper/boris_stepper/boris_projectile_motion.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 25
ny = 7
xmax = 22
ymax = 7
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0'
[]
[E_y_ic]
type = ParsedFunction
expression = '-9.81'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '0'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 0 0'
start_velocities = '10 10 0'
mass = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-2
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check = false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
file_base = 'projectile_motion_rays'
[]
(test/tests/userobjects/particle_stepper/boris_stepper/e_cross_b.i)
[Mesh/gmg]
type = GeneratedMeshGenerator
dim = 2
nx = 20
ny = 20
xmin = -2
xmax = 30
ymin = -20
ymax = 20
[]
[Variables]
[Ex]
[]
[Ey]
[]
[Ez]
[]
[Bx]
[]
[By]
[]
[Bz]
[]
[]
[Functions]
[E_x_ic]
type = ParsedFunction
expression = '0.05'
[]
[E_y_ic]
type = ParsedFunction
expression = '0'
[]
[E_z_ic]
type = ParsedFunction
expression = '0'
[]
[B_x_ic]
type = ParsedFunction
expression = '0'
[]
[B_y_ic]
type = ParsedFunction
expression = '0'
[]
[B_z_ic]
type = ParsedFunction
expression = '1'
[]
[]
[ICs]
[Ex_ic]
type = FunctionIC
variable = Ex
function = E_x_ic
[]
[Ey_ic]
type = FunctionIC
variable = Ey
function = E_y_ic
[]
[Ez_ic]
type = FunctionIC
variable = Ez
function = E_z_ic
[]
[Bx_ic]
type = FunctionIC
variable = Bx
function = B_x_ic
[]
[By_ic]
type = FunctionIC
variable = By
function = B_y_ic
[]
[Bz_ic]
type = FunctionIC
variable = Bz
function = B_z_ic
[]
[]
[UserObjects]
[stepper]
type = BorisStepper
efield_components = 'Ex Ey Ez'
bfield_components = 'Bx By Bz'
[]
[initializer]
type = TestPlacedParticleInitializer
start_points = '0 1 0'
start_velocities = '1 0 0'
mass = 1
weight = 1
charge = 1
[]
[study]
type = TestInitializedPICStudy
stepper = stepper
initializer = initializer
use_custom_rayids = false
always_cache_traces = true
data_on_cache_traces = true
execute_on = 'TIMESTEP_BEGIN'
[]
[]
[RayKernels]
[null]
type = NullRayKernel
[]
[]
[Executioner]
type = Transient
dt = 1e-1
num_steps = 10
[]
[Problem]
solve = false
kernel_coverage_check=false
[]
[Outputs/rays]
type = RayTracingExodus
study = study
output_data_names='v_x v_y v_z charge mass'
execute_on = TIMESTEP_BEGIN
[]