///|
pub(all) struct VlasovStepReport {
before_mass : Double
after_mass : Double
mass_error : Double
minimum : Double
maximum : Double
time : Double
} derive(Debug, ToJson)
///|
pub fn vlasov_advect_x(state : VlasovState, velocity : Double) -> VlasovState {
let shift = velocity * state.config.dt
vlasov_shift_distribution(state, shift)
}
///|
pub fn vlasov_clip_negative(state : VlasovState) -> VlasovState {
let distribution = distribution_positive_part(state)
{
..state,
distribution,
charge_density: vlasov_density(state.config, distribution),
}
}
///|
pub fn vlasov_rescale_mass(state : VlasovState, target : Double) -> VlasovState {
let current = distribution_integral(state)
if current == 0.0 {
state
} else {
let factor = target / current
let distribution = state.distribution.map(fn(value) { value * factor })
{
..state,
distribution,
charge_density: vlasov_density(state.config, distribution),
}
}
}
///|
pub fn vlasov_step_report(state : VlasovState) -> VlasovStepReport {
let next = state.step()
let before_mass = distribution_integral(state)
let after_mass = distribution_integral(next)
{
before_mass,
after_mass,
mass_error: (after_mass - before_mass).abs(),
minimum: distribution_minimum(next),
maximum: distribution_maximum(next),
time: next.time,
}
}
///|
pub fn vlasov_run_reports(
state : VlasovState,
steps : Int,
) -> Array[VlasovStepReport] {
let reports : Array[VlasovStepReport] = []
let mut current = state
for _ in 0.. VlasovState {
vlasov_rescale_mass(state, reference_mass)
}
///|
pub fn vlasov_charge_from_density(
_state : VlasovState,
density : ArrayView[Double],
) -> Array[Double] {
density.map(fn(value) { -elementary_charge * value })
}
///|
pub fn vlasov_distribution_difference(
first : VlasovState,
second : VlasovState,
) -> Array[Double] {
let output = zeros(first.distribution.length())
for i in 0.. Double {
l2_norm(vlasov_distribution_difference(first, second))
}
///|
pub fn vlasov_report_to_csv(reports : ArrayView[VlasovStepReport]) -> String {
let output = StringBuilder()
output.write_string(
"before_mass,after_mass,mass_error,minimum,maximum,time\n",
)
for report in reports {
output.write_string(
"\{report.before_mass},\{report.after_mass},\{report.mass_error},\{report.minimum},\{report.maximum},\{report.time}\n",
)
}
output.to_string()
}
///|
pub fn vlasov_cfl(config : VlasovConfig) -> Double {
let max_velocity = config.velocity_min.abs().max(config.velocity_max.abs())
safe_ratio(config.grid.dx, max_velocity, 0.0)
}
///|
pub fn vlasov_is_positive(state : VlasovState) -> Bool {
distribution_minimum(state) >= 0.0
}
///|
pub fn vlasov_is_normalized(
state : VlasovState,
expected : Double,
tolerance : Double,
) -> Bool {
(distribution_integral(state) - expected).abs() <= tolerance
}