# Filter out receptor atoms with atom names of UNK
    for atom in receptor.GetAtoms():
        if atom.GetName() == 'UNK':
            receptor.DeleteAtom(atom)

    # Write joined PDB with ligand and receptor
    output_filename = os.path.join(docking_basedir, f'{molecule.GetTitle()} - complex.pdb')
    if not os.path.exists(output_filename):
        with oechem.oemolostream(output_filename) as ofs:
            oechem.OEClearResidues(docked_molecule)

            #oechem.OEWriteMolecule(ofs, docked_molecule)

            oechem.OETriposAtomNames(docked_molecule)
            oechem.OEWritePDBFile(ofs, docked_molecule, oechem.OEOFlavor_PDB_Default | oechem.OEOFlavor_PDB_BONDS)

            set_serial(receptor, 'X', docked_molecule.NumAtoms()+1)
            #oechem.OEWritePDBFile(ofs, receptor, oechem.OEOFlavor_PDB_Default | oechem.OEOFlavor_PDB_BONDS)

            oechem.OEWriteMolecule(ofs, receptor)

    # Write PDB of just ligand
    output_filename = os.path.join(docking_basedir, f'{molecule.GetTitle()} - ligand.pdb')
    if not os.path.exists(output_filename):
        with oechem.oemolostream(output_filename) as ofs:
            oechem.OEClearResidues(docked_molecule)

            #oechem.OEWriteMolecule(ofs, docked_molecule)

            oechem.OETriposAtomNames(docked_molecule)
Exemple #2
0
def generate_constraint_opt_input(qc_molecule, dihedrals, maximum_rotation=30, interval=5, filename=None):
    """

    Parameters
    ----------
    qc_molecule
    dihedrals

    Returns
    -------
    QCFractal optimization jobs input

    """
    from openeye import oechem

    optimization_jobs = {}
    tagged_smiles = qc_molecule['identifiers']['canonical_isomeric_explicit_hydrogen_mapped_smiles']
    mol = oechem.OEMol()
    oechem.OESmilesToMol(mol, tagged_smiles)
    atom_map = get_atom_map(mol, tagged_smiles)

    coords = chemi.from_mapped_xyz_to_mol_idx_order(qc_molecule['geometry'], atom_map)

    # convert coord to Angstrom
    coords = coords * utils.BOHR_2_ANGSTROM
    conf = mol.GetConfs().next()
    conf.SetCoords(oechem.OEFloatArray(coords))

    # new molecule for setting dihedral angles
    mol_2 = oechem.OEMol(mol)
    conf_2 = mol_2.GetConfs().next()
    coords_2 = oechem.OEFloatArray(conf_2.GetMaxAtomIdx()*3)
    conf.GetCoords(coords_2)
    mol_2.DeleteConfs()

    interval = radians(interval)
    max_rot = radians(maximum_rotation)
    for dihedral in dihedrals:
        #j = 0
        dih_idx = dihedrals[dihedral]
        tor = []
        for i in dih_idx:
            a = mol.GetAtom(oechem.OEHasMapIdx(i+1))
            tor.append(a)
        dih_angle = oechem.OEGetTorsion(conf, tor[0], tor[1], tor[2], tor[3])
        for i, angle in enumerate(np.arange(dih_angle-max_rot, dih_angle+max_rot, interval)):
            newconf = mol.NewConf(coords_2)
            oechem.OESetTorsion(newconf, tor[0], tor[1], tor[2], tor[3], angle)
            #new_angle = oechem.OEGetTorsion(newconf, tor[0], tor[1], tor[2], tor[3])
            # if new_angle == dih_angle:
            #     j += 1
            #     if j > 1:
            #         # One equivalent angle should be generated.
            #         logger().warning("Openeye did not generate a new conformer for torsion and angle {} {}. Will not generate"
            #                      "qcfractal optimizaiton input".format(dih_idx, angle))
            #         break
            if filename:
                pdb = oechem.oemolostream("{}_{}.pdb".format(filename, i))
                oechem.OEWritePDBFile(pdb, newconf)
            symbols, geometry = chemi.to_mapped_geometry(newconf, atom_map)
            qc_molecule = copy.deepcopy(qc_molecule)
            qc_molecule['geometry'] = geometry
            qc_molecule['symbols'] = symbols
            degree = degrees(angle)
            optimization_jobs['{}_{}'.format(dih_idx, int(round(degree)))] = {
                'type': 'optimization_input',
                'initial_molecule': qc_molecule,
                'dihedral': dih_idx,
                'constraints': {
                    "set": [{
                        "type": "dihedral",
                        "indices": dih_idx,
                        "value": degree
                    }]
                }
            }
    return optimization_jobs
Exemple #3
0
def generate_torsions(inp_mol,
                      output_path,
                      interval,
                      base_name=None,
                      tar=True):
    """
    This function takes a 3D molecule (pdf, mol2 or sd file) and generates structures for a torsion drive on all torsions
    in the molecule. This function uses OpenEye
    Parameters
    ----------
    mol : OEMol
        molecule to generate 1D torsion scans
    output_path: str
        path to output file directory
    interval: int
        angle (in degrees) of interval for torsion drive
    base_name: str
        base name for file. Default is None. If default, use title in OEMol for base name
    tar: bool
        If true, will compress output

    """
    if not base_name:
        base_name = inp_mol.GetTitle()

    mid_tors = [[tor.a, tor.b, tor.c, tor.d]
                for tor in oechem.OEGetTorsions(inp_mol)]

    # This smarts should match terminal torsions such as -CH3, -NH2, -NH3+, -OH, and -SH
    smarts = '[*]~[*]-[X2H1,X3H2,X4H3]-[#1]'
    qmol = oechem.OEQMol()
    if not oechem.OEParseSmarts(qmol, smarts):
        warnings.warn('OEParseSmarts failed')
    ss = oechem.OESubSearch(qmol)
    mol = oechem.OEMol(inp_mol)
    h_tors = []
    oechem.OEPrepareSearch(mol, ss)
    unique = True
    for match in ss.Match(mol, unique):
        tor = []
        for ma in match.GetAtoms():
            tor.append(ma.target)
        h_tors.append(tor)

    # Combine middle and terminal torsions
    all_tors = mid_tors + h_tors
    # Sort all_tors so that it's grouped by central bond
    central_bonds = np.zeros((len(all_tors), 3), dtype=int)
    for i, tor in enumerate(all_tors):
        central_bonds[i][0] = i
        central_bonds[i][1] = tor[1].GetIdx()
        central_bonds[i][2] = tor[2].GetIdx()

    grouped = central_bonds[central_bonds[:, 2].argsort()]
    sorted_tors = [all_tors[i] for i in grouped[:, 0]]

    # Keep only one torsion per rotatable bond
    tors = []
    best_tor = [
        sorted_tors[0][0], sorted_tors[0][0], sorted_tors[0][0],
        sorted_tors[0][0]
    ]
    first_pass = True
    for tor in sorted_tors:
        logger().info("Idxs: {} {} {} {}".format(tor[0].GetIdx(),
                                                 tor[1].GetIdx(),
                                                 tor[2].GetIdx(),
                                                 tor[3].GetIdx()))
        logger().info("Atom Numbers: {} {} {} {}".format(
            tor[0].GetAtomicNum(), tor[1].GetAtomicNum(),
            tor[2].GetAtomicNum(), tor[3].GetAtomicNum()))
        if tor[1].GetIdx() != best_tor[1].GetIdx() or tor[2].GetIdx(
        ) != best_tor[2].GetIdx():
            new_tor = True
            if not first_pass:
                logger().info("Adding to list: {} {} {} {}".format(
                    best_tor[0].GetIdx(), best_tor[1].GetIdx(),
                    best_tor[2].GetIdx(), best_tor[3].GetIdx()))
                tors.append(best_tor)
            first_pass = False
            best_tor = tor
            best_tor_order = tor[0].GetAtomicNum() + tor[3].GetAtomicNum()
            logger().info(
                "new_tor with central bond across atoms: {} {}".format(
                    tor[1].GetIdx(), tor[2].GetIdx()))
        else:
            logger().info("Not a new_tor but now with end atoms: {} {}".format(
                tor[0].GetIdx(), tor[3].GetIdx()))
            tor_order = tor[0].GetAtomicNum() + tor[3].GetAtomicNum()
            if tor_order > best_tor_order:
                best_tor = tor
                best_tor_order = tor_order
    logger().info("Adding to list: {} {} {} {}".format(best_tor[0].GetIdx(),
                                                       best_tor[1].GetIdx(),
                                                       best_tor[2].GetIdx(),
                                                       best_tor[3].GetIdx()))
    tors.append(best_tor)

    logger().info("List of torsion to drive:")
    for tor in tors:
        logger().info("Idx: {} {} {} {}".format(tor[0].GetIdx(),
                                                tor[1].GetIdx(),
                                                tor[2].GetIdx(),
                                                tor[3].GetIdx()))
        logger().info("Atom numbers: {} {} {} {}".format(
            tor[0].GetAtomicNum(), tor[1].GetAtomicNum(),
            tor[2].GetAtomicNum(), tor[3].GetAtomicNum()))

    conf = mol.GetConfs().next()
    coords = oechem.OEFloatArray(conf.GetMaxAtomIdx() * 3)
    conf.GetCoords(coords)
    # Check if coordinates are not zero
    values = np.asarray(
        [coords.__getitem__(i) == 0 for i in range(coords.__len__())])
    if values.all():
        # Generate new coordinates.
        mol2 = generate_conformers(mol, max_confs=1)
        conf = mol2.GetConfs().next()
        coords = oechem.OEFloatArray(conf.GetMaxAtomIdx() * 3)
        conf.GetCoords(coords)
        mol2.DeleteConfs()
    mol.DeleteConfs()

    for tor in tors:
        tor_name = str((tor[0].GetIdx()) + 1) + '_' + str(
            (tor[1].GetIdx()) + 1) + '_' + str(
                (tor[2].GetIdx()) + 1) + '_' + str((tor[3].GetIdx()) + 1)
        folder = os.path.join(output_path, tor_name)
        try:
            os.makedirs(folder)
        except FileExistsError:
            logger().info("Overwriting existing directory {}".format(tor_name))
        for angle in range(0, 360, interval):
            angle_folder = os.path.join(folder, str(angle))
            try:
                os.mkdir(angle_folder)
            except FileExistsError:
                logger().info(
                    "Overwriting existing directory {}".format(tor_name))
            newconf = mol.NewConf(coords)
            oechem.OESetTorsion(newconf, tor[0], tor[1], tor[2], tor[3],
                                radians(angle))
            pdb = oechem.oemolostream('{}/{}_{}_{}.pdb'.format(
                angle_folder, base_name, tor_name, angle))
            oechem.OEWritePDBFile(pdb, newconf)
    if tar:
        # tar archive output
        out = tarfile.open('{}.tar.gz'.format(output_path), mode='w:gz')
        os.chdir(output_path)
        os.chdir('../')
        out.add('{}'.format(base_name))
        out.close()