use extended_matrix::{BasicOperationsTrait, FloatTrait, Position};
use crate::fem::FEM;
use crate::fem::structs::{NODE_DOF, PLATE_NODE_DOF, Plate};
enum PlateElementError {
Number(u32),
SameNodes(u32, u32, u32, u32),
NumberNotExist(u32),
}
impl PlateElementError {
fn compose_error_message(&self) -> String {
match self {
Self::Number(number) => format!("Plate element with number {number} already exists!"),
Self::SameNodes(node_1_number, node_2_number, node_3_number, node_4_number) => {
format!(
"Plate element with nodes numbers [{node_1_number}, {node_2_number}, \
{node_3_number}, {node_4_number}] already exists!"
)
}
Self::NumberNotExist(number) => {
format!("Plate element with number {number} does not exist!")
}
}
}
}
impl<V> FEM<V>
where
V: FloatTrait<Output = V>,
{
fn check_plate_data(
&self,
number: u32,
node_1_number: u32,
node_2_number: u32,
node_3_number: u32,
node_4_number: u32,
) -> Option<PlateElementError> {
for (plate_number, plate_element) in self.get_plate_elements().iter() {
if *plate_number == number {
return Some(PlateElementError::Number(number));
}
if plate_element.is_nodes_numbers_same(&[
node_1_number,
node_2_number,
node_3_number,
node_4_number,
]) {
return Some(PlateElementError::SameNodes(
node_1_number,
node_2_number,
node_3_number,
node_4_number,
));
}
}
None
}
pub fn add_plate(
&mut self,
number: u32,
node_1_number: u32,
node_2_number: u32,
node_3_number: u32,
node_4_number: u32,
young_modulus: V,
poisson_ratio: V,
thickness: V,
shear_factor: V,
) -> Result<(), String> {
self.check_node_exist(node_1_number)?;
self.check_node_exist(node_2_number)?;
self.check_node_exist(node_3_number)?;
self.check_node_exist(node_4_number)?;
if let Some(plate_error) = self.check_plate_data(
number,
node_1_number,
node_2_number,
node_3_number,
node_4_number,
) {
return Err(plate_error.compose_error_message());
}
let plate_element = Plate::create(
number,
node_1_number,
node_2_number,
node_3_number,
node_4_number,
young_modulus,
poisson_ratio,
thickness,
shear_factor,
self.get_nodes(),
self.get_props().get_rel_tol(),
self.get_props().get_abs_tol(),
)?;
let rotation_matrix = plate_element.extract_rotation_matrix();
let local_stiffness_matrix = plate_element
.extract_local_stiffness_matrix(self.get_nodes(), self.get_props().get_rel_tol())?;
let transformed_local_stiffness_matrix = rotation_matrix
.transpose()
.multiply(&local_stiffness_matrix)?
.multiply(&rotation_matrix)?;
let node_1_index = self
.get_nodes()
.get(&node_1_number)
.ok_or(format!("Node {node_1_number} is absent!"))?
.get_index();
let node_2_index = self
.get_nodes()
.get(&node_2_number)
.ok_or(format!("Node {node_2_number} is absent!"))?
.get_index();
let node_3_index = self
.get_nodes()
.get(&node_3_number)
.ok_or(format!("Node {node_3_number} is absent!"))?
.get_index();
let node_4_index = self
.get_nodes()
.get(&node_4_number)
.ok_or(format!("Node {node_4_number} is absent!"))?
.get_index();
let start_positions = [
((0, 0), (node_1_index * NODE_DOF, node_1_index * NODE_DOF)),
(
(0, PLATE_NODE_DOF),
(node_1_index * NODE_DOF, node_2_index * NODE_DOF),
),
(
(0, PLATE_NODE_DOF * 2),
(node_1_index * NODE_DOF, node_3_index * NODE_DOF),
),
(
(0, PLATE_NODE_DOF * 3),
(node_1_index * NODE_DOF, node_4_index * NODE_DOF),
),
(
(PLATE_NODE_DOF, 0),
(node_2_index * NODE_DOF, node_1_index * NODE_DOF),
),
(
(PLATE_NODE_DOF, PLATE_NODE_DOF),
(node_2_index * NODE_DOF, node_2_index * NODE_DOF),
),
(
(PLATE_NODE_DOF, PLATE_NODE_DOF * 2),
(node_2_index * NODE_DOF, node_3_index * NODE_DOF),
),
(
(PLATE_NODE_DOF, PLATE_NODE_DOF * 3),
(node_2_index * NODE_DOF, node_4_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 2, 0),
(node_3_index * NODE_DOF, node_1_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 2, PLATE_NODE_DOF),
(node_3_index * NODE_DOF, node_2_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 2, PLATE_NODE_DOF * 2),
(node_3_index * NODE_DOF, node_3_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 2, PLATE_NODE_DOF * 3),
(node_3_index * NODE_DOF, node_4_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 3, 0),
(node_4_index * NODE_DOF, node_1_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 3, PLATE_NODE_DOF),
(node_4_index * NODE_DOF, node_2_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 3, PLATE_NODE_DOF * 2),
(node_4_index * NODE_DOF, node_3_index * NODE_DOF),
),
(
(PLATE_NODE_DOF * 3, PLATE_NODE_DOF * 3),
(node_4_index * NODE_DOF, node_4_index * NODE_DOF),
),
];
for ((local_row, local_column), (global_row, global_column)) in start_positions {
for i in 0..PLATE_NODE_DOF {
for j in 0..PLATE_NODE_DOF {
let local_stiffness_matrix_element_value =
transformed_local_stiffness_matrix
.get_element_value(&Position(local_row + i, local_column + j))?;
if *local_stiffness_matrix_element_value != V::from(0f32) {
self.get_mut_stiffness_matrix().add_value(
Position(global_row + i, global_column + j),
*local_stiffness_matrix_element_value,
);
}
}
}
}
self.get_mut_plate_elements().insert(number, plate_element);
Ok(())
}
pub(crate) fn check_plate_element_exist(&self, number: u32) -> Result<(), String> {
if !self.get_plate_elements().contains_key(&number) {
return Err(PlateElementError::NumberNotExist(number).compose_error_message());
}
Ok(())
}
}