def boris_algorithm(v0, Bp, Ep, dt, idx): '''Updates the velocities of the particles in the simulation using a Boris particle pusher, as detailed in Birdsall & Langdon (1985), 59-63. INPUT: v0 -- Original particle velocity B -- Magnetic field value at particle position E -- Electric field value at particle position dt -- Simulation time cadence idx -- Particle species identifier OUTPUT: v0 -- Updated particle velocity (overwrites input value on return) DOES SINGLE PARTICLE (NEW FUNCTION) ''' T = (charge[idx] * Bp / mass[idx]) * dt / 2. # Boris variable S = 2. * T / (1. + T[0]**2 + T[1]**2 + T[2]**2) # Boris variable v_minus = v0 + charge[idx] * Ep * dt / (2. * mass[idx]) v_prime = v_minus + cross_product_single(v_minus, T) v_plus = v_minus + cross_product_single(v_prime, S) v0 = v_plus + charge[idx] * Ep * dt / (2. * mass[idx]) return v0
def two_part_velocity_update(part, B, E, dt): ''' Backup velocity update from Matthews (1994), just in case Boris isn't compatible with it. Advances velocity full timestep by first approximating half timestep. ''' W_magnetic = assign_weighting(part[0, :], part[1, :], 0) # Magnetic field weighting for jj in range(Nj): for nn in range(idx_bounds[jj, 0], idx_bounds[jj, 1]): I = int(part[1, nn]) # Nearest (leftmost) node, I Ib = int(part[0, nn] / dx) # Nearest (leftmost) magnetic node We = part[2, nn] # E-field weighting Wb = W_magnetic[nn] # B-field weighting idx = jj # Particle species identifier Ep = E[I, 0:3] * ( 1 - We) + E[I + 1, 0:3] * We # E-field at particle location Bp = B[Ib, 0:3] * ( 1 - Wb) + B[Ib + 1, 0:3] * Wb # B-field at particle location fac = 0.5 * dt * charge[idx] / mass[idx] v_half = part[3:6] + fac * (Ep + cross_product_single(part[3:6], Bp)) part[3:6] += 2 * fac * (Ep + cross_product_single(v_half, Bp)) return part
def velocity_update(vel, Ie, W_elec, Ib, W_mag, idx, B, E, dt): ''' Interpolates the fields to the particle positions using TSC weighting, then updates velocities using a Boris particle pusher. Based on Birdsall & Langdon (1985), pp. 59-63. INPUT: part -- Particle array containing velocities to be updated B -- Magnetic field on simulation grid EIb, W_mag = assign_weighting_TSC(pos, E_nodes=False) -- Electric field on simulation grid dt -- Simulation time cadence W -- Weighting factor of particles to rightmost node OUTPUT: vel -- Returns particle array with updated velocities ''' Ep = E[Ie , 0:3] * W_elec[0] \ + E[Ie + 1, 0:3] * W_elec[1] \ + E[Ie + 2, 0:3] * W_elec[2] # E-field at particle location Bp = B[Ib , 0:3] * W_mag[0] \ + B[Ib + 1, 0:3] * W_mag[1] \ + B[Ib + 2, 0:3] * W_mag[2] # B-field at particle location T = (charge[idx] * Bp / mass[idx]) * dt / 2. # Boris variable S = 2. * T / (1. + T[0]**2 + T[1]**2 + T[2]**2) # Boris variable v_minus = vel + charge[idx] * Ep * dt / (2. * mass[idx]) v_prime = v_minus + aux.cross_product_single(v_minus, T) v_plus = v_minus + aux.cross_product_single(v_prime, S) vel = v_plus + charge[idx] * Ep * dt / (2. * mass[idx]) return vel
def two_step_algorithm(v0, Bp, Ep, dt, idx): fac = 0.5 * dt * charge[idx] / mass[idx] v_half = v0 + fac * (Ep + aux.cross_product_single(v0, Bp)) v0 += 2 * fac * (Ep + aux.cross_product_single(v_half, Bp)) return v0