#![forbid(unsafe_code)]
use sim_kernel::{Cx, Symbol};
use sim_lib_femm_core::FemmResult;
use sim_lib_femm_post::{QuantitySpec, quantity};
use sim_lib_femm_query::{ModelCallable, resolve_excitation};
use sim_lib_femm_sensitiv::total_gradient;
use sim_lib_femm_solve::{GradientTrust, SolveCertificate, SteadySolve};
#[derive(Clone, Debug)]
pub struct QualityAnswer {
pub value: f64,
pub certificate: SolveCertificate,
pub gradient: Option<(Vec<f64>, GradientTrust)>,
}
pub fn quality(
cx: &mut Cx,
solve: &SteadySolve,
quantity_spec: &QuantitySpec,
wrt: Option<&[Symbol]>,
) -> FemmResult<QualityAnswer> {
let excitation = resolve_excitation(cx, &solve.model, &solve.solution.params, quantity_spec)?;
let value = quantity(&solve.solution, quantity_spec, &excitation)?;
let mut certificate = solve.certificate.clone();
let gradient = match wrt {
None => None,
Some(params) => {
let callable = ModelCallable {
model: solve.model.clone(),
};
let mut solve_for_gradient = SteadySolve {
model: solve.model.clone(),
solution: solve.solution.clone(),
factor: solve.factor.clone(),
certificate: solve.certificate.clone(),
};
let result = total_gradient(
cx,
&callable,
&mut solve_for_gradient,
std::slice::from_ref(quantity_spec),
params,
)?;
let values = result.gradient.into_iter().next().unwrap_or_default();
let trust = result
.trust
.into_iter()
.next()
.unwrap_or(GradientTrust::FiniteDifferenceOnly);
certificate.set_gradient_trust(trust.clone());
Some((values, trust))
}
};
Ok(QualityAnswer {
value,
certificate,
gradient,
})
}