use super::CommonArgs;
use crate::StrError;
use russell_lab::Vector;
pub fn vec_02_nv<F>(b: &mut Vector, args: &mut CommonArgs, mut fn_v: F) -> Result<(), StrError>
where
F: FnMut(&mut Vector, usize, &Vector) -> Result<(), StrError>,
{
let (space_ndim, nnode) = args.pad.xxt.dims();
let ii0 = args.ii0;
if b.dim() < ii0 + nnode * space_ndim {
return Err("b.len() must be ≥ ii0 + nnode ⋅ space_ndim");
}
let mut v = Vector::new(space_ndim);
if args.clear {
b.fill(0.0);
}
for p in 0..args.gauss.npoint() {
let iota = args.gauss.coords(p);
let weight = args.gauss.weight(p);
(args.pad.fn_interp)(&mut args.pad.interp, iota); let det_jac = args.pad.calc_jacobian(iota)?;
let nn = &args.pad.interp;
fn_v(&mut v, p, nn)?;
let coef = if args.axisymmetric {
let mut r = 0.0; for m in 0..nnode {
r += nn[m] * args.pad.xxt.get(0, m);
}
det_jac * weight * args.alpha * r
} else {
det_jac * weight * args.alpha
};
if space_ndim == 2 {
for m in 0..nnode {
b[ii0 + 0 + m * 2] += coef * nn[m] * v[0];
b[ii0 + 1 + m * 2] += coef * nn[m] * v[1];
}
} else {
for m in 0..nnode {
b[ii0 + 0 + m * 3] += coef * nn[m] * v[0];
b[ii0 + 1 + m * 3] += coef * nn[m] * v[1];
b[ii0 + 2 + m * 3] += coef * nn[m] * v[2];
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::integ::testing::aux;
use crate::integ::{self, AnalyticalTet4, AnalyticalTri3, CommonArgs, Gauss};
use crate::recovery;
use russell_lab::{vec_approx_eq, Vector};
#[test]
fn capture_some_errors() {
let mut pad = aux::gen_pad_lin2(1.0);
let mut b = Vector::new(4);
let mut v = Vector::new(0);
let nn = Vector::new(0);
let f = |_v: &mut Vector, _p: usize, _nn: &Vector| Ok(());
f(&mut v, 0, &nn).unwrap();
let gauss = Gauss::new(pad.kind);
let mut args = CommonArgs::new(&mut pad, &gauss);
args.ii0 = 1;
assert_eq!(
integ::vec_02_nv(&mut b, &mut args, f).err(),
Some("b.len() must be ≥ ii0 + nnode ⋅ space_ndim")
);
}
#[test]
fn lin2_linear_works() {
const L: f64 = 6.0;
let mut pad = aux::gen_pad_lin2(L);
let cf = L / 6.0;
let (xa, xb) = (pad.xxt.get(0, 0), pad.xxt.get(0, 1));
let b_correct = &[
cf * (2.0 * xa + xb),
cf * (2.0 * xa + xb),
cf * (xa + 2.0 * xb),
cf * (xa + 2.0 * xb),
];
let class = pad.kind.class();
let tolerances = [1e-14, 1e-14];
let selection: Vec<_> = [2, 3].iter().map(|n| Gauss::new_sized(class, *n).unwrap()).collect();
let (space_ndim, nnode) = pad.xxt.dims();
let mut b = Vector::filled(nnode * space_ndim, aux::NOISE);
selection.iter().zip(tolerances).for_each(|(ips, tol)| {
let x_ips = recovery::get_points_coords(&mut pad, ips).unwrap();
let mut args = CommonArgs::new(&mut pad, ips);
integ::vec_02_nv(&mut b, &mut args, |v, p, _| {
v[0] = x_ips[p][0];
v[1] = x_ips[p][0]; Ok(())
})
.unwrap();
vec_approx_eq(&b, b_correct, tol);
});
}
#[test]
fn tri3_constant_works() {
let mut pad = aux::gen_pad_tri3();
let ana = AnalyticalTri3::new(&pad);
const V0: f64 = -3.0;
const V1: f64 = 8.0;
let b_correct = ana.vec_02_nv(V0, V1);
let class = pad.kind.class();
let tolerances = [1e-14, 1e-14];
let selection: Vec<_> = [1, 3].iter().map(|n| Gauss::new_sized(class, *n).unwrap()).collect();
let (space_ndim, nnode) = pad.xxt.dims();
let mut b = Vector::filled(nnode * space_ndim, aux::NOISE);
selection.iter().zip(tolerances).for_each(|(ips, tol)| {
let mut args = CommonArgs::new(&mut pad, ips);
integ::vec_02_nv(&mut b, &mut args, |v, _, _| {
v[0] = V0;
v[1] = V1;
Ok(())
})
.unwrap();
vec_approx_eq(&b, &b_correct, tol);
});
}
#[test]
fn tet4_constant_works() {
const V0: f64 = 2.0;
const V1: f64 = 3.0;
const V2: f64 = 4.0;
let mut pad = aux::gen_pad_tet4();
let ana = AnalyticalTet4::new(&pad);
let b_correct = ana.vec_02_nv(V0, V1, V2);
let class = pad.kind.class();
let tolerances = [1e-15, 1e-15];
let selection: Vec<_> = [1, 4].iter().map(|n| Gauss::new_sized(class, *n).unwrap()).collect();
let (space_ndim, nnode) = pad.xxt.dims();
let mut b = Vector::filled(nnode * space_ndim, aux::NOISE);
selection.iter().zip(tolerances).for_each(|(ips, tol)| {
let mut args = CommonArgs::new(&mut pad, ips);
integ::vec_02_nv(&mut b, &mut args, |v, _, _| {
v[0] = V0;
v[1] = V1;
v[2] = V2;
Ok(())
})
.unwrap();
vec_approx_eq(&b, &b_correct, tol);
});
}
}