use super::CommonArgs;
use crate::StrError;
use russell_lab::{Matrix, Vector};
pub fn mat_01_nsn_bry<F>(kk: &mut Matrix, args: &mut CommonArgs, mut fn_s: F) -> Result<(), StrError>
where
F: FnMut(usize, &Vector, &Vector) -> Result<f64, StrError>,
{
let (space_ndim, nnode) = args.pad.xxt.dims();
let geo_ndim = args.pad.deriv.dims().1;
if space_ndim == 2 && geo_ndim != 1 {
return Err("in 2D, geometry ndim must be equal to 1 (a line)");
}
if space_ndim == 3 && geo_ndim != 2 {
return Err("in 3D, geometry ndim must be equal to 2 (a surface)");
}
let (nrow_kk, ncol_kk) = kk.dims();
let (ii0, jj0) = (args.ii0, args.jj0);
if nrow_kk < ii0 + nnode {
return Err("nrow(K) must be ≥ ii0 + nnode");
}
if ncol_kk < jj0 + nnode {
return Err("ncol(K) must be ≥ jj0 + nnode");
}
let mut un = Vector::new(space_ndim);
if args.clear {
kk.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 mag_n = args.pad.calc_normal_vector(&mut un, iota).unwrap();
let nn = &args.pad.interp;
let s = fn_s(p, &un, nn)?;
let c = if args.axisymmetric {
let mut r = 0.0; for m in 0..nnode {
r += nn[m] * args.pad.xxt.get(0, m);
}
s * mag_n * weight * args.alpha * r
} else {
s * mag_n * weight * args.alpha
};
for m in 0..nnode {
for n in 0..nnode {
kk.add(ii0 + m, jj0 + n, nn[m] * c * nn[n]);
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use crate::integ::testing::aux;
use crate::integ::{self, AnalyticalTri3, CommonArgs, Gauss};
use crate::shapes::{GeoClass, GeoKind, Scratchpad};
use russell_lab::{mat_approx_eq, Matrix, Vector};
#[test]
fn capture_some_errors() {
let mut pad = aux::gen_pad_tri3();
let mut kk = Matrix::new(3, 3);
let un = Vector::new(0);
let nn = Vector::new(0);
let f = |_, _: &Vector, _: &Vector| Ok(0.0);
assert_eq!(f(0, &un, &nn).unwrap(), 0.0);
let gauss = Gauss::new(pad.kind);
let mut args = CommonArgs::new(&mut pad, &gauss);
assert_eq!(
integ::mat_01_nsn_bry(&mut kk, &mut args, f).err(),
Some("in 2D, geometry ndim must be equal to 1 (a line)")
);
let mut pad = aux::gen_pad_tet4();
let gauss = Gauss::new(pad.kind);
let mut args = CommonArgs::new(&mut pad, &gauss);
let mut kk = Matrix::new(4, 4);
assert_eq!(
integ::mat_01_nsn_bry(&mut kk, &mut args, f).err(),
Some("in 3D, geometry ndim must be equal to 2 (a surface)")
);
let mut pad = aux::gen_pad_lin2(1.0);
let gauss = Gauss::new(pad.kind);
let mut args = CommonArgs::new(&mut pad, &gauss);
let mut kk = Matrix::new(2, 2);
args.ii0 = 1;
assert_eq!(
integ::mat_01_nsn_bry(&mut kk, &mut args, f).err(),
Some("nrow(K) must be ≥ ii0 + nnode")
);
args.ii0 = 0;
args.jj0 = 1;
assert_eq!(
integ::mat_01_nsn_bry(&mut kk, &mut args, f).err(),
Some("ncol(K) must be ≥ jj0 + nnode")
);
args.jj0 = 0;
assert_eq!(
integ::mat_01_nsn_bry(&mut kk, &mut args, |_, _, _| Err("stop")).err(),
Some("stop")
);
}
fn tri3_extract_pad_side(pad: &Scratchpad, side: usize) -> Scratchpad {
let mut pad_side = Scratchpad::new(2, GeoKind::Lin2).unwrap();
for i in 0..2 {
let m = pad.kind.edge_node_id(side, i);
pad_side.set_xx(i, 0, pad.xxt.get(0, m));
pad_side.set_xx(i, 1, pad.xxt.get(1, m));
}
pad_side
}
#[test]
fn mat_01_nsn_bry_tri3_works() {
let pad = aux::gen_pad_tri3();
let s = 12.0;
let ana = AnalyticalTri3::new(&pad);
let gauss = Gauss::new_sized(GeoClass::Lin, 2).unwrap();
let mut pad_side = tri3_extract_pad_side(&pad, 0);
let kk_correct = ana.mat_01_nsn_bry(0, s, false);
let mut kk = Matrix::new(2, 2);
let mut args = CommonArgs::new(&mut pad_side, &gauss);
integ::mat_01_nsn_bry(&mut kk, &mut args, |_, _, _| Ok(s)).unwrap();
mat_approx_eq(&kk, &kk_correct, 1e-15);
let mut pad_side = tri3_extract_pad_side(&pad, 1);
let kk_correct = ana.mat_01_nsn_bry(1, s, false);
let mut args = CommonArgs::new(&mut pad_side, &gauss);
integ::mat_01_nsn_bry(&mut kk, &mut args, |_, _, _| Ok(s)).unwrap();
mat_approx_eq(&kk, &kk_correct, 1e-14);
let mut pad_side = tri3_extract_pad_side(&pad, 2);
let kk_correct = ana.mat_01_nsn_bry(2, s, false);
let mut args = CommonArgs::new(&mut pad_side, &gauss);
integ::mat_01_nsn_bry(&mut kk, &mut args, |_, _, _| Ok(s)).unwrap();
mat_approx_eq(&kk, &kk_correct, 1e-14);
}
}