|
4 | 4 | import unittest |
5 | 5 |
|
6 | 6 | from arc.molecule.filtration import (get_octet_deviation_list, get_octet_deviation, filter_structures, |
7 | | - charge_filtration, get_charge_span_list, aromaticity_filtration) |
| 7 | + charge_filtration, get_atom_indices, get_charge_span_list, |
| 8 | + aromaticity_filtration) |
8 | 9 | from arc.molecule.molecule import Molecule |
9 | 10 | from arc.molecule.resonance import generate_resonance_structures, analyze_molecule |
10 | 11 |
|
@@ -126,7 +127,7 @@ def test_radical_site(self): |
126 | 127 | Molecule().from_adjacency_list(adj3)] |
127 | 128 |
|
128 | 129 | for mol in mol_list: |
129 | | - mol.update() # the charge_filtration uses the atom.sorting_label attribute |
| 130 | + mol.update() |
130 | 131 |
|
131 | 132 | filtered_list = charge_filtration(mol_list, get_charge_span_list(mol_list)) |
132 | 133 | self.assertEqual(len(filtered_list), 2) |
@@ -213,7 +214,7 @@ def test_electronegativity(self): |
213 | 214 | Molecule().from_adjacency_list(adj7)] |
214 | 215 |
|
215 | 216 | for mol in mol_list: |
216 | | - mol.update() # the charge_filtration uses the atom.sorting_label attribute |
| 217 | + mol.update() |
217 | 218 |
|
218 | 219 | filtered_list = charge_filtration(mol_list, get_charge_span_list(mol_list)) |
219 | 220 | self.assertEqual(len(filtered_list), 4) |
@@ -301,6 +302,53 @@ def test_aromaticity(self): |
301 | 302 | filtered_list = aromaticity_filtration(mol_list, analyze_molecule(mol_list[0])) |
302 | 303 | self.assertEqual(len(filtered_list), 3) |
303 | 304 |
|
| 305 | + def test_get_atom_indices(self): |
| 306 | + """Test that atoms are mapped to their position in mol.vertices""" |
| 307 | + mol = Molecule().from_smiles('[O]N=O') |
| 308 | + indices = get_atom_indices(mol) |
| 309 | + self.assertEqual(len(indices), len(mol.vertices)) |
| 310 | + for index, atom in enumerate(mol.vertices): |
| 311 | + self.assertEqual(indices[id(atom)], index) |
| 312 | + |
| 313 | + def test_charge_filtration_independent_of_atom_order(self): |
| 314 | + """Test that the charge filtration heuristics return the same structures for either atom order""" |
| 315 | + for smiles, expected, aromatic in (('[O]c1ccc([N+](=O)[O-])cc1', 11, 2), |
| 316 | + ('[CH2]c1ccc([N+](=O)[O-])cc1', 11, 2), |
| 317 | + ('[O]c1ccccc1[N+](=O)[O-]', 11, 2), |
| 318 | + ('[O]c1cccc([N+](=O)[O-])c1', 9, 2), |
| 319 | + ('[O]N=O', 4, 0), |
| 320 | + ('C=N[O]', 3, 0), |
| 321 | + ('NC=O', 2, 0), |
| 322 | + ): |
| 323 | + sorted_list = generate_resonance_structures(Molecule().from_smiles(smiles), |
| 324 | + keep_isomorphic=True, save_order=False) |
| 325 | + saved_list = generate_resonance_structures(Molecule().from_smiles(smiles), |
| 326 | + keep_isomorphic=True, save_order=True) |
| 327 | + self.assertEqual(len(sorted_list), expected, msg=smiles) |
| 328 | + self.assertEqual(len(saved_list), expected, msg=smiles) |
| 329 | + for mol_list in (sorted_list, saved_list): |
| 330 | + self.assertEqual(sum(1 for mol in mol_list |
| 331 | + if any(bond.is_benzene() for bond in mol.get_all_edges())), |
| 332 | + aromatic, msg=smiles) |
| 333 | + |
| 334 | + def test_charge_filtration_of_disconnected_ions(self): |
| 335 | + """Test that a species whose charges sit in disconnected components is filtered |
| 336 | +
|
| 337 | + Charged atoms in different molecular fragments have no path between them, so the charge |
| 338 | + proximity heuristic does not count them, and a species whose only opposite-charge pairs |
| 339 | + are of that kind is not filtered out entirely. |
| 340 | + """ |
| 341 | + for save_order in (False, True): |
| 342 | + for smiles, expected in (('[Li+].[OH-]', 1), |
| 343 | + ('[NH4+].[O-]N=O', 1), |
| 344 | + ('O=C([O-])[O-].[NH4+].[NH4+]', 1), |
| 345 | + ('[Li+].[Li+].[O-][O-]', 1), |
| 346 | + ): |
| 347 | + mol_list = generate_resonance_structures(Molecule().from_smiles(smiles), |
| 348 | + save_order=save_order) |
| 349 | + self.assertEqual(len(mol_list), expected, msg=smiles) |
| 350 | + self.assertTrue(mol_list[0].get_charge_span()) |
| 351 | + |
304 | 352 |
|
305 | 353 | if __name__ == '__main__': |
306 | 354 | unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) |
0 commit comments