use gmt_dos_clients_io::gmt_m2::asm::segment::{AsmCommand, FaceSheetFigure};
use interface::{Data, Read, Update, Write};
use nalgebra::{DMatrix, DMatrixView, DVector};
use std::{fmt::Display, ops::Mul, sync::Arc};
pub struct SelectBy<'a, 'b, T, I>
where
I: Iterator<Item = &'b T>,
T: 'b,
{
iter: I,
mask: Box<dyn Iterator<Item = &'b bool> + 'a>,
}
impl<'a, 'b, T, I> SelectBy<'a, 'b, T, I>
where
I: Iterator<Item = &'b T>,
'b: 'a,
T: 'b,
{
pub fn new(iter: I, mask: &'b [bool]) -> Self {
Self {
iter,
mask: Box::new(mask.iter()),
}
}
}
impl<'a, 'b, T, I> Iterator for SelectBy<'a, 'b, T, I>
where
I: Iterator<Item = &'b T>,
T: 'b + Copy,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
loop {
match (self.iter.next(), self.mask.next()) {
(Some(v), Some(m)) if *m == true => break Some(*v),
(Some(_), Some(_)) => continue,
_ => break None,
}
}
}
}
pub trait SelectByIterator<'a, 'b, T>: Iterator<Item = &'b T> + Sized
where
T: 'b,
'b: 'a,
{
fn select_by(self, mask: &'b [bool]) -> SelectBy<'a, 'b, T, Self> {
SelectBy::new(self, mask)
}
}
impl<'a, 'b, T, I> SelectByIterator<'a, 'b, T> for I
where
T: 'b,
I: Iterator<Item = &'b T>,
'b: 'a,
{
}
#[derive(Debug, Default)]
pub struct Preprocessor {
masks: (Mask, Mask, Mask),
mats: Option<(DMatrix<f64>, DMatrix<f64>)>,
data: Option<Arc<Vec<f64>>>,
positions: Option<Arc<Vec<f64>>>,
positions2modes: Option<DMatrix<f64>>,
}
type Mask = Vec<bool>;
impl Preprocessor {
pub fn new<'a>(
nodes: Vec<f64>,
stiffness: DMatrixView<'a, f64>,
positions2modes: Option<DMatrix<f64>>,
) -> Self {
let m1 = Self::nodes_by(&nodes, |x| x > 0.28);
let m2 = Self::nodes_by(&nodes, |x| x > 0.21 && x < 0.28);
let m3 = Self::nodes_by(&nodes, |x| x < 0.21);
let mats = Self::processor((&m1, &m2, &m3), stiffness);
Self {
masks: (m1, m2, m3),
mats,
positions: Some(Arc::new(vec![0f64; 675])),
positions2modes,
..Default::default()
}
}
pub fn nodes_by<F>(nodes: &[f64], pred: F) -> Mask
where
F: Fn(f64) -> bool,
{
nodes
.chunks(2)
.map(|node| node[0].hypot(node[1]))
.map(|r| pred(r))
.collect()
}
pub fn processor<'a>(
(m1, m2, m3): (&Mask, &Mask, &Mask),
stiffness: DMatrixView<'a, f64>,
) -> Option<(DMatrix<f64>, DMatrix<f64>)> {
let k23: DMatrix<f64> = Kij::new(stiffness, m2, m3).into();
let k33: DMatrix<f64> = Kij::new(stiffness, m3, m3).into();
let k3 = k23.transpose() * &k23 + k33.transpose() * &k33;
let k21: DMatrix<f64> = Kij::new(stiffness, m2, m1).into();
let k31: DMatrix<f64> = Kij::new(stiffness, m3, m1).into();
let k1 = k23.transpose() * &k21 + k33.transpose() * &k31;
let k22: DMatrix<f64> = Kij::new(stiffness, m2, m2).into();
let k32: DMatrix<f64> = Kij::new(stiffness, m3, m2).into();
let k2 = k23.transpose() * &k22 + k33.transpose() * &k32;
k3.try_inverse().map(|ik3| (-&ik3 * k1, ik3 * k2))
}
pub fn apply(&self, p: &mut [f64]) {
let (m1, m2, m3) = &self.masks;
let p1: DVector<f64> = VCMi::new(p, m1).into();
let p2: DVector<f64> = VCMi::new(p, m2).into();
if let Some((a, b)) = &self.mats {
let p3 = a * p1 + b * p2;
p.iter_mut()
.zip(m3)
.filter_map(|(p, &m)| if m { Some(p) } else { None })
.zip(p3.as_slice())
.for_each(|(p, &p3)| *p = p3);
}
}
}
impl Mul<&[f64]> for &Preprocessor {
type Output = Vec<f64>;
fn mul(self, rhs: &[f64]) -> Self::Output {
let (m1, m2, m3) = &self.masks;
let p1: DVector<f64> = VCMi::new(rhs, m1).into();
let p2: DVector<f64> = VCMi::new(rhs, m2).into();
if let Some((a, b)) = &self.mats {
let p3 = a * p1 + b * p2;
let mut p = rhs.to_vec();
p.iter_mut()
.zip(m3)
.filter_map(|(p, &m)| if m { Some(p) } else { None })
.zip(p3.as_slice())
.for_each(|(p, &p3)| *p = p3);
p
} else {
vec![]
}
}
}
impl Update for Preprocessor {
fn update(&mut self) {
let data = self.data.take();
self.positions = data
.as_ref()
.map(|data| (&*self) * data)
.map(|x| Arc::new(x));
}
}
impl Write<AsmCommand<7>> for Preprocessor {
fn write(&mut self) -> Option<Data<AsmCommand<7>>> {
self.positions.clone().as_ref().map(|x| x.into())
}
}
impl Read<AsmCommand<7>> for Preprocessor {
fn read(&mut self, data: Data<AsmCommand<7>>) {
self.data = Some(data.as_arc());
}
}
impl Write<FaceSheetFigure<7>> for Preprocessor {
fn write(&mut self) -> Option<Data<FaceSheetFigure<7>>> {
self.positions
.as_ref()
.map(|x| DVector::from_column_slice(x))
.zip(self.positions2modes.as_ref())
.map(|(p, mat)| mat * p)
.map(|x| Data::new(x.as_slice().to_vec()))
}
}
#[derive(Debug)]
struct VCMi<'a> {
vcm: &'a [f64],
mask: &'a Mask,
}
impl<'a> VCMi<'a> {
pub fn new(vcm: &'a [f64], mask: &'a Mask) -> Self {
Self { vcm, mask }
}
pub fn len(&self) -> usize {
self.mask
.iter()
.filter(|x| **x)
.enumerate()
.last()
.unwrap()
.0
+ 1
}
pub fn iter(&self) -> impl Iterator<Item = f64> + 'a {
self.vcm
.iter()
.zip(self.mask)
.filter_map(|(v, &m)| if m { Some(*v) } else { None })
}
}
impl<'a> From<VCMi<'a>> for DVector<f64> {
fn from(value: VCMi<'a>) -> Self {
let n = value.len();
DVector::from_iterator(n, value.iter())
}
}
impl<'a> Display for VCMi<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{:?}", self.iter().collect::<Vec<f64>>())
}
}
#[derive(Debug)]
struct Kij<'a> {
mat: DMatrixView<'a, f64>,
rows_mask: &'a Mask,
columns_mask: &'a Mask,
}
impl<'a> Kij<'a> {
pub fn new(mat: DMatrixView<'a, f64>, rows_mask: &'a Mask, columns_mask: &'a Mask) -> Self {
Self {
mat,
rows_mask,
columns_mask,
}
}
}
impl<'a> From<Kij<'a>> for DMatrix<f64> {
fn from(value: Kij<'a>) -> Self {
let columns: Vec<_> = value
.mat
.column_iter()
.zip(value.columns_mask)
.filter_map(|(c, &m)| if m { Some(c) } else { None })
.collect();
let mat = DMatrix::<f64>::from_columns(&columns);
let rows: Vec<_> = mat
.row_iter()
.zip(value.rows_mask)
.filter_map(|(r, &m)| if m { Some(r) } else { None })
.collect();
DMatrix::<f64>::from_rows(&rows)
}
}
#[cfg(all(feature = "serde", feature = "polars"))]
#[cfg(test)]
mod tests {
use std::{env, fs::File, path::Path};
use super::*;
use gmt_fem::FEM;
use polars::prelude::*;
fn nodes() -> Result<Vec<f64>, Box<dyn std::error::Error>> {
let file = File::open("ASMS-nodes.parquet")?;
let df = ParquetReader::new(file).finish()?;
Ok(df["S7"]
.as_series()
.unwrap()
.iter()
.filter_map(|series| {
if let AnyValue::List(series) = series {
series
.f64()
.ok()
.map(|x| x.into_iter().take(2).filter_map(|x| x).collect::<Vec<_>>())
} else {
None
}
})
.flatten()
.collect())
}
#[cfg(feature = "serde")]
#[test]
fn processor() {
let n = 675;
let mut stiffness = DMatrix::<f64>::zeros(n, n);
stiffness.fill(1f64);
let Ok(asm_nodes) = nodes() else {
return;
};
let pp = Preprocessor::new(asm_nodes.clone(), stiffness.as_view(), None);
let (m1, m2, m3) = &pp.masks;
let mut stiffness = DMatrix::<f64>::zeros(n, n);
let m2_iter = m2
.iter()
.enumerate()
.filter_map(|(i, &m)| if m { Some(i) } else { None });
let m3_iter = m3
.iter()
.enumerate()
.filter_map(|(i, &m)| if m { Some(i) } else { None });
for i in m2_iter.clone() {
stiffness[(i, i)] = 1f64;
}
for i in m3_iter.clone() {
stiffness[(i, i)] = 1f64;
}
for (i, j) in m2_iter.zip(m3_iter) {
stiffness[(i, j)] = 0.5f64;
stiffness[(j, i)] = 0.5f64;
}
let mut pp = Preprocessor::new(asm_nodes, stiffness.as_view(), None);
let mut p = vec![0f64; n];
p.iter_mut()
.zip(m2)
.filter_map(|(p, &m)| if m { Some(p) } else { None })
.for_each(|p| *p = 1f64);
let pf = &pp * p.as_slice();
let p1 = VCMi::new(&pf, &m1);
let p2 = VCMi::new(&pf, &m2);
let p3 = VCMi::new(&pf, &m3);
println!("{p1}");
println!("{p2}");
println!("{p3}");
}
#[test]
fn adapter() {
let v = vec![1, 2, 3, 4, 5];
let m = vec![true, true, false, false, true];
let vf: Vec<_> = v.iter().select_by(&m).collect();
dbg!(vf);
let v = vec![1, 2, 3, 4, 5];
let m = vec![true; 5];
let vf: Vec<_> = v.iter().select_by(&m).collect();
dbg!(vf);
let v = vec![1, 2, 3, 4, 5];
let m = vec![false; 5];
let vf: Vec<_> = v.iter().select_by(&m).collect();
dbg!(vf);
}
}