use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Read;
use crate::library_manager::with_library_manager;
use serde_json::Value;
#[derive(Debug, Clone)]
pub struct KineticData {
pub HashMapOfReactantsAndProducts: HashMap<String, HashMap<String, HashSet<String>>>, pub lib_name: String,
pub LibKineticData: HashMap<String, Value>, pub AllLibraries: Vec<String>, pub AllEquations: Vec<String>, pub EquationReactionMap: HashMap<String, String>, pub UserEquationReactionMap: HashMap<String, String>,
pub FoundReactionsByProducts: Vec<String>,
pub FoundReactionsByReagents: Vec<String>,
pub FoundReactionDatasByIDs: Vec<Value>,
}
impl KineticData {
pub fn new() -> Self {
Self {
HashMapOfReactantsAndProducts: HashMap::new(),
lib_name: String::new(),
LibKineticData: HashMap::new(),
AllLibraries: Vec::new(),
AllEquations: Vec::new(),
EquationReactionMap: HashMap::new(),
UserEquationReactionMap: HashMap::new(),
FoundReactionsByProducts: Vec::new(),
FoundReactionsByReagents: Vec::new(),
FoundReactionDatasByIDs: Vec::new(),
}
}
pub fn open_json_files(&mut self, big_mech: &str) -> () {
self.lib_name = big_mech.to_owned();
let mut file =
with_library_manager(|manager| File::open(manager.reactbase_path())).unwrap();
let mut file_contents = String::new();
file.read_to_string(&mut file_contents).unwrap();
let reactlibrary: HashMap<String, HashMap<String, Value>> =
serde_json::from_str::<HashMap<String, HashMap<String, _>>>(&file_contents).unwrap();
self.AllLibraries = reactlibrary.keys().map(|k| k.to_string()).collect();
let library_of_kinetic_parameters = reactlibrary.get(big_mech).unwrap();
self.LibKineticData = library_of_kinetic_parameters.to_owned();
let mut file =
with_library_manager(|manager| File::open(manager.dict_reaction_path())).unwrap();
let mut file_contents = String::new();
file.read_to_string(&mut file_contents).unwrap();
let reaction_db: HashMap<String, HashMap<String, HashMap<String, HashSet<String>>>> =
serde_json::from_str(&file_contents).unwrap();
let library_of_reagents_and_products: &HashMap<String, HashMap<String, HashSet<String>>> =
reaction_db.get(big_mech).unwrap();
self.HashMapOfReactantsAndProducts = library_of_reagents_and_products.to_owned();
}
pub fn print_all_reactions(&mut self) -> () {
let all_reactions: Vec<String> =
self.LibKineticData.keys().map(|k| k.to_string()).collect();
let all_equations: Vec<String> = self
.LibKineticData
.keys()
.map(|k| {
self.LibKineticData
.get(k)
.unwrap()
.get("eq")
.unwrap()
.as_str()
.unwrap()
.to_string()
})
.collect();
self.AllEquations = all_equations.clone();
let EquationReactionIDMap: HashMap<String, String> = all_equations
.iter()
.zip(all_reactions.iter())
.map(|(eq, r)| (eq.to_string(), r.to_string()))
.collect();
self.EquationReactionMap = EquationReactionIDMap;
} pub fn search_reaction_by_equation(&mut self, equation: &str) -> (String, Value) {
let reaction_id = self.EquationReactionMap.get(equation).unwrap();
let reaction = self.LibKineticData.get(reaction_id).unwrap();
return (reaction_id.clone(), reaction.clone());
}
fn search_reaction_by_substances(
&mut self,
substances: Vec<String>,
SubstanceType: &str,
) -> Vec<String> {
let substances: HashSet<String> = substances.iter().cloned().collect();
let mut found_reactions: Vec<String> = Vec::new();
let db_object = &self.HashMapOfReactantsAndProducts;
let db_object_mut = &mut db_object.clone();
let all_reaction_ID: Vec<&str> = self.LibKineticData.keys().map(|k| k.as_str()).collect();
for r_id in all_reaction_ID {
let base_substances: &mut HashSet<String> = db_object_mut
.get_mut(r_id)
.expect("REASON")
.get_mut(SubstanceType)
.expect("REASON");
if substances.is_subset(&base_substances) {
found_reactions.push(r_id.to_string());
}
}
return found_reactions;
}
pub fn search_reaction_by_reagents_and_products(&mut self, reagents: Vec<String>) -> () {
let found_reactions_by_reagents =
self.search_reaction_by_substances(reagents.clone(), "reagents");
self.FoundReactionsByReagents = found_reactions_by_reagents.clone();
let found_reactions_by_products = self.search_reaction_by_substances(reagents, "products");
self.FoundReactionsByProducts = found_reactions_by_products.clone();
}
pub fn search_reactdata_by_reaction_id(&mut self, reaction_id: &str) -> Value {
let reaction = self.LibKineticData.get(reaction_id).unwrap();
return reaction.clone();
}
pub fn search_reactdata_for_vector_of_IDs(&mut self, reaction_ids: Vec<String>) -> Vec<Value> {
let mut vec_of_reactions: Vec<Value> = Vec::new();
for r_id in reaction_ids {
let reaction = self.LibKineticData.get(&r_id).unwrap();
vec_of_reactions.push(reaction.clone());
}
self.FoundReactionDatasByIDs = vec_of_reactions.clone();
return vec_of_reactions;
}
pub fn get_reactions_by_field(&self, field: &str, field_value: &str) -> Vec<Value> {
self.LibKineticData
.values()
.filter(|reaction| {
reaction
.get(field)
.and_then(|v| v.as_str())
.map_or(false, |v| v == field_value)
})
.cloned()
.collect()
}
#[allow(dead_code)]
pub fn form_user_chosen_data(
&self,
what_to_get: SearchVariants,
mech_name: Option<String>,
) -> HashMap<String, HashMap<String, Value>> {
let big_mech = if let Some(mech_name) = { mech_name } {
mech_name
} else {
self.lib_name.clone()
};
let reaction_ids = self.get_search_results(what_to_get);
if reaction_ids.len() == 0 {
return HashMap::new();
}
let mut hash_map = HashMap::new();
let mut hash_map_id_data = HashMap::new();
for r_id in reaction_ids {
let reaction = self.LibKineticData.get(&r_id).unwrap();
hash_map_id_data.insert(r_id.clone(), reaction.clone());
}
hash_map.insert(big_mech.clone(), hash_map_id_data.clone());
return hash_map;
}
#[allow(dead_code)]
pub fn get_search_results(&self, what_to_get: SearchVariants) -> Vec<String> {
match what_to_get {
SearchVariants::FoundReactionsByProducts => self.FoundReactionsByProducts.clone(),
SearchVariants::FoundReactionsByReagents => self.FoundReactionsByReagents.clone(),
}
}
}
pub enum SearchVariants {
FoundReactionsByProducts,
FoundReactionsByReagents,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_kinetic_data_new() {
let mut kin_instance = KineticData::new();
let lib = "NUIG";
let LibVec: HashSet<String> = vec![
"Beckstead".to_string(),
"NUIG".to_string(),
"Cantera".to_string(),
"Beckstead_c".to_string(),
"Aramco".to_string(),
]
.into_iter()
.collect();
kin_instance.open_json_files(lib);
kin_instance.print_all_reactions();
assert_eq!(kin_instance.HashMapOfReactantsAndProducts.is_empty(), false);
assert_eq!(kin_instance.LibKineticData.is_empty(), false);
let all_lib: HashSet<String> = kin_instance.AllLibraries.clone().into_iter().collect();
assert_eq!(all_lib, LibVec);
assert_eq!(kin_instance.AllEquations.is_empty(), false);
let equation = kin_instance
.LibKineticData
.get("1")
.unwrap()
.get("eq")
.unwrap()
.as_str()
.unwrap()
.to_string();
let (reaction_id, reaction) = kin_instance.search_reaction_by_equation(&equation);
assert_eq!(reaction_id, "1".to_string());
assert_eq!(reaction.get("eq").unwrap().as_str().unwrap(), equation);
let substances: Vec<String> = vec!["CO".to_string(), "O".to_string()];
kin_instance.search_reaction_by_reagents_and_products(substances);
assert_eq!(kin_instance.FoundReactionsByProducts.is_empty(), false);
assert_eq!(kin_instance.FoundReactionsByReagents.is_empty(), false);
kin_instance.search_reactdata_for_vector_of_IDs(vec!["1".to_string(), "2".to_string()]);
assert_eq!(kin_instance.FoundReactionDatasByIDs.is_empty(), false);
}
#[test]
fn test_search_value() {
let mut kin_instance = KineticData::new();
let lib = "NUIG";
kin_instance.open_json_files(lib);
kin_instance.print_all_reactions();
let data_of_reacion = kin_instance.LibKineticData.get("1").unwrap();
println!(" data_of_reacion {:?}", data_of_reacion);
}
#[test]
fn test_search_data_by_field() {
let mut kin_instance = KineticData::new();
kin_instance.open_json_files("NUIG");
let reactions_by_field = kin_instance.get_reactions_by_field("type", "falloff");
println!(" reactions_by_field {:?}", reactions_by_field);
assert_eq!(reactions_by_field.len(), 109);
}
#[test]
fn test_form_user_chosen_data() {
let mut kin_instance = KineticData::new();
kin_instance.open_json_files("NUIG");
kin_instance.FoundReactionsByProducts = vec!["1".to_string(), "2".to_string()];
kin_instance.FoundReactionsByReagents = vec!["3".to_string(), "4".to_string()];
let result =
kin_instance.form_user_chosen_data(SearchVariants::FoundReactionsByProducts, None);
assert_eq!(result.len(), 1);
assert!(result.contains_key("NUIG"));
let nuig_data = result.get("NUIG").unwrap();
assert_eq!(nuig_data.len(), 2);
assert!(nuig_data.contains_key("1"));
assert!(nuig_data.contains_key("2"));
let result = kin_instance.form_user_chosen_data(
SearchVariants::FoundReactionsByReagents,
Some("CustomMech".to_string()),
);
assert_eq!(result.len(), 1);
assert!(result.contains_key("CustomMech"));
let custom_mech_data = result.get("CustomMech").unwrap();
assert_eq!(custom_mech_data.len(), 2);
assert!(custom_mech_data.contains_key("3"));
assert!(custom_mech_data.contains_key("4"));
kin_instance.FoundReactionsByProducts = vec![];
let result =
kin_instance.form_user_chosen_data(SearchVariants::FoundReactionsByProducts, None);
assert_eq!(result.len(), 0);
}
#[test]
fn test_form_user_chosen_data_integration() {
let mut kin_instance = KineticData::new();
kin_instance.open_json_files("NUIG");
kin_instance
.search_reaction_by_reagents_and_products(vec!["O".to_string(), "H".to_string()]);
let result =
kin_instance.form_user_chosen_data(SearchVariants::FoundReactionsByProducts, None);
assert!(!result.is_empty());
assert!(result.contains_key("NUIG"));
let nuig_data = result.get("NUIG").unwrap();
assert!(!nuig_data.is_empty());
for (reaction_id, reaction_data) in nuig_data {
assert_eq!(
reaction_data,
kin_instance.LibKineticData.get(reaction_id).unwrap()
);
}
}
}