RatRod-rs 0.2.1

An FEM implementation written in Rust
Documentation
use std::{collections::HashMap, rc::Rc, fs::{self, File}, process::exit, io::Write};

use sparse_matrix::{matrix::coo_mat::CooMat, vector::Vector};

use crate::{elements::{Element, ElementType, truss::Truss, beam::Beam, ElementTrait}, node::Node, material::Material, section::Section};

use serde::{Serialize, Deserialize};

use serde_json_any_key::any_key_map;

#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct Model{
    pub epsilon                 :   f64,
    pub dimension               :   u8,
    pub degrees_of_freedom      :   u8,
    pub f                       :   Vector, 
    pub u                       :   Vector, 
    pub m                       :   CooMat, 
    pub f_r                     :   Vector, 
    pub u_r                     :   Vector, 
    pub m_r                     :   CooMat, 
    pub u_boundary_conditions   :   Vec<Option<f64>>,
    #[serde(with = "any_key_map")]
    pub elements                :   HashMap<Vec<usize>,Box<Element>>,
    pub nodes                   :   Vec<Rc<Node>>,
    pub materials               :   Vec<Rc<Material>>,
    pub sections                :   Vec<Rc<Section>>
}

impl Model{
    pub fn new(dim : u8, epsilon : f64) -> Self{
        let dof = match dim {
            1 => 1,
            2 => 3,
            3 => 6,
            _ => panic!()
        };
        Model {
            epsilon,
            degrees_of_freedom      :   dof,
            dimension               :   dim,
            f                       :   Vector::null(0),
            u                       :   Vector::null(0),
            m                       :   CooMat::new(0, 0),
            f_r                     :   Vector::null(0),
            u_r                     :   Vector::null(0),
            m_r                     :   CooMat::new(0,0),
            u_boundary_conditions   :   vec![],
            elements                :   HashMap::new(),
            nodes                   :   vec![],
            materials               :   vec![],
            sections                :   vec![]
        }
    }

    pub fn save(&self, file: &str) {
        let to_write = serde_json::to_string(&self).expect("Unable to serialize model");
        fs::write(file, to_write).expect("Unable to write file");
    }

    pub fn load(file: &str) -> Self {
        let file_content = fs::read_to_string(file).expect("Unable to read file");
        serde_json::from_str(&file_content).expect("Unable to process the file")
    }

    pub fn add_element(&mut self, element : ElementType, nodes : Vec<usize>, material : usize, section : usize) -> &mut Self{
        self.elements.insert(nodes.clone(), Box::new(
                match element {
                    ElementType::Truss => Element::Truss(Truss { nodes : (self.nodes[nodes[0]].clone(), self.nodes[nodes[1]].clone()), material : self.materials[material].clone(), section : self.sections[section].clone()}),
                    ElementType::Beam => Element::Beam(Beam { nodes : (self.nodes[nodes[0]].clone(), self.nodes[nodes[1]].clone()), material : self.materials[material].clone(), section : self.sections[section].clone()})
                }));
        self
    }

    pub fn add_node(&mut self, node : Node) -> &mut Self {
        self.nodes.push(Rc::new(node));
        self.m.rows += self.degrees_of_freedom as usize;
        self.m.columns += self.degrees_of_freedom as usize;
        for _ in 0..self.degrees_of_freedom{
            self.f.values.push(0.);
            self.u.values.push(0.);
            self.u_boundary_conditions.push(None);
        }
        self
    }

    pub fn add_material(&mut self, material : Material) -> &mut Self {
        self.materials.push(Rc::new(material));
        self
    }

    pub fn add_section(&mut self, section : Section) -> &mut Self {
        self.sections.push(Rc::new(section));
        self
    }

    pub fn solve(&mut self) -> &mut Self{
        for (nodes, element) in &self.elements {
            self.m += element.get_matrix(self.dimension, self.m.rows, nodes);
        }
        self.reduce();
        let p_r = self.m_r.to_csr();
        self.u_r = p_r.minres(&self.f_r, self.epsilon).unwrap();
        self.developp();
        let problem = self.m.to_csr();
        self.f = (&problem * &self.u).unwrap();
        self
    }

    pub fn reduce(&mut self) -> &mut Self {
        self.m_r  = self.m.clone();
        let mut reduced_vector = vec![];
        let mut j = 0;
        for i in 0..self.u_boundary_conditions.len(){
            if self.u_boundary_conditions[i] != None {
                self.m_r.drop_row(j);
                self.m_r.drop_col(j);
                self.m_r.rows -= 1;
                self.m_r.columns -= 1;
            } else {
                reduced_vector.push(self.f.values[i]);
                j+=1;
            }
        }
        self.f_r = Vector { values : reduced_vector };
        self
    }

    pub fn developp(&mut self) -> &mut Self {
        let mut j = 0;
        for i in 0..self.u_boundary_conditions.len(){
            match self.u_boundary_conditions[i] {
                Some(value) => self.u.values[i] = value,
                None => {
                    self.u.values[i] = self.u_r.values[j];
                    j+=1;
                },
            }
        }
        self
    }

    pub fn add_u_boundary_condition(&mut self, node : usize, field : u8, value : f64) -> &mut Self {
        self.u_boundary_conditions[self.degrees_of_freedom  as usize * node + field as usize] = Some(value);
        self
    }

    pub fn remove_u_boundary_condition(&mut self, node : usize, field : u8) -> &mut Self {
        self.u_boundary_conditions[self.degrees_of_freedom  as usize * node + field as usize] = None;
        self
    }

    pub fn set_force(&mut self, node : usize, field : u8, value : f64) -> &mut Self{
        self.f.values[self.degrees_of_freedom as usize * node + field as usize] = value;
        self
    }
}