use crate::types;
use crate::config;
pub type SmilesDB = std::collections::HashMap<String, std::sync::Arc<SMILESDocument>>;
#[derive(Debug)]
pub struct SMILESDocument {
ids: Vec<types::ID>,
data: Vec<types::SMILES>,
}
impl SMILESDocument {
pub fn len(&self) -> usize { self.ids.len() }
pub fn get_id(&self, idx: usize) -> &types::ID { &self.ids[idx] }
pub fn get_data(&self, idx: usize) -> &types::SMILES { &self.data[idx] }
pub fn desc(&self) -> String {
vec![
format!("{}", self.len()),
].join("\t\t")
}
pub fn new_from_smiles_vec(smiles_vec: &Vec<&String>, ids_input: &Vec<String>) -> Self {
let ids = ids_input.to_vec();
let data: Vec<types::SMILES> = smiles_vec.iter()
.map(|s| s.to_string())
.collect();
Self { ids, data }
}
pub fn new_from_chembl(filepath: &std::path::Path) -> Self {
let sc = chiral_db_sources::chembl::SourceChembl::new(filepath);
let (smiles_vec, ids) = sc.get_smiles_id_pairs();
SMILESDocument::new_from_smiles_vec(&smiles_vec, &ids)
}
pub fn get_doc_ob_molecule(&self) -> Vec<(types::ID, types::SMILES)> {
(0..(self.len()))
.map(|idx| (
self.get_id(idx).to_string(),
self.get_data(idx).to_string()
))
.collect()
}
}
fn ob_substructure_match_mol(smarts: &types::SMARTS, smiles: &types::SMILES) -> types::SubstructureMatch {
let sp = openbabel::smartspattern::SmartsPattern::new_from_smarts(smarts);
let mol = openbabel::molecule::Molecule::new_from_smiles(smiles);
sp.find_match(&mol)
}
fn ob_substructure_match_doc(smarts: &types::SMARTS, doc_mol: &Vec<(types::ID, types::SMILES)>) -> types::ResultSubstructure {
doc_mol.iter()
.map(|(id, smiles)| (id.to_string(), ob_substructure_match_mol(smarts, smiles)))
.filter(|(_id, m)| m.len() > 0)
.collect()
}
pub fn query_substructure(toolkit: &types::Toolkit, smarts_query: &types::SMARTS, doc_smiles: &SMILESDocument) -> types::ResultSubstructure {
match toolkit {
types::Toolkit::OpenBabel => {
let doc_mol = doc_smiles.get_doc_ob_molecule();
ob_substructure_match_doc(smarts_query, &doc_mol)
}
}
}
fn load_smiles_chembl(smiles_doc: &config::SmilesDocumentConfig) -> SMILESDocument {
let filepath = std::path::Path::new(&smiles_doc.filepath);
SMILESDocument::new_from_chembl(&filepath)
}
pub fn load_smiles_db(conf: &config::Config) -> SmilesDB {
let mut smiles_db = SmilesDB::new();
if let Some(smiles_doc) = &conf.smiles_doc {
for smiles_doc in smiles_doc.iter() {
match &smiles_doc.source {
types::Source::Chembl => {
smiles_db.insert(smiles_doc.name.clone(), std::sync::Arc::new(load_smiles_chembl(smiles_doc)));
}
types::Source::Zinc => {
unimplemented!();
}
}
}
}
smiles_db
}
#[cfg(test)]
mod test_substructure {
use super::*;
#[test]
fn test_smiels_doc_new_from_smiles_vec() {
let filepath = std::path::Path::new("../chiral-db-example-data/ChEMBL/chembl_30_chemreps_100.txt");
let sc = chiral_db_sources::chembl::SourceChembl::new(&filepath);
let (smiles_vec, ids) = sc.get_smiles_id_pairs();
let sd = SMILESDocument::new_from_smiles_vec(&smiles_vec, &ids);
assert_eq!(sd.len(), 100);
}
#[test]
fn test_query_substructure() {
let filepath = std::path::Path::new("../chiral-db-example-data/ChEMBL/chembl_30_chemreps_10k.txt");
let sc = chiral_db_sources::chembl::SourceChembl::new(&filepath);
let (smiles_vec, ids) = sc.get_smiles_id_pairs();
let sd = SMILESDocument::new_from_smiles_vec(&smiles_vec, &ids);
let smarts_1 = String::from("Cc1cc(NC(=O)c2cc(Cl)cc(Cl)c2O)ccc1Sc1nc2ccccc2s1");
let res_1 = query_substructure(&types::Toolkit::OpenBabel, &smarts_1, &sd);
assert_eq!(res_1.len(), 1);
assert!(res_1.contains_key("CHEMBL263810"));
let smarts_2 = String::from("Sc1nc2ccccc2s1");
let res_2 = query_substructure(&types::Toolkit::OpenBabel, &smarts_2, &sd);
assert_eq!(res_2.len(), 2);
assert!(res_2.contains_key("CHEMBL6685"));
assert!(res_2.contains_key("CHEMBL263810"));
}
}