Exemple #1
0
def MakeAlpha(ifs, ofs):
    phival = math.pi / -3.0
    psival = math.pi / -3.0
    chival = math.pi
    nrphis = 0
    nrpsis = 0
    nrchis = 0
    mol = oechem.OEGraphMol()
    while oechem.OEReadMolecule(ifs, mol):
        if not oechem.OEHasResidues(mol):
            oechem.OEPerceiveResidues(mol, oechem.OEPreserveResInfo_All)
        # remove cross-links
        for bond in mol.GetBonds():
            if bond.GetBgn().GetAtomicNum() == oechem.OEElemNo_S and \
               bond.GetEnd().GetAtomicNum() == oechem.OEElemNo_S:
                mol.DeleteBond(bond)

        oechem.OEFindRingAtomsAndBonds(mol)
        hv = oechem.OEHierView(mol)
        for res in hv.GetResidues():
            if not oechem.OEIsStandardProteinResidue(res):
                continue

            # set psi and phi angles
            if not oechem.OESetTorsion(res, oechem.OEProtTorType_Phi, phival):
                oeres = res.GetOEResidue()
                print("Unable to set phi for %s %d" %
                      (oeres.GetName(), oeres.GetResidueNumber()))
            else:
                nrphis += 1

            if not oechem.OESetTorsion(res, oechem.OEProtTorType_Psi, psival):
                oeres = res.GetOEResidue()
                print("Unable to set psi for %s %d" %
                      (oeres.GetName(), oeres.GetResidueNumber()))
            else:
                nrpsis += 1

            # set chis
            if oechem.OEGetResidueIndex(
                    res.GetOEResidue().GetName()) == oechem.OEResidueIndex_PRO:
                continue  # It does not make sense to set Proline chi angles to 180

            for chi in oechem.OEGetChis(res):
                if not oechem.OESetTorsion(res, chi, chival):
                    oeres = res.GetOEResidue()
                    print("Unable to set chi %s for %s %d" %
                          (oechem.OEGetProteinTorsionName(chi),
                           oeres.GetName(), oeres.GetResidueNumber()))
                else:
                    nrchis += 1
        oechem.OEWriteMolecule(ofs, mol)

    print(nrphis, " phi  torsion angle set to ", phival * oechem.cvar.Rad2Deg)
    print(nrpsis, " psi  torsion angle set to ", psival * oechem.cvar.Rad2Deg)
    print(nrchis, " chis torsion angle set to ", chival * oechem.cvar.Rad2Deg)
Exemple #2
0
def gen_torsional_confs(mol, dih, num_points, include_input=False):
    """Drives the primary torsion in the molecule and generates labeled 
    torsional conformers.

    Inputs:
        mol - OEMol 
                must have a 'CONFORMER_LABEL' in the sd_data
    """
    angle_list = [2*i*oechem.Pi/num_points for i in range(num_points)]

    dih_atoms = [x for x in dih.GetAtoms()]

    # Create new output OEMol
    torsion_conformers = oechem.OEMol(mol)

    if not include_input:
        torsion_conformers.DeleteConfs()

    for conf_id, conf in enumerate(mol.GetConfs()):
        conf_name = get_sd_data(conf, 'CONFORMER_LABEL')
        for angle_idx, angle in enumerate(angle_list):
            angle_deg = int(round(angle*oechem.Rad2Deg))
            oechem.OESetTorsion(conf, 
                    dih_atoms[0], dih_atoms[1], dih_atoms[2], dih_atoms[3],
                    angle)

            new_conf = torsion_conformers.NewConf(conf)
            new_conf.SetDimension(3)
            new_conf_name = conf_name + '_{:02d}'.format(angle_idx)
            oechem.OESetSDData(new_conf, 'CONFORMER_LABEL', new_conf_name)
            oechem.OESetSDData(new_conf, 'TORSION_ANGLE', "{:.0f}".format(angle_deg))
            new_conf.SetDoubleData('TORSION_ANGLE', angle_deg)
            new_conf.SetTitle('{}: Angle {:.0f}'.format(conf_name, angle_deg))

    return torsion_conformers
Exemple #3
0
def generate_grid_conformers(molecule,
                             dihedrals,
                             intervals,
                             max_rotation=360,
                             copy_mol=True):
    """
    Generate conformers using torsion angle grids.

    Parameters
    ----------
    molecule: OEMol
    dihedrals: list of
    intervals

    Returns
    -------

    """
    # molecule must be mapped
    if copy_mol:
        molecule = copy.deepcopy(molecule)
    if cmiles.utils.has_atom_map(molecule):
        remove_map(molecule)
    else:
        raise ValueError("Molecule must have map indices")

    # Check length of dihedrals match length of intervals

    conf_mol = generate_conformers(molecule, max_confs=1)
    conf = conf_mol.GetConfs().next()
    coords = oechem.OEFloatArray(conf.GetMaxAtomIdx() * 3)
    conf.GetCoords(coords)

    torsions = [[conf_mol.GetAtom(oechem.OEHasMapIdx(i + 1)) for i in dih]
                for dih in dihedrals]

    for i, tor in enumerate(torsions):
        copy_conf_mol = copy.deepcopy(conf_mol)
        conf_mol.DeleteConfs()
        for conf in copy_conf_mol.GetConfs():
            coords = oechem.OEFloatArray(conf.GetMaxAtomIdx() * 3)
            conf.GetCoords(coords)
            for angle in range(5, max_rotation + 5, intervals[i]):
                newconf = conf_mol.NewConf(coords)
                oechem.OESetTorsion(newconf, tor[0], tor[1], tor[2], tor[3],
                                    radians(angle))

    restore_map(conf_mol)
    return conf_mol
Exemple #4
0
def get_best_conf(mol, dih, num_points):
    """Drive the primary torsion in the molecule and select the lowest 
       energy conformer to represent each dihedral angle
    """
    delta = 360.0 / num_points
    angle_list = [2 * i * oechem.Pi / num_points for i in range(num_points)]

    dih_atoms = [x for x in dih.GetAtoms()]

    # Create new output OEMol
    title = mol.GetTitle()
    tor_mol = oechem.OEMol()

    opts = oeszybki.OETorsionScanOptions()
    opts.SetDelta(delta)
    opts.SetForceFieldType(oeszybki.OEForceFieldType_MMFF94)
    opts.SetSolvationType(oeszybki.OESolventModel_NoSolv)
    tmp_angle = 0.0
    tor = oechem.OETorsion(dih_atoms[0], dih_atoms[1], dih_atoms[2],
                           dih_atoms[3], tmp_angle)

    oeszybki.OETorsionScan(tor_mol, mol, tor, opts)
    oechem.OECopySDData(tor_mol, mol)

    # if 0 and 360 sampled because of rounding
    if tor_mol.NumConfs() > num_points:
        for conf in tor_mol.GetConfs():
            continue
        tor_mol.DeleteConf(conf)

    for angle, conf in zip(angle_list, tor_mol.GetConfs()):
        angle_deg = int(round(angle * oechem.Rad2Deg))
        tor_mol.SetActive(conf)
        oechem.OESetTorsion(conf, dih_atoms[0], dih_atoms[1], dih_atoms[2],
                            dih_atoms[3], angle)

        conf_name = title + '_{:02d}'.format(conf.GetIdx())
        oechem.OESetSDData(conf, 'CONFORMER_LABEL', conf_name)
        oechem.OESetSDData(conf, 'TORSION_ANGLE', "{:.0f}".format(angle_deg))
        conf.SetDoubleData('TORSION_ANGLE', angle_deg)
        conf.SetTitle('{}: Angle {:.0f}'.format(conf_name, angle_deg))

    return tor_mol
Exemple #5
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 #6
0
    def process(self, mol, port):
        """
            The input to this cube will be an OEMol with one or more conformers
            with "CONFORMER_LABEL" SD Data of the form 'XY-1234567_1_2_3_4_00_00'
        """
        num_confs = mol.NumConfs()

        last_conf = mol.GetActive()
        last_conf_name = oechem.OEGetSDData(last_conf, "CONFORMER_LABEL")
        self.log.info(
            "Processing conformer {} on {} at {:%Y-%m-%d %H:%M:%S}".format(
                last_conf_name, os.environ["HOSTNAME"],
                datetime.datetime.now()))

        if num_confs == self.args.num_points:
            self.success.emit(mol)
            self.log.info(
                "Completed scan for {} on {} at {:%Y-%m-%d %H:%M:%S}".format(
                    mol.GetTitle(), os.environ["HOSTNAME"],
                    datetime.datetime.now()))
            return

        if num_confs == 1 and not mol.HasData(self.conf_selection_tag):
            self.log.info(
                "Conformer {} is a fresh starting conformer on {} at {:%Y-%m-%d %H:%M:%S}"
                .format(mol.GetTitle(), os.environ["HOSTNAME"],
                        datetime.datetime.now()))
            mol.SetIntData(self.conf_selection_tag, last_conf.GetIdx())
            last_conf.SetDoubleData("TORSION_ANGLE", 0.0)
            oechem.OESetSDData(last_conf, "TORSION_ANGLE", "0.0")
            self.log.info(
                "Sending conformer {} to energy calculation from {} at {:%Y-%m-%d %H:%M:%S}"
                .format(last_conf_name, os.environ["HOSTNAME"],
                        datetime.datetime.now()))
            self.to_energy_calc.emit(mol)
            return

        try:
            torsion_tag = "TORSION_ATOMS_FRAGMENT"
            torsion_atoms_in_fragment = get_sd_data(mol, torsion_tag).split()
            dihedral_atom_indices = [
                int(x) - 1 for x in torsion_atoms_in_fragment
            ]

            dih, _ = get_dihedral(mol, dihedral_atom_indices)
            dih_atoms = [x for x in dih.GetAtoms()]

            # if the last energy calculation failed
            if not oechem.OEHasSDData(last_conf, "PSI4_ENERGY"):
                self.log.info(
                    "Conformer {} found to have NO ENERGY on {} at {:%Y-%m-%d %H:%M:%S}"
                    .format(last_conf_name, os.environ["HOSTNAME"],
                            datetime.datetime.now()))
                mol.PopActive()
                last_conf = mol.GetActive()

            new_conf = mol.NewConf(last_conf)
            mol.PushActive(new_conf)
            conf_no = num_confs
            conformer_label = last_conf_name[:-3] + "_{:02d}".format(conf_no)
            oechem.OESetSDData(new_conf, "CONFORMER_LABEL", conformer_label)

            angle = num_confs * 2 * oechem.Pi / self.args.num_points
            angle_deg = oechem.Rad2Deg * angle
            new_conf.SetDoubleData("TORSION_ANGLE", angle_deg)
            oechem.OESetSDData(new_conf, "TORSION_ANGLE",
                               "{:.1f}".format(angle_deg))

            if not oechem.OESetTorsion(new_conf, dih_atoms[0], dih_atoms[1],
                                       dih_atoms[2], dih_atoms[3], angle):
                self.log.error(
                    "Could not rotate conformer {} by {:.1f} on {} at {:%Y-%m-%d %H:%M:%S}"
                    .format(
                        last_conf_name,
                        angle_deg,
                        os.environ["HOSTNAME"],
                        datetime.datetime.now(),
                    ))

            mol.SetIntData(self.conf_selection_tag, new_conf.GetIdx())
            self.log.info(
                "Sending conformer {} to energy calculation from {} at {:%Y-%m-%d %H:%M:%S}"
                .format(conformer_label, os.environ["HOSTNAME"],
                        datetime.datetime.now()))
            self.to_energy_calc.emit(mol)

        except Exception as e:
            self.log.error(
                "COuld not drive torsion in  conformer {} on {} at {:%Y-%m-%d %H:%M:%S}: {}"
                .format(last_conf_name, os.environ["HOSTNAME"],
                        datetime.datetime.now(), e))
            self.failure.emit(mol)
Exemple #7
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()