///|
pub(all) struct PicQuality {
finite : Bool
nonnegative_density : Bool
energy_drift : Double
charge_error : Double
} derive(Debug, ToJson)
///|
pub fn relative_energy_drift(initial : Double, ending : Double) -> Double {
if initial == 0.0 {
(ending - initial).abs()
} else {
(ending - initial).abs() / initial.abs()
}
}
///|
pub fn distribution_is_nonnegative(distribution : ArrayView[Double]) -> Bool {
for value in distribution {
if value < 0.0 || value != value {
return false
}
}
true
}
///|
pub fn distribution_mass_error(
config : VlasovConfig,
left : ArrayView[Double],
right : ArrayView[Double],
) -> Double {
(distribution_sum(config, left) - distribution_sum(config, right)).abs()
}
///|
fn array_is_finite(values : ArrayView[Double]) -> Bool {
for value in values {
if value != value || value.abs() > 1.0e300 {
return false
}
}
true
}
///|
pub fn assess_pic_quality(state : PicState) -> PicQuality {
let density = particle_number_density(state.grid, state.particles)
let finite = array_is_finite(density) &&
array_is_finite(state.field.electric) &&
array_is_finite(state.field.potential) &&
state.time == state.time
let energy = kinetic_energy(state.particles) + field_energy(state.field)
{
finite,
nonnegative_density: distribution_is_nonnegative(density),
energy_drift: relative_energy_drift(energy, energy),
charge_error: total_charge(state.grid, state.field.charge_density).abs(),
}
}