use nucleide_material::Material;
use nucleide_nuclei::dialects::to_zaid;
use crate::{Code, EmitOptions, Emitted, Error, Result};
pub fn emit_serpent(mat: &Material, opts: &EmitOptions) -> Result<Emitted> {
let density = opts.density_for(mat)?;
let fracs = mat.weight_fractions().map_err(|_| Error::Degenerate)?;
let mut accounted = Vec::with_capacity(fracs.len());
let mut text = format!("mat {} {}\n", opts.name, -density);
for (id, w) in &fracs {
text.push_str(&format!(" {}.{} {}\n", to_zaid(*id), opts.serpent_lib, -w));
accounted.push((*id, mat.comp.get(id).copied().unwrap_or(0.0)));
}
Ok(Emitted {
code: Code::Serpent,
text,
accounted,
dropped: Vec::new(),
reparsed: false,
})
}
#[cfg(test)]
mod tests {
use super::*;
use nucleide_nuclei::NuclideId;
#[test]
fn serpent_card_shape() {
let mut mat = Material::new();
mat.add_nuclide(NuclideId::from_name("U235").unwrap(), 5.0);
mat.add_nuclide(NuclideId::from_name("U238").unwrap(), 95.0);
let opts = EmitOptions::new("leu").with_density(10.0);
let out = emit_serpent(&mat, &opts).unwrap();
assert!(out.text.starts_with("mat leu -10\n"));
assert!(out.text.contains("92235.03c -0.05"));
assert!(out.text.contains("92238.03c -0.95"));
assert!(!out.reparsed);
assert!((out.mass_out() - 100.0).abs() < 1e-12);
}
#[test]
fn serpent_needs_density() {
let mut mat = Material::new();
mat.add_nuclide(NuclideId::from_name("U235").unwrap(), 1.0);
let opts = EmitOptions::new("leu");
assert!(matches!(
emit_serpent(&mat, &opts),
Err(Error::MissingDensity)
));
}
}