Пример #1
0
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
Пример #4
0
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)
Пример #5
0
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)))
Пример #7
0
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
    ]
Пример #8
0
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)
Пример #11
0
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)))
Пример #12
0
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]
Пример #13
0
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))
Пример #14
0
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)
Пример #15
0
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
Пример #20
0
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)
Пример #21
0
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)
Пример #22
0
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)))
Пример #23
0
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)
Пример #24
0
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)
Пример #25
0
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))
Пример #26
0
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
Пример #27
0
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)
Пример #28
0
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)
Пример #29
0
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)