KiThe 0.1.5

A collection of structures and functions useful for chemical kinetics, chemical thermodynamics, combustion, heat and mass transfer, shock tubes and so on and so far. Work in progress. Advices and contributions will be appreciated
Documentation
use crate::Kinetics::User_reactions::KinData;
use RustedSciThe::numerical::BVP_api::BVP;
use RustedSciThe::symbolic::symbolic_engine::Expr;
use std::collections::HashMap;
const R: Expr = Expr::Const(8.314);
fn as_const(value: f64) -> Expr {
    Expr::Const(value)
}
fn Arr(T: Expr, A: f64, n: f64, E: f64) -> Expr {
    let A = Expr::Const(A);
    let n = Expr::Const(n);
    let E = Expr::Const(E);
    let k0 = A * (T.clone()).pow(n);
    let k = k0 * (E / (R * T)).exp();
    k
}

pub struct SimpleReactorTask {
    pub problem_name: Option<String>,
    pub problem_description: Option<String>,
    pub stoichiometry: KinData,
    pub reaction_data: Option<Vec<HashMap<String, Vec<f64>>>>,
    pub arrhenius_parameters: Vec<(f64, f64, f64)>,
    pub thermal_effects: Vec<f64>,
    pub Cp: f64,
    pub Lambda: f64,
    pub m: f64,
    pub scaling: HashMap<String, f64>,
}

impl SimpleReactorTask {
    pub fn new() -> Self {
        Self {
            problem_name: None,
            problem_description: None,
            stoichiometry: KinData::new(),
            reaction_data: None,
            arrhenius_parameters: Vec::new(),
            thermal_effects: Vec::new(),
            Cp: 0.0,
            Lambda: 0.0,
            m: 0.0,
            scaling: HashMap::new(),
        }
    }

    pub fn set_problem_name(&mut self, name: &str) {
        self.problem_name = Some(name.to_string());
    }

    pub fn set_problem_description(&mut self, description: &str) {
        self.problem_description = Some(description.to_string());
    }
    pub fn set_vector_of_reactions(
        &mut self,
        vector_of_reactions: Vec<String>,
        groups: Option<HashMap<String, HashMap<String, usize>>>,
    ) {
        self.stoichiometry
            .set_reactions_directly(vector_of_reactions, groups);
        self.stoichiometry.analyze_reactions();
    }
    pub fn set_reaction_data(&mut self, reaction_data: Vec<HashMap<String, Vec<f64>>>) {
        self.reaction_data = Some(reaction_data.clone());
        let mut arrhenius_parameters = Vec::new();
        let mut thermal_effects = Vec::new();
        for i in 0..reaction_data.len() {
            let reaction = &reaction_data[i];
            let Q = reaction.get("Q").expect("for reaction Q is not defined")[0];
            thermal_effects.push(Q);
            let kin = reaction
                .get("kin")
                .expect("for reaction Arrhenius parameters is not defined")
                .as_slice();
            arrhenius_parameters.push((kin[0], kin[1], kin[2]));
        }
    }
    pub fn set_arrhenius_parameters(&mut self, arrhenius_parameters: Vec<(f64, f64, f64)>) {
        self.arrhenius_parameters = arrhenius_parameters;
    }
    pub fn set_thermal_effects(&mut self, thermal_effects: Vec<f64>) {
        self.thermal_effects = thermal_effects;
    }
    pub fn parse_from_file(&mut self, file_path: &str) -> Result<(), Box<dyn std::error::Error>> {
        let content = std::fs::read_to_string(file_path)?;
        let sections: Vec<&str> = content.split("\n\n").collect();

        for section in sections {
            let lines: Vec<&str> = section.lines().collect();
            if lines.is_empty() {
                continue;
            }

            match lines[0].trim() {
                "DESCRIPTION" => {
                    let description = lines[1..].join("\n");
                    self.set_problem_description(&description);
                }
                "REACTIONS" => {
                    let mut reaction_data = Vec::new();
                    let mut vector_of_reactions = Vec::new();
                    for line in &lines[1..] {
                        let parts: Vec<&str> = line.split_whitespace().collect();
                        if parts.len() < 5 {
                            continue;
                        }

                        // Parse the line: reaction Q A n Ea
                        let reaction_eq = parts[0].to_string();
                        let Q: f64 = parts[1].parse()?;
                        let A: f64 = parts[2].parse()?;
                        let n: f64 = parts[3].parse()?;
                        let Ea: f64 = parts[4].parse()?;

                        let mut reaction_map = HashMap::new();

                        reaction_map.insert("Q".to_string(), vec![Q]);
                        reaction_map.insert("kin".to_string(), vec![A, n, Ea]);

                        reaction_data.push(reaction_map);
                        vector_of_reactions.push(reaction_eq)
                    }

                    self.set_reaction_data(reaction_data);
                    self.set_vector_of_reactions(vector_of_reactions, None);
                }
                _ => continue,
            }
        }
        Ok(())
    }
}

pub struct SimpleReactorSolver {
    pub task: SimpleReactorTask,
    pub solver: BVP,
}