#![allow(warnings)]
pub mod kinetics;
mod mechfinder;
use kinetics::{ElementaryStruct, FalloffStruct, PressureStruct, ThreeBodyStruct};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Number, Value};
use std::collections::{HashMap, HashSet};
use std::f64;
#[derive(Debug, PartialEq, Serialize, Clone)]
#[serde(rename_all = "lowercase")]
enum ReactionType {
Elem,
Falloff,
Pressure,
#[serde(rename = "threebody")]
ThreeBody,
Empirical,
}
impl<'de> Deserialize<'de> for ReactionType {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"elem" => Ok(ReactionType::Elem),
"falloff" => Ok(ReactionType::Falloff),
"pressure" => Ok(ReactionType::Pressure),
"threebody" | "three-body" => Ok(ReactionType::ThreeBody),
"empirical" => Ok(ReactionType::Empirical),
_ => Err(serde::de::Error::custom(format!(
"Unknown reaction type: {}",
s
))),
}
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ReactionData {
#[serde(rename = "type")]
reaction_type: ReactionType,
eq: String,
pub react: Option<HashMap<String, f64>>,
#[serde(flatten)]
data: ReactionKinetics,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(untagged)]
enum ReactionKinetics {
Elementary(ElementaryStruct),
Falloff(FalloffStruct),
Pressure(PressureStruct),
ThreeBody(ThreeBodyStruct),
}
pub fn parse_kinetic_data(
big_mech: &str,
vec_of_reactions: &[String],
vec_of_reaction_value: Vec<Value>,
) -> (Map<String, Value>, Vec<String>) {
let mut reaction_data_hash = Map::new();
let mut equations = Vec::new();
for (reaction_record, reaction_id) in vec_of_reaction_value.iter().zip(vec_of_reactions) {
println!("reaction_record {:#?} \n \n ", reaction_record);
let react_code = format!("{}_{}", big_mech, reaction_id);
if let Ok(mut reactiondata) =
serde_json::from_value::<ReactionData>(reaction_record.clone())
{
equations.push(reactiondata.eq.clone());
match &mut reactiondata.data {
ReactionKinetics::Elementary(elem_data) => {}
ReactionKinetics::ThreeBody(threebody_data) => {}
ReactionKinetics::Falloff(falloff_data) => {}
_ => {}
}
let value = serde_json::to_value(&reactiondata).unwrap();
reaction_data_hash.insert(react_code, value);
} else {
println!("Error parsing reaction: {}", reaction_record);
}
}
(reaction_data_hash, equations)
}
pub fn parse_kinetic_data_vec(
vec_of_reaction_value: Vec<Value>,
) -> (Vec<ReactionData>, Vec<String>) {
let mut reaction_dat = Vec::new();
let mut equations = Vec::new();
for reaction_record in vec_of_reaction_value.iter() {
println!("reaction_record {:#?} \n \n ", reaction_record);
if let Ok(mut reactiondata) =
serde_json::from_value::<ReactionData>(reaction_record.clone())
{
equations.push(reactiondata.eq.clone());
match &mut reactiondata.data {
ReactionKinetics::Elementary(elem_data) => {}
ReactionKinetics::ThreeBody(threebody_data) => {}
ReactionKinetics::Falloff(falloff_data) => {}
_ => {}
}
reaction_dat.push(reactiondata);
} else {
println!("Error parsing reaction: {}", reaction_record);
}
}
(reaction_dat, equations)
}
#[derive(Debug)]
pub struct Mechanism_search {
pub task_substances: Vec<String>,
pub task_library: String,
pub mechanism: Vec<String>,
pub reactants: Vec<String>,
pub vec_of_reactions: Vec<String>,
pub reactdata:Vec<ReactionData>,
}
impl Mechanism_search {
pub fn new(
task_substances: Vec<String>,
task_library: String,
) -> Self {
Self {
task_substances: task_substances,
task_library: task_library,
mechanism: Vec::new(),
reactants: Vec::new(),
vec_of_reactions: Vec::new(),
reactdata: Vec::new(),
}
}
pub fn default() -> Self {
Self {
task_substances: Vec::new(),
task_library: String::new(),
mechanism: Vec::new(),
reactants: Vec::new(),
vec_of_reactions: Vec::new(),
reactdata: Vec::new(),
}
}
pub fn mechfinder_api(&mut self) -> (Vec<String>, Vec<String>, Vec<String>) {
let vec: Vec<&str> = self.task_substances.iter().map(|s| s.as_str()).collect();
let big_mech = self.task_library.clone();
println!("задание {:?}, библиотека {:?}", &big_mech, &vec);
let (mechanism, reactants, vec_of_reactions, vec_of_reaction_value) =
mechfinder::mechfinder(&big_mech, vec);
let (mut reactdata, vec_of_equations) =
parse_kinetic_data_vec(vec_of_reaction_value.clone()); self.mechanism = mechanism;
self.reactants = reactants;
self.vec_of_reactions = vec_of_reactions;
self.reactdata = reactdata.clone();
return (
self.mechanism.to_owned(),
self.reactants.to_owned(),
self.vec_of_reactions.to_owned(),
);
}
}
const ELEM_TESTING_JSON: &str = r#"{"type": "elem",
"eq": "NAPH+C2H3<=>NAPHV+C2H4",
"Arrenius": [0.408, 4.02, 36822.949]}"#;
const FALOFF_TESTING_JSON: &str = r#" {"type": "falloff",
"eq": "C4H71-3+CH3(+M)<=>C5H10-2(+M)",
"low_rate": [3.91e+60, -12.81, 26143.75],
"high_rate": [100000000000000.0, -0.32, -1097.2009],
"eff": {"H2": 2.0, "H2O": 6.0, "CH4": 2.0, "CO": 1.5, "CO2": 2.0, "C2H6": 3.0, "AR": 0.7},
"troe": [0.104, 1606.0, 60000.0, 6118.0]} "#;
const PRES_TESTING_JSON: &str = " '1736': {'type': 'pres', 'eq': 'SC4H9<=>C3H6+CH3',
'Arrenius': {'0.001': [2.89e+40, -9.76, 140552.983],
'0.01': [1.8e+44, -10.5, 154800.281],
'0.1': [2.51e+46, -10.73, 168311.37099999998],
'1.0': [4.74e+44, -9.85, 175020.903],
'10.0': [3.79e+37, -7.44, 169846.532],
'100.0': [4.79e+26, -4.01, 154344.334]}}";
const THREE_BODY_TESTING_JSON: &str = r#"{"type": "threebody",
"eq": "H2+M<=>H+H+M",
"Arrenius": [4.577e+19, -1.4, 436705.19999999995],
"eff": {"H2": 2.5, "H2O": 12.0, "CO": 1.9, "CO2": 3.8, "HE": 0.83, "CH4": 2.0, "C2H6": 3.0} }"#;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mechfinder_api() {
let mut mech_search = Mechanism_search::new(
vec!["O".to_string(), "NH3".to_string(), "NO".to_string()],
"NUIG".to_string(),
);
let (mechanism, reactants, vec_of_reactions) = mech_search.mechfinder_api();
assert!(!mechanism.is_empty());
assert!(!reactants.is_empty());
assert!(!vec_of_reactions.is_empty());
}
#[test]
fn test_default_values() {
let mech_search = Mechanism_search::default();
assert!(mech_search.task_substances.is_empty());
assert!(mech_search.task_library.is_empty());
assert!(mech_search.mechanism.is_empty());
assert!(mech_search.reactants.is_empty());
assert!(mech_search.vec_of_reactions.is_empty());
}
#[test]
fn test_ELEM_parse_kinetic_data() {
let big_mech: &str = "NUIG";
let vec_of_reactions = vec!["1".to_string()];
let reaction = ELEM_TESTING_JSON;
let vec_of_reaction_value: Vec<Value> = vec![serde_json::from_str(reaction).unwrap()];
let (ReactionDataHash, _) =
parse_kinetic_data(big_mech, &vec_of_reactions, vec_of_reaction_value);
assert!(!ReactionDataHash.is_empty());
let key = format!("{}_{}", big_mech, &vec_of_reactions[0]);
let elem_react_testing_instance: ElementaryStruct =
serde_json::from_value::<ElementaryStruct>(ReactionDataHash[&key].clone()).unwrap();
println!("K_const {:?}", elem_react_testing_instance.K_const(298.15));
assert!(elem_react_testing_instance.K_const(298.15) > 0.0);
}
#[test]
fn test_THREEBODY_parse_kinetic_data() {
let ThreeBodyStruct_test_str: &str = r#"{"Arrenius": [4.577e+19, -1.4, 436705.19999999995],
"eff": {"H2": 2.5, "H2O": 12.0, "CO": 1.9, "CO2": 3.8, "HE": 0.83, "CH4": 2.0, "C2H6": 3.0} }"#;
let big_mech: &str = "NUIG";
let vec_of_reactions = vec!["2".to_string()];
let reaction = THREE_BODY_TESTING_JSON;
let vec_of_reaction_value: Vec<Value> = vec![serde_json::from_str(reaction).unwrap()];
let (ReactionDataHash, _) =
parse_kinetic_data(big_mech, &vec_of_reactions, vec_of_reaction_value);
assert!(!ReactionDataHash.is_empty());
println!("ReactionDataHash: {:?} \n \n", ReactionDataHash);
let key = format!("{}_{}", big_mech, &vec_of_reactions[0]);
let threebody_react_testing_instance: ThreeBodyStruct =
serde_json::from_value::<ThreeBodyStruct>(
serde_json::from_str(ThreeBodyStruct_test_str).unwrap(),
)
.unwrap();
println!(
"threebody_react_testing_instance {:?}",
threebody_react_testing_instance
);
let mut Concentrations: HashMap<String, f64> = HashMap::new();
Concentrations.insert("H".to_string(), 0.5);
Concentrations.insert("O".to_string(), 0.5);
assert!(threebody_react_testing_instance.K_const(298.15, Concentrations) > 0.0);
}
#[test]
fn test_THREEBODY_from_lib() {
use crate::Kinetics::User_reactions::KinData;
let mut kinetics = KinData::new();
let C1_react = Some(vec!["C1".to_string()]);
kinetics.shortcut_reactions = C1_react.clone();
kinetics.set_reactions_from_shortcuts();
kinetics.reactdata_parsing();
assert!(kinetics.vec_of_reaction_data.iter().len() > 0);
}
#[test]
fn test_FALOFF_parse_kinetic_data() {
let big_mech: &str = "NUIG";
let vec_of_reactions = vec!["3".to_string()];
let reaction = FALOFF_TESTING_JSON;
let vec_of_reaction_value: Vec<Value> = vec![serde_json::from_str(reaction).unwrap()];
let (ReactionDataHash, _) =
parse_kinetic_data(big_mech, &vec_of_reactions, vec_of_reaction_value);
println!("ReactionDataHash: {:#?}", ReactionDataHash);
assert!(!ReactionDataHash.is_empty());
let key = format!("{}_{}", big_mech, &vec_of_reactions[0]);
let falloff_react_testing_instance: FalloffStruct =
serde_json::from_value::<FalloffStruct>(ReactionDataHash[&key].clone()).unwrap();
let mut Concentrations: HashMap<String, f64> = HashMap::new();
Concentrations.insert("H".to_string(), 0.5);
Concentrations.insert("O".to_string(), 0.5);
assert!(falloff_react_testing_instance.K_const(298.15, Concentrations) > 0.0);
}
}