Coverage for chempropstereo/tests/test_rdkit.py: 100%
36 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-03-22 21:04 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-03-22 21:04 +0000
1"""Unit tests for chiral center detection and canonical ranking using RDKit."""
3import numpy as np
4from rdkit import Chem
7def test_chiral_center_detection():
8 """Test detection of chiral centers in molecules using RDKit.
10 This test verifies that the FindPotentialStereo function from RDKit
11 accurately identifies chiral centers in given SMILES strings. It checks
12 both legacy and non-legacy stereo perception modes. The chiral centers
13 detected are compared against expected descriptors (clockwise 'CW' or
14 counterclockwise 'CCW'). The test ensures that chiral centers are correctly
15 specified and that their controlling atoms match the expected neighbors.
16 It also asserts that non-chiral atoms are marked as unspecified.
17 """
19 def check_molecule(smiles, descriptions, use_legacy):
20 Chem.SetUseLegacyStereoPerception(use_legacy)
21 mol = Chem.MolFromSmiles(smiles)
22 info_list = Chem.FindPotentialStereo(mol, cleanIt=False, flagPossible=False)
23 assert len(info_list) == len(descriptions)
24 for center, desc in zip(info_list, descriptions):
25 assert center.type == Chem.StereoType.Atom_Tetrahedral
26 assert center.specified == Chem.StereoSpecified.Specified
27 atom = mol.GetAtomWithIdx(center.centeredOn)
28 neighbors = [n.GetIdx() for n in atom.GetNeighbors()]
29 assert atom.GetChiralTag() == getattr(
30 Chem.ChiralType, f"CHI_TETRAHEDRAL_{desc}"
31 )
32 assert center.descriptor == getattr(Chem.StereoDescriptor, f"Tet_{desc}")
33 assert all(i == j for i, j in zip(center.controllingAtoms, neighbors))
34 for atom in mol.GetAtoms():
35 if atom.GetIdx() not in [center.centeredOn for center in info_list]:
36 assert atom.GetChiralTag() == Chem.ChiralType.CHI_UNSPECIFIED
38 original_use_legacy = Chem.GetUseLegacyStereoPerception()
39 for use_legacy in [True, False]:
40 check_molecule("C[C@@H](O)N", ["CW"], use_legacy)
41 check_molecule("C[C@H](O)N", ["CCW"], use_legacy)
42 check_molecule("C[C@H](N)O", ["CCW"], use_legacy)
43 check_molecule("C[C@@H](O)[C@@H](C)N", ["CW", "CW"], use_legacy)
44 check_molecule("C[C@@H](O)[C@H](C)N", ["CW", "CCW"], use_legacy)
45 Chem.SetUseLegacyStereoPerception(original_use_legacy)
48def test_canonical_ranking():
49 """Test canonical ranking of atoms in a molecule.
51 Checks that the canonical ranking from RDKit produces the expected
52 order of atoms in a molecule. The test molecule is a chiral molecule
53 with a stereocenter and a tetrahedral stereobond. The test also checks
54 that the hydrogen atoms are correctly sorted last in the canonical
55 ranking.
56 """
57 mol = Chem.MolFromSmiles("C[C@@H]([C@@H](C)N)O")
58 order = np.argsort(Chem.CanonicalRankAtoms(mol)).tolist()
59 assert order == [0, 3, 4, 5, 1, 2]
60 mol = Chem.AddHs(mol)
61 order = np.argsort(Chem.CanonicalRankAtoms(mol)).tolist()
62 assert order == [16, 14, 15, 6, 7, 8, 11, 12, 13, 9, 10, 5, 4, 0, 3, 1, 2]
63 ranked_elements = "".join([mol.GetAtomWithIdx(i).GetSymbol() for i in order])
64 assert ranked_elements == "HHHHHHHHHHHONCCCC" # Hydrogens first