///|
pub(all) struct BoundaryBatchResult {
alive : Array[Particle]
absorbed : Int
reflected : Int
wrapped : Int
} derive(Debug, ToJson)
///|
pub fn apply_particle_boundary_batch(
grid : Grid1D,
boundary : Boundary1D,
particles : ArrayView[Particle],
) -> BoundaryBatchResult {
let alive : Array[Particle] = []
let mut absorbed = 0
let mut reflected = 0
let mut wrapped = 0
for particle in particles {
let result = apply_boundary(grid, boundary, particle.x, particle.v)
if result.alive {
if boundary == Reflecting && result.v != particle.v {
reflected = reflected + 1
}
if boundary == Periodic && result.x != particle.x {
wrapped = wrapped + 1
}
alive.push(
Particle::new(
x=result.x,
v=result.v,
weight=particle.weight,
charge=particle.charge,
mass=particle.mass,
),
)
} else {
absorbed = absorbed + 1
}
}
{ alive, absorbed, reflected, wrapped }
}
///|
pub fn boundary_loss_fraction(
result : BoundaryBatchResult,
original_count : Int,
) -> Double {
safe_ratio(result.absorbed.to_double(), original_count.to_double(), 0.0)
}
///|
pub fn boundary_reflection_fraction(
result : BoundaryBatchResult,
original_count : Int,
) -> Double {
safe_ratio(result.reflected.to_double(), original_count.to_double(), 0.0)
}
///|
pub fn boundary_wrap_fraction(
result : BoundaryBatchResult,
original_count : Int,
) -> Double {
safe_ratio(result.wrapped.to_double(), original_count.to_double(), 0.0)
}
///|
pub fn reflect_position(grid : Grid1D, x : Double) -> Double {
let mut result = x
let mut passes = 0
while (result < 0.0 || result >= grid.length) && passes < 16 {
if result < 0.0 {
result = -result
} else {
result = 2.0 * grid.length - result
}
passes = passes + 1
}
clamp(result, 0.0, grid.length)
}
///|
pub fn apply_reflecting_position(
grid : Grid1D,
x : Double,
v : Double,
) -> (Double, Double) {
let result = apply_boundary(grid, Reflecting, x, v)
(result.x, result.v)
}
///|
pub fn boundary_valid(grid : Grid1D, particles : ArrayView[Particle]) -> Bool {
let mut valid = true
for particle in particles {
if particle.x < 0.0 || particle.x >= grid.length {
valid = false
}
}
valid
}
///|
pub fn boundary_positions(
grid : Grid1D,
particles : ArrayView[Particle],
) -> Array[Double] {
particles.map(fn(particle) { grid.wrap(particle.x) })
}
///|
pub fn boundary_velocity_flux(
grid : Grid1D,
particles : ArrayView[Particle],
) -> Double {
let mut flux = 0.0
for particle in particles {
if particle.x < 0.0 || particle.x >= grid.length {
flux = flux + particle.v * particle.weight
}
}
flux
}