Skip to content

Commit

Permalink
Merge pull request #76 from molssi-seamm/dev
Browse files Browse the repository at this point in the history
Rotated molecule from SMILES, InChI, or InChIKey to standard orientation
  • Loading branch information
seamm authored May 5, 2024
2 parents c6b5bcf + dcb9338 commit 10ce340
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 28 deletions.
5 changes: 5 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
=======
History
=======
2024.5.6 -- Rotated molecule from SMILES, InChI, or InChIKey to standard orientation
* Molecules created from line notation are created in an random orientation. This
enhancement rotates them to the standard orientation, which will look nice for
small, symmetric molecules.

2024.5.5 -- Bugfix: bonds in RDKit
* There was an indexing bug translating bonds back from RDKit to SEAMM. The famous
0/1 problem!
Expand Down
37 changes: 12 additions & 25 deletions molsystem/inchi.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def to_inchi(self, key=False, openbabel=False):

return inchi.strip()

def from_inchi(self, inchi, name=None, openbabel=True):
def from_inchi(self, inchi, name=None, reorient=True, openbabel=True):
"""Create the system from a InChI string.
Parameters
Expand All @@ -83,6 +83,8 @@ def from_inchi(self, inchi, name=None, openbabel=True):
The InChI string
name : str = None
The name of the molecule
reorient : bool = True
Whether to reorient to the standard orientation
openbabel : bool = False
Whether to use Openbabel rather than default of RDKit
Expand Down Expand Up @@ -116,15 +118,18 @@ def from_inchi(self, inchi, name=None, openbabel=True):
AllChem.EmbedMolecule(mol)
self.from_RDKMol(mol)

print(f"{self.n_atoms=}")
print(f"{self.atoms.symbols=}")
# Rotate to standard orientation
rdkMol = self.to_RDKMol()
rdkConf = rdkMol.GetConformers()[0]
Chem.rdMolTransforms.CanonicalizeConformer(rdkConf)
self.from_RDKMol(rdkMol)

if name is not None:
self.name = name
else:
self.name = save

def from_inchikey(self, inchikey, name=None):
def from_inchikey(self, inchikey, name=None, reorient=True):
"""Create the system from an InChIKey string.
Parameters
Expand All @@ -133,33 +138,15 @@ def from_inchikey(self, inchikey, name=None):
The InChIKey string
name : str = None
The name of the molecule
reorient : bool = True
Whether to reorient to the standard orientation
Returns
-------
None
"""
inchi = self._get_inchi(inchikey)

save = self.name

obConversion = OB.OBConversion()
obConversion.SetInAndOutFormats("inchi", "mdl")
mol = OB.OBMol()
obConversion.ReadString(mol, inchi)

# Add hydrogens
mol.AddHydrogens()

# Get coordinates for a 3-D structure
builder = OB.OBBuilder()
builder.Build(mol)

self.from_OBMol(mol)

if name is not None:
self.name = name
else:
self.name = save
self.from_inchi(inchi, reorient=reorient)

def _get_inchi(self, inchikey):
"""Get the InChI from PubChem given the InChIKey."""
Expand Down
2 changes: 2 additions & 0 deletions molsystem/rdkit_.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def to_RDKMol(self):
1: Chem.BondType.SINGLE,
2: Chem.BondType.DOUBLE,
3: Chem.BondType.TRIPLE,
5: Chem.BondType.AROMATIC,
}
for row in self.bonds.bonds():
rdk_mol.AddBond(
Expand Down Expand Up @@ -108,6 +109,7 @@ def from_RDKMol(self, rdk_mol):
Chem.BondType.SINGLE: 1,
Chem.BondType.DOUBLE: 2,
Chem.BondType.TRIPLE: 3,
Chem.BondType.AROMATIC: 5,
}
for rdk_bond in rdk_mol.GetBonds():
i = rdk_bond.GetBeginAtom().GetIdx()
Expand Down
11 changes: 10 additions & 1 deletion molsystem/smiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def to_smiles(self, canonical=False, hydrogens=False, isomeric=True, rdkit=False

return smiles.strip()

def from_smiles(self, smiles, name=None, rdkit=False):
def from_smiles(self, smiles, name=None, reorient=True, rdkit=False):
"""Create the system from a SMILES string.
Parameters
Expand All @@ -103,6 +103,8 @@ def from_smiles(self, smiles, name=None, rdkit=False):
The SMILES string
name : str = None
The name of the molecule
reorient : bool = True
Whether to reorient to the standard orientation
rdkit : bool = False
Whether to use RDKit rather than default of OpenBabel
Expand Down Expand Up @@ -136,6 +138,13 @@ def from_smiles(self, smiles, name=None, rdkit=False):

self.from_OBMol(mol)

# Rotate to standard orientation
if reorient:
rdkMol = self.to_RDKMol()
rdkConf = rdkMol.GetConformers()[0]
Chem.rdMolTransforms.CanonicalizeConformer(rdkConf)
self.from_RDKMol(rdkMol)

if name is not None:
self.name = name
else:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_angiotensin.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def testdb():
# Angiotensin II from SMILES
system = db.create_system("angiotensin")
configuration = system.create_configuration("SMILES")
configuration.from_smiles(SMILES)
configuration.from_smiles(SMILES, reorient=False)

# And read in
system.read_cif_file(data_path / "1n9v.cif")
Expand Down
2 changes: 1 addition & 1 deletion tests/test_openbabel.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ def test_all_residue_search(configuration):
"PHE_LL": [(64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75)],
}

configuration.from_smiles(SMILES)
configuration.from_smiles(SMILES, reorient=False)

for name, sc in sidechains.items():
smarts = f"[NH1X3][C@@H]({sc})[CX3]=[OX1]"
Expand Down

0 comments on commit 10ce340

Please sign in to comment.