graph_symmetry/ext/molecule/
molecule.rs1use super::atom;
7
8pub struct Molecule {
9 pub atoms: Vec<atom::Atom>,
10}
11
12impl Molecule {
13 pub fn from_smiles(smiles: &str) -> Self {
14 let mut builder = purr::graph::Builder::new();
15
16 match purr::read::read(smiles, &mut builder, None) {
17 Ok(_) => {
18 match builder.build() {
20 Ok(mut atoms) => {
21 let aromatic_flags: Vec<bool> = atoms.iter().map(|atom| atom.is_aromatic()).collect();
26 for atom_idx in 0..(atoms.len()) {
27 for bond in atoms[atom_idx].bonds.iter_mut() {
28 if aromatic_flags[atom_idx] && aromatic_flags[bond.tid] {
29 *bond = purr::graph::Bond::new(purr::feature::BondKind::Aromatic, bond.tid);
30 }
31 }
32 }
33
34 let new_atoms: Vec<atom::Atom> = atoms.iter().map(|a| atom::Atom::from_atom_purr(&a)).collect();
35 Self { atoms: new_atoms }
36 },
37 Err(e) => {
38 println!("error on purr builder: {:?}", e);
39 Self { atoms: vec![] }
40 }
41 }
42 },
43 Err(e) => {
44 println!("error smiles parsing: {:?}", e);
45 Self { atoms: vec![] }
46 }
47 }
48 }
49
50 pub fn smiles_with_index(&self, smiles: &String, numbering: &Vec<usize>) -> String {
51 if self.atoms.len() == 0 {
52 return "smiles parsing errro".to_string()
53 }
54
55 let mut new_smiles: String = String::from("");
56 let mut cur: usize = 0;
57
58 for i in 0..(self.atoms.len()-1) {
59 let atom_string: String = self.atoms[i].kind.to_string();
60 let mapped_number = match numbering.len() > 0 {
61 true => numbering[i],
62 false => i
63 };
64 if atom_string.as_bytes()[0] == "[".as_bytes()[0] {
65 new_smiles += &format!("[{atom_string}:{index}]", atom_string=String::from(&atom_string[1..(atom_string.len()-1)]), index=mapped_number);
66 while smiles.as_bytes()[cur] != "]".as_bytes()[0] {
67 cur += 1;
68 }
69 cur += 1;
70 } else {
71 new_smiles += &format!("[{atom_string}:{index}]", atom_string=atom_string, index=mapped_number);
72 cur += atom_string.len();
73 }
74
75 let cur_last: usize = cur;
76 let next_atom_string: String = self.atoms[i+1].kind.to_string();
77 while next_atom_string.as_bytes()[0] != smiles.as_bytes()[cur] {
78 cur += 1;
79 if cur >= smiles.len() {
80 break;
81 }
82 }
83
84 new_smiles += &smiles[cur_last..cur];
85 }
86
87
88 let mapped_number = match numbering.len() > 0 {
89 true => numbering[self.atoms.len() - 1],
90 false => self.atoms.len() - 1
91 };
92 let atom_string: String = self.atoms[self.atoms.len() - 1].kind.to_string();
93 new_smiles += &format!("[{atom_string}:{index}]", atom_string=atom_string, index=mapped_number);
94 cur += atom_string.len();
95 new_smiles += &smiles[cur..smiles.len()];
96
97 new_smiles
98 }
99}
100
101#[cfg(test)]
102mod test_ext_mol_molecule {
103 use super::*;
104
105 #[test]
106 fn test_purr_features() {
107 let smiles: String = "cc1".to_string();
108 let mol = Molecule::from_smiles(&smiles);
109 assert_eq!(mol.atoms.len(), 0);
110 }
111
112 #[test]
113 fn test_from_smiles() {
114 let smiles: String = "c1ccccc1CN".to_string();
115 let mol = Molecule::from_smiles(&smiles);
116 assert_eq!(mol.atoms[0].kind, "c".to_string());
117 assert_eq!(mol.atoms[0].bonds.len(), 2);
118 assert_eq!(mol.atoms[1].kind, "c".to_string());
119 assert_eq!(mol.atoms[1].bonds.len(), 2);
120 assert_eq!(mol.atoms[2].kind, "c".to_string());
121 assert_eq!(mol.atoms[2].bonds.len(), 2);
122 assert_eq!(mol.atoms[3].kind, "c".to_string());
123 assert_eq!(mol.atoms[3].bonds.len(), 2);
124 assert_eq!(mol.atoms[4].kind, "c".to_string());
125 assert_eq!(mol.atoms[4].bonds.len(), 2);
126 assert_eq!(mol.atoms[5].kind, "c".to_string());
127 assert_eq!(mol.atoms[5].bonds.len(), 3);
128 assert_eq!(mol.atoms[6].kind, "C".to_string());
129 assert_eq!(mol.atoms[6].bonds.len(), 2);
130 assert_eq!(mol.atoms[7].kind, "N".to_string());
131 assert_eq!(mol.atoms[7].bonds.len(), 1);
132 }
133}