Ejemplo n.º 1
0
def get_linear_angle(mol, ind):
    flag, catoms = is_linear_ligand(mol, ind)
    if flag:
        vec1 = np.array(mol.getAtomCoords(catoms[0])) - np.array(mol.getAtomCoords(ind))
        vec2 = np.array(mol.getAtomCoords(catoms[1])) - np.array(mol.getAtomCoords(ind))
        ang = vecangle(vec1, vec2)
    else:
        ang = 0
    return flag, ang
Ejemplo n.º 2
0
def getconnections(core, catom, Midx, BL, ABXang):
    Ocoords = core.getAtom(catom).coords()
    Mcoords = core.getAtom(Midx).coords()
    backbcoords = alignPtoaxis(Ocoords, Ocoords, vecdiff(Ocoords, Mcoords), BL)
    am = atom3D('C', backbcoords)
    connPts = []
    for iphi in range(1, 359, 10):
        for itheta in range(1, 179, 1):
            P = PointTranslateSph(Ocoords, backbcoords, [BL, iphi, itheta])
            am.setcoords(P)
            ang = 180-vecangle(vecdiff(Ocoords, Mcoords), vecdiff(P, Ocoords))
            if abs(ang - ABXang) < 1:
                connPts.append(P)
    return connPts
Ejemplo n.º 3
0
def is_linear_ligand(mol, ind):
    catoms = mol.getBondedAtomsSmart(ind)
    metal_ind = mol.findMetal()[0]
    flag = False
    if metal_ind in catoms and len(catoms) == 2:
        ind_next = find_the_other_ind(catoms[:], metal_ind)
        _catoms = mol.getBondedAtomsSmart(ind_next)
        if len(_catoms) == 1:
            flag = True
        elif len(_catoms) == 2:
            ind_next2 = find_the_other_ind(_catoms[:], ind)
            vec1 = np.array(mol.getAtomCoords(ind)) - np.array(mol.getAtomCoords(ind_next))
            vec2 = np.array(mol.getAtomCoords(ind_next2)) - np.array(mol.getAtomCoords(ind_next))
            ang = vecangle(vec1, vec2)
            if ang > 170:
                flag = True
    # print(flag, catoms)
    return flag, catoms
Ejemplo n.º 4
0
def GetBoundsMatrices(mol, natoms, catoms=[], shape=[], A=[]):
    """Generate distance bounds matrices. The basic idea is outlined in ref [1].
    We first apply 1-2 (bond length) and 1-3 (bond angle) constraints, read from the FF-optimized initial conformer.
    Next, to bias the search towards coordinating conformers, approximate connection atom distance constraints based 
    on topological distances are also included.

    Parameters
    ----------
        mol : mol3D
            mol3D class instance of molecule.
        natoms : int
            Number of atoms in the molecule.
        catoms : list, optional
            List of ligand connection atoms. Default is Empty.
        shape : dict
            Dict containing angles.
        A : list
            List of lists making a distance 2 connectivity matrix.
        
    Returns
    -------
        LB : np.array
            Lower bound matrix.
        UB : np.array
            Upper bound matrix.

    """
    LB = np.zeros((natoms, natoms))  # lower bound
    UB = np.zeros((natoms, natoms))  # upper bound, both symmetric
    # Set constraints for all atoms excluding the dummy metal atom
    for i in range(natoms - 1):
        for j in range(natoms - 1):
            # 1-2 constraints: UB = LB = BL
            if mol.OBMol.GetBond(i + 1, j + 1) is not None:
                UB[i][j] = distance(mol.getAtomCoords(i), mol.getAtomCoords(j))
                UB[j][i] = distance(mol.getAtomCoords(i), mol.getAtomCoords(j))
                LB[i][j] = distance(mol.getAtomCoords(i), mol.getAtomCoords(j))
                LB[j][i] = distance(mol.getAtomCoords(i), mol.getAtomCoords(j))
    for i in range(natoms - 1):
        for j in range(natoms - 1):
            for k in range(natoms - 1):
                # 1-3 constraints: UB = LB = BL
                if mol.OBMol.GetBond(
                        i + 1, j + 1) is not None and mol.OBMol.GetBond(
                            j + 1, k + 1) is not None and j != k and i != k:
                    AB = vecdiff(mol.getAtomCoords(j), mol.getAtomCoords(i))
                    BC = vecdiff(mol.getAtomCoords(k), mol.getAtomCoords(j))
                    UB[i][k] = CosRule(norm(AB), norm(BC),
                                       180 - vecangle(AB, BC))
                    UB[k][i] = CosRule(norm(AB), norm(BC),
                                       180 - vecangle(AB, BC))
                    LB[i][k] = CosRule(norm(AB), norm(BC),
                                       180 - vecangle(AB, BC))
                    LB[k][i] = CosRule(norm(AB), norm(BC),
                                       180 - vecangle(AB, BC))

    # Set constraints for atoms bonded to the dummy metal atom
    # Currently assumes all M-L bonds are 2 Angstroms
    dummy_idx = natoms - 1
    M_L_bond = 2
    for catom in catoms:
        # Set 1-2 constraints
        UB[catom][dummy_idx] = M_L_bond
        UB[dummy_idx][catom] = M_L_bond
        LB[catom][dummy_idx] = M_L_bond
        LB[dummy_idx][catom] = M_L_bond
    if len(catoms) > 1:
        # Set 1-3 contraints for ligating atoms
        for i in range(len(catoms[:-1])):
            for j in range(i + 1, len(catoms)):
                angle = shape[str(i) + '-' + str(j)]
                lig_distance = CosRule(M_L_bond, M_L_bond, angle)
                UB[catoms[i]][catoms[j]] = lig_distance
                UB[catoms[j]][catoms[i]] = lig_distance
                LB[catoms[i]][catoms[j]] = lig_distance
                LB[catoms[j]][catoms[i]] = lig_distance

    expanded_vdwrad = vdwrad.copy()
    expanded_vdwrad[
        'Fe'] = 1.5  # Default vdw radius for the dummy metal is 1.5
    for i in range(natoms):
        for j in range(i):
            # fill LBs with sums of vdW radii and UBs with arbitrary large cutoff
            if LB[i][j] == 0:
                LB[i][j] = expanded_vdwrad[mol.getAtom(
                    i).sym] + expanded_vdwrad[mol.getAtom(j).sym]
                LB[j][i] = expanded_vdwrad[mol.getAtom(
                    i).sym] + expanded_vdwrad[mol.getAtom(j).sym]
                UB[i][j] = 100
                UB[j][i] = 100
    return LB, UB
Ejemplo n.º 5
0
def oct_comp(file_in, angle_ref=oct_angle_ref, catoms_arr=None, debug=False):
    my_mol = create_mol_with_xyz(_file_in=file_in)
    num_coord_metal, catoms = get_num_coord_metal(file_in=file_in)
    # metal_ind = my_mol.findMetal()[0]
    metal_coord = my_mol.getAtomCoords(my_mol.findMetal()[0])
    catom_coord = []
    if not catoms_arr == None:
        catoms = catoms_arr
        num_coord_metal = len(catoms_arr)
    theta_arr, oct_dist = [], []
    for atom in catoms:
        coord = my_mol.getAtomCoords(atom)
        catom_coord.append(coord)
    th_input_arr = []
    for idx1, coord1 in enumerate(catom_coord):
        delr1 = (np.array(coord1) - np.array(metal_coord)).tolist()
        theta_tmp = []
        for idx2, coord2 in enumerate(catom_coord):
            if idx2 != idx1:
                delr2 = (np.array(coord2) - np.array(metal_coord)).tolist()
                theta = vecangle(delr1, delr2)
                theta_tmp.append(theta)
        th_input_arr.append([catoms[idx1], theta_tmp])
    th_output_arr, sum_del_angle, catoms_arr, max_del_sig_angle = loop_target_angle_arr(
        th_input_arr, angle_ref)
    if debug:
        print(('th:', th_output_arr))
        print(('sum_del:', sum_del_angle))
        print(('catoms_arr:', catoms_arr))
        print(
            ('catoms_type:', [my_mol.getAtom(x).symbol() for x in catoms_arr]))
    for idx, ele in enumerate(th_output_arr):
        theta_arr.append([catoms_arr[idx], sum_del_angle[idx], ele])
    # theta_arr.sort(key=sort_sec_ele)
    # theta_trunc_arr = theta_arr[0:6]
    theta_trunc_arr = theta_arr
    # print('truncated theta array:', theta_trunc_arr)
    theta_trunc_arr_T = list(map(list, list(zip(*theta_trunc_arr))))
    oct_catoms = theta_trunc_arr_T[0]
    oct_angle_devi = theta_trunc_arr_T[1]
    oct_angle_all = theta_trunc_arr_T[2]
    if debug:
        print(('Summation of deviation angle for catoms:', oct_angle_devi))
        print(('Angle for catoms:', oct_angle_all))
    for atom in oct_catoms:
        coord = catom_coord[catoms.index(atom)]
        dist = distance(coord, metal_coord)
        oct_dist.append(dist)
    oct_dist.sort()
    # print('!!!oct_dist:', oct_dist)
    try:  # For Oct
        dist_del_arr = np.array([
            oct_dist[3] - oct_dist[0], oct_dist[4] - oct_dist[1],
            oct_dist[5] - oct_dist[2]
        ])
        min_posi = np.argmin(dist_del_arr)
        if min_posi == 0:
            dist_eq, dist_ax = oct_dist[:4], oct_dist[4:]
        elif min_posi == 1:
            dist_eq, dist_ax = oct_dist[1:5], [oct_dist[0], oct_dist[5]]
        else:
            dist_eq, dist_ax = oct_dist[2:], oct_dist[:2]
    except IndexError:  # For one empty site
        if (oct_dist[3] - oct_dist[0]) > (oct_dist[4] - oct_dist[1]):
            dist_ax, dist_eq = oct_dist[:1], oct_dist[1:]  # ax dist is smaller
        else:
            dist_ax, dist_eq = oct_dist[4:], oct_dist[:4]  # eq dist is smaller
    dist_del_all = oct_dist[-1] - oct_dist[0]
    if debug:
        print(('dist:', dist_eq, dist_ax))
    dist_del_eq = max(dist_eq) - min(dist_eq)
    dist_del_ax = max(dist_ax) - min(dist_ax)
    dist_del_eq_ax = max(abs(max(dist_eq) - min(dist_ax)),
                         abs(max(dist_ax) - min(dist_eq)))
    oct_dist_del = [dist_del_eq, dist_del_ax, dist_del_eq_ax, dist_del_all]
    if debug:
        print(('distance difference for catoms to metal (eq, ax, eq_ax):',
               oct_dist_del))
    return oct_angle_devi, oct_dist_del, max_del_sig_angle, catoms_arr
Ejemplo n.º 6
0
def oct_comp(file_in, angle_ref=oct_angle_ref, catoms_arr=None,
             debug=False):
    my_mol = create_mol_with_xyz(_file_in=file_in)
    num_coord_metal, catoms = get_num_coord_metal(file_in=file_in)
    # metal_ind = my_mol.findMetal()[0]
    metal_coord = my_mol.getAtomCoords(my_mol.findMetal()[0])
    catom_coord = []
    if not catoms_arr == None:
        catoms = catoms_arr
        num_coord_metal = len(catoms_arr)
    theta_arr, oct_dist = [], []
    for atom in catoms:
        coord = my_mol.getAtomCoords(atom)
        catom_coord.append(coord)
    th_input_arr = []
    for idx1, coord1 in enumerate(catom_coord):
        delr1 = (np.array(coord1) - np.array(metal_coord)).tolist()
        theta_tmp = []
        for idx2, coord2 in enumerate(catom_coord):
            if idx2 != idx1:
                delr2 = (np.array(coord2) - np.array(metal_coord)).tolist()
                theta = vecangle(delr1, delr2)
                theta_tmp.append(theta)
        th_input_arr.append([catoms[idx1], theta_tmp])
    th_output_arr, sum_del_angle, catoms_arr, max_del_sig_angle = loop_target_angle_arr(th_input_arr, angle_ref)
    if debug:
        print('th:', th_output_arr)
        print('sum_del:', sum_del_angle)
        print('catoms_arr:', catoms_arr)
        print('catoms_type:', [my_mol.getAtom(x).symbol() for x in catoms_arr])
    for idx, ele in enumerate(th_output_arr):
        theta_arr.append([catoms_arr[idx], sum_del_angle[idx], ele])
    # theta_arr.sort(key=sort_sec_ele)
    # theta_trunc_arr = theta_arr[0:6]
    theta_trunc_arr = theta_arr
    # print('truncated theta array:', theta_trunc_arr)
    theta_trunc_arr_T = list(map(list, zip(*theta_trunc_arr)))
    oct_catoms = theta_trunc_arr_T[0]
    oct_angle_devi = theta_trunc_arr_T[1]
    oct_angle_all = theta_trunc_arr_T[2]
    if debug:
        print('Summation of deviation angle for catoms:', oct_angle_devi)
        print('Angle for catoms:', oct_angle_all)
    for atom in oct_catoms:
        coord = catom_coord[catoms.index(atom)]
        dist = distance(coord, metal_coord)
        oct_dist.append(dist)
    oct_dist.sort()
    # print('!!!oct_dist:', oct_dist)
    try:  ### For Oct
        dist_del_arr = np.array([oct_dist[3] - oct_dist[0], oct_dist[4] - oct_dist[1], oct_dist[5] - oct_dist[2]])
        min_posi = np.argmin(dist_del_arr)
        if min_posi == 0:
            dist_eq, dist_ax = oct_dist[:4], oct_dist[4:]
        elif min_posi == 1:
            dist_eq, dist_ax = oct_dist[1:5], [oct_dist[0], oct_dist[5]]
        else:
            dist_eq, dist_ax = oct_dist[2:], oct_dist[:2]
    except IndexError:  ## For one empty site
        if (oct_dist[3] - oct_dist[0]) > (oct_dist[4] - oct_dist[1]):
            dist_ax, dist_eq = oct_dist[:1], oct_dist[1:]  # ax dist is smaller
        else:
            dist_ax, dist_eq = oct_dist[4:], oct_dist[:4]  # eq dist is smaller
    dist_del_all = oct_dist[-1] - oct_dist[0]
    if debug:
        print('dist:', dist_eq, dist_ax)
    dist_del_eq = max(dist_eq) - min(dist_eq)
    dist_del_ax = max(dist_ax) - min(dist_ax)
    dist_del_eq_ax = max(abs(max(dist_eq) - min(dist_ax)), abs(max(dist_ax) - min(dist_eq)))
    oct_dist_del = [dist_del_eq, dist_del_ax, dist_del_eq_ax, dist_del_all]
    if debug:
        print('distance difference for catoms to metal (eq, ax, eq_ax):', oct_dist_del)
    return oct_angle_devi, oct_dist_del, max_del_sig_angle, catoms_arr
Ejemplo n.º 7
0
def decorate_ligand(args, ligand_to_decorate, decoration, decoration_index):
    # structgen depends on decoration_manager, and decoration_manager depends on structgen.ffopt
    # Thus, this import needs to be placed here to avoid a circular dependence
    from molSimplify.Scripts.structgen import ffopt
    # INPUT
    #   - args: placeholder for input arguments
    #   - ligand_to_decorate: mol3D ligand
    #   - decoration: list of smiles/decorations
    #   - decoration_index: list of ligand atoms to replace
    # OUTPUT
    #   - new_ligand: built ligand
    #   - complex3D: list of all mol3D ligands and core
    #   - emsg: error messages
    #if args.debug:
    #    print  'decorating ligand'
    lig = ligand_to_decorate
    ## reorder to ensure highest atom index
    ## removed first
    sort_order = [
        i[0] for i in sorted(enumerate(decoration_index), key=lambda x: x[1])
    ]
    sort_order = sort_order[::-1]  ## reverse

    decoration_index = [decoration_index[i] for i in sort_order]
    decoration = [decoration[i] for i in sort_order]
    if args.debug:
        print(('decoration_index  is  ' + str(decoration_index)))
    licores = getlicores()
    if not isinstance(lig, mol3D):
        lig, emsg = lig_load(lig, licores)
    else:
        lig.convert2OBMol()
        lig.charge = lig.OBMol.GetTotalCharge()
    lig.convert2mol3D()  # convert to mol3D

    ## create new ligand
    merged_ligand = mol3D()
    merged_ligand.copymol3D(lig)
    for i, dec in enumerate(decoration):
        print(('** decoration number ' + str(i) + ' attaching ' + dec +
               ' at site ' + str(decoration_index[i]) + '**\n'))
        dec, emsg = lig_load(dec, licores)
        # dec.OBMol.AddHydrogens()
        dec.convert2mol3D()  # convert to mol3D
        if args.debug:
            print(i)
            print(decoration_index)

            print((merged_ligand.getAtom(decoration_index[i]).symbol()))
            print((merged_ligand.getAtom(decoration_index[i]).coords()))
            merged_ligand.writexyz('basic.xyz')
        #dec.writexyz('dec' + str(i) + '.xyz')
        Hs = dec.getHsbyIndex(0)
        if len(Hs) > 0 and (not len(dec.cat)):
            dec.deleteatom(Hs[0])
            dec.charge = dec.charge - 1

        #dec.writexyz('dec_noH' + str(i) + '.xyz')
        if len(dec.cat) > 0:
            decind = dec.cat[0]
        else:
            decind = 0
        dec.alignmol(dec.getAtom(decind),
                     merged_ligand.getAtom(decoration_index[i]))
        r1 = dec.getAtom(decind).coords()
        r2 = dec.centermass()  # center of mass
        rrot = r1
        decb = mol3D()
        decb.copymol3D(dec)
        ####################################
        # center of mass of local environment (to avoid bad placement of bulky ligands)
        auxmol = mol3D()
        for at in dec.getBondedAtoms(decind):
            auxmol.addAtom(dec.getAtom(at))
        if auxmol.natoms > 0:
            r2 = auxmol.centermass()  # overwrite global with local centermass
            ####################################
            # rotate around axis and get both images
            theta, u = rotation_params(merged_ligand.centermass(), r1, r2)
            #print('u = ' + str(u) + ' theta  = ' + str(theta))
            dec = rotate_around_axis(dec, rrot, u, theta)
            if args.debug:
                dec.writexyz('dec_ARA' + str(i) + '.xyz')
            decb = rotate_around_axis(decb, rrot, u, theta - 180)
            if args.debug:
                decb.writexyz('dec_ARB' + str(i) + '.xyz')
            d1 = distance(dec.centermass(), merged_ligand.centermass())
            d2 = distance(decb.centermass(), merged_ligand.centermass())
            dec = dec if (d2 < d1) else decb  # pick best one
        #####################################
        # check for linear molecule
        auxm = mol3D()
        for at in dec.getBondedAtoms(decind):
            auxm.addAtom(dec.getAtom(at))
        if auxm.natoms > 1:
            r0 = dec.getAtom(decind).coords()
            r1 = auxm.getAtom(0).coords()
            r2 = auxm.getAtom(1).coords()
            if checkcolinear(r1, r0, r2):
                theta, urot = rotation_params(
                    r1,
                    merged_ligand.getAtom(decoration_index[i]).coords(), r2)
                theta = vecangle(
                    vecdiff(
                        r0,
                        merged_ligand.getAtom(decoration_index[i]).coords()),
                    urot)
                dec = rotate_around_axis(dec, r0, urot, theta)

        ## get the default distance between atoms in question
        connection_neighbours = merged_ligand.getAtom(
            merged_ligand.getBondedAtomsnotH(decoration_index[i])[0])
        new_atom = dec.getAtom(decind)
        target_distance = connection_neighbours.rad + new_atom.rad
        position_to_place = vecdiff(new_atom.coords(),
                                    connection_neighbours.coords())
        old_dist = norm(position_to_place)
        missing = (target_distance - old_dist) / 2
        dec.translate([missing * position_to_place[j] for j in [0, 1, 2]])

        r1 = dec.getAtom(decind).coords()
        u = vecdiff(r1, merged_ligand.getAtom(decoration_index[i]).coords())
        dtheta = 2
        optmax = -9999
        totiters = 0
        decb = mol3D()
        decb.copymol3D(dec)
        # check for minimum distance between atoms and center of mass distance
        while totiters < 180:
            #print('totiters '+ str(totiters))
            dec = rotate_around_axis(dec, r1, u, dtheta)
            d0 = dec.mindist(
                merged_ligand)  # try to maximize minimum atoms distance
            d0cm = dec.distance(
                merged_ligand)  # try to maximize center of mass distance
            iteropt = d0cm + d0  # optimization function
            if (iteropt > optmax):  # if better conformation, keep
                decb = mol3D()
                decb.copymol3D(dec)
                optmax = iteropt
                #temp = mol3D()
                #temp.copymol3D(merged_ligand)
                #temp.combine(decb)
                #temp.writexyz('opt_iter_'+str(totiters)+'.xyz')
                #print('new max! ' + str(iteropt) )
            totiters += 1
        dec = decb
        if args.debug:
            dec.writexyz('dec_aligned' + str(i) + '.xyz')
            print(('natoms before delete ' + str(merged_ligand.natoms)))
            print(('obmol before delete at  ' + str(decoration_index[i]) +
                   ' is ' + str(merged_ligand.OBMol.NumAtoms())))
        ## store connectivity for deleted H
        BO_mat = merged_ligand.populateBOMatrix()
        row_deleted = BO_mat[decoration_index[i]]
        bonds_to_add = []

        # find where to put the new bonds ->>> Issue here.
        for j, els in enumerate(row_deleted):
            if els > 0:
                # if there is a bond with an atom number
                # before the deleted atom, all is fine
                # else, we subtract one as the row will be be removed
                if j < decoration_index[i]:
                    bond_partner = j
                else:
                    bond_partner = j - 1
                if len(dec.cat) > 0:
                    bonds_to_add.append(
                        (bond_partner, (merged_ligand.natoms - 1) + dec.cat[0],
                         els))
                else:
                    bonds_to_add.append(
                        (bond_partner, merged_ligand.natoms - 1, els))

        ## perfrom delete
        merged_ligand.deleteatom(decoration_index[i])

        merged_ligand.convert2OBMol()
        if args.debug:
            merged_ligand.writexyz('merged del ' + str(i) + '.xyz')
        ## merge and bond
        merged_ligand.combine(dec, bond_to_add=bonds_to_add)
        merged_ligand.convert2OBMol()

        if args.debug:
            merged_ligand.writexyz('merged' + str(i) + '.xyz')
            merged_ligand.printxyz()
            print('************')

    merged_ligand.convert2OBMol()
    merged_ligand, emsg = ffopt('MMFF94', merged_ligand, [], 0, [], False, [],
                                100)
    BO_mat = merged_ligand.populateBOMatrix()
    if args.debug:
        merged_ligand.writexyz('merged_relaxed.xyz')
        print(BO_mat)
    return (merged_ligand)