def rmsd_to_me(self, other_conf): """Calculate the rms distance between this conformer and another one. :param other_conf: The other conformer to align. :type other_conf: MyConformer :return: The rmsd, a float. :rtype: float """ # Make a new molecule. amol = Chem.MolFromSmiles(self.smiles, sanitize=False) amol = MOH.check_sanitization(amol) amol = MOH.try_reprotanation(amol) # Add the conformer of the other MyConformer object. amol.AddConformer(self.conformer(), assignId=True) amol.AddConformer(other_conf.conformer(), assignId=True) # Get the two confs. first_conf = amol.GetConformers()[0] last_conf = amol.GetConformers()[-1] # Return the RMSD. amol = MOH.try_deprotanation(amol) rmsd = AllChem.GetConformerRMS(amol, first_conf.GetId(), last_conf.GetId(), prealigned=True) return rmsd
def make_mol_frm_smiles_sanitze(self): """Construct a rdkit.mol for this object, in case you only received the smiles. Also, sanitize the molecule regardless. :return: Returns the rdkit.mol object, though it's also stored in self.rdkit_mol. :rtype: rdkit.mol object. """ # If given a SMILES string. if self.rdkit_mol == "": try: # sanitize = False makes it respect double-bond stereochemistry m = Chem.MolFromSmiles(self.orig_smi_deslt, sanitize=False) except: m = None else: # If given a RDKit Mol Obj m = self.rdkit_mol if m is not None: # Sanitize and hopefully correct errors in the smiles string such # as incorrect nitrogen charges. m = MOH.check_sanitization(m) self.rdkit_mol = m return m
def smiles(self, noh=False): """Get the desalted, canonical smiles string associated with this object. (Not the input smiles!) :param noh: Whether or not hydrogen atoms should be included in the canonical smiles string., defaults to False :param noh: bool, optional :return: The canonical smiles string, or None if it cannot be determined. :rtype: str or None """ # See if it's already been calculated. if noh == False: # They want the hydrogen atoms. if self.can_smi != "": # Return previously determined canonical SMILES. return self.can_smi else: # Need to determine canonical SMILES. try: can_smi = Chem.MolToSmiles(self.rdkit_mol, isomericSmiles=True, canonical=True) except: # Sometimes this conversion just can't happen. Happened # once with this beast, for example: # CC(=O)NC1=CC(=C=[N+]([O-])O)C=C1O Utils.log("Warning: Couldn't put " + self.orig_smi + " (" + self.name + ") in canonical form. Got this error: " + str(sys.exc_info()[0]) + ". This molecule will be " + "discarded.") self.can_smi = None return None self.can_smi = can_smi return can_smi else: # They don't want the hydrogen atoms. if self.can_smi_noh != "": # Return previously determined string. return self.can_smi_noh # So remove hydrogens. Note that this assumes you will have called # this function previously with noh = False amol = copy.copy(self.rdkit_mol) amol = MOH.try_deprotanation(amol) self.can_smi_noh = Chem.MolToSmiles(amol, isomericSmiles=True, canonical=True) return self.can_smi_noh
def make_first_3d_conf_no_min(self): """Makes the associated rdkit.mol object 3D by adding the first conformer. This also adds hydrogen atoms to the associated rdkit.mol object. Note that it does not perform a minimization, so it is not too expensive.""" # Set the first 3D conformer if len(self.conformers) > 0: # It's already been done. return # Add hydrogens. JDD: I don't think this undoes dimorphite-dl, but we # need to check that. self.rdkit_mol = MOH.try_reprotanation(self.rdkit_mol) # Add a single conformer. RMSD cutoff very small so all conformers # will be accepted. And not minimizing (False). self.add_conformers(1, 1e60, False)
def make_first_3d_conf_no_min(self): """Makes the associated rdkit.mol object 3D by adding the first conformer. This also adds hydrogen atoms to the associated rdkit.mol object. Note that it does not perform a minimization, so it is not too expensive.""" # Set the first 3D conformer if len(self.conformers) > 0: # It's already been done. return # Add hydrogens. This adds explicit hydrogens, while respecting # Dimorphite-DL protonation states. self.rdkit_mol = MOH.try_reprotanation(self.rdkit_mol) # Add a single conformer. RMSD cutoff very small so all conformers # will be accepted. And not minimizing (False). self.add_conformers(1, 1e60, False)
def parallel_make_taut(contnr, mol_index, max_variants_per_compound): """Makes alternate tautomers for a given molecule container. This is the function that gets fed into the parallelizer. :param contnr: The molecule container. :type contnr: MolContainer.MolContainer :param mol_index: The molecule index. :type mol_index: int :param max_variants_per_compound: To control the combinatorial explosion, only this number of variants (molecules) will be advanced to the next step. :type max_variants_per_compound: int :return: A list of MyMol.MyMol objects, containing the alternate tautomeric forms. :rtype: list """ # Get the MyMol.MyMol within the molecule container corresponding to the # given molecule index. mol = contnr.mols[mol_index] # Create a temporary RDKit mol object, since that's what MolVS works with. # TODO: There should be a copy function m = MyMol.MyMol(mol.smiles()).rdkit_mol # For tautomers to work, you need to not have any explicit hydrogens. m = Chem.RemoveHs(m) # Make sure it's not None. if m is None: Utils.log("\tCould not generate tautomers for " + contnr.orig_smi + ". I'm deleting it.") return # Molecules should be kekulized already, but let's double check that. # Because MolVS requires kekulized input. Chem.Kekulize(m) m = MOH.check_sanitization(m) if m is None: return None # Limit to max_variants_per_compound tauts. Note that another batch could # add more, so you'll need to once again trim to this number later. But # this could at least help prevent the combinatorial explosion at this # stage. enum = tautomer.TautomerEnumerator(max_tautomers=max_variants_per_compound) tauts_rdkit_mols = enum.enumerate(m) # Make all those tautomers into MyMol objects. tauts_mols = [MyMol.MyMol(m) for m in tauts_rdkit_mols] # Keep only those that have reasonable substructures. tauts_mols = [ t for t in tauts_mols if t.remove_bizarre_substruc() == False ] # If there's more than one, let the user know that. if len(tauts_mols) > 1: Utils.log("\t" + mol.smiles(True) + " has tautomers.") # Now collect the final results. results = [] for tm in tauts_mols: tm.inherit_contnr_props(contnr) tm.genealogy = mol.genealogy[:] tm.name = mol.name if tm.smiles() != mol.smiles(): tm.genealogy.append(tm.smiles(True) + " (tautomer)") results.append(tm) return results