Diff of /tests/test_spatial.py [000000] .. [3b722e]

Switch to unified view

a b/tests/test_spatial.py
1
import os
2
3
import pytest
4
from numpy.testing import (assert_almost_equal,
5
                           assert_array_equal,
6
                           assert_array_almost_equal)
7
import numpy as np
8
9
import oddt
10
from oddt.spatial import (angle,
11
                          dihedral,
12
                          rmsd,
13
                          distance,
14
                          rotate)
15
from .utils import shuffle_mol
16
17
18
test_data_dir = os.path.dirname(os.path.abspath(__file__))
19
20
ASPIRIN_SDF = """
21
     RDKit          3D
22
23
 13 13  0  0  0  0  0  0  0  0999 V2000
24
    3.3558   -0.4356   -1.0951 C   0  0  0  0  0  0  0  0  0  0  0  0
25
    2.0868   -0.6330   -0.3319 C   0  0  0  0  0  0  0  0  0  0  0  0
26
    2.0284   -0.9314    0.8534 O   0  0  0  0  0  0  0  0  0  0  0  0
27
    1.0157   -0.4307   -1.1906 O   0  0  0  0  0  0  0  0  0  0  0  0
28
   -0.2079   -0.5332   -0.5260 C   0  0  0  0  0  0  0  0  0  0  0  0
29
   -0.9020   -1.7350   -0.6775 C   0  0  0  0  0  0  0  0  0  0  0  0
30
   -2.1373   -1.8996   -0.0586 C   0  0  0  0  0  0  0  0  0  0  0  0
31
   -2.6805   -0.8641    0.6975 C   0  0  0  0  0  0  0  0  0  0  0  0
32
   -1.9933    0.3419    0.8273 C   0  0  0  0  0  0  0  0  0  0  0  0
33
   -0.7523    0.5244    0.2125 C   0  0  0  0  0  0  0  0  0  0  0  0
34
   -0.0600    1.8264    0.3368 C   0  0  0  0  0  0  0  0  0  0  0  0
35
    0.9397    2.1527   -0.2811 O   0  0  0  0  0  0  0  0  0  0  0  0
36
   -0.6931    2.6171    1.2333 O   0  0  0  0  0  0  0  0  0  0  0  0
37
  1  2  1  0
38
  2  3  2  0
39
  2  4  1  0
40
  4  5  1  0
41
  5  6  2  0
42
  6  7  1  0
43
  7  8  2  0
44
  8  9  1  0
45
  9 10  2  0
46
 10 11  1  0
47
 11 12  2  0
48
 11 13  1  0
49
 10  5  1  0
50
M  END
51
52
"""
53
54
55
def test_angles():
56
    """Test spatial computations - angles"""
57
58
    # Angles
59
    assert_array_almost_equal(angle(np.array((1, 0, 0)),
60
                                    np.array((0, 0, 0)),
61
                                    np.array((0, 1, 0))), 90)
62
63
    assert_array_almost_equal(angle(np.array((1, 0, 0)),
64
                                    np.array((0, 0, 0)),
65
                                    np.array((1, 1, 0))), 45)
66
67
    # Check benzene ring angle
68
    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
69
    mol.make3D()
70
    assert_array_almost_equal(angle(mol.coords[0],
71
                                    mol.coords[1],
72
                                    mol.coords[2]), 120, decimal=1)
73
74
75
def test_dihedral():
76
    """Test dihedrals"""
77
    # Dihedrals
78
    assert_array_almost_equal(dihedral(np.array((1, 0, 0)),
79
                                       np.array((0, 0, 0)),
80
                                       np.array((0, 1, 0)),
81
                                       np.array((1, 1, 0))), 0)
82
83
    assert_array_almost_equal(dihedral(np.array((1, 0, 0)),
84
                                       np.array((0, 0, 0)),
85
                                       np.array((0, 1, 0)),
86
                                       np.array((1, 1, 1))), -45)
87
88
    # Check benzene ring dihedral
89
    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
90
    mol.make3D()
91
    assert abs(dihedral(*mol.coords[:4])) < 2.
92
93
94
def test_distance():
95
    mol1 = oddt.toolkit.readstring('sdf', ASPIRIN_SDF)
96
    d = distance(mol1.coords, mol1.coords)
97
    n_atoms = len(mol1.coords)
98
    assert d.shape, (n_atoms == n_atoms)
99
    assert_array_equal(d[np.eye(len(mol1.coords), dtype=bool)], np.zeros(n_atoms))
100
101
    d = distance(mol1.coords, mol1.coords.mean(axis=0).reshape(1, 3))
102
    assert d.shape, (n_atoms == 1)
103
    ref_dist = [[3.556736951371501], [2.2058040428631056], [2.3896002745745415],
104
                [1.6231668718498249], [0.7772981740050453], [2.0694947503940004],
105
                [2.8600587871157184], [2.9014207091233857], [2.1850791695403564],
106
                [0.9413368403116871], [1.8581710293650173], [2.365629642108773],
107
                [2.975007440512798]]
108
    assert_array_almost_equal(d, ref_dist)
109
110
111
def test_spatial():
112
    """Test spatial misc computations"""
113
    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
114
    mol.make3D()
115
    mol2 = mol.clone
116
    # Test rotation
117
    assert_almost_equal(mol2.coords, rotate(mol2.coords, np.pi, np.pi, np.pi))
118
119
    # Rotate perpendicular to ring
120
    mol2.coords = rotate(mol2.coords, 0, 0, np.pi)
121
122
    # RMSD
123
    assert_almost_equal(rmsd(mol, mol2, method=None), 2.77, decimal=1)
124
    # Hungarian must be close to zero (RDKit is 0.3)
125
    assert_almost_equal(rmsd(mol, mol2, method='hungarian'), 0, decimal=0)
126
    # Minimized by symetry must close to zero
127
    assert_almost_equal(rmsd(mol, mol2, method='min_symmetry'), 0, decimal=0)
128
129
130
def test_rmsd():
131
    # pick one molecule from docked poses
132
    mols = list(oddt.toolkit.readfile('sdf', os.path.join(test_data_dir, 'data/dude/xiap/actives_docked.sdf')))
133
    mols = list(filter(lambda x: x.title == '312335', mols))
134
135
    res = {
136
        'method=None':
137
            [4.7536, 2.5015, 2.7942, 1.1282, 0.7444, 1.6257, 4.7625,
138
             2.7168, 2.5504, 1.9304, 2.6201, 3.1742, 3.2254, 4.7785,
139
             4.8035, 7.8963, 2.2385, 4.8625, 3.2037],
140
        'method=hungarian':
141
            [0.9013, 1.0730, 1.0531, 1.0286, 0.7353, 1.4094, 0.5391,
142
             1.3297, 1.0881, 1.7796, 2.6064, 3.1577, 3.2135, 0.8126,
143
             1.2909, 2.5217, 2.0836, 1.8325, 3.1874],
144
        'method=min_symmetry':
145
            [0.9013, 1.0732, 1.0797, 1.0492, 0.7444, 1.6257, 0.5391,
146
             1.5884, 1.0935, 1.9304, 2.6201, 3.1742, 3.2254, 1.1513,
147
             1.5206, 2.5361, 2.2385, 1.971, 3.2037],
148
        }
149
150
    kwargs_grid = [{'method': None},
151
                   {'method': 'hungarian'},
152
                   {'method': 'min_symmetry'}]
153
    for kwargs in kwargs_grid:
154
        res_key = '_'.join('%s=%s' % (k, v)
155
                           for k, v in sorted(kwargs.items()))
156
        assert_array_almost_equal([rmsd(mols[0], mol, **kwargs)
157
                                  for mol in mols[1:]],
158
                                  res[res_key], decimal=4)
159
160
    # test shuffled rmsd
161
    for _ in range(5):
162
        for kwargs in kwargs_grid:
163
            # dont use method=None in shuffled tests
164
            if kwargs['method'] is None:
165
                continue
166
            res_key = '_'.join('%s=%s' % (k, v)
167
                               for k, v in sorted(kwargs.items()))
168
            assert_array_almost_equal([rmsd(mols[0],
169
                                            shuffle_mol(mol),
170
                                            **kwargs)
171
                                       for mol in mols[1:]],
172
                                      res[res_key], decimal=4)
173
174
175
def test_rmsd_errors():
176
    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
177
    mol.make3D()
178
    mol.addh()
179
    mol2 = next(oddt.toolkit.readfile('sdf', os.path.join(test_data_dir, 'data/dude/xiap/actives_docked.sdf')))
180
181
    for method in [None, 'hungarian', 'min_symmetry']:
182
        with pytest.raises(ValueError, match='Unequal number of atoms'):
183
            rmsd(mol, mol2, method=method)
184
185
        for _ in range(5):
186
            with pytest.raises(ValueError, match='Unequal number of atoms'):
187
                rmsd(shuffle_mol(mol), shuffle_mol(mol2), method=method)