def SetupMoleculeWriters(): """Setup molecule writers.""" Writer = None WriterFiltered = None if OptionsInfo["CountMode"]: return (Writer, WriterFiltered) Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"]) MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"]) if OptionsInfo["OutfileFilteredMode"]: WriterFiltered = RDKitUtil.MoleculesWriter( OptionsInfo["OutfileFiltered"], **OptionsInfo["OutfileParams"]) if WriterFiltered is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["OutfileFiltered"]) MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["OutfileFiltered"]) return (Writer, WriterFiltered)
def SetupMoleculeWriters(CombineMatchResults, Outfile, GroupsOutfiles): """Set up molecule writers for output files.""" Writer = None GroupOutfilesWriters = [] if CombineMatchResults: Writer = RDKitUtil.MoleculesWriter(Outfile, **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % Outfile) MiscUtil.PrintInfo("Generating file %s..." % Outfile) else: for GroupOutfile in GroupsOutfiles: GroupOutfileWriter = RDKitUtil.MoleculesWriter( GroupOutfile, **OptionsInfo["OutfileParams"]) if GroupOutfileWriter is None: MiscUtil.PrintError( "Failed to setup a writer for output fie %s " % Writer) GroupOutfilesWriters.append(GroupOutfileWriter) GroupsCount = len(GroupsOutfiles) if GroupsCount > 4: MiscUtil.PrintInfo( "Generating %d output files with the following file name format: %s<GroupName>.%s" % (GroupsCount, OptionsInfo["OutfileBasename"], OptionsInfo["OutfileExt"])) else: Delmiter = ', ' OutfileNames = Delmiter.join(GroupsOutfiles) MiscUtil.PrintInfo("Generating %d output files: %s..." % (GroupsCount, OutfileNames)) return (Writer, GroupOutfilesWriters)
def PerformOneToOneAlignment(ValidRefMols, ValidProbeMols, Writer): """Perform pairwise alignment""" ValidRefMolCount = len(ValidRefMols) ValidProbeMolCount = len(ValidProbeMols) MolCount = ValidRefMolCount if ValidRefMolCount > ValidProbeMolCount: MolCount = ValidProbeMolCount if ValidRefMolCount != ValidProbeMolCount: MiscUtil.PrintWarning( "Number of valid reference molecules, %d, is not equal to number of valid probe molecules, %d .\n" % (ValidRefMolCount, ValidProbeMolCount)) MiscUtil.PrintWarning( "Pairwise alignment will be performed only for first %s molecules.\n" % (MolCount)) # Process molecules... AlignmentFailedCount = 0 for MolIndex in range(0, MolCount): RefMol = ValidRefMols[MolIndex] ProbeMol = ValidProbeMols[MolIndex] RefMolName = RDKitUtil.GetMolName(RefMol, (MolIndex + 1)) ProbeMolName = RDKitUtil.GetMolName(ProbeMol, (MolIndex + 1)) Status = PerformAlignmentAndWrieOutput(RefMol, ProbeMol, RefMolName, ProbeMolName, Writer) if not Status: AlignmentFailedCount += 1 return AlignmentFailedCount
def ProcessMoleculesUsingSingleProcess(Mols, Writer): """Process and calculate energy of molecules using a single process.""" MiscUtil.PrintInfo("\nCalculating energy...") (MolCount, ValidMolCount, EnergyFailedCount) = [0] * 3 for Mol in Mols: MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 CalcStatus, Energy = CalculateMoleculeEnergy(Mol, MolCount) if CalcStatus: Energy = "%.2f" % Energy else: if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Failed to calculate energy for molecule %s" % MolName) EnergyFailedCount += 1 continue WriteMolecule(Writer, Mol, Energy) return (MolCount, ValidMolCount, EnergyFailedCount)
def GenerateConformers(): """Generate conformers.""" # Setup a molecule reader... MiscUtil.PrintInfo("\nProcessing file %s..." % OptionsInfo["Infile"]) Mols = RDKitUtil.ReadMolecules(OptionsInfo["Infile"], **OptionsInfo["InfileParams"]) # Set up a molecule writer... Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"]) MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"]) MolCount, ValidMolCount, ConfGenFailedCount = ProcessMolecules( Mols, Writer) if Writer is not None: Writer.close() MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount) MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) MiscUtil.PrintInfo( "Number of molecules failed during conformation generation or minimization: %d" % ConfGenFailedCount) MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount + ConfGenFailedCount))
def WriteMolecules(Mols): """Write out molecules.""" Outfile = OptionsInfo["Outfile"] # Set up a molecule writer... Writer = None Writer = RDKitUtil.MoleculesWriter(Outfile, **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % Outfile) MiscUtil.PrintInfo("\nGenerating file %s...\n" % Outfile) Compute2DCoords = OptionsInfo["OutfileParams"]["Compute2DCoords"] SetSMILESMolProps = OptionsInfo["OutfileParams"]["SetSMILESMolProps"] # Write out molecules... FirstMol = True for Mol in Mols: if FirstMol: FirstMol = False if SetSMILESMolProps: RDKitUtil.SetWriterMolProps(Writer, Mol) RDKitUtil.SetWriterMolProps(Writer, Mol) if Compute2DCoords: AllChem.Compute2DCoords(Mol) Writer.write(Mol) if Writer is not None: Writer.close() MiscUtil.PrintInfo("Total number of diverse molecules selected: %d" % (len(Mols)))
def WorkerProcess(EncodedMolInfo): """Process data for a worker process.""" MolIndex, EncodedMol = EncodedMolInfo CalcStatus = False ConfIDs = None ConfEnergies = None if EncodedMol is None: return [MolIndex, None, CalcStatus, ConfIDs, ConfEnergies] Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) if RDKitUtil.IsMolEmpty(Mol): if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, (MolIndex + 1)) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) return [MolIndex, None, CalcStatus, ConfIDs, ConfEnergies] Mol, CalcStatus, ConfIDs, ConfEnergies = GenerateMolConformers( Mol, (MolIndex + 1)) return [ MolIndex, RDKitUtil.MolToBase64EncodedMolString( Mol, PropertyPickleFlags=Chem.PropertyPickleOptions.MolProps | Chem.PropertyPickleOptions.PrivateProps), CalcStatus, ConfIDs, ConfEnergies ]
def CalculateOneToOneRMSDValues(ValidRefMols, ValidProbeMols, OutFH, OutDelim): """Calculate pairwise RMSD values.""" ValidRefMolCount = len(ValidRefMols) ValidProbeMolCount = len(ValidProbeMols) MolCount = ValidRefMolCount if ValidRefMolCount > ValidProbeMolCount: MolCount = ValidProbeMolCount if ValidRefMolCount != ValidProbeMolCount: MiscUtil.PrintWarning("Number of valid reference molecules, %d, is not equal to number of valid probe molecules, %d .\n" % (ValidRefMolCount, ValidProbeMolCount)) MiscUtil.PrintWarning("Pairwise RMSD will be calculated only for first %s molecules.\n" % (MolCount)) # Process molecules... for MolIndex in range(0, MolCount): RefMol = ValidRefMols[MolIndex] ProbeMol = ValidProbeMols[MolIndex] RefMolName = RDKitUtil.GetMolName(RefMol, (MolIndex + 1)) ProbeMolName = RDKitUtil.GetMolName(ProbeMol, (MolIndex + 1)) RMSD = CalculateRMSDValue(RefMol, ProbeMol) Line = "%s%s%s%s%s\n" % (RefMolName, OutDelim, ProbeMolName, OutDelim, RMSD) OutFH.write(Line)
def ProcessMoleculesUsingMultipleProcesses(Mols, Writer): """Process molecules and calculate descriptors using multiprocessing.""" DescriptorsCount = len(OptionsInfo["SpecifiedDescriptorNames"]) MiscUtil.PrintInfo( "\nCalculating %d molecular %s for each molecule using multiprocessing......" % (DescriptorsCount, ("descroptors" if DescriptorsCount > 1 else "descriptor"))) MPParams = OptionsInfo["MPParams"] # Setup data for initializing a worker process... MiscUtil.PrintInfo("Encoding options info...") InitializeWorkerProcessArgs = ( MiscUtil.ObjectToBase64EncodedString(Options), MiscUtil.ObjectToBase64EncodedString(OptionsInfo)) # Setup a encoded mols data iterable for a worker process... WorkerProcessDataIterable = RDKitUtil.GenerateBase64EncodedMolStrings(Mols) # Setup process pool along with data initialization for each process... MiscUtil.PrintInfo( "\nConfiguring multiprocessing using %s method..." % ("mp.Pool.imap()" if re.match("^Lazy$", MPParams["InputDataMode"], re.I) else "mp.Pool.map()")) MiscUtil.PrintInfo("NumProcesses: %s; InputDataMode: %s; ChunkSize: %s\n" % (MPParams["NumProcesses"], MPParams["InputDataMode"], ("automatic" if MPParams["ChunkSize"] is None else MPParams["ChunkSize"]))) ProcessPool = mp.Pool(MPParams["NumProcesses"], InitializeWorkerProcess, InitializeWorkerProcessArgs) # Start processing... if re.match("^Lazy$", MPParams["InputDataMode"], re.I): Results = ProcessPool.imap(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) elif re.match("^InMemory$", MPParams["InputDataMode"], re.I): Results = ProcessPool.map(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) else: MiscUtil.PrintError( "The value, %s, specified for \"--inputDataMode\" is not supported." % (MPParams["InputDataMode"])) (MolCount, ValidMolCount) = [0] * 2 for Result in Results: MolCount += 1 MolIndex, EncodedMol, CalculatedValues = Result if EncodedMol is None: continue ValidMolCount += 1 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) # Write descriptor values... WriteDescriptorValues(Mol, MolCount, Writer, CalculatedValues) return (MolCount, ValidMolCount)
def ProcessMoleculesUsingSingleProcess(RefMol, Mols, Writer): """Process and minimize molecules using a single process.""" (MolCount, ValidMolCount, CoreScaffoldMissingCount, MinimizationFailedCount) = [0] * 4 for Mol in Mols: MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 # Setup a reference molecule core containing common scaffold atoms... RefMolCore = SetupCoreScaffold(RefMol, Mol, MolCount) if RefMolCore is None: CoreScaffoldMissingCount += 1 continue Mol, CalcStatus, Energy, ScaffoldEmbedRMSD = ConstrainAndMinimizeMolecule(Mol, RefMolCore, MolCount) if not CalcStatus: MinimizationFailedCount += 1 continue WriteMolecule(Writer, Mol, Energy, ScaffoldEmbedRMSD) return (MolCount, ValidMolCount, CoreScaffoldMissingCount, MinimizationFailedCount)
def AlignMolecules(): """Align molecules.""" if not re.match("^(OneToOne|FirstToAll)$", OptionsInfo["Mode"], re.I): MiscUtil.PrintError( "Alignment couldn't be performed: Specified mode, %s, is not supported" % OptionsInfo["Mode"]) RefFile = OptionsInfo["RefFile"] ProbeFile = OptionsInfo["ProbeFile"] Outfile = OptionsInfo["Outfile"] # Read reference and probe molecules... OptionsInfo["InfileParams"]["AllowEmptyMols"] = False MiscUtil.PrintInfo("\nProcessing file %s..." % (RefFile)) ValidRefMols, RefMolCount, ValidRefMolCount = RDKitUtil.ReadAndValidateMolecules( RefFile, **OptionsInfo["InfileParams"]) MiscUtil.PrintInfo("Processing file %s..." % (ProbeFile)) ValidProbeMols, ProbeMolCount, ValidProbeMolCount = RDKitUtil.ReadAndValidateMolecules( ProbeFile, **OptionsInfo["InfileParams"]) # Set up a molecule writer... Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"]) MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"]) AlignmentFailedCount = 0 if re.match("^OneToOne$", OptionsInfo["Mode"], re.I): AlignmentFailedCount = PerformOneToOneAlignment( ValidRefMols, ValidProbeMols, Writer) elif re.match("^FirstToAll$", OptionsInfo["Mode"], re.I): AlignmentFailedCount = PerformFirstToAllAlignment( ValidRefMols, ValidProbeMols, Writer) else: MiscUtil.PrintError( "Alignment couldn't be performed: Specified mode, %s, is not supported" % OptionsInfo["Mode"]) if Writer is not None: Writer.close() MiscUtil.PrintInfo( "\nTotal number of molecules: Reference - %d; Probe - %d" % (RefMolCount, ProbeMolCount)) MiscUtil.PrintInfo( "Number of valid molecules: Reference - %d; Probe - %d" % (ValidRefMolCount, ValidProbeMolCount)) MiscUtil.PrintInfo( "Number of probe molecules failed during alignment: %d" % AlignmentFailedCount) MiscUtil.PrintInfo( "Number of ignored molecules: Reference - %d; Probe - %d" % ((RefMolCount - ValidRefMolCount), (ProbeMolCount - ValidProbeMolCount + AlignmentFailedCount)))
def WorkerProcess(EncodedMolInfo): """Process data for a worker process.""" MolIndex, EncodedMol = EncodedMolInfo if EncodedMol is None: return [MolIndex, None, False, None] Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) if RDKitUtil.IsMolEmpty(Mol): MolName = RDKitUtil.GetMolName(Mol, (MolIndex + 1)) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) return [MolIndex, None, False, None] MolWithHs = Chem.AddHs(Mol) EncodedMolWithHs = RDKitUtil.MolToBase64EncodedMolString( MolWithHs, PropertyPickleFlags=Chem.PropertyPickleOptions.MolProps | Chem.PropertyPickleOptions.PrivateProps) # Retrieve charges... CalcStatus, PartialCharges = CalculateMolPartialCharges( MolWithHs, (MolIndex + 1)) return [MolIndex, EncodedMolWithHs, CalcStatus, PartialCharges]
def CalculateEnergy(): """Calculate single point energy calculation.""" # Setup a molecule reader... MiscUtil.PrintInfo("\nProcessing file %s..." % OptionsInfo["Infile"]) Mols = RDKitUtil.ReadMolecules(OptionsInfo["Infile"], **OptionsInfo["InfileParams"]) # Set up a molecule writer... Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"]) MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"]) MolCount, ValidMolCount, EnergyFailedCount = ProcessMolecules(Mols, Writer) if Writer is not None: Writer.close() MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount) MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) MiscUtil.PrintInfo( "Number of molecules failed during energy calculation: %d" % EnergyFailedCount) MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount + EnergyFailedCount))
def ProcessMoleculesUsingSingleProcess(Mols, Writer): """Process molecules and calculate partial charges using a single process. """ MiscUtil.PrintInfo("Calculating partial atomic charges...") Compute2DCoords = OptionsInfo["OutfileParams"]["Compute2DCoords"] MolCount, ValidMolCount, CalcFailedCount = [0] * 3 for Mol in Mols: MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 MolWithHs = Chem.AddHs(Mol) # Retrieve charges... CalcStatus, PartialCharges = CalculateMolPartialCharges( MolWithHs, MolCount) if not CalcStatus: CalcFailedCount += 1 continue # Write out charges... WriteMolPartialCharges(Writer, MolWithHs, PartialCharges, Compute2DCoords) return (MolCount, ValidMolCount, CalcFailedCount)
def RemoveMolSalts(Mol, Remover, MolNum): """Remove salts from mol and return unsalted mol along with mol salty status.""" UnsaltedMol = Mol SaltyStatus = False if Remover is not None: KeptMol, DeletedMols = Remover.StripMolWithDeleted( Mol, dontRemoveEverything=False) if len(DeletedMols) >= 1: SaltyStatus = True if RDKitUtil.IsMolEmpty(KeptMol): if len(DeletedMols) >= 1: # Take the larged fragment from DeletedMols UnsaltedMol = GetLargestMol(DeletedMols) else: # Use largest fragment as unsalted molecule... MolFrags = Chem.GetMolFrags(Mol, asMols=True) if len(MolFrags) > 1: # Keep the largest fragment as unsalted molecule... SaltyStatus = True UnsaltedMol = GetLargestMol(MolFrags) if SaltyStatus: Chem.SanitizeMol(UnsaltedMol) MolName = RDKitUtil.GetMolName(Mol, MolNum) if len(MolName): UnsaltedMol.SetProp("_Name", MolName) return (UnsaltedMol, SaltyStatus)
def WorkerProcess(EncodedMolInfo): """Process data for a worker process.""" MolIndex, EncodedMol = EncodedMolInfo CoreScaffoldMissingStatus = False CalcStatus = False Energy = None ScaffoldEmbedRMSD = None if EncodedMol is None: return [MolIndex, None, CoreScaffoldMissingStatus, CalcStatus, Energy, ScaffoldEmbedRMSD] RefMol = OptionsInfo["RefMol"] Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) if RDKitUtil.IsMolEmpty(Mol): if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, (MolIndex + 1)) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) return [MolIndex, None, CoreScaffoldMissingStatus, CalcStatus, Energy, ScaffoldEmbedRMSD] # Setup a reference molecule core containing common scaffold atoms... RefMolCore = SetupCoreScaffold(RefMol, Mol, (MolIndex + 1)) if RefMolCore is None: CoreScaffoldMissingStatus = True return [MolIndex, None, CalcStatus, CoreScaffoldMissingStatus, Energy, ScaffoldEmbedRMSD] Mol, CalcStatus, Energy, ScaffoldEmbedRMSD = ConstrainAndMinimizeMolecule(Mol, RefMolCore, (MolIndex + 1)) return [MolIndex, RDKitUtil.MolToBase64EncodedMolString(Mol, PropertyPickleFlags = Chem.PropertyPickleOptions.MolProps | Chem.PropertyPickleOptions.PrivateProps), CoreScaffoldMissingStatus, CalcStatus, Energy, ScaffoldEmbedRMSD]
def ProcessMoleculesUsingSingleProcess(Mols, Writer): """Process molecules and calculate descriptors using a single process.""" DescriptorsCount = len(OptionsInfo["SpecifiedDescriptorNames"]) MiscUtil.PrintInfo( "\nCalculating %d molecular %s for each molecule..." % (DescriptorsCount, ("descroptors" if DescriptorsCount > 1 else "descriptor"))) (MolCount, ValidMolCount) = [0] * 2 for MolIndex, Mol in enumerate(Mols): MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 # Calculate and write descriptor values... CalculatedValues = CalculateDescriptorValues(MolIndex, Mol) WriteDescriptorValues(Mol, MolCount, Writer, CalculatedValues) return (MolCount, ValidMolCount)
def PerformConstrainedMinimization(): """Perform constrained minimization.""" # Read and validate reference molecule... RefMol = RetrieveReferenceMolecule() # Setup a molecule reader for input file... MiscUtil.PrintInfo("\nProcessing file %s..." % OptionsInfo["Infile"]) OptionsInfo["InfileParams"]["AllowEmptyMols"] = True Mols = RDKitUtil.ReadMolecules(OptionsInfo["Infile"], **OptionsInfo["InfileParams"]) # Set up a molecule writer... Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"]) MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"]) MolCount, ValidMolCount, CoreScaffoldMissingCount, MinimizationFailedCount = ProcessMolecules(RefMol, Mols, Writer) if Writer is not None: Writer.close() MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount) MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) MiscUtil.PrintInfo("Number of molecules with missing core scaffold: %d" % CoreScaffoldMissingCount) MiscUtil.PrintInfo("Number of molecules failed during conformation generation or minimization: %d" % MinimizationFailedCount) MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount + CoreScaffoldMissingCount + MinimizationFailedCount))
def GenerateAndMinimizeConformers(Mol, MolCount, Writer): "Generate and mininize conformers for a molecule and write out the lowest energy conformer." if OptionsInfo["AddHydrogens"]: Mol = Chem.AddHs(Mol) ConfIDs = EmbedMolecule(Mol) if not len(ConfIDs): MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning( "Minimization couldn't be performed for molecule %s: Embedding failed...\n" % MolName) return False CalcEnergyMap = {} for ConfID in ConfIDs: try: if OptionsInfo["UseUFF"]: Status = AllChem.UFFOptimizeMolecule( Mol, confId=ConfID, maxIters=OptionsInfo["MaxIters"]) elif OptionsInfo["UseMMFF"]: Status = AllChem.MMFFOptimizeMolecule( Mol, confId=ConfID, maxIters=OptionsInfo["MaxIters"]) else: MiscUtil.PrintError( "Minimization couldn't be performed: Specified forcefield, %s, is not supported" % OptionsInfo["ForceField"]) except RuntimeError as ErrMsg: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning( "Minimization couldn't be performed for molecule %s:\n%s\n" % (MolName, ErrMsg)) return False EnergyStatus, Energy = GetConformerEnergy(Mol, ConfID) if not EnergyStatus: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning( "Failed to retrieve calculated energy for conformation number %d of molecule %s. Try again after removing any salts or cleaing up the molecule...\n" % (ConfID, MolName)) return False if Status != 0: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning( "Minimization failed to converge for conformation number %d of molecule %s in %d steps. Try using higher value for \"--maxIters\" option...\n" % (ConfID, MolName, OptionsInfo["MaxIters"])) CalcEnergyMap[ConfID] = Energy SortedConfIDs = sorted(ConfIDs, key=lambda ConfID: CalcEnergyMap[ConfID]) MinEnergyConfID = SortedConfIDs[0] if OptionsInfo["RemoveHydrogens"]: Mol = Chem.RemoveHs(Mol) Writer.write(Mol, confId=MinEnergyConfID) return True
def SetupMoleculeWriters(ClustersCount): """Set up molecule writers for SD and text files.""" Writer = None ClustersOutfilesWriters = [] TextOutFileMode = OptionsInfo["TextOutFileMode"] TextOutFileDelim = OptionsInfo["TextOutFileDelim"] TextOutFileTitleLine = OptionsInfo["TextOutFileTitleLine"] if OptionsInfo["SingleOutFileMode"]: Outfile = OptionsInfo["Outfile"] if TextOutFileMode: Writer = open(Outfile, "w") else: Writer = RDKitUtil.MoleculesWriter(Outfile, **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % Outfile) if TextOutFileMode: if TextOutFileTitleLine: WriteTextFileHeaderLine(Writer, TextOutFileDelim) MiscUtil.PrintInfo("Generating file %s..." % Outfile) else: for ClusterIndex in range(0, ClustersCount): Outfile = OptionsInfo["ClustersOutfiles"][ClusterIndex] if TextOutFileMode: ClusterWriter = open(Outfile, "w") else: ClusterWriter = RDKitUtil.MoleculesWriter( Outfile, **OptionsInfo["OutfileParams"]) if ClusterWriter is None: MiscUtil.PrintError( "Failed to setup a writer for output fie %s " % Outfile) if TextOutFileMode: if TextOutFileTitleLine: WriteTextFileHeaderLine(ClusterWriter, TextOutFileDelim) ClustersOutfilesWriters.append(ClusterWriter) if ClustersCount > 4: MiscUtil.PrintInfo( "Generating %d output files with the following file name format: %s_Cluster<Num>.%s" % (ClustersCount, OptionsInfo["OutfileBasename"], OptionsInfo["OutfileExt"])) else: Delmiter = ',' OutfileNames = Delmiter.join(OptionsInfo["ClustersOutfiles"]) MiscUtil.PrintInfo("Generating %d output files: %s..." % (ClustersCount, OutfileNames)) return (Writer, ClustersOutfilesWriters)
def SetupCoreScaffoldByMCS(RefMol, Mol, MolCount): """Setup a reference molecule core containing common scaffold atoms between a pair of molecules using MCS.""" MCSParams = OptionsInfo["MCSParams"] Mols = [RefMol, Mol] MCSResultObject = rdFMCS.FindMCS( Mols, maximizeBonds=MCSParams["MaximizeBonds"], threshold=MCSParams["Threshold"], timeout=MCSParams["TimeOut"], verbose=MCSParams["Verbose"], matchValences=MCSParams["MatchValences"], ringMatchesRingOnly=MCSParams["RingMatchesRingOnly"], completeRingsOnly=MCSParams["CompleteRingsOnly"], matchChiralTag=MCSParams["MatchChiralTag"], atomCompare=MCSParams["AtomCompare"], bondCompare=MCSParams["BondCompare"], seedSmarts=MCSParams["SeedSMARTS"]) if MCSResultObject.canceled: if not OptionsInfo["QuietMode"]: MiscUtil.PrintWarning( "MCS failed to identify a common core scaffold between reference moecule and input molecule %s. Specify a different set of parameters using \"-m, --mcsParams\" option and try again." % (RDKitUtil.GetMolName(Mol, MolCount))) return None CoreNumAtoms = MCSResultObject.numAtoms CoreNumBonds = MCSResultObject.numBonds SMARTSCore = MCSResultObject.smartsString if not len(SMARTSCore): if not OptionsInfo["QuietMode"]: MiscUtil.PrintWarning( "MCS failed to identify a common core scaffold between reference moecule and input molecule %s. Specify a different set of parameters using \"-m, --mcsParams\" option and try again." % (RDKitUtil.GetMolName(Mol, MolCount))) return None if CoreNumAtoms < MCSParams["MinNumAtoms"]: if not OptionsInfo["QuietMode"]: MiscUtil.PrintWarning( "Number of atoms, %d, in core scaffold identified by MCS is less than, %d, as specified by \"minNumAtoms\" parameter in \"-m, --mcsParams\" option." % (CoreNumAtoms, MCSParams["MinNumAtoms"])) return None if CoreNumBonds < MCSParams["MinNumBonds"]: if not OptionsInfo["QuietMode"]: MiscUtil.PrintWarning( "Number of bonds, %d, in core scaffold identified by MCS is less than, %d, as specified by \"minNumBonds\" parameter in \"-m, --mcsParams\" option." % (CoreNumBonds, MCSParams["MinNumBonds"])) return None return GenerateCoreMol(RefMol, SMARTSCore)
def CompareMoleculeShapes(): """Compare shape of molecules.""" if not re.match("^(OneToOne|AllToAll|FirstToAll)$", OptionsInfo["Mode"], re.I): MiscUtil.PrintError("Shape comparison couldn't be performed: Specified mode, %s, is not supported" % OptionsInfo["Mode"]) if not re.match("^(Open3A|CrippenOpen3A)$", OptionsInfo["Alignment"], re.I): MiscUtil.PrintError("Shape couldn't be performed: Specified alignment mode, %s, is not supported" % OptionsInfo["Alignment"]) RefFile = OptionsInfo["RefFile"] ProbeFile = OptionsInfo["ProbeFile"] Outfile = OptionsInfo["Outfile"] OutDelim = OptionsInfo["OutDelim"] # Read reference and probe molecules... OptionsInfo["InfileParams"]["AllowEmptyMols"] = False MiscUtil.PrintInfo("\nProcessing file %s..." % (RefFile)) ValidRefMols, RefMolCount, ValidRefMolCount = RDKitUtil.ReadAndValidateMolecules(RefFile, **OptionsInfo["InfileParams"]) MiscUtil.PrintInfo("Processing file %s..." % (ProbeFile)) ValidProbeMols, ProbeMolCount, ValidProbeMolCount = RDKitUtil.ReadAndValidateMolecules(ProbeFile, **OptionsInfo["InfileParams"]) # Set up output file... MiscUtil.PrintInfo("Generating file %s...\n" % Outfile) OutFH = open(Outfile, "w") if OutFH is None: MiscUtil.PrintError("Couldn't open output file: %s.\n" % (Outfile)) if OptionsInfo["UseCrippenOpen3A"]: Line = "RefMolID%sProbeMolID%sCrippenOpen3AScore" % (OutDelim, OutDelim) else: Line = "RefMolID%sProbeMolID%sOpen3AScore" % (OutDelim, OutDelim) if OptionsInfo["CalcTanimotoDistance"]: Line = "%s%sTanimotoDistance" % (Line, OutDelim) if OptionsInfo["CalcProtrudeDistance"]: Line = "%s%sProtrudeDistance" % (Line, OutDelim) OutFH.write("%s\n" % Line) if re.match("^OneToOne$", OptionsInfo["Mode"], re.I): PerformOneToOneShapeComparison(ValidRefMols, ValidProbeMols, OutFH, OutDelim) elif re.match("^AllToAll$", OptionsInfo["Mode"], re.I): PerformAllToAllShapeComparison(ValidRefMols, ValidProbeMols, OutFH, OutDelim) elif re.match("^FirstToAll$", OptionsInfo["Mode"], re.I): PerformFirstToAllShapeComparison(ValidRefMols, ValidProbeMols, OutFH, OutDelim) else: MiscUtil.PrintError("Shape comaprison couldn't be performed: Specified mode, %s, is not supported" % OptionsInfo["Mode"]) OutFH.close() MiscUtil.PrintInfo("\nTotal number of molecules: Reference - %d; Probe - %d" % (RefMolCount, ProbeMolCount)) MiscUtil.PrintInfo("Number of valid molecules: Reference - %d; Probe - %d" % (ValidRefMolCount, ValidProbeMolCount)) MiscUtil.PrintInfo("Number of ignored molecules: Reference - %d; Probe - %d" % ((RefMolCount - ValidRefMolCount), (ProbeMolCount - ValidProbeMolCount)))
def ProcessMoleculesUsingMultipleProcesses(Mols, Writer): """Process and remove salts from molecules using multiprocessing.""" MiscUtil.PrintInfo("\nRemoving salts using multiprocessing...") MPParams = OptionsInfo["MPParams"] Compute2DCoords = OptionsInfo["OutfileParams"]["Compute2DCoords"] # Setup data for initializing a worker process... InitializeWorkerProcessArgs = (MiscUtil.ObjectToBase64EncodedString(Options), MiscUtil.ObjectToBase64EncodedString(OptionsInfo)) # Setup a encoded mols data iterable for a worker process by pickling only public # and private molecule properties... WorkerProcessDataIterable = RDKitUtil.GenerateBase64EncodedMolStrings(Mols) # Setup process pool along with data initialization for each process... MiscUtil.PrintInfo("\nConfiguring multiprocessing using %s method..." % ("mp.Pool.imap()" if re.match("^Lazy$", MPParams["InputDataMode"], re.I) else "mp.Pool.map()")) MiscUtil.PrintInfo("NumProcesses: %s; InputDataMode: %s; ChunkSize: %s\n" % (MPParams["NumProcesses"], MPParams["InputDataMode"], ("automatic" if MPParams["ChunkSize"] is None else MPParams["ChunkSize"]))) ProcessPool = mp.Pool(MPParams["NumProcesses"], InitializeWorkerProcess, InitializeWorkerProcessArgs) # Start processing... if re.match("^Lazy$", MPParams["InputDataMode"], re.I): Results = ProcessPool.imap(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) elif re.match("^InMemory$", MPParams["InputDataMode"], re.I): Results = ProcessPool.map(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) else: MiscUtil.PrintError("The value, %s, specified for \"--inputDataMode\" is not supported." % (MPParams["InputDataMode"])) SetSMILESMolProps = OptionsInfo["OutfileParams"]["SetSMILESMolProps"] (MolCount, ValidMolCount, SaltsMolCount) = [0] * 3 FirstMol = True for Result in Results: MolCount += 1 MolIndex, EncodedMol, SaltyStatus = Result if EncodedMol is None: continue ValidMolCount += 1 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) if FirstMol: FirstMol = False if SetSMILESMolProps: RDKitUtil.SetWriterMolProps(Writer, Mol) if SaltyStatus: SaltsMolCount += 1 WriteMolecule(Writer, Mol, Compute2DCoords) return (MolCount, ValidMolCount, SaltsMolCount)
def ProcessMoleculesUsingSingleProcess(Mols, GroupsPatternMols, Writer, GroupOutfilesWriters): """Process and search molecules using a single process.""" MiscUtil.PrintInfo("\nSearching functional groups...") Compute2DCoords = OptionsInfo["OutfileParams"]["Compute2DCoords"] CombineMatchResults = OptionsInfo["CombineMatchResults"] SetSMILESMolProps = OptionsInfo["OutfileParams"]["SetSMILESMolProps"] GroupsPatternsMatchCountList = [0] * len( OptionsInfo["SpecifiedFunctionalGroups"]) (MolCount, ValidMolCount, RemainingMolCount) = [0] * 3 FirstMol = True for Mol in Mols: MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 if FirstMol: FirstMol = False if SetSMILESMolProps: if Writer is not None: RDKitUtil.SetWriterMolProps(Writer, Mol) for GroupOutfileWriter in GroupOutfilesWriters: if GroupOutfileWriter is not None: RDKitUtil.SetWriterMolProps(GroupOutfileWriter, Mol) # Match molecule against functional group patterns... MolMatched, GroupsPatternMatchStatusList = MatchMolecule( Mol, GroupsPatternMols) # Update functional group match count... for GroupIndex, MatchStatus in enumerate(GroupsPatternMatchStatusList): if MatchStatus: GroupsPatternsMatchCountList[GroupIndex] += 1 if not MolMatched: continue RemainingMolCount += 1 WriteMolecule(Writer, GroupOutfilesWriters, Mol, Compute2DCoords, CombineMatchResults, GroupsPatternMatchStatusList) return (MolCount, ValidMolCount, RemainingMolCount, GroupsPatternsMatchCountList)
def CalculatePartialCharges(): """Calculate partial atomic charges.""" Infile = OptionsInfo["Infile"] Outfile = OptionsInfo["Outfile"] MiscUtil.PrintInfo("Calculating partial atomic charges...") # Setup a molecule reader... MiscUtil.PrintInfo("\nProcessing file %s..." % Infile) Mols = RDKitUtil.ReadMolecules(Infile, **OptionsInfo["InfileParams"]) # Setup a writer... Compute2DCoords = OptionsInfo["OutfileParams"]["Compute2DCoords"] Writer = RDKitUtil.MoleculesWriter(Outfile, **OptionsInfo["OutfileParams"]) if Writer is None: MiscUtil.PrintError("Failed to setup a writer for output fie %s " % Outfile) MiscUtil.PrintInfo("Generating file %s..." % Outfile) # Process molecules... MolCount, ValidMolCount, CalcFailedCount = [0] * 3 for Mol in Mols: MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 MolWithHs = Chem.AddHs(Mol) # Retrieve charges... PartialCharges = CalculateMolPartialCharges(MolWithHs, MolCount) if not len(PartialCharges): CalcFailedCount += 1 continue # Write out charges... WriteMolPartialCharges(Writer, MolWithHs, PartialCharges, Compute2DCoords) if Writer is not None: Writer.close() MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount) MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) MiscUtil.PrintInfo("Number of molecules failed during calculation of partial charges: %d" % CalcFailedCount) MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount + CalcFailedCount))
def RetrieveReactantsMolecules(): """Retrieve reactant molecules from each reactant file and return a list containing lists of molecules for each reactant file.""" MiscUtil.PrintInfo("\nProcessing reactant file(s)...") ReactantsMolsList = [] ReactantFilesList = OptionsInfo["ReactantFilesList"] UseReactantNames = OptionsInfo["UseReactantNames"] ReactantCount = 0 for FileIndex in range(0, len(ReactantFilesList)): ReactantCount += 1 ReactantFile = ReactantFilesList[FileIndex] MiscUtil.PrintInfo("\nProcessing reactant file: %s..." % ReactantFile) Mols = RDKitUtil.ReadMolecules(ReactantFile, **OptionsInfo["InfileParams"]) ValidMols = [] MolCount = 0 ValidMolCount = 0 for Mol in Mols: MolCount += 1 if Mol is None: continue if RDKitUtil.IsMolEmpty(Mol): MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Ignoring empty molecule: %s" % MolName) continue ValidMolCount += 1 # Check and set mol name... if UseReactantNames: MolName = RDKitUtil.GetMolName(Mol) if not len(MolName): MolName = "React%dMol%d" % (ReactantCount, MolCount) Mol.SetProp("_Name", MolName) ValidMols.append(Mol) ReactantsMolsList.append(ValidMols) MiscUtil.PrintInfo("Total number of molecules: %d" % MolCount) MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount)) return ReactantsMolsList
def MinimizeMolecule(Mol, MolNum=None): "Minimize molecule." if OptionsInfo["AddHydrogens"]: Mol = Chem.AddHs(Mol, addCoords=True) Status = 0 try: if OptionsInfo["UseUFF"]: Status = AllChem.UFFOptimizeMolecule( Mol, maxIters=OptionsInfo["MaxIters"]) elif OptionsInfo["UseMMFF"]: Status = AllChem.MMFFOptimizeMolecule( Mol, maxIters=OptionsInfo["MaxIters"], mmffVariant=OptionsInfo["MMFFVariant"]) else: MiscUtil.PrintError( "Minimization couldn't be performed: Specified forcefield, %s, is not supported" % OptionsInfo["ForceField"]) except (ValueError, RuntimeError, Chem.rdchem.KekulizeException) as ErrMsg: if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolNum) MiscUtil.PrintWarning( "Minimization couldn't be performed for molecule %s:\n%s\n" % (MolName, ErrMsg)) return (Mol, False, None) if Status != 0: if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolNum) MiscUtil.PrintWarning( "Minimization failed to converge for molecule %s in %d steps. Try using higher value for \"--maxIters\" option...\n" % (MolName, OptionsInfo["MaxIters"])) Energy = None if OptionsInfo["EnergyOut"]: EnergyStatus, Energy = GetEnergy(Mol) if EnergyStatus: Energy = "%.2f" % Energy else: if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolNum) MiscUtil.PrintWarning( "Failed to retrieve calculated energy for molecule %s. Try again after removing any salts or cleaing up the molecule...\n" % (MolName)) if OptionsInfo["RemoveHydrogens"]: Mol = Chem.RemoveHs(Mol) return (Mol, True, Energy)
def PerformFirstToAllShapeComparison(ValidRefMols, ValidProbeMols, OutFH, OutDelim): """Perform shape comparison between first reference molecues and all probe molecules. """ # Process molecules... RefMol = ValidRefMols[0] RefMolCount = 1 RefMolName = RDKitUtil.GetMolName(RefMol, RefMolCount) ProbeMolCount = 0 for ProbeMol in ValidProbeMols: ProbeMolCount += 1 ProbeMolName = RDKitUtil.GetMolName(ProbeMol, ProbeMolCount) PerformShapeComparisonAndWrieOutput(RefMol, ProbeMol, RefMolName, ProbeMolName, OutFH, OutDelim)
def ProcessMoleculesUsingMultipleProcesses(Mols, Writer): """Process and calculate energy of molecules using process.""" MiscUtil.PrintInfo("\nCalculating energy using multiprocessing...") MPParams = OptionsInfo["MPParams"] # Setup data for initializing a worker process... InitializeWorkerProcessArgs = (MiscUtil.ObjectToBase64EncodedString(Options), MiscUtil.ObjectToBase64EncodedString(OptionsInfo)) # Setup a encoded mols data iterable for a worker process... WorkerProcessDataIterable = RDKitUtil.GenerateBase64EncodedMolStrings(Mols) # Setup process pool along with data initialization for each process... MiscUtil.PrintInfo("\nConfiguring multiprocessing using %s method..." % ("mp.Pool.imap()" if re.match("^Lazy$", MPParams["InputDataMode"], re.I) else "mp.Pool.map()")) MiscUtil.PrintInfo("NumProcesses: %s; InputDataMode: %s; ChunkSize: %s\n" % (MPParams["NumProcesses"], MPParams["InputDataMode"], ("automatic" if MPParams["ChunkSize"] is None else MPParams["ChunkSize"]))) ProcessPool = mp.Pool(MPParams["NumProcesses"], InitializeWorkerProcess, InitializeWorkerProcessArgs) # Start processing... if re.match("^Lazy$", MPParams["InputDataMode"], re.I): Results = ProcessPool.imap(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) elif re.match("^InMemory$", MPParams["InputDataMode"], re.I): Results = ProcessPool.map(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) else: MiscUtil.PrintError("The value, %s, specified for \"--inputDataMode\" is not supported." % (MPParams["InputDataMode"])) (MolCount, ValidMolCount, EnergyFailedCount) = [0] * 3 for Result in Results: MolCount += 1 MolIndex, EncodedMol, CalcStatus, Energy = Result if EncodedMol is None: continue ValidMolCount += 1 if CalcStatus: Energy = "%.2f" % Energy else: if not OptionsInfo["QuietMode"]: MolName = RDKitUtil.GetMolName(Mol, MolCount) MiscUtil.PrintWarning("Failed to calculate energy for molecule %s" % MolName) EnergyFailedCount += 1 continue Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) WriteMolecule(Writer, Mol, Energy) return (MolCount, ValidMolCount, EnergyFailedCount)
def ProcessMoleculesUsingMultipleProcesses(RefMol, Mols, Writer): """Process and minimize molecules using multiprocessing.""" MPParams = OptionsInfo["MPParams"] # Setup data for initializing a worker process... MiscUtil.PrintInfo("Encoding options info and reference molecule...") OptionsInfo["EncodedRefMol"] = RDKitUtil.MolToBase64EncodedMolString(RefMol) InitializeWorkerProcessArgs = (MiscUtil.ObjectToBase64EncodedString(Options), MiscUtil.ObjectToBase64EncodedString(OptionsInfo)) # Setup a encoded mols data iterable for a worker process... WorkerProcessDataIterable = RDKitUtil.GenerateBase64EncodedMolStrings(Mols) # Setup process pool along with data initialization for each process... MiscUtil.PrintInfo("\nConfiguring multiprocessing using %s method..." % ("mp.Pool.imap()" if re.match("^Lazy$", MPParams["InputDataMode"], re.I) else "mp.Pool.map()")) MiscUtil.PrintInfo("NumProcesses: %s; InputDataMode: %s; ChunkSize: %s\n" % (MPParams["NumProcesses"], MPParams["InputDataMode"], ("automatic" if MPParams["ChunkSize"] is None else MPParams["ChunkSize"]))) ProcessPool = mp.Pool(MPParams["NumProcesses"], InitializeWorkerProcess, InitializeWorkerProcessArgs) # Start processing... if re.match("^Lazy$", MPParams["InputDataMode"], re.I): Results = ProcessPool.imap(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) elif re.match("^InMemory$", MPParams["InputDataMode"], re.I): Results = ProcessPool.map(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) else: MiscUtil.PrintError("The value, %s, specified for \"--inputDataMode\" is not supported." % (MPParams["InputDataMode"])) (MolCount, ValidMolCount, CoreScaffoldMissingCount, MinimizationFailedCount) = [0] * 4 for Result in Results: MolCount += 1 MolIndex, EncodedMol, CoreScaffoldMissingStatus, CalcStatus, Energy, ScaffoldEmbedRMSD = Result if EncodedMol is None: continue ValidMolCount += 1 if CoreScaffoldMissingStatus: CoreScaffoldMissingStatus += 1 continue if not CalcStatus: MinimizationFailedCount += 1 continue Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) WriteMolecule(Writer, Mol, Energy, ScaffoldEmbedRMSD) return (MolCount, ValidMolCount, CoreScaffoldMissingCount, MinimizationFailedCount)