Bioisostere Examples

The following table lists the currently available Bioisostere TK examples:

Program

Description

brood_database

Building Brood Database (CHOMP)

brood_query

Creating Brood Query

brood_hitlist

Generating Brood Hits

brood_matches

Generating Brood Matches

fragment_overlay

Overlay between Fragments

replace_fragment

Replacing a Fragment in a Molecule

cpddb

Building and Using an External Compound Database

2molLinker_query

Creating a Brood Query for Linking Two Molecules (Bridging)

Building Brood Database (CHOMP)

The following code example shows how to build a Brood database from a library of molecules.

Listing 1: Building Brood Database (CHOMP)

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.


from openeye import oechem
from openeye import oebioisostere
from openeye import oemolprop

class ChompOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "ChompOptions")

        dbParam = oechem.OEStringParameter("-out")
        dbParam.SetVisibility(oechem.OEParamVisibility_Simple)
        dbParam.SetBrief("Output database folder name")
        dbParam.SetRequired(True)
        dbParam.SetKeyless(2)
        self._dbParam = self.AddParameter(dbParam)

        self._fragOpts = oebioisostere.ToFragmentOptions(self.AddOption(oebioisostere.OEFragmentOptions()))
        self._screenOpts = oebioisostere.ToDBScreenOptions(self.AddOption(oebioisostere.OEDBScreenOptions()))
        pass

    def CreateCopy(self):
        return self

    def GetDBName(self):
        return self._dbParam.GetStringValue()

    def GetFragOpts(self):
        return self._fragOpts

    def GetScreenOpts(self):
        return self._screenOpts


def main(argv=[__name__]):
    chompOpts = ChompOptions()
    opts = oechem.OESimpleAppOptions(chompOpts, "BroodDataBase", oechem.OEFileStringType_Mol)
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    chompOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())

    print("Generating fragments...")
    builder = oebioisostere.OEDBBuilder(chompOpts.GetFragOpts())
    for mol in ifs.GetOEMols():
        builder.Generate(mol)

    print("Building 2D fragments library...")
    builder.Filter(oebioisostere.OECreateFragFilter())
    builder.Expand(oebioisostere.OECreateFlipperOptions())
    builder.Screen(chompOpts.GetScreenOpts())

    print("Generating fragment conformers...")
    writer = oebioisostere.OEDBWriter()
    writer.Init(chompOpts.GetDBName())
    count = 0
    for frag in builder.GetFrags():
        if oebioisostere.OEGenerateConformers(frag):
            writer.Write(frag)
            count += 1
    writer.Finish()
    print("Generated fragments: %d" % count)


if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

brood_database.py

Creating Brood Query

The following code example shows how to create a Brood query from a molecule that could be used for bioisosteric fragment replacements using Brood.

See also

Listing 2: Creating Brood Query

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.


from openeye import oechem
from openeye import oebioisostere

class QueryOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "QueryOptions")

        idxParam = oechem.OEUIntParameter("-atomIndices")
        idxParam.SetIsList(True)
        idxParam.SetRequired(True)
        idxParam.SetBrief("Index of atoms in fragment")
        self._idxParam = self.AddParameter(idxParam)

        duParam = oechem.OEFileStringParameter("-du", oechem.OEFileStringType_DU)
        duParam.SetBrief("Design unit containing protein target for bump check")
        self._duParam = self.AddParameter(duParam)

        maskParam = oechem.OEUIntParameter("-proteinMask", oechem.OEDesignUnitComponents_TargetComplexNoSolvent)
        maskParam.SetBrief("Design unit mask to identify protein target")
        self._maskParam = self.AddParameter(maskParam)
        
        selectDUParam = oechem.OEFileStringParameter("-selectDU", oechem.OEFileStringType_DU)
        selectDUParam.SetBrief("Design unit containing select protein for bump check")
        self._selectDUParam = self.AddParameter(selectDUParam)

        maskSelectParam = oechem.OEUIntParameter("-proteinSelectMask", oechem.OEDesignUnitComponents_TargetComplexNoSolvent)
        maskSelectParam.SetBrief("Design unit mask to identify select protein target")
        self._maskSelectParam = self.AddParameter(maskSelectParam)

    def CreateCopy(self):
        return self

    def GetIndices(self):
        indices = []
        for idx in self._idxParam.GetStringValues():
            indices.append(int(idx))
        return indices

    def GetDU(self):
        ifs = oechem.oeifstream()
        if not self._duParam.GetHasValue():
            return None
        if not ifs.open(self._duParam.GetStringValue()):
            oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
        du = oechem.OEDesignUnit()
        if not oechem.OEReadDesignUnit(ifs, du):
            oechem.OEThrow.Fatal("Unable to read design unit")
        return du

    def GetProteinMask(self):
        mask = self._maskParam.GetStringValue()
        if mask == "":
            mask = self._maskParam.GetStringDefault()
        return int(mask)


    def GetSelectDU(self):
        ifs = oechem.oeifstream()
        if not self._selectDUParam.GetHasValue():
            return None
        if not ifs.open(self._selectDUParam.GetStringValue()):
            oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
        selectDU = oechem.OEDesignUnit()
        if not oechem.OEReadDesignUnit(ifs, selectDU):
            oechem.OEThrow.Fatal("Unable to read design unit")
        return selectDU

    def GetSelectProteinMask(self):
        mask = self._maskSelectParam.GetStringValue()
        if mask == "":
            mask = self._maskSelectParam.GetStringDefault()
        return int(mask)

def main(argv=[__name__]):
    queryOpts = QueryOptions()
    opts = oechem.OESimpleAppOptions(queryOpts, "BroodQuery", oechem.OEFileStringType_Mol3D, "oeb")
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    queryOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())

    ofs = oechem.oemolostream()
    if not ofs.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())

    queryMol = oechem.OEMol()
    if not oechem.OEReadMolecule(ifs, queryMol):
        oechem.OEThrow.Fatal("Unable to load molecule")

    indices = queryOpts.GetIndices()
    atoms = []
    for idx in indices:
        atom = queryMol.GetAtom(oechem.OEHasAtomIdx(idx))
        if not atom:
            oechem.OEThrow.Fatal("Invalid atom index %d" % idx)
        atoms.append(atom)

    selection = oechem.OEAtomBondSet()
    selection.AddAtoms(atoms)

    query = oebioisostere.OEBroodQuery()
    du = queryOpts.GetDU()
    selectDU = queryOpts.GetSelectDU()
    
    if du is None and selectDU is None:
        retCode = oebioisostere.OECreateBroodQuery(query, queryMol, selection)
    elif du is None and selectDU is not None:
        passingProteinSelect = True
        retCode = oebioisostere.OECreateBroodQuery(query, queryMol, selection, selectDU, queryOpts.GetSelectProteinMask(), passingProteinSelect)
    elif selectDU is None:
        retCode = oebioisostere.OECreateBroodQuery(query, queryMol, selection, du, queryOpts.GetProteinMask())
    else:
        retCode = oebioisostere.OECreateBroodQuery(query, queryMol, selection, du, queryOpts.GetProteinMask(),selectDU,queryOpts.GetSelectProteinMask())
    
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("%s" % oebioisostere.OEGetBroodStatus(retCode))
    oebioisostere.OEWriteBroodQuery(ofs, query)

if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

brood_query.py

Generating Brood Hits

The following code example shows how to perform bioisosteric fragment replacements on a Brood query and generate a hit list.

Listing 3: Generating Brood Hits

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.


from openeye import oechem
from openeye import oebioisostere

class BroodOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "BroodOptions")

        dbParam = oechem.OEStringParameter("-db")
        dbParam.SetRequired(True)
        dbParam.SetVisibility(oechem.OEParamVisibility_Simple)
        dbParam.SetBrief("Database folder")
        self._dbParam = self.AddParameter(dbParam)

        self._genOpts = oebioisostere.ToGeneralOptions(self.AddOption(oebioisostere.OEBroodGeneralOptions()))
        self._scoreOpts = oebioisostere.ToScoreOptions(self.AddOption(oebioisostere.OEBroodScoreOptions()))
        self._hitOpts = oebioisostere.ToHitlistOptions(self.AddOption(oebioisostere.OEBroodHitlistOptions()))
        pass

    def CreateCopy(self):
        return self

    def GetDatabase(self):
        return self._dbParam.GetStringValue()

    def GetGenOpts(self):
        return self._genOpts

    def GetScoreOpts(self):
        return self._scoreOpts

    def GetHitlistOpts(self):
        return self._hitOpts


def main(argv=[__name__]):
    broodOpts = BroodOptions()
    opts = oechem.OESimpleAppOptions(broodOpts, "BroodHitlist", oechem.OEFileStringType_Mol3D,
                                     oechem.OEFileStringType_Mol3D)
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    broodOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())

    ofs = oechem.oemolostream()
    if not ofs.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())

    query = oebioisostere.OEBroodQuery()
    retCode = oebioisostere.OEReadBroodQuery(ifs, query)
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Failed: %s" % oebioisostere.OEGetBroodStatus(retCode))
        
    reader = oebioisostere.OEDBReader()
    retCode = reader.Init(broodOpts.GetDatabase(), query, broodOpts.GetGenOpts())
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Unable to load Brood database")

    overlay = oebioisostere.OEBroodOverlay(broodOpts.GetGenOpts(), broodOpts.GetScoreOpts())
    overlay.SetupRef(query);

    hlist = oebioisostere.OEHitlistBuilder(query, broodOpts.GetGenOpts(), broodOpts.GetHitlistOpts())

    packetCount = 0
    packet = oebioisostere.OEBroodDBPacket()
    while reader.GetNextPacket(packet):
        packetCount += 1
        print("Processing packet %d with %d fragments" % (packetCount, packet.GetFragCount()))
        vecScores = overlay.Overlay(packet)
        hlist.AddScores(vecScores);
    print("Generating hitlist...")
    hlist.Build();
    print("Total number of fragments overlayed: %d" % hlist.GetAddCount())
    print("Number of final hits: %d" % hlist.GetHitCount())

    for idx, hit in enumerate(hlist.GetHits()):
        oechem.OEWriteMolecule(ofs, hit.GetMol())
        comboScore = hit.GetComboScore()
        if broodOpts.GetGenOpts().GetScoreType() == oebioisostere.OEBroodScoreType_ET:
            comboScore = hit.GetETComboScore()
        print("Hit: %d %s Combo Score: %2f Belief Score: %.2f Complexity: %2f"
              % (idx+1, hit.GetMol().GetTitle(), comboScore, hit.GetBeliefScore(), hit.GetComplexity()))


if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

brood_hitlist.py

Generating Brood Matches

The following code example shows how to perform bioisosteric fragment replacements on a Brood query and generate all possible matches. This could be a use case when generating all possible design ideas using BROOD and postprocessing them with other tools.

Listing 4: Generating Brood Matches

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.

import sys

from openeye import oechem
from openeye import oebioisostere

class BroodOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "BroodOptions")

        dbParam = oechem.OEStringParameter("-db")
        dbParam.SetRequired(True)
        dbParam.SetVisibility(oechem.OEParamVisibility_Simple)
        dbParam.SetBrief("Database folder")
        self._dbParam = self.AddParameter(dbParam)

        self._genOpts = oebioisostere.ToGeneralOptions(self.AddOption(oebioisostere.OEBroodGeneralOptions()))
        self._scoreOpts = oebioisostere.ToScoreOptions(self.AddOption(oebioisostere.OEBroodScoreOptions()))
        self._buildOpts = oebioisostere.ToBuildOptions(self.AddOption(oebioisostere.OEBroodBuildOptions()))
        pass

    def CreateCopy(self):
        return self

    def GetDatabase(self):
        return self._dbParam.GetStringValue()

    def GetGenOpts(self):
        return self._genOpts

    def GetScoreOpts(self):
        return self._scoreOpts

    def GetBuildOpts(self):
        return self._buildOpts


def main(argv=[__name__]):
    broodOpts = BroodOptions()
    opts = oechem.OESimpleAppOptions(broodOpts, "BroodMatching", oechem.OEFileStringType_Mol3D,
                                     oechem.OEFileStringType_Mol3D)
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    broodOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())

    ofs = oechem.oemolostream()
    if not ofs.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())

    query = oebioisostere.OEBroodQuery()
    retCode = oebioisostere.OEReadBroodQuery(ifs, query)
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Failed: %s" % oebioisostere.OEGetBroodStatus(retCode))

    reader = oebioisostere.OEDBReader()
    retCode = reader.Init(broodOpts.GetDatabase(), query, broodOpts.GetGenOpts())
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Unable to load Brood database")

    overlay = oebioisostere.OEBroodOverlay(broodOpts.GetGenOpts(), broodOpts.GetScoreOpts())
    overlay.SetupRef(query);
    builder = oebioisostere.OEBroodMolBuilder(query, broodOpts.GetGenOpts(), broodOpts.GetBuildOpts())

    packetCount = 0
    packet = oebioisostere.OEBroodDBPacket()
    totalCount = 0
    successCount = 0
    while reader.GetNextPacket(packet):
        packetCount += 1
        print("Processing packet %d with %d fragments" % (packetCount, packet.GetFragCount()))
        vecScores = overlay.Overlay(packet)
        for score in vecScores:
            totalCount += 1
            if score.GetStatus() == oebioisostere.OEBroodStatusCode_Success:
                hit = oebioisostere.OEBroodHit()
                if builder.Build(score, hit) == oebioisostere.OEBroodStatusCode_Success:
                    oechem.OEWriteMolecule(ofs, hit.GetMol())
                    successCount += 1

    print("Total number of fragments overlayed: %d" % totalCount)
    print("Number of successful matches: %d" % successCount)


if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

brood_matching.py

Overlay between Fragments

The following code example shows how to overlay a fragment against a query fragment. This could be a use case when working with synthons and trying to find similar synthons based on 3D similarity.

Listing 5: Overlay between Fragments

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.

import sys

from openeye import oechem
from openeye import oebioisostere

def main(argv=[__name__]):
    genOpts = oebioisostere.OEBroodGeneralOptions()
    opts = oechem.OERefInputAppOptions(genOpts, "FragmentOverlay", oechem.OEFileStringType_Mol3D,
                                     oechem.OEFileStringType_Mol3D, oechem.OEFileStringType_Mol3D, "-queryFrag")
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    genOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())

    rfs = oechem.oemolistream()
    if not rfs.open(opts.GetRefFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetRefFile())

    ofs = oechem.oemolostream()
    if not ofs.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())

    query = oechem.OEMol()
    if not oechem.OEReadMolecule(rfs, query):
        oechem.OEThrow.Fatal("Failed to read Query fragment")

    prep = oebioisostere.OEBroodFragPrep()
    overlay = oebioisostere.OEFragOverlay(genOpts, oebioisostere.OEBroodScoreOptions())
    overlay.SetupRef(query);

    for frag in ifs.GetOEMols():
        print("Overlaying %s" % frag.GetTitle())
        prep.Prep(frag)
        score = oebioisostere.OEBroodScore()
        ret_code = overlay.Overlay(frag, score)
        if ret_code == oebioisostere.OEBroodStatusCode_Success:
            outmol = oechem.OEGraphMol()
            score.GetFragMol(outmol)
            overlay.Transform(outmol)
            comboScore = score.GetComboScore()
            if genOpts.GetScoreType() == oebioisostere.OEBroodScoreType_ET:
                comboScore = score.GetETComboScore()
            print("Fragment: %s Combo Score: %2f" % (frag.GetTitle(), comboScore))
            oechem.OEWriteMolecule(ofs, outmol)
        else:
            errMsg = oebioisostere.OEGetBroodStatus(ret_code)
            print("%s: %s" % (frag.GetTitle(), errMsg))
    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

fragment_overlay.py

Replacing a Fragment in a Molecule

The following code example shows how to replace a fragment in a molecule defined in the form of a BROOD query.

Listing 6: Replacing a Fragment in a Molecule

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.

import sys

from openeye import oechem
from openeye import oebioisostere

class BroodOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "BroodOptions")
        self._genOpts = oebioisostere.ToGeneralOptions(self.AddOption(oebioisostere.OEBroodGeneralOptions()))
        self._scoreOpts = oebioisostere.ToScoreOptions(self.AddOption(oebioisostere.OEBroodScoreOptions()))
        self._buildOpts = oebioisostere.ToBuildOptions(self.AddOption(oebioisostere.OEBroodBuildOptions()))
        pass

    def CreateCopy(self):
        return self

    def GetGenOpts(self):
        return self._genOpts

    def GetScoreOpts(self):
        return self._scoreOpts

    def GetBuildOpts(self):
        return self._buildOpts


def main(argv=[__name__]):
    broodOpts = BroodOptions()
    opts = oechem.OERefInputAppOptions(broodOpts, "ReplaceFragment", oechem.OEFileStringType_Mol3D,
                                     oechem.OEFileStringType_Mol3D, oechem.OEFileStringType_Mol3D, "-query")
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    broodOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())

    rfs = oechem.oemolistream()
    if not rfs.open(opts.GetRefFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetRefFile())

    ofs = oechem.oemolostream()
    if not ofs.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())

    query = oebioisostere.OEBroodQuery()
    retCode = oebioisostere.OEReadBroodQuery(rfs, query)
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Failed: %s" % oebioisostere.OEGetBroodStatus(retCode))

    prep = oebioisostere.OEBroodFragPrep()
    overlay = oebioisostere.OEBroodOverlay(broodOpts.GetGenOpts(), broodOpts.GetScoreOpts())
    overlay.SetupRef(query);
    builder = oebioisostere.OEBroodMolBuilder(query, broodOpts.GetGenOpts(), broodOpts.GetBuildOpts())

    for frag in ifs.GetOEMols():
        print("Replacement fragment %s" % frag.GetTitle())
        prep.Prep(frag)
        score = oebioisostere.OEBroodScore()
        ret_code = overlay.Overlay(frag, score)
        if ret_code == oebioisostere.OEBroodStatusCode_Success:
            comboScore = score.GetComboScore()
            if broodOpts.GetGenOpts().GetScoreType() == oebioisostere.OEBroodScoreType_ET:
                comboScore = score.GetETComboScore()
            print("Fragment: %s Combo Score: %2f" % (frag.GetTitle(), comboScore))
            hit = oebioisostere.OEBroodHit()
            if builder.Build(score, hit) == oebioisostere.OEBroodStatusCode_Success:
                oechem.OEWriteMolecule(ofs, hit.GetMol())
        else:
            errMsg = oebioisostere.OEGetBroodStatus(ret_code)
            print("%s: %s" % (frag.GetTitle(), errMsg))
    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

replace_fragment.py

Building and Using an External Compound Database

The following code example shows how to build and use an external (in-house) compound database to find similar 2D compounds to a generated hit list.

Listing 7: Building and using an external compound database

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.


from openeye import oechem
from openeye import oebioisostere

class BroodOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "BroodOptions")

        dbParam = oechem.OEStringParameter("-db")
        dbParam.SetRequired(True)
        dbParam.SetVisibility(oechem.OEParamVisibility_Simple)
        dbParam.SetBrief("Brood Database Directory")
        self._dbParam = self.AddParameter(dbParam)
        
        cpddbParam = oechem.OEStringParameter("-cpddb")
        cpddbParam.SetRequired(True)
        cpddbParam.SetVisibility(oechem.OEParamVisibility_Simple)
        cpddbParam.SetBrief("CPDDatabase File (database of known compounds to identify available compounds similar to hits)")
        self._cpddbParam = self.AddParameter(cpddbParam)

        self._genOpts = oebioisostere.ToGeneralOptions(self.AddOption(oebioisostere.OEBroodGeneralOptions()))
        self._scoreOpts = oebioisostere.ToScoreOptions(self.AddOption(oebioisostere.OEBroodScoreOptions()))
        self._hitOpts = oebioisostere.ToHitlistOptions(self.AddOption(oebioisostere.OEBroodHitlistOptions()))
        pass

    def CreateCopy(self):
        return self

    def GetDatabase(self):
        return self._dbParam.GetStringValue()
        
    def GetCPDDatabase(self):
        return self._cpddbParam.GetStringValue()

    def GetGenOpts(self):
        return self._genOpts

    def GetScoreOpts(self):
        return self._scoreOpts

    def GetHitlistOpts(self):
        return self._hitOpts


def main(argv=[__name__]):
    broodOpts = BroodOptions()
    opts = oechem.OESimpleAppOptions(broodOpts, "BroodCPDDB", oechem.OEFileStringType_Mol3D,
                                     "oeb")
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    broodOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
        
    query = oebioisostere.OEBroodQuery()
    retCode = oebioisostere.OEReadBroodQuery(ifs, query)
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Failed: %s" % oebioisostere.OEGetBroodStatus(retCode))

    reader = oebioisostere.OEDBReader()
    retCode = reader.Init(broodOpts.GetDatabase(), query, broodOpts.GetGenOpts())
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("Unable to load Brood database")
        
    ifsCPDDB = oechem.oemolistream()
    if not ifsCPDDB.open(broodOpts.GetCPDDatabase()):
        oechem.OEThrow.Fatal("Unable to load Brood CPDDatabase file")
        
    cpddb = oebioisostere.OECPDDatabase()
    retValue = cpddb.Prep(ifsCPDDB)
    print("Prepration Mode: %s" % oebioisostere.OEGetBroodStatus(retValue))
    
    numOfCPDDBMolecule = cpddb.GetNumMolecules()
    print("Number of molecules in CPDDatabse: %d" % numOfCPDDBMolecule)
    
    if retValue == oebioisostere.OEBroodStatusCode_NewFPGenerated:
      ofsCPDDB = oechem.oemolostream()
      if not ofsCPDDB.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing the newly generated finegrprint" , opts.GetOutFile())
      
      if cpddb.Write(ifsCPDDB, ofsCPDDB):
        print("Fingerprints are written in the %s. You can use this file in the future with -cpddb for improved efficiency over current useage." % ofsCPDDB.GetFileName())
      else:
        oechem.OEThrow.Warning("Fingerprint mismatch in writing updated -cpddb file." % ofsCPDDB.GetFileName())

    overlay = oebioisostere.OEBroodOverlay(broodOpts.GetGenOpts(), broodOpts.GetScoreOpts())
    overlay.SetupRef(query);

    hlist = oebioisostere.OEHitlistBuilder(query, broodOpts.GetGenOpts(), broodOpts.GetHitlistOpts())

    packet = oebioisostere.OEBroodDBPacket()
    while reader.GetNextPacket(packet):
        vecScores = overlay.Overlay(packet)
        hlist.AddScores(vecScores);
    print("Generating hitlist...")
    hlist.Build();
    print("Number of final hits: %d \n" % hlist.GetHitCount())

    for idx, hit in enumerate(hlist.GetHits()):
        vecCpddbValues = cpddb.GetSimilarMolecules(hit.GetMol())
        if not len(vecCpddbValues) == 0:
          print("Hit Mol (SMILES): %s \nAnalog Mol (SMILES): %s \nAnalog Mol Label: %s \n \n"
              % (oechem.OEMolToSmiles(hit.GetMol()),vecCpddbValues[0], vecCpddbValues[1]))

if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))

Download code

brood_cpddb.py

Creating Brood Query by Linking Two Molecules (Bridging)

The following code example shows how to create a Brood query from two molecules to find a suitable linker between the two using bioisosteric fragment replacements using Brood.

See also

Listing 8: Creating Brood Query by Linking Two Molecules (Bridging)

#!/usr/bin/env python
# (C) 2022 Cadence Design Systems, Inc. (Cadence) 
# All rights reserved.
# TERMS FOR USE OF SAMPLE CODE The software below ("Sample Code") is
# provided to current licensees or subscribers of Cadence products or
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. Cadence claims no rights to Customer's
# modifications. Modification of Sample Code is at Customer's sole and
# exclusive risk. Sample Code may require Customer to have a then
# current license or subscription to the applicable Cadence offering.
# THE SAMPLE CODE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED.  OPENEYE DISCLAIMS ALL WARRANTIES, INCLUDING, BUT
# NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. In no event shall Cadence be
# liable for any damages or liability in connection with the Sample Code
# or its use.


from openeye import oechem
from openeye import oebioisostere

class QueryOptions(oechem.OEOptions):
    def __init__(self):
        oechem.OEOptions.__init__(self, "2MolLinkerQueryOptions")

        idxNo1Param = oechem.OEUIntParameter("-atomIndicesNo1")
        idxNo1Param.SetIsList(True)
        idxNo1Param.SetRequired(True)
        idxNo1Param.SetBrief("Index of atoms in fragment No.1")
        self._idxNo1Param = self.AddParameter(idxNo1Param)
        
        idxNo2Param = oechem.OEUIntParameter("-atomIndicesNo2")
        idxNo2Param.SetIsList(True)
        idxNo2Param.SetRequired(True)
        idxNo2Param.SetBrief("Index of atoms in fragment No.2")
        self._idxNo2Param = self.AddParameter(idxNo2Param)

        duParam = oechem.OEFileStringParameter("-du", oechem.OEFileStringType_DU)
        duParam.SetBrief("Design unit containing protein target for bump check")
        self._duParam = self.AddParameter(duParam)

        maskParam = oechem.OEUIntParameter("-proteinMask", oechem.OEDesignUnitComponents_TargetComplexNoSolvent)
        maskParam.SetBrief("Design unit mask to identify protein target")
        self._maskParam = self.AddParameter(maskParam)
        
        selectDUParam = oechem.OEFileStringParameter("-selectDU", oechem.OEFileStringType_DU)
        selectDUParam.SetBrief("Design unit containing select protein for bump check")
        self._selectDUParam = self.AddParameter(selectDUParam)

        maskSelectParam = oechem.OEUIntParameter("-proteinSelectMask", oechem.OEDesignUnitComponents_TargetComplexNoSolvent)
        maskSelectParam.SetBrief("Design unit mask to identify select protein target")
        self._maskSelectParam = self.AddParameter(maskSelectParam)

    def CreateCopy(self):
        return self

    def GetFirstMolIndices(self):
        indices = []
        for idx in self._idxNo1Param.GetStringValues():
            indices.append(int(idx))
        return indices

    def GetSecondMolIndices(self):
        indices = []
        for idx in self._idxNo2Param.GetStringValues():
            indices.append(int(idx))
        return indices

    def GetDU(self):
        ifs = oechem.oeifstream()
        if not self._duParam.GetHasValue():
            return None
        if not ifs.open(self._duParam.GetStringValue()):
            oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
        du = oechem.OEDesignUnit()
        if not oechem.OEReadDesignUnit(ifs, du):
            oechem.OEThrow.Fatal("Unable to read design unit")
        return du

    def GetProteinMask(self):
        mask = self._maskParam.GetStringValue()
        if mask == "":
            mask = self._maskParam.GetStringDefault()
        return int(mask)


    def GetSelectDU(self):
        ifs = oechem.oeifstream()
        if not self._selectDUParam.GetHasValue():
            return None
        if not ifs.open(self._selectDUParam.GetStringValue()):
            oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
        selectDU = oechem.OEDesignUnit()
        if not oechem.OEReadDesignUnit(ifs, selectDU):
            oechem.OEThrow.Fatal("Unable to read design unit")
        return selectDU

    def GetSelectProteinMask(self):
        mask = self._maskSelectParam.GetStringValue()
        if mask == "":
            mask = self._maskSelectParam.GetStringDefault()
        return int(mask)

def main(argv=[__name__]):
    queryOpts = QueryOptions()
    opts = oechem.OERefInputAppOptions(queryOpts, "2MolLinkerBroodQuery", oechem.OEFileStringType_Mol3D, oechem.OEFileStringType_Mol3D, oechem.OEFileStringType_Mol3D , "-in2")
    if oechem.OEConfigureOpts(opts, argv, False) == oechem.OEOptsConfigureStatus_Help:
        return 0
    queryOpts.UpdateValues(opts)

    ifs = oechem.oemolistream()
    if not ifs.open(opts.GetInFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetInFile())
        
    rfs = oechem.oemolistream()
    if not rfs.open(opts.GetRefFile()):
        oechem.OEThrow.Fatal("Unable to open %s for reading" % opts.GetRefFile())
        
    ofs = oechem.oemolostream()
    if not ofs.open(opts.GetOutFile()):
        oechem.OEThrow.Fatal("Unable to open %s for writing" % opts.GetOutFile())

    firstMol = oechem.OEMol()
    if not oechem.OEReadMolecule(ifs, firstMol):
        oechem.OEThrow.Fatal("Unable to load molecule 1")
        
    secondMol = oechem.OEMol()
    if not oechem.OEReadMolecule(rfs, secondMol):
        oechem.OEThrow.Fatal("Unable to load molecule 2")

    firstMolIndices = queryOpts.GetFirstMolIndices()
    firstMolAtoms = []
    for idx in firstMolIndices:
        firstMolAtom = firstMol.GetAtom(oechem.OEHasAtomIdx(idx))
        if not firstMolAtom:
            oechem.OEThrow.Fatal("Invalid atom index %d" % idx)
        firstMolAtoms.append(firstMolAtom)
  
    secondMolIndices = queryOpts.GetSecondMolIndices()
    secondMolAtoms = []
    for idx in secondMolIndices:
        secondMolAtom = secondMol.GetAtom(oechem.OEHasAtomIdx(idx))
        if not secondMolAtom:
            oechem.OEThrow.Fatal("Invalid atom index %d" % idx)
        secondMolAtoms.append(secondMolAtom)

    firstMolSelection = oechem.OEAtomBondSet()
    firstMolSelection.AddAtoms(firstMolAtoms)

    secondMolSelection = oechem.OEAtomBondSet()
    secondMolSelection.AddAtoms(secondMolAtoms)
    
    query = oebioisostere.OEBroodQuery()
    du = queryOpts.GetDU()
    selectDU = queryOpts.GetSelectDU()
    
    if du is None and selectDU is None:
        retCode = oebioisostere.OECreateBroodQuery(query, firstMol, secondMol, firstMolSelection, secondMolSelection)
    elif du is None and selectDU is not None:
        passingProteinSelect = True
        retCode = oebioisostere.OECreateBroodQuery(query, firstMol, secondMol, firstMolSelection, secondMolSelection, selectDU, queryOpts.GetSelectProteinMask(), passingProteinSelect)
    elif selectDU is None:
        retCode = oebioisostere.OECreateBroodQuery(query, firstMol, secondMol, firstMolSelection, secondMolSelection, du, queryOpts.GetProteinMask())
    else:
        retCode = oebioisostere.OECreateBroodQuery(query, firstMol, secondMol, firstMolSelection, secondMolSelection, du, queryOpts.GetProteinMask(), selectDU, queryOpts.GetSelectProteinMask())
    
    if retCode != oebioisostere.OEBroodStatusCode_Success:
        oechem.OEThrow.Fatal("%s" % oebioisostere.OEGetBroodStatus(retCode))
    oebioisostere.OEWriteBroodQuery(ofs, query)

if __name__ == "__main__":
    import sys
    sys.exit(main(sys.argv))