Ejemplo n.º 1
0
    def createMolecule(self, mol, molTitle):
        '''
        Get a OE residue, return a OE molecule
        '''
        # Creating a new Res GraphMol
        newMol = oechem.OEGraphMol()
        newMol.SetTitle(molTitle)
        # Create every atom found in the OEHierResidue
        for atom in mol.GetAtoms():
            newMol.NewAtom(atom)

        #---------------------------------------------#
        # Recreate the molecule from atom coordinates #
        #---------------------------------------------#

        # Using OpenEye's charge model. Works on molecules with fully specified
        # hydrogen counts. Charge determined based on atom valence.
        oechem.OEDetermineConnectivity(newMol)
        oechem.OEFindRingAtomsAndBonds(newMol)
        oechem.OEPerceiveBondOrders(newMol)
        oechem.OEAssignImplicitHydrogens(newMol)
        oechem.OEAssignFormalCharges(newMol)

        # Other things to consider
        # Set atom radius
        #oechem.OEAssignBondiVdWRadii(newMol)
        #oechem.OEAssignPartialCharges(newMol,
        #                              oechem.OECharges_None,
        #                              False,
        #                              False)

        return newMol
Ejemplo n.º 2
0
def mol_from_json(symbols, connectivity, geometry, permute_xyz=False):
    """
    Generate OEMol from QCSchema molecule specs
    Parameters
    ----------
    inp_molecule: dict
        Must have symbols and connectivity and/or geometry
        Note: If geometry is given, the molecule will have a tag indicating that the goemetry came from QCSchema. This
        will ensure that the order of the atoms and configuration is not change for generation of mapped SMILES and
        isomeric SMILES.

    Returns
    -------
    molecule: OEMol

    """

    molecule = oechem.OEMol()
    for s in symbols:
        molecule.NewAtom(_symbols[s])

    # Add connectivity
    for bond in connectivity:
        a1 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[0]))
        a2 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[1]))
        bond_order = bond[-1]
        if not isinstance(bond_order, int) and not bond_order.is_integer():
            raise ValueError(
                "bond order must be a whole number. A bond order of 1.5 is not allowed"
            )
        molecule.NewBond(a1, a2, int(bond_order))

    # Add geometry
    if molecule.NumAtoms() != geometry.shape[0] / 3:
        raise ValueError(
            "Number of atoms in molecule does not match length of position array"
        )

    molecule.SetCoords(oechem.OEFloatArray(geometry))
    molecule.SetDimension(3)

    if not permute_xyz:
        # Add tag that the geometry is from JSON and shouldn't be changed.
        geom_tag = oechem.OEGetTag("json_geometry")
        molecule.SetData(geom_tag, True)
    oechem.OEDetermineConnectivity(molecule)
    oechem.OEFindRingAtomsAndBonds(molecule)
    # No need to perceive Bond Order because the information was added from the connectivity table. Apparently, this
    # function does many different perceptions under the hood and it can add implicit hydrogens to divalent N that should be negatively charged.
    #oechem.OEPerceiveBondOrders(molecule)
    # This seems to add hydrogens that are not in the json
    #oechem.OEAssignImplicitHydrogens(molecule)
    oechem.OEAssignFormalCharges(molecule)
    oechem.OEAssignAromaticFlags(molecule)
    oechem.OEPerceiveChiral(molecule)
    oechem.OE3DToAtomStereo(molecule)
    oechem.OE3DToBondStereo(molecule)

    return molecule
Ejemplo n.º 3
0
def mol_from_json(symbols, connectivity, geometry, permute_xyz=False):
    """
    Generate OEMol from QCSchema molecule specs
    Parameters
    ----------
    inp_molecule: dict
        Must have symbols and connectivity and/or geometry
        Note: If geometry is given, the molecule will have a tag indicating that the goemetry came from QCSchema. This
        will ensure that the order of the atoms and configuration is not change for generation of mapped SMILES and
        isomeric SMILES.

    Returns
    -------
    molecule: OEMol

    """

    molecule = oechem.OEMol()
    for s in symbols:
        molecule.NewAtom(_symbols[s])

    # Add connectivity
    for bond in connectivity:
        a1 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[0]))
        a2 = molecule.GetAtom(oechem.OEHasAtomIdx(bond[1]))
        molecule.NewBond(a1, a2, bond[-1])

    # Add geometry
    if molecule.NumAtoms() != geometry.shape[0] / 3:
        raise ValueError(
            "Number of atoms in molecule does not match length of position array"
        )

    molecule.SetCoords(oechem.OEFloatArray(geometry))
    molecule.SetDimension(3)

    if not permute_xyz:
        # Add tag that the geometry is from JSON and shouldn't be changed.
        geom_tag = oechem.OEGetTag("json_geometry")
        molecule.SetData(geom_tag, True)
    oechem.OEDetermineConnectivity(molecule)
    oechem.OEFindRingAtomsAndBonds(molecule)
    oechem.OEPerceiveBondOrders(molecule)
    # This seems to add hydrogens that are not in the json
    #oechem.OEAssignImplicitHydrogens(molecule)
    oechem.OEAssignFormalCharges(molecule)
    oechem.OEAssignAromaticFlags(molecule)
    oechem.OEPerceiveChiral(molecule)
    oechem.OE3DToAtomStereo(molecule)
    oechem.OE3DToBondStereo(molecule)

    return molecule
Ejemplo n.º 4
0
 def _process_mol(mol: oechem.OEMol, explicit_H: Optional[str] = None):
     if explicit_H == 'all':
         oechem.OEAddExplicitHydrogens(mol)
     elif explicit_H == 'polar':
         oechem.OESuppressHydrogens(mol, explicit_H)
     elif explicit_H is None:
         oechem.OESuppressHydrogens(mol)
     else:
         raise ValueError
     oechem.OEAssignAromaticFlags(mol)
     oechem.OEAssignHybridization(mol)
     oechem.OEAssignFormalCharges(mol)
     mol.Sweep()
Ejemplo n.º 5
0
def get_sf_elements(mol):
    sfObj = SymmetryFunction()
    oechem.OEAssignFormalCharges(mol)
    oechem.OEAssignHybridization(mol)
    rsf, asf = sfObj.CalculateSymmetryFunction(mol)
    tsf1 = sfObj.CalculateTorsionSymmetryFunction(mol, 1)
    tsf2 = sfObj.CalculateTorsionSymmetryFunction(mol, 2)
    tsf = []
    for elem1, elem2 in zip(tsf1, tsf2):
        tsf.append(elem1 + elem2)

    sf_elements = rsf
    sf_elements.extend(asf)
    sf_elements.extend(tsf)

    return sf_elements
Ejemplo n.º 6
0
def generate_molecule_from_smiles(smiles, idx=0):
    """
    Generate oemol with geometry from smiles
    """
    print("Molecule %d is %s" % (idx, smiles))
    mol = oechem.OEMol()
    mol.SetTitle("MOL%d" % idx)
    oechem.OESmilesToMol(mol, smiles)
    oechem.OEAddExplicitHydrogens(mol)
    oechem.OETriposAtomNames(mol)
    oechem.OETriposBondTypeNames(mol)
    oechem.OEAssignFormalCharges(mol)
    omega = oeomega.OEOmega()
    omega.SetMaxConfs(1)
    omega.SetStrictStereo(False)
    mol.SetTitle("MOL_%d" % idx)
    omega(mol)
    return mol
Ejemplo n.º 7
0
def _computeNetCharge(molecule):
    """
    Compute the net formal charge on the molecule.
    Formal charges are assigned by this function.

    Parameters
    ----------
    molecule : openeye.oechem.OEMol
        The molecule for which a net formal charge is to be computed

    Returns
    -------
    net_charge : float
        The net formal charge on the molecule

    """
    from openeye import oechem
    oechem.OEAssignFormalCharges(molecule)
    charges = [atom.GetFormalCharge() for atom in molecule.GetAtoms()]
    net_charge = np.array(charges).sum()
    return net_charge
Ejemplo n.º 8
0
def generateOEMolFromTopologyResidue(residue,
                                     geometry=False,
                                     tripos_atom_names=False):
    """
    Generate an OpenEye OEMol molecule from an OpenMM Topology Residue.

    Parameters
    ----------
    residue : simtk.openmm.app.topology.Residue
        The topology Residue from which an OEMol is to be created.
        An Exception will be thrown if this residue has external bonds.
    geometry : bool, optional, default=False
        If True, will generate a single configuration with OEOmega.
        Note that stereochemistry will be *random*.
    tripos_atom_names : bool, optional, default=False
        If True, will generate and assign Tripos atom names.

    Returns
    -------
    molecule : openeye.oechem.OEMol
        The OEMol molecule corresponding to the topology.
        Atom order will be preserved and bond orders assigned.

    The Antechamber `bondtype` program will be used to assign bond orders, and these
    will be converted back into OEMol bond type assignments.

    Note that there is no way to preserve stereochemistry since `Residue` does
    not note stereochemistry in any way.

    """
    # Raise an Exception if this residue has external bonds.
    if len(list(residue.external_bonds())) > 0:
        raise Exception(
            "Cannot generate an OEMol from residue '%s' because it has external bonds."
            % residue.name)

    from openeye import oechem
    # Create OEMol where all atoms have bond order 1.
    molecule = oechem.OEMol()
    molecule.SetTitle(residue.name)  # name molecule after first residue
    for atom in residue.atoms():
        oeatom = molecule.NewAtom(atom.element.atomic_number)
        oeatom.SetName(atom.name)
        oeatom.AddData("topology_index", atom.index)
    oeatoms = {oeatom.GetName(): oeatom for oeatom in molecule.GetAtoms()}
    for (atom1, atom2) in residue.bonds():
        order = 1
        molecule.NewBond(oeatoms[atom1.name], oeatoms[atom2.name], order)

    # Write out a mol2 file without altering molecule.
    import tempfile
    tmpdir = tempfile.mkdtemp()
    mol2_input_filename = os.path.join(tmpdir,
                                       'molecule-before-bond-perception.mol2')
    ac_output_filename = os.path.join(tmpdir,
                                      'molecule-after-bond-perception.ac')
    ofs = oechem.oemolostream(mol2_input_filename)
    m2h = True
    substruct = False
    oechem.OEWriteMol2File(ofs, molecule, m2h, substruct)
    ofs.close()
    # Run Antechamber bondtype
    import subprocess
    #command = 'bondtype -i %s -o %s -f mol2 -j full' % (mol2_input_filename, ac_output_filename)
    command = 'antechamber -i %s -fi mol2 -o %s -fo ac -j 2' % (
        mol2_input_filename, ac_output_filename)
    [status, output] = getstatusoutput(command)

    # Define mapping from GAFF bond orders to OpenEye bond orders.
    order_map = {1: 1, 2: 2, 3: 3, 7: 1, 8: 2, 9: 5, 10: 5}
    # Read bonds.
    infile = open(ac_output_filename)
    lines = infile.readlines()
    infile.close()
    antechamber_bond_types = list()
    for line in lines:
        elements = line.split()
        if elements[0] == 'BOND':
            antechamber_bond_types.append(int(elements[4]))
    oechem.OEClearAromaticFlags(molecule)
    for (bond, antechamber_bond_type) in zip(molecule.GetBonds(),
                                             antechamber_bond_types):
        #bond.SetOrder(order_map[antechamber_bond_type])
        bond.SetIntType(order_map[antechamber_bond_type])
    oechem.OEFindRingAtomsAndBonds(molecule)
    oechem.OEKekulize(molecule)
    oechem.OEAssignFormalCharges(molecule)
    oechem.OEAssignAromaticFlags(molecule, oechem.OEAroModelOpenEye)

    # Clean up.
    os.unlink(mol2_input_filename)
    os.unlink(ac_output_filename)
    os.rmdir(tmpdir)

    # Generate Tripos atom names if requested.
    if tripos_atom_names:
        oechem.OETriposAtomNames(molecule)

    # Assign geometry
    if geometry:
        from openeye import oeomega
        omega = oeomega.OEOmega()
        omega.SetMaxConfs(1)
        omega.SetIncludeInput(False)
        omega.SetStrictStereo(False)
        omega(molecule)

    return molecule
Ejemplo n.º 9
0
def main():
    opt = parser.parse_args()

    global which_gaff
    if opt.gaff:
        which_gaff = opt.gaff
    else:
        which_gaff = 1  # 2--> gaff2

    global lig_input_mol2
    if opt.lig:
        lig_input_mol2 = opt.lig
    else:
        lig_input_mol2 = 'lig_in.mol2'

    # ============== #
    # new protocol:
    # (1) amber bond typer --> ac file (2) openeye convert aromatic mol2 --> kekule form assignment with oechem.OEKekulize(mol)
    # ============== #

    command = '$AMBERHOME/bin/antechamber -i %s -fi mol2 -o lig.ac -fo ac -j 2 -dr n -pf y' % lig_input_mol2
    print(command)
    subprocess.call(command, shell=True)

    molecule = oechem.OEGraphMol()

    ifs = oechem.oemolistream(lig_input_mol2)
    flavor = oechem.OEIFlavor_Generic_Default | oechem.OEIFlavor_MOL2_Default | oechem.OEIFlavor_MOL2_Forcefield
    ifs.SetFlavor(oechem.OEFormat_MOL2, flavor)
    oechem.OEReadMol2File(ifs, molecule)
    print(molecule.GetTitle())

    # Define mapping from GAFF bond orders to OpenEye bond orders.
    order_map = {1: 1, 2: 2, 3: 3, 7: 1, 8: 2, 9: 5, 10: 5}
    # Read bonds.
    infile = open('lig.ac')
    lines = infile.readlines()
    infile.close()
    antechamber_bond_types = list()
    for line in lines:
        elements = line.split()
        if elements[0] == 'BOND':
            antechamber_bond_types.append(int(elements[4]))
    oechem.OEClearAromaticFlags(molecule)
    for (bond, antechamber_bond_type) in zip(molecule.GetBonds(),
                                             antechamber_bond_types):
        #bond.SetOrder(order_map[antechamber_bond_type])
        bond.SetIntType(order_map[antechamber_bond_type])
    oechem.OEFindRingAtomsAndBonds(molecule)
    oechem.OEKekulize(molecule)
    oechem.OEAssignFormalCharges(molecule)
    oechem.OEAssignAromaticFlags(molecule, oechem.OEAroModelOpenEye)
    """
    charges = [ atom.GetFormalCharge() for atom in molecule.GetAtoms() ]
    net_charge = np.array(charges).sum()
    print("Net Charge:", net_charge)
    """
    subprocess.call('grep CHARGE lig.ac', shell=True)
    with open('lig.ac', "r") as f:
        line = f.readline()
        #        if line.find("CHARGE") > -1 and len(line.split())> 2:
        #            net_charge = int( float( line.split()[1] ) )
        if line.find("CHARGE") > -1:
            net_charge = int(line[line.find("(") + 1:line.find(")")])
    print("Net Charge:", net_charge)

    # Write mol2 file for this molecule.
    outmol = oechem.OEMol(molecule)
    ofs = oechem.oemolostream()
    filename = 'lig_oe.mol2'
    ofs.open(filename)
    oechem.OEWriteMolecule(ofs, outmol)
    ofs.close()

    if which_gaff == 1:
        gaff = "gaff"
    elif which_gaff == 2:
        gaff = "gaff2"

    command = "$AMBERHOME/bin/antechamber -i lig_oe.mol2 -fi mol2 -o lig_bcc.mol2 -fo mol2 -c bcc -at %s -nc %i -j 5 -pf y -dr n" \
    % (gaff, net_charge)
    print(command)
    subprocess.call(command, shell=True)

    command = "$AMBERHOME/bin/parmchk2 -i lig_bcc.mol2 -f mol2 -s %d -o lig.frcmod" % (
        which_gaff)
    print(command)
    subprocess.call(command, shell=True)
Ejemplo n.º 10
0
def mk_conformers(options, molecule, maxconf=99, verbose=True):
    """
    Enumerate the list of conformers and associated properties for each protonation and tautomeric state.

    Parameters
    ----------
    options
    molecule : openeye.oechem
        The molecule read from the PDB whose protomer and tautomer states are to be enumerated.
    maxconf : int, optional, default=128
        Maximum number of protomers/tautomers to generate.

    Returns
    -------
    conformers : list of Conformer
        The list of protomers/tautomers generated.

    """
    conformers = list()

    formalChargeOptions = oequacpac.OEFormalChargeOptions(maxconf)
    tautomerOptions = oequacpac.OETautomerOptions(maxconf)
    # enumerate pka states
    index = 0
    for pkaState in oequacpac.OEEnumerateFormalCharges(molecule, formalChargeOptions):
        if (index > maxconf): break
        # enumerate tautomers of pka states
        for tautomer in oequacpac.OEEnumerateTautomers(pkaState, tautomerOptions):
            if (index > maxconf): break
            # Assign conformer name.
            name = options.ligand+'%02d' % index
            tautomer.SetTitle(name)
            # DEBUG: Write molecule before charging.
            ofs = oechem.oemolostream()
            ofs.open(name + '-before.mol2')
            outmol = oechem.OEMol(tautomer)
            oechem.OEWriteMolecule(ofs, outmol)
            ofs.close()
            # Compute formal charge.
            oechem.OEAssignFormalCharges(tautomer)
            formal_charge = 0.0
            for atom in tautomer.GetAtoms():
                formal_charge += atom.GetFormalCharge()
            if verbose: print "formal charge: %d" % formal_charge
            # Assign canonical AM1BCC charges.
            assign_canonical_am1bcc_charges(tautomer)
            # DEBUG: Write molecule after charging.
            ofs = oechem.oemolostream()
            outmol = oechem.OEMol(tautomer)
            ofs.open(name + '-after.mol2')
            oechem.OEWriteMolecule(ofs, outmol)
            ofs.close()
            # Create conformer.
            conformer = Conformer(name, formal_charge, tautomer)
            # Append to protomer/tautomer list.
            conformers.append(conformer)
            # Keep count of protomers/tautomers.
            index += 1
            # Show output if requested.
            if verbose:
                print "%12s %+5d %8d atoms" % (name, conformer.charge, conformer.natoms)

    if verbose: print "%d protomer/tautomer states were enumerated" % len(conformers)

    return conformers
Ejemplo n.º 11
0
def mk_conformers_epik(options, molecule, maxconf=99, verbose=True, pH=7):
    """
    Enumerate the list of conformers and associated properties for each protonation and tautomeric state using epik from the Schrodinger Suite.
    Parameters
    ----------
    options
    molecule : openeye.oechem
        The molecule read from the PDB whose protomer and tautomer states are to be enumerated.
    maxconf : int, optional, default=128
        Maximum number of protomers/tautomers to generate.
    pH : float, optional, default=7.0
        pH to use for conformer enumeration
    Returns
    -------
    conformers : list of Conformer
        The list of protomers/tautomers generated.
    """

    from schrodinger import structure # Requires Schrodinger Suite

    # Write mol2 file.
    if verbose: print "Writing input file as mol2..."
    outmol = oechem.OEMol(molecule)
    ofs = oechem.oemolostream()
    ofs.open('epik-input.mol2')
    oechem.OEWriteMolecule(ofs, outmol)
    ofs.close()
    # Use low level writer to get atom names correct.
    ofs = oechem.oemolostream()
    ofs.open('epik-input.mol2')
    for (dest_atom, src_atom) in zip(outmol.GetAtoms(), molecule.GetAtoms()):
        dest_atom.SetName(src_atom.GetName())
    oechem.OEWriteMol2File(ofs, outmol, True)
    ofs.close()

    # Write mol2 file.
    if verbose: print "Writing input file as sdf..."
    outmol = oechem.OEMol(molecule)
    ofs = oechem.oemolostream()
    ofs.open('epik-input.sdf')
    oechem.OEWriteMolecule(ofs, outmol)
    ofs.close()

    # Write pdb file.
    if verbose: print "Writing input file as pdb..."
    outmol = oechem.OEMol(molecule)
    ofs = oechem.oemolostream()
    ofs.open('epik-input.pdb')
    oechem.OEWriteMolecule(ofs, outmol)
    ofs.close()

    # Write input for epik.
    if verbose: print "Converting input file to Maestro format..."
    reader = structure.StructureReader("epik-input.mol2")
    writer = structure.StructureWriter("epik-input.mae")
    for st in reader:
        writer.append(st)
    reader.close()
    writer.close()

    # Run epik to enumerate protomers/tautomers and get associated state penalties.
    if verbose: print "Running Epik..."
    cmd = '%s/epik -imae epik-input.mae -omae epik-output.mae -pht 10.0 -ms 100 -nt -pKa_atom -ph %f -WAIT' % (os.environ['SCHRODINGER'], pH)
    output = commands.getoutput(cmd)
    if verbose: print output

    # Convert output from epik from .mae to .sdf.
    if verbose: print "Converting output file to SDF..."
    reader = structure.StructureReader("epik-output.mae")
    writer = structure.StructureWriter("epik-output.sdf")
    for st in reader:
        writer.append(st)
    reader.close()
    writer.close()

    # Also convert to .mol2.
    if verbose: print "Converting output file to MOL2..."
    reader = structure.StructureReader("epik-output.mae")
    writer = structure.StructureWriter("epik-output.mol2")
    for st in reader:
        writer.append(st)
    reader.close()
    writer.close()

    # Find minimum charge.
    ifs = oechem.oemolistream()
    ifs.open('epik-output.mol2')
    molecule = oechem.OEGraphMol()
    min_formal_charge = 1000
    while oechem.OEReadMolecule(ifs, molecule):
        # Check aromaticity.
        oechem.OEAssignAromaticFlags(molecule)

        # Assign formal charge
        oechem.OEAssignFormalCharges(molecule)
        formal_charge = 0
        for atom in molecule.GetAtoms():
            formal_charge += atom.GetFormalCharge()
        # Keep most negative formal charge
        min_formal_charge = min(min_formal_charge, formal_charge)

    ifs.close()
    if verbose: print "Minimum formal charge = %d" % min_formal_charge

    # Read conformers from SDF and mol2 (converted from Epik).
    if verbose: print "Reading conformers from SDF..."
    ifs_sdf = oechem.oemolistream()
    ifs_sdf.SetFormat(oechem.OEFormat_SDF)
    ifs_sdf.open('epik-output.sdf')
    sdf_molecule = oechem.OEGraphMol()

    ifs_mol2 = oechem.oemolistream()
    ifs_mol2.open('epik-output.mol2')
    mol2_molecule = oechem.OEGraphMol()

    conformer_index = 1
    conformers = list()
    while oechem.OEReadMolecule(ifs_sdf, sdf_molecule):
        if verbose: print "Conformer %d" % conformer_index

        # Read corresponding mol2 molecule.
        oechem.OEReadMolecule(ifs_mol2, mol2_molecule)
        oechem.OEAssignAromaticFlags(mol2_molecule) # check aromaticity

        # Make a copy of the mol2 molecule.
        molecule = oechem.OEMol(mol2_molecule)

        # Set name
        name = options.ligand+'%02d' % conformer_index
        molecule.SetTitle(name)

        # Assign formal charge
        oechem.OEAssignFormalCharges(molecule)
        formal_charge = 0.0
        for atom in molecule.GetAtoms():
            formal_charge += atom.GetFormalCharge()
        if verbose: print "formal charge: %d" % formal_charge

        # DEBUG: Write mol2 file before assigning charges.
        if verbose: print "Writing %s to mol2..." % name
        outmol = oechem.OEMol(molecule)
        ofs = oechem.oemolostream()
        ofs.open(name + '.mol2')
        oechem.OEWriteMolecule(ofs, outmol)
        ofs.close()

        # Assign canonical AM1BCC charges.
        try:
            if verbose: print "Assigning AM1-BCC charges..."
            #assign_canonical_am1bcc_charges(molecule)
            assign_simple_am1bcc_charges(molecule)
        except Exception as e:
            print str(e)
            continue

        # Get Epik data.
        epik_Ionization_Penalty = float(oechem.OEGetSDData(sdf_molecule, "r_epik_Ionization_Penalty"))
        epik_Ionization_Penalty_Charging = float(oechem.OEGetSDData(sdf_molecule, "r_epik_Ionization_Penalty_Charging"))
        epik_Ionization_Penalty_Neutral = float(oechem.OEGetSDData(sdf_molecule, "r_epik_Ionization_Penalty_Neutral"))
        epik_State_Penalty = float(oechem.OEGetSDData(sdf_molecule, "r_epik_State_Penalty"))
        epik_Tot_Q = int(oechem.OEGetSDData(sdf_molecule, "i_epik_Tot_Q"))

        # Compute number of protons.
        nprotons = epik_Tot_Q - min_formal_charge + 1

        # Compute effective pKa.
        import numpy as np
        kT = 298 * 6.022e23 * 1.381e-23 / 4184 # kcal/mol for 298 K
        pKa = options.pH - epik_State_Penalty / (nprotons * kT * np.log(10))
        print "effective pKa = %8.3f" % pKa

        # DEBUG
        print "%24s : pKa penalty %8.3f kcal/mol | tautomer penalty %8.3f kcal/mol | total state penalty %8.3f\n" % (name, epik_Ionization_Penalty, epik_State_Penalty - epik_Ionization_Penalty, epik_State_Penalty)

        # Create a conformer and append it to the list.
        conformer = Conformer(name, epik_Tot_Q, molecule, state_penalty=epik_State_Penalty)
        conformers.append(conformer)
        print epik_Tot_Q # DEBUG
        # Increment counter.
        conformer_index += 1

    ifs_sdf.close()
    ifs_mol2.close()

    if verbose: print "%d protomer/tautomer states were enumerated" % len(conformers)

    return conformers
Ejemplo n.º 12
0
def mk_single_conformer_epik(mol_name, molecule, verbose=True, pH=7):
    """
    Enumerate the list of conformers and associated properties for each protonation and
    tautomeric state using epik from the Schrodinger Suite, and save the conformer with
    the lowest penalty.

    Parameters
    ----------
    mol_name : string
        Molecule's name.
    molecule : openeye.oechem
        The molecule whose protomer and tautomer states are to be enumerated.
    pH : float, optional, default=7.0
        pH to use for conformer enumeration

    Returns
    -------
    molecule : openeye.oechem.OEMol
        The conformer with the lowest penalty.

    """

    # Write mol2 file.
    if verbose:
        print "Writing input file as mol2..."
    outmol = oechem.OEMol(molecule)
    ofs = oechem.oemolostream()
    ofs.open('epik-input.mol2')
    oechem.OEWriteMolecule(ofs, outmol)
    ofs.close()

    # Run Schrodinger's epik
    try:
        import run_epik
        run_epik.main(verbose, pH)
    except ImportError:
        import subprocess
        schrodinger_run = os.path.join(os.environ['SCHRODINGER'], 'run')
        run_epik_script = os.path.join(os.path.dirname(__file__), 'run_epik.py')
        cmd = schrodinger_run + ' ' + run_epik_script + ' {!r} {:f}'.format(verbose, pH)
        return_code = subprocess.call(cmd, shell=True)
        if return_code != 0:
            raise RuntimeError('{!r} failed, exit status: {:d}'.format(cmd, return_code))

    # Find minimum charge.
    ifs = oechem.oemolistream()
    ifs.open('epik-output.mol2')
    molecule = oechem.OEGraphMol()
    min_formal_charge = 1000
    while oechem.OEReadMolecule(ifs, molecule):
        # Check aromaticity.
        oechem.OEAssignAromaticFlags(molecule)

        # Assign formal charge
        oechem.OEAssignFormalCharges(molecule)
        formal_charge = 0
        for atom in molecule.GetAtoms():
            formal_charge += atom.GetFormalCharge()

        # Keep most negative formal charge
        min_formal_charge = min(min_formal_charge, formal_charge)

    ifs.close()
    if verbose:
        print "Minimum formal charge = %d" % min_formal_charge

    # Read conformer with lowest penalty from SDF (converted from Epik).
    if verbose:
        print "Reading conformers from SDF..."
    ifs_sdf = oechem.oemolistream()
    ifs_sdf.SetFormat(oechem.OEFormat_SDF)
    ifs_sdf.open('epik-output.sdf')
    sdf_molecule = oechem.OEGraphMol()
    oechem.OEReadMolecule(ifs_sdf, sdf_molecule)  # Read the molecule with lowest penalty
    ifs_sdf.close()

    # Get Epik data.
    epik_Ionization_Penalty = float(oechem.OEGetSDData(sdf_molecule, "r_epik_Ionization_Penalty"))
    epik_Ionization_Penalty_Charging = float(oechem.OEGetSDData(sdf_molecule, "r_epik_Ionization_Penalty_Charging"))
    epik_Ionization_Penalty_Neutral = float(oechem.OEGetSDData(sdf_molecule, "r_epik_Ionization_Penalty_Neutral"))
    epik_State_Penalty = float(oechem.OEGetSDData(sdf_molecule, "r_epik_State_Penalty"))
    epik_Tot_Q = int(oechem.OEGetSDData(sdf_molecule, "i_epik_Tot_Q"))

    # Read conformer with lowest penalty from MOL2 (converted from Epik).
    ifs_mol2 = oechem.oemolistream()
    ifs_mol2.open('epik-output.mol2')
    mol2_molecule = oechem.OEMol()
    oechem.OEReadMolecule(ifs_mol2, mol2_molecule)
    ifs_mol2.close()

    # Make a copy of the mol2 molecule.
    molecule = oechem.OEMol(mol2_molecule)
    oechem.OEAssignAromaticFlags(molecule)
    molecule.SetTitle(mol_name)

    # Assign formal charge
    oechem.OEAssignFormalCharges(molecule)
    formal_charge = 0.0
    for atom in molecule.GetAtoms():
        formal_charge += atom.GetFormalCharge()
    if verbose:
        print "formal charge: %d" % formal_charge

    # Assign canonical AM1BCC charges.
    if verbose:
        print "Assigning AM1-BCC charges..."
    assign_canonical_am1bcc_charges(molecule)

    # Save result in mol2 file
    if verbose:
        print "Writing %s to mol2..." % mol_name
    ofs = oechem.oemolostream()
    ofs.open(mol_name + '.mol2')
    oechem.OEWriteMolecule(ofs, molecule)
    ofs.close()

    # Compute number of protons.
    nprotons = epik_Tot_Q - min_formal_charge + 1

    # Compute effective pKa.
    import numpy as np
    kT = 298 * 6.022e23 * 1.381e-23 / 4184 # kcal/mol for 298 K
    pKa = pH - epik_State_Penalty / (nprotons * kT * np.log(10))
    print "effective pKa = %8.3f" % pKa

    # DEBUG
    print "%24s : pKa penalty %8.3f kcal/mol | tautomer penalty %8.3f kcal/mol | total state penalty %8.3f" % (mol_name, epik_Ionization_Penalty, epik_State_Penalty - epik_Ionization_Penalty, epik_State_Penalty)
    print epik_Tot_Q

    return molecule
Ejemplo n.º 13
0
def create_openeye_molecule(pdb, options, verbose=True):
    """
    Create OpenEye molecule from PDB representation.

    The molecule will have hydrogens added and be normalized, but the overall geometry will not be altered.

    Parameters
    ----------
    pdb : Pdb
       The PDB-extracted entries for the ligand.

    Returns
    -------
    molecule : openeye.oechem.OEMol
        Molecule representation.
    options : options struct
        Options structure.

    """

    # Create a molecule container.
    molecule = oechem.OEGraphMol()

    # Open a PDB file reader from the stored PDB string representation of HETATM and CONECT records.
    print pdb.pdb_extract
    ifs = oechem.oemolistream()
    ifs.openstring(pdb.pdb_extract)
    flavor = oechem.OEIFlavor_Generic_Default | oechem.OEIFlavor_PDB_Default | oechem.OEIFlavor_PDB_ALL
    ifs.SetFlavor(oechem.OEFormat_PDB, flavor)
    oechem.OEReadPDBFile(ifs, molecule)

    # Add explicit hydrogens.
    oechem.OEDetermineConnectivity(molecule)
    oechem.OEFindRingAtomsAndBonds(molecule)
    oechem.OEAssignAromaticFlags(molecule) # check aromaticity
    oechem.OEPerceiveBondOrders(molecule)

    # We must assign implicit hydrogens first so that the valence model will be correct.
    oechem.OEAssignImplicitHydrogens(molecule)
    oechem.OEAssignFormalCharges(molecule)

    # Now add explicit hydrogens.
    polarOnly = False
    set3D = True
    oechem.OEAddExplicitHydrogens(molecule, polarOnly, set3D)

    # TODO: Sequentially number hydrogen atoms.

    # Perceive stereochemostry.
    oechem.OEPerceiveChiral(molecule)

    # Set title.
    molecule.SetTitle(options.ligand)

    # Write out PDB form of this molecule.
    # TODO: Fix atom numbering.
    #if verbose: print "Writing input molecule as PDB..."
    #outmol = oechem.OEMol(molecule)
    #ofs = oechem.oemolostream()
    #flavor = oechem.OEOFlavor_Generic_Default | oechem.OEOFlavor_PDB_Default
    #ofs.SetFlavor(oechem.OEFormat_PDB, flavor)
    #ofs.open(options.ligand + '.pdb')
    #oechem.OEWriteMolecule(ofs, outmol)
    #ofs.close()

    # Write mol2 file for this molecule.
    if verbose: print "Writing input molecule as mol2..."
    outmol = oechem.OEMol(molecule)
    ofs = oechem.oemolostream()
    filename = options.ligand + '.mol2'
    ofs.open(filename)
    oechem.OEWriteMolecule(ofs, outmol)
    ofs.close()
    # Use low level writer to get atom names correct.
    ofs = oechem.oemolostream()
    ofs.open(filename)
    for (dest_atom, src_atom) in zip(outmol.GetAtoms(), molecule.GetAtoms()):
        dest_atom.SetName(src_atom.GetName())
    oechem.OEWriteMol2File(ofs, outmol, True)
    ofs.close()
    # Read and write in PDB format.
    if verbose: print "Converting mol2 to PDB..."
    ifs = oechem.oemolistream()
    ofs = oechem.oemolostream()
    if ifs.open(options.ligand + '.mol2'):
        if ofs.open(options.ligand + '.pdb'):
            for mol in ifs.GetOEGraphMols():
                oechem.OEWriteMolecule(ofs, mol)

    return molecule
# SaaS offerings (each a "Customer").
# Customer is hereby permitted to use, copy, and modify the Sample Code,
# subject to these terms. OpenEye 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 OpenEye 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 OpenEye be
# liable for any damages or liability in connection with the Sample Code
# or its use.

# @ <SNIPPET>
from openeye import oechem
import sys

ifs = oechem.oemolistream(sys.argv[1])
ofs = oechem.oemolostream(sys.argv[2])
mol = oechem.OEGraphMol()
oechem.OEReadPDBFile(ifs, mol)
# @ <SNIPPET-CONNECT-PERCEIVE>
oechem.OEDetermineConnectivity(mol)
oechem.OEFindRingAtomsAndBonds(mol)
oechem.OEPerceiveBondOrders(mol)
oechem.OEAssignImplicitHydrogens(mol)
oechem.OEAssignFormalCharges(mol)
# @ </SNIPPET-CONNECT-PERCEIVE>
oechem.OEWriteMolecule(ofs, mol)
# @ </SNIPPET>