Exemple #1
0
def calculate_SIMPLE(residue, ligand_name, ligand_atoms, centroid_ligand):
    """Calculates SIMPLE interaction between residue - ligand pair:
            1. Check RNA residue - ligand distance
            2. Compare the distance to CUTOFF:
                - write down 1 if the distance <= CUTOFF
                - write down 0 if the distance > CUTOFF

        :param residue: residue as OpenBabel object
        :param ligand_name: ligand_name^pose_number
        :param ligand_atoms: coordinates of all ligand's atoms
        :type residue: openbabel.OBResidue
        :type ligand_name: str
        :type ligand_atoms: list
        :return: [ligand_name^pose_number, residue_number:residue_chain, binary info about interaction (0/1)]
        :rtype: list
    """

    # List of sublists of all atoms' coords of the residue
    residue_atoms = []

    for atom in openbabel.OBResidueAtomIter(residue):
        if atom.GetAtomicNum() != 1:
            residue_atoms.append(
                np.array([atom.GetX(), atom.GetY(),
                          atom.GetZ()]))

    result = [
        ligand_name,
        str(residue.GetNum()) + ':' + str(residue.GetChain()), 0
    ]

    if measure_distance(
            centroid(residue_atoms), centroid_ligand
    ) > config.RES_LIGAND_MIN_DIST:  # RNA residue centroid and ligand centroid are futher than declared threshold, no chance for any contact
        return result

    # Flag to iterate over residue's atoms as long as we do not find an atom within CUTOFF distance from ligand
    flag = True

    for rna_atom in residue_atoms:
        if flag:
            for ligand_atom in ligand_atoms:
                if check_distance(ligand_atom, rna_atom,
                                  config.CUT_OFF_SIMPLE):
                    result[-1] = 1  # Condition met; write down 1
                    flag = False
                    break
        else:
            break

    return result
Exemple #2
0
def calculate_PBS(residue, ligand_name, ligand_atoms, centroid_ligand):
    """Calculates PBS interaction between residue - ligand pair:
            1. Divide RNA residue into 3 groups Phosphate/Base/Sugar (P/B/S)
            2. Check each group - ligand distance
            3. Compare the distance to CUTOFF:
                - write down 1 if the distance <= CUTOFF
                - write down 0 if the distance > CUTOFF

        :param residue: residue as OpenBabel object
        :param ligand_name: ligand_name^pose_number
        :param ligand_atoms: coordinates of all ligand's atoms
        :type residue: openbabel.OBResidue
        :type ligand_name: str
        :type ligand_atoms: list
        :return: [ligand_name^pose_number, residue_number:residue_chain, binary info about interaction in P group (0/1), binary info about interaction in B group (0/1), binary info about interaction in S group (0/1)]
        :rtype: list
    """

    # List of residue's atoms as OBAtoms objects
    residue_atoms = []
    residue_atoms_coords = []

    for atom in openbabel.OBResidueAtomIter(residue):
        if atom.GetAtomicNum() != 1:
            residue_atoms.append(atom)
            residue_atoms_coords.append(
                np.array([atom.GetX(), atom.GetY(),
                          atom.GetZ()]))

    result = [
        ligand_name,
        str(residue.GetNum()) + ':' + str(residue.GetChain()), 0, 0, 0
    ]

    if measure_distance(
            centroid(residue_atoms_coords), centroid_ligand
    ) > config.RES_LIGAND_MIN_DIST:  # RNA residue centroid and ligand centroid are futher than declared threshold, no chance for any contact
        return result

    # Flag to iterate over residue's atoms as long as we do not find an atom of the defined P/B/S group within CUTOFF distance from ligand
    flags = [True, True, True]

    for rna_atom in residue_atoms:
        # Flag to check if we deal with atom that does not belong to any of the defined P/B/S groups
        atom_group_type = False
        rna_atom_name = residue.GetAtomID(rna_atom).strip()
        rna_atom_coords = np.array(
            [rna_atom.GetX(),
             rna_atom.GetY(),
             rna_atom.GetZ()])

        for g in range(len(config.GROUPS)):
            # If atom present in the group
            if rna_atom_name in config.GROUPS[g]:
                atom_group_type = True  # If atom belongs to one of the 3 groups
                if flags[g]:
                    for ligand_atom in ligand_atoms:
                        if check_distance(ligand_atom, rna_atom_coords,
                                          config.CUT_OFF_SIMPLE):
                            result[g - 3] = 1  # Condition met; write down 1
                            flags[g] = False
                            break

        if not atom_group_type:
            raise Exception('Unknown atom type %s' %
                            rna_atom_name)  # MAYBE NEEDS TO BE CHANGED

    return result
Exemple #3
0
def calculate_PI_INTERACTIONS(RNA_rings, RNA_all_atoms, all_ligands_CA_dict,
                              filename_ligand, extension_ligand, precision):
    """Calculates Pi-cation, Pi-anion & Pi-stacking interactions between all residues' aromatic rings - all ligands' pairs.\n
        .. note::
            Important note: each ring of purines is considered separately.\n
        Pi-cation & Pi-anion Geometric Rules:
            - Cation/anion - aromatic ring's center distance < 6.0 A
            - Angle between aromatic ring's planar and cation/anion ~ 90 +/- 30\n
        Three types of Pi-stacking interactions:
            - Sandwich
            - Parallel Displaced
            - T-shaped\n
        Pi-stacking Geometric Rules:
            - All types' common rules:
                - Aromatic ring center - aromatic ring center distance < 5.5 A
                - Aromatic rings' offset < 2.0 A\n
            - For sandwich & parallel displaced types:
                - Angle between aromatic rings' planars < 30\n
            - For T-shaped type:
                - Angle between aromatic rings' planars ~ 90 +/- 30\n\n

        :param RNA_rings: list of all RNA aromatic rings found by OpenBabel
        :param RNA_all_atoms: list of all RNA atoms
        :param all_ligands_CA_dict: dictionary containing ligand's cations & anions {'prefix^pose':[[list of cations coords],[list of anions coords]]}
        :param filename_ligand: path to ligands input file
        :param extension_ligand: extension of ligands input file
        :param precision: fingerprint type
        :type RNA_rings: list
        :type RNA_all_atoms: list
        :type all_ligands_CA_dict: dict
        :type filename_ligand: str
        :type extension_ligand: str
        :type precision: str
        :return: calculated 3 Pi-interaction for RNA - all ligands
        :rtype: list
       """

    ######################################################
    #  Create dictionary of all ligands' aromatic rings  #
    ######################################################

    mols = list(pybel.readfile(extension_ligand, filename_ligand))
    all_ligands_rings_dict = {}

    print("Looking for Pi-interactions...")
    for i in tqdm(range(len(mols))):

        rings_candidates = mols[i].OBMol.GetSSSR()

        name = get_ligand_name_pose(all_ligands_rings_dict, mols[i].title)

        all_ligands_rings_dict[name] = [
        ]  # {'prefix^pose':[[aromatic ring,[its atoms coords]]]}
        rings = []
        all_atoms = mols[i].atoms

        for ring in rings_candidates:
            if ring.IsAromatic():
                ring_atoms = [a for a in all_atoms if ring.IsMember(a.OBAtom)]
                rings.append([ring, ring_atoms])

        all_ligands_rings_dict[name].extend(rings)

    #########################################
    #  Common part for all Pi-interactions  #
    #########################################

    # There will be 3 results of Pi-interactions: : Pi-cation, Pi-anion, Pi-stacking
    RESULTS = [[], [], []]

    # print ("Looping over RNA rings...")
    for ring in RNA_rings:  # Unlike in previous functions, iteration is over all RNA rings

        ring_atoms_RNA = [a for a in RNA_all_atoms if ring.IsMember(a.OBAtom)]
        atoms_creating_planar_space_RNA = np.array(
            [
                ring_atoms_RNA[0].coords, ring_atoms_RNA[1].coords,
                ring_atoms_RNA[2].coords
            ],
            dtype=np.longdouble
        )  # add 3 atoms (we do not need more) from RNA ring to calculate planar
        planar_RNA = calculate_planar(atoms_creating_planar_space_RNA)
        residue = structure.OBMol.GetAtom(
            ring_atoms_RNA[0].idx).GetResidue()  # Get RNA ring's residue
        ring_center_RNA = centroid([ra.coords for ra in ring_atoms_RNA])

        results = [
            [], [], []
        ]  # There will 3 be results for each RNA residue from 3 Pi-interactions: : Pi-cation, Pi-anion, Pi-stacking

        #################################################
        #  Calculate Pi-cation & Pi-anion interactions  #
        #################################################

        for ligand_name in all_ligands_CA_dict.keys():

            ligand_ion_coords = [
                all_ligands_CA_dict[ligand_name][0],
                all_ligands_CA_dict[ligand_name][1]
            ]  # Calculate Pi-cations & Pi-anions interactions

            for j in range(2):  # Pi-cation & Pi-anion interactions

                results[j].append([
                    ligand_name,
                    str(residue.GetNum()) + ':' + str(residue.GetChain()), 0
                ])

                for ion in ligand_ion_coords[j]:

                    if config.MIN_DIST < measure_distance(
                            ion, ring_center_RNA
                    ) < config.PI_ION_DISTANCE:  # Measure ring center-cation/anion distance

                        ion_ring_center = vector(ring_center_RNA, ion)
                        angle = calculate_angle(
                            ion_ring_center, planar_RNA
                        )  # Calculate angle between cation/anion-ring center and aromatic ring's planar

                        if angle > 90:
                            angle = 180 - angle  # We are 'on the other side'
                        pi_ion_angle = 90 - angle  # The angle is equal to the complementary acute angle

                        if abs(config.PI_ION_ANGLE -
                               pi_ion_angle) < config.PI_ION_ANGLE_DEV:
                            results[j][-1][-1] = 1

        ########################################
        #  Calculate Pi-stacking interactions  #
        ########################################

        for ligand_name in all_ligands_rings_dict.keys():

            results[2].append([
                ligand_name,
                str(residue.GetNum()) + ':' + str(residue.GetChain()), 0
            ])

            ligand_rings = all_ligands_rings_dict[
                ligand_name]  # Take list of ligand's aromatic rings & their atoms as Pybel Atom objects

            for aring in ligand_rings:

                ring_atoms_ligand = aring[1]
                atoms_creating_planar_space_ligand = np.array(
                    [
                        ring_atoms_ligand[0].coords,
                        ring_atoms_ligand[1].coords,
                        ring_atoms_ligand[2].coords
                    ],
                    dtype=np.longdouble
                )  # Add 3 atoms (we do not need more) from ring to calculate planar
                planar_ligand = calculate_planar(
                    atoms_creating_planar_space_ligand)
                ring_center_ligand = centroid(
                    [ra.coords for ra in ring_atoms_ligand])
                centroid_distance = measure_distance(
                    ring_center_RNA,
                    ring_center_ligand)  # Measure ring - ring distance
                planar_angle = calculate_angle(planar_RNA, planar_ligand)

                # Calculate aromatic rings' center offset (project each ring center into the other ring)
                proj1 = projection(planar_ligand, ring_center_ligand,
                                   ring_center_RNA)
                proj2 = projection(planar_RNA, ring_center_RNA,
                                   ring_center_ligand)
                offset = min(measure_distance(proj1, ring_center_ligand),
                             measure_distance(proj2, ring_center_RNA))

                if config.MIN_DIST < centroid_distance < config.RING_RING_MAX and offset < config.PISTACK_OFFSET_MAX:
                    planar_angle = calculate_angle(
                        planar_RNA, planar_ligand
                    )  # Calculate planar - planar angle, which is equal to angle between normal vectors of both planes

                    if planar_angle > 90:
                        planar_angle = 180 - planar_angle  # We are 'on the other side'

                    if planar_angle < config.PI_ANGLE_DISPLACED:  # Sandwich & Displaced Pi-stacking interactions
                        results[2][-1][-1] = 1

                    elif abs(
                            config.PLANAR_ANGLE_TSHAPED - planar_angle
                    ) < config.PLANAR_ANGLE_TSHAPED_DEV:  # T-shaped Pi-stacking interaction
                        results[2][-1][-1] = 1

                    else:
                        continue

        ###########################################################
        #  Merge all the Pi-interactions results and return them  #
        ###########################################################

        for j in range(
                3
        ):  # Append results from calculated 3 Pi-interactions: Pi-cation, Pi-anion, Pi-stacking
            RESULTS[j].extend(results[j])

    return RESULTS
Exemple #4
0
def calculate_CATION_ANION(residue, RNA_anions, ligand_name,
                           ligand_cation_coords, precision):
    """ Calculates cation-anion interaction between residue - ligand pair.
        Simplified graphical representation:\n
        C ***** A\n
            where:\n
            C  - cation\n
            A  - anion\n
        Geometric Rule is:
            - 0.5 A < cation-anion distance < 5.5 A\n
        - If fingerprint's type is FULL:
            - simply checks if there is any cation-anion interaction in residue - ligand pair
        - If fingerprint's type is XP:
            - calculates total number of cation-anion interactions in residue - ligand pair

        :param residue: residue as OpenBabel object
        :param RNA_anions: residue's anions coordinates [OP1, OP2]
        :param ligand_name: ligand_name^pose_number
        :param ligand_cation_coords: list of ligand's cations coords
        :param precision: fingerprint type
        :type residue: openbabel.OBResidue
        :type RNA_anions: list
        :type ligand_name: str
        :type ligand_cation_coords: list
        :type precision: str
        :return: calculated interaction for particular ligand - residue
        :rtype: list

    """

    result = [
        ligand_name,
        str(residue.GetNum()) + ':' + str(residue.GetChain()), 0
    ]

    # Important for 'FULL' fingerprint as we are searching for only the first occurance of cation-anion interaction
    searching_flag = True

    for anion in anions_RNA:

        if searching_flag:
            RNA_anion_coords = np.array(
                [anion.GetX(), anion.GetY(),
                 anion.GetZ()])

            for cation in ligand_cation_coords:

                dist = measure_distance(
                    cation, RNA_anion_coords)  # Measure cation-anion distance

                if config.MIN_DIST < dist < config.MAX_CA_DIST:

                    if precision == 'XP':
                        result[-1] += 1

                    else:
                        result[-1] = 1
                        searching_flag = False  # Just found first cation-anion interaction, no need to search further
                        break
        else:
            break

    return result
Exemple #5
0
def calculate_HAL(residue, acceptors_RNA, ligand_name, ligand_donors_coords,
                  precision):
    """Calculates halogen bond between residue - ligand pair.
        Simplified graphical representation:\n
        Y --- O \***** X --- C\n
            where:\n
            Y  - acceptor'; atom covalently bond to the acceptor\n
            O  - halogen bond acceptor\n
            X  - halogen [F, Br, I, Cl]\n
            C  - halogen donor: Carbon\n
            \* - halogen bond\n
        .. note::
            There may be two Ys, if O is part of the ring. If so, we need to apply above rules to both Ys.\n
        Geometric Rules are:
            - X-O distance < 4.0 A
            - C-X-O angle ~ 165 +/- 30
            - X-O-Y angle ~ 120 +/- 30\n
        - If fingerprint's type is FULL:
            - simply checks if there is any halogen bonding in residue - ligand pair
        - If fingerprint's type is XP:
            - calculates total number of halogen bondings in residue - ligand pair

        :param residue: residue as OpenBabel object
        :param acceptors_RNA: residue's hydrogen bond acceptors
        :param ligand_name: ligand_name^pose_number
        :param ligand_donors_coords: [list of tuples (C, halogen)]
        :param precision: fingerprint type
        :type residue: openbabel.OBResidue
        :type acceptors_RNA: list
        :type ligand_name: str
        :type ligand_donors_coords: list
        :type precision: str
        :return: calculated interaction for particular ligand - residue
        :rtype: list
    """

    result = [
        ligand_name,
        str(residue.GetNum()) + ':' + str(residue.GetChain()), 0
    ]

    # Important for 'FULL' fingerprint as we are searching for only the first halogen bond
    searching_flag = True

    for RNA_acceptor_set in acceptors_RNA:

        if searching_flag:

            RNA_acc_coords = np.array([
                RNA_acceptor_set[0].GetX(), RNA_acceptor_set[0].GetY(),
                RNA_acceptor_set[0].GetZ()
            ])
            # Flag to mark if we have found halogen bonding for one particular acceptor
            acc_bond_found = False

            for donor in ligand_donors_coords:

                if not acc_bond_found:

                    for y in range(len(RNA_acceptor_set[1:])
                                   ):  # For all Y's neighbours (max 2)

                        RNA_acc_y_coords = np.array([
                            RNA_acceptor_set[y + 1].GetX(),
                            RNA_acceptor_set[y + 1].GetY(),
                            RNA_acceptor_set[y + 1].GetZ()
                        ])  # coords of RNA acceptor' - Y
                        dist = measure_distance(
                            donor[1], RNA_acc_coords)  # Measure X-O distance

                        if config.MIN_DIST < dist < config.MAX_HAL_DIST:

                            dh = vector(donor[0], donor[1])
                            ha = vector(RNA_acc_coords, donor[1])
                            ah = vector(donor[1], RNA_acc_coords)
                            aa = vector(RNA_acc_y_coords, RNA_acc_coords)
                            angle_acc = calculate_angle(
                                dh, ha)  # Calculate C-X-O angle
                            angle_don = calculate_angle(
                                ah, aa)  # Calculate X-O-Y angle

                            if (abs(angle_acc - config.HALOGEN_ACC_ANGLE) <
                                    config.HALOGEN_ANGLE_DEV) and (
                                        abs(angle_don -
                                            config.HALOGEN_DON_ANGLE) <
                                        config.HALOGEN_ANGLE_DEV):

                                if precision == 'XP':
                                    result[-1] += 1
                                else:
                                    searching_flag = False  # Just found first halogen bond, no need to search further
                                    result[-1] = 1

                                # If we found halogen bond for one O-Y pair, there is no need to check angles for another Y of the same O (if O has 2 neighbours)
                                acc_bond_found = True
                                break
        else:
            break

    return result
Exemple #6
0
def calculate_HB_no_dha(residue, acceptors_RNA, donors_RNA, ligand_name,
                        ligand_donors_acceptors, precision):
    """Calculates hydrogen bond between residue - ligand pair.
        Simplified graphical representation:\n
        A \***** H --- D\n
            where:
            A  - hydrogen bond acceptor\n
            H  - hydrogen\n
            D  - hydrogen bond acceptor\n
            \* - hydrogen bond\n
        Geometric Rule is:
            1. D-A distance < 3.9 A\n
            If fingerprint's type is FULL:
                - simply checks if there is any hydrogen bonding in residue - ligand pair
            If fingerprint's type is XP:
                - calculates total number of hydrogen bondings in residue - ligand pair
                - assigns type for each hydrogen bonding (strong/moderate/weak), depending on the D-A distance, and calculates number of each type's occurence
                    - strong hydrogen bond:   2.2 A < D-A < 2.5 A
                    - moderate hydrogen bond: 2.5 A < D-A < 3.5 A
                    - weak hydrogen bond:     3.5 A < D-A < 3.9 A

        :param residue: residue as OpenBabel object
        :param acceptors_RNA: residue's hydrogen bond acceptors
        :param donors_RNA: all tuples (D, H) of the residue
        :param ligand_name: ligand_name^pose_number
        :param ligand_donors_acceptors: [[sublist of acceptors coords], [sublist of tuples (D, H) coords]]
        :param precision: fingerprint type
        :type residue: openbabel.OBResidue
        :type acceptors_RNA: list
        :type donors_RNA: list
        :type ligand_name: str
        :type ligand_donors_acceptors: list
        :type precision: str
        :return: calculated interaction for particular ligand - residue
        :rtype: list
    """

    if precision == 'XP':
        result = [
            ligand_name,
            str(residue.GetNum()) + ':' + str(residue.GetChain()), 0, 0, 0, 0
        ]
    else:
        result = [
            ligand_name,
            str(residue.GetNum()) + ':' + str(residue.GetChain()), 0
        ]

    # List of ligand's (D, H) tuples
    ligand_donors_coords = ligand_donors_acceptors[1]
    # List of ligand's acceptors
    ligand_acceptors_coords = ligand_donors_acceptors[0]
    # Important for 'FULL' fingerprint as we are searching only for the first hydrogen bond
    searching_flag = True

    for RNA_acceptor_set in acceptors_RNA:

        RNA_acc = RNA_acceptor_set[
            0]  # We do not need coords of acceptor's neighobours

        if searching_flag:
            RNA_acc_coords = np.array(
                [RNA_acc.GetX(),
                 RNA_acc.GetY(),
                 RNA_acc.GetZ()])

            for donor in ligand_donors_coords:
                dist = measure_distance(donor[0],
                                        RNA_acc_coords)  # Measure D-A distance

                if config.MIN_DIST < dist < config.MAX_HB_DIST:
                    modify_HB_result_list(precision, result, dist)

                    if precision == 'FULL':
                        searching_flag = False
                        break
        else:
            break

    if searching_flag:

        for RNA_don in donors_RNA:
            #res = str(residue.GetNum())+ ':' + str(residue.GetChain())
            #if res == '35:B': print donors_RNA

            if searching_flag:

                RNA_don_coords = np.array(
                    [RNA_don[0].GetX(), RNA_don[0].GetY(), RNA_don[0].GetZ()])
                #RNA_donH_coords = np.array([RNA_don[1].GetX(), RNA_don[1].GetY(), RNA_don[1].GetZ()])

                for acceptor in ligand_acceptors_coords:

                    dist = measure_distance(RNA_don_coords,
                                            acceptor)  # Measure D-A distance

                    if config.MIN_DIST < dist < config.MAX_HB_DIST:

                        modify_HB_result_list(precision, result, dist)

                        if precision == 'FULL':
                            searching_flag = False
                            break

            else:
                break

    return result
Exemple #7
0
                str(residue.GetNum()) + ':' + str(residue.GetChain()))
            RNA_nucleotides.append(str(residue.GetName()))
            acceptors_RNA, donors_RNA = find_RNA_HB_HAL_acc_don(residue)
            anions_RNA = find_RNA_anions(residue)

            residue_atoms_coords = []
            for atom in openbabel.OBResidueAtomIter(residue):
                if atom.GetAtomicNum() != 1:
                    residue_atoms_coords.append(
                        np.array([atom.GetX(),
                                  atom.GetY(),
                                  atom.GetZ()]))

            for ligand_name_HB, ligand_values_HB in ligands_hba_hbd.items():
                if measure_distance(
                        centroid(residue_atoms_coords),
                        centroid(ligands_all_atoms[ligand_name_HB])
                ) > config.RES_LIGAND_MIN_DIST:  # RNA residue centroid and ligand centroid are futher than declared threshold, no chance for any contact
                    continue

                if consider_dha:
                    result = calculate_HB(residue, acceptors_RNA, donors_RNA,
                                          ligand_name_HB, ligand_values_HB,
                                          fingerprint)
                else:
                    result = calculate_HB_no_dha(residue, acceptors_RNA,
                                                 donors_RNA, ligand_name_HB,
                                                 ligand_values_HB, fingerprint)

                if fingerprint == 'FULL':
                    if result[-1] != 0:
                        assign_interactions_results(result, RESULTS,