use crate::chemparser::chemparse;
use crate::constants::{AVOGADRO, R_ELECTRON_CM};
use crate::db::XrayDb;
use crate::elam::CrossSectionKind;
use crate::error::{Result, XrayDbError};
impl XrayDb {
pub fn material_mu(
&self,
formula: &str,
density: f64,
energies: &[f64],
kind: CrossSectionKind,
) -> Result<Vec<f64>> {
let composition = chemparse(formula)?;
let mut species = Vec::with_capacity(composition.len());
for (sym, &count) in &composition {
let molar_mass = self.molar_mass(sym)?;
species.push((sym.as_str(), count, molar_mass));
}
let total_weight: f64 = species
.iter()
.map(|(_, count, molar_mass)| count * molar_mass)
.sum();
if total_weight <= 0.0 {
return Err(XrayDbError::InvalidFormula(format!(
"zero weight formula: {formula}"
)));
}
let mut mu = vec![0.0_f64; energies.len()];
for &(sym, count, molar_mass) in &species {
let frac = count * molar_mass / total_weight;
let elem_mu = self.mu_elam(sym, energies, kind)?;
for (i, &val) in elem_mu.iter().enumerate() {
mu[i] += frac * val;
}
}
for val in &mut mu {
*val *= density;
}
Ok(mu)
}
pub fn xray_delta_beta(
&self,
formula: &str,
density: f64,
energy: f64,
) -> Result<(f64, f64, f64)> {
let composition = chemparse(formula)?;
let mut species = Vec::with_capacity(composition.len());
for (sym, &count) in &composition {
let molar_mass = self.molar_mass(sym)?;
species.push((sym.as_str(), count, molar_mass));
}
let wavelength = 1.0e-7 * crate::constants::PLANCK_HC / energy;
let total_weight: f64 = species
.iter()
.map(|(_, count, molar_mass)| count * molar_mass)
.sum();
if total_weight <= 0.0 {
return Err(XrayDbError::InvalidFormula(format!(
"zero weight formula: {formula}"
)));
}
let mut sum_f1 = 0.0_f64;
let mut sum_f2 = 0.0_f64;
for &(sym, count, _) in &species {
let z = self.atomic_number(sym)? as f64;
let f1_vals = self.f1_chantler(sym, &[energy])?;
let f2_vals = self.f2_chantler(sym, &[energy])?;
sum_f1 += count * (z + f1_vals[0]);
sum_f2 += count * f2_vals[0];
}
let prefactor = R_ELECTRON_CM * wavelength * wavelength * density * AVOGADRO
/ (2.0 * std::f64::consts::PI * total_weight);
let delta = prefactor * sum_f1;
let beta = prefactor * sum_f2;
let atlen = if beta > 0.0 {
wavelength / (4.0 * std::f64::consts::PI * beta)
} else {
f64::INFINITY
};
Ok((delta, beta, atlen))
}
}