def add_image(self, complex): complex.thumbnail = tempfile.NamedTemporaryFile( delete=False, suffix='.png', dir=self.temp_dir.name).name complex.image = tempfile.NamedTemporaryFile( delete=False, suffix='.png', dir=self.temp_dir.name).name mol = complex.rdmol Chem.AssignStereochemistryFrom3D(mol) Chem.rdCoordGen.AddCoords(mol) mol = Draw.rdMolDraw2D.PrepareMolForDrawing(mol) drawer = Draw.rdMolDraw2D.MolDraw2DSVG(256, 192) drawer.drawOptions().additionalAtomLabelPadding = 0.3 drawer.DrawMolecule(mol) drawer.FinishDrawing() svg = drawer.GetDrawingText() svg = svg.replace('stroke-linecap:butt', 'stroke-linecap:round') svg2png(bytestring=svg, write_to=complex.thumbnail, output_width=256, output_height=192) svg2png(bytestring=svg, write_to=complex.image, output_width=1024, output_height=768)
def file_to_rdkit_mol(file_path: Path) -> Chem.Mol: """ Args: file_path: Path of the file used to generate the rdkit molecule. return: RDKit molecule object generated from its file (or None if incorrect file type is provided). """ # Read the file if file_path.suffix == ".pdb": mol = Chem.MolFromPDBFile(file_path.as_posix(), removeHs=False, sanitize=False) elif file_path.suffix == ".mol2": mol = Chem.MolFromMol2File(file_path.as_posix(), removeHs=False, sanitize=False) elif file_path.suffix == ".mol" or file_path.suffix == ".sdf": mol = Chem.MolFromMolFile(file_path.as_posix(), removeHs=False, sanitize=False, strictParsing=True) else: raise FileTypeError( f"The file type {file_path.suffix} is not supported.") # run some sanitation Chem.SanitizeMol( mol, (Chem.SANITIZE_ALL ^ Chem.SANITIZE_SETAROMATICITY ^ Chem.SANITIZE_ADJUSTHS), ) Chem.SetAromaticity(mol, Chem.AromaticityModel.AROMATICITY_MDL) Chem.AssignStereochemistryFrom3D(mol) # set the name of the input file mol.SetProp("_Name", file_path.stem) return mol
def to_rdmol(plams_mol, sanitize=True, properties=True, assignChirality=False): """ Translate a PLAMS molecule into an RDKit molecule type. PLAMS |Molecule|, |Atom| or |Bond| properties are pickled if they are neither booleans, floats, integers, floats nor strings, the resulting property names are appended with '_pickled'. :parameter plams_mol: A PLAMS molecule :parameter bool sanitize: Kekulize, check valencies, set aromaticity, conjugation and hybridization :parameter bool properties: If all |Molecule|, |Atom| and |Bond| properties should be converted from PLAMS to RDKit format. :parameter bool assignChirality: Assign R/S and cis/trans information, insofar as this was not yet present in the PLAMS molecule. :type plams_mol: |Molecule| :return: an RDKit molecule :rtype: rdkit.Chem.Mol """ if isinstance(plams_mol, Chem.Mol): return plams_mol # Create rdkit molecule e = Chem.EditableMol(Chem.Mol()) # Add atoms and assign properties to the RDKit atom if *properties* = True for pl_atom in plams_mol.atoms: rd_atom = Chem.Atom(pl_atom.atnum) if 'charge' in pl_atom.properties: rd_atom.SetFormalCharge(pl_atom.properties.charge) if properties: if 'pdb_info' in pl_atom.properties: set_PDBresidueInfo(rd_atom, pl_atom.properties.pdb_info) for prop in pl_atom.properties: if prop not in ('charge', 'pdb_info', 'stereo'): prop_to_rdmol(pl_atom, rd_atom, prop) # Check for R/S information if pl_atom.properties.stereo: stereo = pl_atom.properties.stereo.lower() if stereo == 'counter-clockwise': rd_atom.SetChiralTag( Chem.rdchem.ChiralType.CHI_TETRAHEDRAL_CCW) elif stereo == 'clockwise': rd_atom.SetChiralTag(Chem.rdchem.ChiralType.CHI_TETRAHEDRAL_CW) e.AddAtom(rd_atom) # Mapping of PLAMS bond orders to RDKit bond types: def plams_to_rd_bonds(bo): if bo > 1.4 and bo < 1.6: return 12 # bond type for aromatic bond else: return int(bo) # Add bonds to the RDKit molecule for bond in plams_mol.bonds: a1 = plams_mol.atoms.index(bond.atom1) a2 = plams_mol.atoms.index(bond.atom2) e.AddBond(a1, a2, Chem.BondType(plams_to_rd_bonds(bond.order))) rdmol = e.GetMol() # Check for cis/trans information for pl_bond, rd_bond in zip(plams_mol.bonds, rdmol.GetBonds()): if pl_bond.properties.stereo: stereo = pl_bond.properties.stereo.lower() if stereo == 'e' or stereo == 'trans': rd_bond.SetStereo(Chem.rdchem.BondStereo.STEREOE) elif stereo == 'z' or stereo == 'cis': rd_bond.SetStereo(Chem.rdchem.BondStereo.STEREOZ) elif stereo == 'up': rd_bond.SetBondDir(Chem.rdchem.BondDir.ENDUPRIGHT) elif stereo == 'down': rd_bond.SetBondDir(Chem.rdchem.BondDir.ENDDOWNRIGHT) # Assign properties to RDKit molecule and bonds if *properties* = True if properties: for prop in plams_mol.properties: prop_to_rdmol(plams_mol, rdmol, prop) for pl_bond, rd_bond in zip(plams_mol.bonds, rdmol.GetBonds()): for prop in pl_bond.properties: if prop != 'stereo': prop_to_rdmol(pl_bond, rd_bond, prop) if sanitize: Chem.SanitizeMol(rdmol) conf = Chem.Conformer() for i, atom in enumerate(plams_mol.atoms): xyz = Geometry.Point3D(atom._getx(), atom._gety(), atom._getz()) conf.SetAtomPosition(i, xyz) rdmol.AddConformer(conf) # REB: Assign all stereochemistry, if it wasn't already there if assignChirality: Chem.rdmolops.AssignAtomChiralTagsFromStructure( rdmol, confId=conf.GetId(), replaceExistingTags=False) try: Chem.AssignStereochemistryFrom3D(rdmol, confId=conf.GetId(), replaceExistingTags=False) except AttributeError: pass return rdmol
def cap_unit(self, unit, n_neighbors=3): indices = sorted(unit.atoms.indices) capped = Chem.rdchem.RWMol() n_indices = len(indices) if not n_indices: return capped neighbor_ints = rdutils.get_neighbor_ints(self.rdmol, indices, n_neighbors) new_conf = Chem.rdchem.Conformer(n_indices + len(neighbor_ints)) conf = self.rdmol.GetConformer(0) only_on_atoms = [] # add unit atoms indices = list(map(int, indices)) for ix in indices: at = self.rdmol.GetAtomWithIdx(ix) new = capped.AddAtom(at) new_conf.SetAtomPosition(new, list(conf.GetAtomPosition(ix))) # add neighbor atoms with AltLoc "+" for ix in neighbor_ints: at = self.rdmol.GetAtomWithIdx(ix) new = capped.AddAtom(at) at = capped.GetAtomWithIdx(new) old_info = at.GetPDBResidueInfo() info = rdutils.copy_pdbinfo(old_info) # info.SetAltLoc("+") at.SetMonomerInfo(info) at.SetNoImplicit(False) new_conf.SetAtomPosition(new, list(conf.GetAtomPosition(ix))) only_on_atoms.append(new) # add bonds all_ints = indices + neighbor_ints # things RDKit complains about: np.uint, np.uint32, np.uintp, np.uintc # capped_ints = np.arange(len(all_ints), dtype=np.uintc) capped_ints = list(map(int, range(len(all_ints)))) # omg for i, j in itertools.combinations(capped_ints, 2): bond = self.rdmol.GetBondBetweenAtoms(all_ints[i], all_ints[j]) if bond is not None: capped.AddBond(i, j, bond.GetBondType()) capped.AddConformer(new_conf) # add Hs Chem.SanitizeMol( capped, (Chem.SANITIZE_ALL ^ Chem.SANITIZE_SETAROMATICITY ^ Chem.SANITIZE_ADJUSTHS ^ Chem.SANITIZE_CLEANUPCHIRALITY ^ Chem.SANITIZE_KEKULIZE), ) hcapped = Chem.AddHs(capped, explicitOnly=False, addCoords=True, onlyOnAtoms=only_on_atoms) # info_template = hcapped.GetAtomWithIdx(0).GetPDBResidueInfo() # for i in range(capped_ints[-1], hcapped.GetNumAtoms()): # at = hcapped.GetAtomWithIdx(i) # new_info = rdutils.copy_pdbinfo(info_template) # new_info.SetName("H") # new_info.SetAltLoc("-") # at.SetMonomerInfo(new_info) # Chem.AssignStereochemistry(hcapped) # Chem.SanitizeMol(hcapped) # Chem.SanitizeMol(hcapped, # ( # Chem.SANITIZE_ALL # ^ Chem.SANITIZE_SETAROMATICITY # ^ Chem.SANITIZE_ADJUSTHS # ^ Chem.SANITIZE_CLEANUPCHIRALITY # ^ Chem.SANITIZE_KEKULIZE # ),) Chem.AssignStereochemistryFrom3D(hcapped, 0) return hcapped
def assign_stereochemistry(rdmol): if rdmol.GetNumConformers(): Chem.AssignStereochemistryFrom3D(rdmol) else: Chem.AssignStereochemistry(rdmol, cleanIt=True)