///|
pub fn push_particle(
grid : Grid1D,
particle : Particle,
electric~ : Double,
dt~ : Double,
) -> Particle {
let acceleration = particle.charge * electric / particle.mass
let next_velocity = particle.v + acceleration * dt
Particle::new(
x=grid.wrap(particle.x + next_velocity * dt),
v=next_velocity,
weight=particle.weight,
charge=particle.charge,
mass=particle.mass,
)
}
///|
pub fn stable_pic_dt(
grid : Grid1D,
maximum_speed : Double,
safety_factor : Double,
) -> Double {
if maximum_speed <= 0.0 || safety_factor <= 0.0 {
0.0
} else {
safety_factor * grid.dx / maximum_speed
}
}
///|
pub fn kinetic_temperature(particles : ArrayView[Particle]) -> Double {
let variance = velocity_variance(particles)
if particles.length() == 0 {
0.0
} else {
let mass = particles[0].mass
mass * variance / boltzmann_constant
}
}
///|
pub fn advance_particles(
grid : Grid1D,
particles : ArrayView[Particle],
electric : ArrayView[Double],
dt : Double,
) -> Array[Particle] {
particles.map(fn(particle) {
let field = sample_linear(grid, electric, particle.x)
push_particle(grid, particle, electric=field, dt~)
})
}
///|
pub fn particle_speed_range(
particles : ArrayView[Particle],
) -> (Double, Double) {
if particles.length() == 0 {
(0.0, 0.0)
} else {
let mut minimum = particles[0].v
let mut maximum = particles[0].v
for particle in particles {
if particle.v < minimum {
minimum = particle.v
}
if particle.v > maximum {
maximum = particle.v
}
}
(minimum, maximum)
}
}