///|
pub(all) struct EnsembleMember {
id : Int
seed : Int
diagnostics : Array[PicDiagnostics]
} derive(Debug, ToJson)
///|
pub(all) struct EnsembleSummary {
members : Int
mean_final_energy : Double
spread_final_energy : Double
mean_charge_error : Double
maximum_particle_loss : Int
} derive(Debug, ToJson)
///|
pub fn run_ensemble(
scenario : SimulationScenario,
members : Int,
) -> Array[EnsembleMember] {
let output : Array[EnsembleMember] = []
for id in 0.. Array[Double] {
members.map(fn(item) {
if item.diagnostics.length() == 0 {
0.0
} else {
item.diagnostics[item.diagnostics.length() - 1].total_energy()
}
})
}
///|
pub fn ensemble_charge_errors(
members : ArrayView[EnsembleMember],
) -> Array[Double] {
members.map(fn(item) {
if item.diagnostics.length() < 2 {
0.0
} else {
(item.diagnostics[0].total_charge -
item.diagnostics[item.diagnostics.length() - 1].total_charge).abs()
}
})
}
///|
pub fn ensemble_particle_losses(
members : ArrayView[EnsembleMember],
) -> Array[Int] {
members.map(fn(item) {
if item.diagnostics.length() < 2 {
0
} else {
item.diagnostics[0].particles -
item.diagnostics[item.diagnostics.length() - 1].particles
}
})
}
///|
pub fn summarize_ensemble(
members : ArrayView[EnsembleMember],
) -> EnsembleSummary {
let energies = ensemble_final_energies(members)
let charges = ensemble_charge_errors(members)
let losses = ensemble_particle_losses(members)
{
members: members.length(),
mean_final_energy: mean(energies),
spread_final_energy: sample_span(energies),
mean_charge_error: mean(charges),
maximum_particle_loss: losses.fold(init=0, fn(acc, value) { acc.max(value) }),
}
}
///|
pub fn ensemble_summary_to_csv(summary : EnsembleSummary) -> String {
"members,mean_final_energy,spread_final_energy,mean_charge_error,maximum_particle_loss\n\{summary.members},\{summary.mean_final_energy},\{summary.spread_final_energy},\{summary.mean_charge_error},\{summary.maximum_particle_loss}\n"
}
///|
pub fn ensemble_diagnostics_to_csv(
members : ArrayView[EnsembleMember],
) -> String {
let output = StringBuilder()
output.write_string("member,step,time,particles,total_charge,total_energy\n")
for ensemble_item in members {
for i in 0.. Bool {
summary.mean_charge_error <= charge_tolerance &&
summary.spread_final_energy <= energy_spread_tolerance
}