Computing Library › Worked Examples
Worked Examples

A Particle-in-Cell Push-and-Weight Step

Advance one macro-particle with the Boris rotation, deposit its charge to the grid, and see the core loop of a PIC plasma code.

Problem

Particle-in-cell (PIC) codes track many macro-particles moving in fields defined on a grid. Each step interpolates fields to particle positions, pushes velocities and positions, then weights (deposits) charge and current back to the grid to update the fields. We work one push-and-weight cycle.

Boris push

Kronos motion — hero particle loop

The Boris algorithm advances velocity in a magnetic field by a half electric kick, a magnetic rotation, and a second half kick. It conserves energy in a static B field exactly, which naive integrators do not, making it the standard PIC pusher.

python
import numpy as np
q,m,dt=1.0,1.0,0.1
x=np.array([0.3]); v=np.array([1.0,0.5,0.0])
E=np.array([0.1,0.0,0.0]); B=np.array([0.0,0.0,1.0])
vm=v+ (q*E/m)*(dt/2)                 # half E kick
t=(q*B/m)*(dt/2); s=2*t/(1+t@t)
vp=vm+np.cross(vm+np.cross(vm,t),s)  # rotation
v=vp+(q*E/m)*(dt/2)                  # half E kick
x=x+v[0]*dt
# linear weighting to two nearest grid nodes (grid spacing 1)
i=int(np.floor(x)); f=x-i
rho={i:q*(1-f)[0], i+1:q*f[0]}
print('new v',np.round(v,3),'charge to nodes',{k:round(val,3) for k,val in rho.items()})

Result

The magnetic term rotates the velocity vector without changing its magnitude, while the electric kicks add energy. Linear weighting splits the particle's charge between the two nearest grid nodes in proportion to distance, so a particle at fraction f from node i deposits (1-f) to node i and f to node i+1. Summing over all particles gives the charge density that feeds the field solve.