Expose new default parameter objects to python (#1150)

* Fix a bug in the python DistGeom tests.

* test new features

* add simple parameter objects for ETDG, ETKDG, and KDG

* Update conformation generation documentation to use the new parameter objects.
This commit is contained in:
Greg Landrum
2016-11-06 10:17:47 +01:00
committed by GitHub
parent 3b4fc09e46
commit bada20dbaf
3 changed files with 61 additions and 31 deletions

View File

@@ -120,6 +120,15 @@ PyObject *getMolBoundsMatrix(ROMol &mol, bool set15bounds = true,
return PyArray_Return(res);
}
DGeomHelpers::EmbedParameters *getETKDG() {
return new DGeomHelpers::EmbedParameters(DGeomHelpers::ETKDG);
}
DGeomHelpers::EmbedParameters *getKDG() {
return new DGeomHelpers::EmbedParameters(DGeomHelpers::KDG);
}
DGeomHelpers::EmbedParameters *getETDG() {
return new DGeomHelpers::EmbedParameters(DGeomHelpers::ETDG);
}
}
BOOST_PYTHON_MODULE(rdDistGeom) {
@@ -311,6 +320,15 @@ BOOST_PYTHON_MODULE(rdDistGeom) {
docString.c_str());
python::def("EmbedMolecule", RDKit::EmbedMolecule2,
(python::arg("mol"), python::arg("params")), docString.c_str());
python::def("ETKDG", RDKit::getETKDG,
"Returns an EmbedParameters object for the ETKDG method.",
python::return_value_policy<python::manage_new_object>());
python::def("ETDG", RDKit::getETDG,
"Returns an EmbedParameters object for the ETDG method.",
python::return_value_policy<python::manage_new_object>());
python::def("KDG", RDKit::getKDG,
"Returns an EmbedParameters object for the KDG method.",
python::return_value_policy<python::manage_new_object>());
docString =
"Returns the distance bounds matrix for a molecule\n\

View File

@@ -400,11 +400,11 @@ class TestCase(unittest.TestCase):
def _compareConfs(self, mol, ref, molConfId, refConfId):
self.assertEqual(mol.GetNumAtoms(), ref.GetNumAtoms())
molConf = mol.GetConformer(molConfId)
refConf = mol.GetConformer(refConfId)
refConf = ref.GetConformer(refConfId)
for i in range(mol.GetNumAtoms()):
mp = molConf.GetAtomPosition(i)
rp = refConf.GetAtomPosition(i)
self.assertAlmostEqual((mp - rp).Length(), 0.0, 4)
self.assertAlmostEqual((mp - rp).Length(), 0.0, 3)
def test9EmbedParams(self):
mol = Chem.AddHs(Chem.MolFromSmiles('OCCC'))
@@ -424,6 +424,10 @@ class TestCase(unittest.TestCase):
params.useExpTorsionAnglePrefs = True
self.assertEqual(rdDistGeom.EmbedMolecule(mol, params), 0)
self._compareConfs(mol, ref, 0, 0)
params = rdDistGeom.ETDG()
params.randomSeed = 42
self.assertEqual(rdDistGeom.EmbedMolecule(mol, params), 0)
self._compareConfs(mol, ref, 0, 0)
fn = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol', 'DistGeomHelpers', 'test_data',
'simple_torsion.etkdg.mol')
@@ -434,6 +438,10 @@ class TestCase(unittest.TestCase):
params.useBasicKnowledge = True
self.assertEqual(rdDistGeom.EmbedMolecule(mol, params), 0)
self._compareConfs(mol, ref, 0, 0)
params = rdDistGeom.ETKDG()
params.randomSeed = 42
self.assertEqual(rdDistGeom.EmbedMolecule(mol, params), 0)
self._compareConfs(mol, ref, 0, 0)
fn = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol', 'DistGeomHelpers', 'test_data',
'simple_torsion.kdg.mol')
@@ -443,6 +451,10 @@ class TestCase(unittest.TestCase):
params.useBasicKnowledge = True
self.assertEqual(rdDistGeom.EmbedMolecule(mol, params), 0)
self._compareConfs(mol, ref, 0, 0)
params = rdDistGeom.KDG()
params.randomSeed = 42
self.assertEqual(rdDistGeom.EmbedMolecule(mol, params), 0)
self._compareConfs(mol, ref, 0, 0)
if __name__ == '__main__':

View File

@@ -227,21 +227,20 @@ cyclobutane
M END
<BLANKLINE>
Or you can add 3D coordinates by embedding the molecule:
Or you can add 3D coordinates by embedding the molecule (we're using the ETKDG
method here, which is described in more detail below):
>>> AllChem.EmbedMolecule(m2)
0
>>> AllChem.UFFOptimizeMolecule(m2)
>>> AllChem.EmbedMolecule(m2,AllChem.ETKDG())
0
>>> print(Chem.MolToMolBlock(m2)) # doctest: +NORMALIZE_WHITESPACE
cyclobutane
RDKit 3D
<BLANKLINE>
4 4 0 0 0 0 0 0 0 0999 V2000
-0.7883 0.5560 -0.2718 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.4153 -0.9091 -0.1911 C 0 0 0 0 0 0 0 0 0 0 0 0
0.7883 -0.5560 0.6568 C 0 0 0 0 0 0 0 0 0 0 0 0
0.4153 0.9091 0.5762 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.8321 0.5405 -0.1981 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.3467 -0.8825 -0.2651 C 0 0 0 0 0 0 0 0 0 0 0 0
0.7190 -0.5613 0.7314 C 0 0 0 0 0 0 0 0 0 0 0 0
0.4599 0.9032 0.5020 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0
2 3 1 0
3 4 1 0
@@ -249,14 +248,11 @@ cyclobutane
M END
<BLANKLINE>
The optimization step isn't necessary, but it substantially improves the quality of the conformation.
To get good 3D conformations, it's almost always a good idea to add hydrogens to the molecule first:
To get good 3D conformations, it's almost always a good idea to add
hydrogens to the molecule first:
>>> m3 = Chem.AddHs(m2)
>>> AllChem.EmbedMolecule(m3)
0
>>> AllChem.UFFOptimizeMolecule(m3)
>>> AllChem.EmbedMolecule(m3,AllChem.ETKDG())
0
These can then be removed:
@@ -267,10 +263,10 @@ cyclobutane
RDKit 3D
<BLANKLINE>
4 4 0 0 0 0 0 0 0 0999 V2000
0.2851 1.0372 -0.0171 C 0 0 0 0 0 0 0 0 0 0 0 0
1.0352 -0.2833 0.0743 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.2851 -1.0372 0.0171 C 0 0 0 0 0 0 0 0 0 0 0 0
-1.0352 0.2833 -0.0743 C 0 0 0 0 0 0 0 0 0 0 0 0
0.3497 0.9755 -0.2202 C 0 0 0 0 0 0 0 0 0 0 0 0
0.9814 -0.3380 0.2534 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.3384 -1.0009 -0.1474 C 0 0 0 0 0 0 0 0 0 0 0 0
-0.9992 0.3532 0.1458 C 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 0
2 3 1 0
3 4 1 0
@@ -551,7 +547,7 @@ The full process of embedding and optimizing a molecule is easier than all the a
0
>>> m3=Chem.AddHs(m)
>>> # use the new method
>>> AllChem.EmbedMolecule(m3, useExpTorsionAnglePrefs=True, useBasicKnowledge=True)
>>> AllChem.EmbedMolecule(m3, AllChem.ETKDG())
0
The RDKit also has an implementation of the MMFF94 force field available. [#mmff1]_, [#mmff2]_, [#mmff3]_, [#mmff4]_, [#mmffs]_
@@ -588,18 +584,23 @@ to each other and the RMS values calculated.
>>> AllChem.AlignMolConformers(m2, RMSlist=rmslist)
>>> print(len(rmslist))
9
>>> m = Chem.MolFromSmiles('C1CCC1OC')
>>> m3=Chem.AddHs(m)
>>> # run CSD-based method
>>> cids = AllChem.EmbedMultipleConfs(m3, useExpTorsionAnglePrefs=True, useBasicKnowledge=True, numConfs=10)
>>> print(len(cids))
10
rmslist contains the RMS values between the first conformer and all others.
The RMS between two specific conformers (e.g. 1 and 9) can also be calculated. The flag prealigned lets the user specify if the conformers are already aligned (by default, the function aligns them).
The RMS between two specific conformers (e.g. 1 and 9) can also be calculated.
The flag prealigned lets the user specify if the conformers are already aligned
(by default, the function aligns them).
>>> rms = AllChem.GetConformerRMS(m2, 1, 9, prealigned=True)
We can also generate multiple conformers using the new CSD-based method:
>>> m = Chem.MolFromSmiles('C1CCC1OC')
>>> m3=Chem.AddHs(m)
>>> # run the new CSD-based method
>>> cids = AllChem.EmbedMultipleConfs(m3, 10, AllChem.ETKDG())
>>> print(len(cids))
10
More 3D functionality of the RDKit is described in the Cookbook.
@@ -607,9 +608,8 @@ More 3D functionality of the RDKit is described in the Cookbook.
The original, default, 2D->3D conversion provided with the RDKit is not intended
to be a replacement for a “real” conformational analysis tool; it
merely provides quick 3D structures for cases when they are
required. On the other hand, the second method, when a sufficiently
large number of conformers are generated, should be adequate for most
purposes.
required. We believe, however, that the newer ETKDG method[#riniker2]_ should be
adequate for most purposes.
Preserving Molecules