#[cfg(fem)]
mod fem;
use std::{env, ops::Deref, path::Path};
#[cfg(fem)]
pub use fem::*;
use serde::Deserialize;
#[derive(Debug, Default, Clone, serde::Deserialize, serde::Serialize)]
pub struct SegmentSingularModes {
mode_nodes: Vec<Vec<f64>>,
actuator_nodes: Vec<Vec<f64>>,
raw_modes: Vec<f64>,
modes: Vec<f64>,
mode_2_force: Vec<f64>,
shape: (usize, usize),
}
impl SegmentSingularModes {
pub fn new(
mode_nodes: Vec<Vec<f64>>,
actuator_nodes: Vec<Vec<f64>>,
raw_modes: Vec<f64>,
modes: Vec<f64>,
mode_2_force: Vec<f64>,
shape: (usize, usize),
) -> Self {
Self {
mode_nodes,
actuator_nodes,
raw_modes,
modes,
mode_2_force,
shape,
}
}
#[cfg(feature = "faer")]
pub fn mat_ref(&self) -> faer::mat::MatRef<'_, f64> {
let (ns, na) = self.shape;
faer::mat::MatRef::from_column_major_slice(&self.raw_modes, ns, na)
}
#[cfg(feature = "faer")]
pub fn mode2force_mat_ref(&self) -> faer::mat::MatRef<'_, f64> {
let (_, na) = self.shape;
let ns = self.mode_2_force.len() / na;
faer::mat::MatRef::from_column_major_slice(&self.mode_2_force, na, ns)
}
pub fn mode2force(&self) -> nalgebra::DMatrix<f64> {
let (_, na) = self.shape;
let ns = self.mode_2_force.len() / na;
nalgebra::DMatrix::from_column_slice(na, ns, &self.mode_2_force)
}
pub fn raw_modes_into_mat(&self) -> nalgebra::DMatrix<f64> {
let (ns, na) = self.shape;
nalgebra::DMatrix::from_column_slice(ns, na, &self.raw_modes)
}
pub fn modes_into_mat(&self, n_mode: Option<usize>) -> nalgebra::DMatrix<f64> {
let (ns, ..) = self.shape;
if let Some(n) = n_mode {
nalgebra::DMatrix::from_column_slice(ns, n, &self.modes[..ns * n])
} else {
nalgebra::DMatrix::from_column_slice(ns, self.modes.len() / ns, &self.modes)
}
}
pub fn shape(&self) -> (usize, usize) {
self.shape
}
pub fn raw_modes_iter(&self) -> impl Iterator<Item = &f64> {
self.raw_modes.iter()
}
}
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
pub enum NullSpace {
Rbm,
RbmHp,
}
fn expected_fem<'de, D>(d: D) -> Result<String, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(d)?;
let Ok(fem_id) = env::var("FEM_REPO").map(|v| {
Path::new(&v)
.file_name()
.expect("invalid name for FEM folder")
.to_string_lossy()
.into_owned()
}) else {
return Ok(s);
};
if s != fem_id {
return Err(serde::de::Error::custom(format!(
r#"SingularModes FEM ID mismatch: expected "{fem_id}", found "{s}""#
)));
}
Ok(s)
}
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
pub struct SingularModes {
#[serde(deserialize_with = "expected_fem")]
fem_id: String,
modes: Vec<SegmentSingularModes>,
null_space: NullSpace,
}
impl Deref for SingularModes {
type Target = [SegmentSingularModes];
fn deref(&self) -> &Self::Target {
self.modes.as_slice()
}
}
impl SingularModes {
pub fn new() -> Result<Self, env::VarError> {
Ok(Self {
fem_id: env::var("FEM_REPO").map(|v| {
Path::new(&v)
.file_name()
.expect("invalid name for FEM folder")
.to_string_lossy()
.into_owned()
})?,
modes: Vec::new(),
null_space: NullSpace::Rbm,
})
}
pub fn push(&mut self, segment: SegmentSingularModes) {
self.modes.push(segment);
}
pub fn modes_into_mat(&self, n_mode: Option<usize>) -> Vec<nalgebra::DMatrix<f64>> {
self.iter()
.map(|segment| segment.modes_into_mat(n_mode))
.collect()
}
pub fn raw_modes_into_mat(&self) -> Vec<nalgebra::DMatrix<f64>> {
self.iter()
.map(|segment| segment.raw_modes_into_mat())
.collect()
}
pub fn mode2force(&self) -> Vec<nalgebra::DMatrix<f64>> {
self.iter().map(|segment| segment.mode2force()).collect()
}
}