Beispiel #1
0
def halogenbond_acceptor_halogen(mol1,
                                 mol2,
                                 base_angle_acceptor=120,
                                 base_angle_halogen=180,
                                 tolerance=30,
                                 cutoff=4):
    """Returns pairs of acceptor-halogen atoms, which meet halogen bond criteria

    Parameters
    ----------
        mol1, mol2 : oddt.toolkit.Molecule object
            Molecules to compute halogen bond acceptor and halogen pairs

        cutoff : float, (default=4)
            Distance cutoff for A-H pairs

        base_angle_acceptor : int, (default=120)
            Base angle determining allowed direction of halogen bond formation,
            which is devided by the number of neighbors of acceptor atom
            to establish final directional angle

        base_angle_halogen : int (default=180)
            Ideal base angle between halogen bond and halogen-neighbor bond

        tolerance : int, (default=30)
            Range (+/- tolerance) from perfect direction (base_angle/n_neighbors)
            in which halogen bonds are considered as strict.

    Returns
    -------
        a, h : atom_dict-type numpy array
            Aligned arrays of atoms forming halogen bond, firstly acceptors,
            secondly halogens

        strict : numpy array, dtype=bool
            Boolean array align with atom pairs, informing whether atoms
            form 'strict' halogen bond (pass all angular cutoffs). If false,
            only distance cutoff is met, therefore the bond is 'crude'.
    """
    a, h = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[mol2.atom_dict['ishalogen']], cutoff)
    # skip empty values
    if len(a) > 0 and len(h) > 0:
        angle1 = angle(h['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :], a['neighbors'])
        angle2 = angle(a['coords'][:, np.newaxis, :],
                       h['coords'][:, np.newaxis, :], h['neighbors'])
        a_neighbors_num = np.sum(~np.isnan(a['neighbors'][:, :, 0]),
                                 axis=-1)[:, np.newaxis]
        h_neighbors_num = np.sum(~np.isnan(h['neighbors'][:, :, 0]),
                                 axis=-1)[:, np.newaxis]
        strict = (((np.nan_to_num(angle1) >
                    (base_angle_acceptor / a_neighbors_num - tolerance))
                   | np.isnan(angle1)) &
                  ((np.nan_to_num(angle2) >
                    (base_angle_halogen / h_neighbors_num - tolerance))
                   | np.isnan(angle2))).all(axis=-1)
        return a, h, strict
    else:
        return a, h, np.array([], dtype=bool)
Beispiel #2
0
def halogenbond_acceptor_halogen(mol1,
                                 mol2,
                                 base_angle_acceptor=120,
                                 base_angle_halogen=180,
                                 tolerance=30,
                                 cutoff=4):
    """Returns pairs of acceptor-halogen atoms, which meet halogen bond criteria

    Parameters
    ----------
    mol1, mol2 : oddt.toolkit.Molecule object
        Molecules to compute halogen bond acceptor and halogen pairs

    cutoff : float, (default=4)
        Distance cutoff for A-H pairs

    base_angle_acceptor : int, (default=120)
        Base angle determining allowed direction of halogen bond formation,
        which is devided by the number of neighbors of acceptor atom
        to establish final directional angle

    base_angle_halogen : int (default=180)
        Ideal base angle between halogen bond and halogen-neighbor bond

    tolerance : int, (default=30)
        Range (+/- tolerance) from perfect direction (base_angle/n_neighbors)
        in which halogen bonds are considered as strict.

    Returns
    -------
    a, h : atom_dict-type numpy array
        Aligned arrays of atoms forming halogen bond, firstly acceptors,
        secondly halogens

    strict : numpy array, dtype=bool
        Boolean array align with atom pairs, informing whether atoms
        form 'strict' halogen bond (pass all angular cutoffs). If false,
        only distance cutoff is met, therefore the bond is 'crude'.
    """
    a, h = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[mol2.atom_dict['ishalogen']],
                          cutoff)
    # skip empty values
    if len(a) > 0 and len(h) > 0:
        angle1 = angle(h['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :],
                       a['neighbors'])
        angle2 = angle(a['coords'][:, np.newaxis, :],
                       h['coords'][:, np.newaxis, :],
                       h['neighbors'])
        a_neighbors_num = np.sum(~np.isnan(a['neighbors'][:, :, 0]), axis=-1)[:, np.newaxis]
        h_neighbors_num = np.sum(~np.isnan(h['neighbors'][:, :, 0]), axis=-1)[:, np.newaxis]
        strict = (((np.nan_to_num(angle1) > (base_angle_acceptor / a_neighbors_num - tolerance)) |
                   np.isnan(angle1)) &
                  ((np.nan_to_num(angle2) > (base_angle_halogen / h_neighbors_num - tolerance)) |
                   np.isnan(angle2))).all(axis=-1)
        return a, h, strict
    else:
        return a, h, np.array([], dtype=bool)
Beispiel #3
0
def pi_stacking(mol1, mol2, cutoff=5, tolerance=30):
    """Returns pairs of rings, which meet pi stacking criteria

    Parameters
    ----------
    mol1, mol2 : oddt.toolkit.Molecule object
        Molecules to compute ring pairs

    cutoff : float, (default=5)
        Distance cutoff for Pi-stacking pairs

    tolerance : int, (default=30)
        Range (+/- tolerance) from perfect direction (parallel or
        perpendicular) in which pi-stackings are considered as strict.

    Returns
    -------
    r1, r2 : ring_dict-type numpy array
        Aligned arrays of rings forming pi-stacking

    strict_parallel : numpy array, dtype=bool
        Boolean array align with ring pairs, informing whether rings
        form 'strict' parallel pi-stacking. If false, only distance cutoff is met,
        therefore the stacking is 'crude'.

    strict_perpendicular : numpy array, dtype=bool
        Boolean array align with ring pairs, informing whether rings
        form 'strict' perpendicular pi-stacking (T-shaped, T-face, etc.).
        If false, only distance cutoff is met, therefore the stacking is 'crude'.
    """
    r1, r2 = close_contacts(mol1.ring_dict,
                            mol2.ring_dict,
                            cutoff,
                            x_column='centroid',
                            y_column='centroid')
    if len(r1) > 0 and len(r2) > 0:
        angle1 = angle_2v(r1['vector'], r2['vector'])
        angle2 = angle(r1['vector'] + r1['centroid'], r1['centroid'],
                       r2['centroid'])
        angle3 = angle(r2['vector'] + r2['centroid'], r2['centroid'],
                       r1['centroid'])
        strict_parallel = (((angle1 > 180 - tolerance) |
                            (angle1 < tolerance)) &
                           ((angle2 > 180 - tolerance) | (angle2 < tolerance) |
                            (angle3 > 180 - tolerance) | (angle3 < tolerance)))
        strict_perpendicular = (
            (angle1 > 90 - tolerance) & (angle1 < 90 + tolerance) &
            (((angle2 > 180 - tolerance) | (angle2 < tolerance)) &
             ((angle3 > 90 - tolerance) | (angle3 < 90 + tolerance)) |
             ((angle2 > 90 - tolerance) | (angle2 < 90 + tolerance)) &
             ((angle3 > 180 - tolerance) | (angle3 < tolerance))))
        return r1, r2, strict_parallel, strict_perpendicular
    else:
        return r1, r2, np.array([], dtype=bool), np.array([], dtype=bool)
Beispiel #4
0
def hbond_acceptor_donor(mol1, mol2, cutoff=3.5, base_angle=120, tolerance=30):
    """Returns pairs of acceptor-donor atoms, which meet H-bond criteria

    Parameters
    ----------
        mol1, mol2 : oddt.toolkit.Molecule object
            Molecules to compute H-bond acceptor and H-bond donor pairs

        cutoff : float, (default=3.5)
            Distance cutoff for A-D pairs

        base_angle : int, (default=120)
            Base angle determining allowed direction of hydrogen bond formation,
            which is devided by the number of neighbors of acceptor atom
            to establish final directional angle

        tolerance : int, (default=30)
            Range (+/- tolerance) from perfect direction (base_angle/n_neighbors)
            in which H-bonds are considered as strict.

    Returns
    -------
        a, d : atom_dict-type numpy array
            Aligned arrays of atoms forming H-bond, firstly acceptors,
            secondly donors.

        strict : numpy array, dtype=bool
            Boolean array align with atom pairs, informing whether atoms
            form 'strict' H-bond (pass all angular cutoffs). If false,
            only distance cutoff is met, therefore the bond is 'crude'.
    """
    a, d = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[mol2.atom_dict['isdonor']], cutoff)
    # skip empty values
    if len(a) > 0 and len(d) > 0:
        angle1 = angle(d['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :], a['neighbors'])
        a_neighbors_num = np.sum(~np.isnan(a['neighbors'][:, :, 0]),
                                 axis=-1)[:, np.newaxis]
        angle2 = angle(a['coords'][:, np.newaxis, :],
                       d['coords'][:, np.newaxis, :], d['neighbors'])
        d_neighbors_num = np.sum(~np.isnan(d['neighbors'][:, :, 0]),
                                 axis=-1)[:, np.newaxis]
        strict = ((
            (np.nan_to_num(angle1) >
             (base_angle / a_neighbors_num - tolerance)) | np.isnan(angle1)) &
                  ((np.nan_to_num(angle2) >
                    (base_angle / d_neighbors_num - tolerance))
                   | np.isnan(angle2))).all(axis=-1)
        return a, d, strict
    else:
        return a, d, np.array([], dtype=bool)
Beispiel #5
0
def hbond_acceptor_donor(mol1, mol2, cutoff=3.5, base_angle=120, tolerance=30):
    """Returns pairs of acceptor-donor atoms, which meet H-bond criteria

    Parameters
    ----------
    mol1, mol2 : oddt.toolkit.Molecule object
        Molecules to compute H-bond acceptor and H-bond donor pairs

    cutoff : float, (default=3.5)
        Distance cutoff for A-D pairs

    base_angle : int, (default=120)
        Base angle determining allowed direction of hydrogen bond formation,
        which is devided by the number of neighbors of acceptor atom
        to establish final directional angle

    tolerance : int, (default=30)
        Range (+/- tolerance) from perfect direction (base_angle/n_neighbors)
        in which H-bonds are considered as strict.

    Returns
    -------
    a, d : atom_dict-type numpy array
        Aligned arrays of atoms forming H-bond, firstly acceptors,
        secondly donors.

    strict : numpy array, dtype=bool
        Boolean array align with atom pairs, informing whether atoms
        form 'strict' H-bond (pass all angular cutoffs). If false,
        only distance cutoff is met, therefore the bond is 'crude'.
    """
    a, d = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[mol2.atom_dict['isdonor']],
                          cutoff)
    # skip empty values
    if len(a) > 0 and len(d) > 0:
        angle1 = angle(d['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :],
                       a['neighbors'])
        a_neighbors_num = np.sum(~np.isnan(a['neighbors'][:, :, 0]), axis=-1)[:, np.newaxis]
        angle2 = angle(a['coords'][:, np.newaxis, :],
                       d['coords'][:, np.newaxis, :],
                       d['neighbors'])
        d_neighbors_num = np.sum(~np.isnan(d['neighbors'][:, :, 0]), axis=-1)[:, np.newaxis]
        strict = (((np.nan_to_num(angle1) > (base_angle / a_neighbors_num - tolerance)) |
                   np.isnan(angle1)) &
                  ((np.nan_to_num(angle2) > (base_angle / d_neighbors_num - tolerance)) |
                   np.isnan(angle2))).all(axis=-1)
        return a, d, strict
    else:
        return a, d, np.array([], dtype=bool)
Beispiel #6
0
def hbond_acceptor_donor(mol1,
                         mol2,
                         cutoff=3.5,
                         tolerance=30,
                         donor_exact=False):
    """Returns pairs of acceptor-donor atoms, which meet H-bond criteria

    Parameters
    ----------
    mol1, mol2 : oddt.toolkit.Molecule object
        Molecules to compute H-bond acceptor and H-bond donor pairs

    cutoff : float, (default=3.5)
        Distance cutoff for A-D pairs

    tolerance : int, (default=30)
        Range (+/- tolerance) from perfect direction defined by acceptor/donor hybridization
        in which H-bonds are considered as strict.
    donor_exact : bool
        Use exact protonation states for donors, i.e. require Hs on donor.
        By default ODDT implies some tautomeric structures as protonated,
        even if there is no H on specific atom.

    Returns
    -------
    a, d : atom_dict-type numpy array
        Aligned arrays of atoms forming H-bond, firstly acceptors,
        secondly donors.

    strict : numpy array, dtype=bool
        Boolean array align with atom pairs, informing whether atoms
        form 'strict' H-bond (pass all angular cutoffs). If false,
        only distance cutoff is met, therefore the bond is 'crude'.
    """
    donor_mask = mol2.atom_dict['isdonor']
    if donor_exact:
        donor_mask = donor_mask & (mol2.atom_dict['numhs'] > 0)
    a, d = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[donor_mask], cutoff)
    # skip empty values
    if len(a) > 0 and len(d) > 0:
        angle1 = angle(d['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :], a['neighbors'])
        angle2 = angle(a['coords'][:, np.newaxis, :],
                       d['coords'][:, np.newaxis, :], d['neighbors'])
        strict = (_check_angles(angle1, a['hybridization'], tolerance)
                  & _check_angles(angle2, d['hybridization'], tolerance))
        return a, d, strict
    else:
        return a, d, np.array([], dtype=bool)
Beispiel #7
0
def acceptor_metal(mol1, mol2, base_angle = 120, tolerance = 30, cutoff = 4):
    """Returns pairs of acceptor-metal atoms, which meet metal coordination criteria
    Note: This function is directional (mol1 holds acceptors, mol2 holds metals)
    
    Parameters
    ----------
        mol1, mol2 : oddt.toolkit.Molecule object
            Molecules to compute acceptor and metal pairs
        
        cutoff : float, (default=4)
            Distance cutoff for A-M pairs
        
        base_angle : int, (default=120)
            Base angle determining allowed direction of metal coordination, which is devided by the number of neighbors of acceptor atom to establish final directional angle
        
        tolerance : int, (default=30)
            Range (+/- tolerance) from perfect direction (base_angle/n_neighbors) in metal coordination are considered as strict.
    
    Returns
    -------
        a, d : atom_dict-type numpy array
            Aligned arrays of atoms forming metal coordination, firstly acceptors, secondly metals.
        
        strict : numpy array, dtype=bool
            Boolean array align with atom pairs, informing whether atoms form 'strict' metal coordination (pass all angular cutoffs). If false, only distance cutoff is met, therefore the interaction is 'crude'.
    """
    a, m = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']], mol2.atom_dict[mol2.atom_dict['ismetal']], cutoff)
    #skip empty values
    if len(a) > 0 and len(m) > 0:
        angle1 = angle(m['coords'][:,np.newaxis,:],a['coords'][:,np.newaxis,:],a['neighbors'])
        a_neighbors_num = np.sum(~np.isnan(a['neighbors'][:,:,0]), axis=-1)[:,np.newaxis]
        strict = ((angle1>(base_angle/a_neighbors_num-tolerance)) | np.isnan(angle1)).all(axis=-1)
        return a, m, strict
    else:
        return a, m, np.array([], dtype=bool)
Beispiel #8
0
def pi_stacking(mol1, mol2, cutoff = 5, tolerance = 30):
    """Returns pairs of rings, which meet pi stacking criteria
    
    Parameters
    ----------
        mol1, mol2 : oddt.toolkit.Molecule object
            Molecules to compute ring pairs
        
        cutoff : float, (default=5)
            Distance cutoff for Pi-stacking pairs
        
        tolerance : int, (default=30)
            Range (+/- tolerance) from perfect direction (parallel or perpendicular) in which pi-stackings are considered as strict.
    
    Returns
    -------
        r1, r2 : ring_dict-type numpy array
            Aligned arrays of rings forming pi-stacking
        
        strict_parallel : numpy array, dtype=bool
            Boolean array align with ring pairs, informing whether rings form 'strict' parallel pi-stacking. If false, only distance cutoff is met, therefore the stacking is 'crude'.
        
        strict_perpendicular : numpy array, dtype=bool
            Boolean array align with ring pairs, informing whether rings form 'strict' perpendicular pi-stacking (T-shaped, T-face, etc.). If false, only distance cutoff is met, therefore the stacking is 'crude'.
    """
    r1, r2 = close_contacts(mol1.ring_dict, mol2.ring_dict, cutoff, x_column = 'centroid', y_column = 'centroid')
    if len(r1) > 0 and len(r2) > 0:
        angle1 = angle_2v(r1['vector'],r2['vector'])
        angle2 = angle(r1['vector'] + r1['centroid'],r1['centroid'], r2['centroid'])
        strict_parallel = ((angle1 > 180 - tolerance) | (angle1 < tolerance)) & ((angle2 > 180 - tolerance) | (angle2 < tolerance))
        strict_perpendicular = ((angle1 > 90 - tolerance) & (angle1 < 90 + tolerance)) & ((angle2 > 180 - tolerance) | (angle2 < tolerance))
        return r1, r2, strict_parallel, strict_perpendicular
    else:
        return r1, r2, np.array([], dtype=bool), np.array([], dtype=bool)
Beispiel #9
0
def acceptor_metal(mol1, mol2, base_angle = 120, tolerance = 30, cutoff = 4):
    """Returns pairs of acceptor-metal atoms, which meet metal coordination criteria
    Note: This function is directional (mol1 holds acceptors, mol2 holds metals)

    Parameters
    ----------
        mol1, mol2 : oddt.toolkit.Molecule object
            Molecules to compute acceptor and metal pairs

        cutoff : float, (default=4)
            Distance cutoff for A-M pairs

        base_angle : int, (default=120)
            Base angle determining allowed direction of metal coordination, which is devided by the number of neighbors of acceptor atom to establish final directional angle

        tolerance : int, (default=30)
            Range (+/- tolerance) from perfect direction (base_angle/n_neighbors) in metal coordination are considered as strict.

    Returns
    -------
        a, d : atom_dict-type numpy array
            Aligned arrays of atoms forming metal coordination, firstly acceptors, secondly metals.

        strict : numpy array, dtype=bool
            Boolean array align with atom pairs, informing whether atoms form 'strict' metal coordination (pass all angular cutoffs). If false, only distance cutoff is met, therefore the interaction is 'crude'.
    """
    a, m = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']], mol2.atom_dict[mol2.atom_dict['ismetal']], cutoff)
    #skip empty values
    if len(a) > 0 and len(m) > 0:
        angle1 = angle(m['coords'][:,np.newaxis,:],a['coords'][:,np.newaxis,:],a['neighbors'])
        a_neighbors_num = np.sum(~np.isnan(a['neighbors'][:,:,0]), axis=-1)[:,np.newaxis]
        strict = ((angle1>(base_angle/a_neighbors_num-tolerance)) | np.isnan(angle1)).all(axis=-1)
        return a, m, strict
    else:
        return a, m, np.array([], dtype=bool)
Beispiel #10
0
def test_angles():
    """Test spatial computations - angles"""

    # Angles
    assert_array_almost_equal(angle(np.array((1, 0, 0)),
                                    np.array((0, 0, 0)),
                                    np.array((0, 1, 0))), 90)

    assert_array_almost_equal(angle(np.array((1, 0, 0)),
                                    np.array((0, 0, 0)),
                                    np.array((1, 1, 0))), 45)

    # Check benzene ring angle
    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
    mol.make3D()
    assert_array_almost_equal(angle(mol.coords[0],
                                    mol.coords[1],
                                    mol.coords[2]), 120, decimal=1)
Beispiel #11
0
def test_angles():
    """Test spatial computations - angles"""

    # Angles
    assert_array_almost_equal(
        angle(np.array((1, 0, 0)), np.array((0, 0, 0)), np.array((0, 1, 0))),
        90)

    assert_array_almost_equal(
        angle(np.array((1, 0, 0)), np.array((0, 0, 0)), np.array((1, 1, 0))),
        45)

    # Check benzene ring angle
    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
    mol.make3D()
    assert_array_almost_equal(angle(mol.coords[0], mol.coords[1],
                                    mol.coords[2]),
                              120,
                              decimal=1)
Beispiel #12
0
def halogenbond_acceptor_halogen(mol1, mol2, tolerance=30, cutoff=4):
    """Returns pairs of acceptor-halogen atoms, which meet halogen bond criteria

    Parameters
    ----------
    mol1, mol2 : oddt.toolkit.Molecule object
        Molecules to compute halogen bond acceptor and halogen pairs

    cutoff : float, (default=4)
        Distance cutoff for A-H pairs

    tolerance : int, (default=30)
        Range (+/- tolerance) from perfect direction defined by atoms hybridization
        in which halogen bonds are considered as strict.

    Returns
    -------
    a, h : atom_dict-type numpy array
        Aligned arrays of atoms forming halogen bond, firstly acceptors,
        secondly halogens

    strict : numpy array, dtype=bool
        Boolean array align with atom pairs, informing whether atoms
        form 'strict' halogen bond (pass all angular cutoffs). If false,
        only distance cutoff is met, therefore the bond is 'crude'.
    """
    a, h = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[mol2.atom_dict['ishalogen']], cutoff)
    # skip empty values
    if len(a) > 0 and len(h) > 0:
        angle1 = angle(h['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :], a['neighbors'])
        angle2 = angle(a['coords'][:, np.newaxis, :],
                       h['coords'][:, np.newaxis, :], h['neighbors'])
        strict = (_check_angles(angle1, a['hybridization'], tolerance)
                  & _check_angles(angle2, np.ones_like(h['hybridization']),
                                  tolerance))
        return a, h, strict
    else:
        return a, h, np.array([], dtype=bool)
Beispiel #13
0
def acceptor_metal(mol1, mol2, tolerance=30, cutoff=4):
    """Returns pairs of acceptor-metal atoms, which meet metal coordination criteria
    Note: This function is directional (mol1 holds acceptors, mol2 holds metals)

    Parameters
    ----------
    mol1, mol2 : oddt.toolkit.Molecule object
        Molecules to compute acceptor and metal pairs

    cutoff : float, (default=4)
        Distance cutoff for A-M pairs

    tolerance : int, (default=30)
        Range (+/- tolerance) from perfect direction defined by atoms hybridization
        in metal coordination are considered as strict.

    Returns
    -------
    a, d : atom_dict-type numpy array
        Aligned arrays of atoms forming metal coordination,
        firstly acceptors, secondly metals.

    strict : numpy array, dtype=bool
        Boolean array align with atom pairs, informing whether atoms
        form 'strict' metal coordination (pass all angular cutoffs).
        If false, only distance cutoff is met, therefore the interaction
        is 'crude'.
    """
    a, m = close_contacts(mol1.atom_dict[mol1.atom_dict['isacceptor']],
                          mol2.atom_dict[mol2.atom_dict['ismetal']], cutoff)
    # skip empty values
    if len(a) > 0 and len(m) > 0:
        angle1 = angle(m['coords'][:, np.newaxis, :],
                       a['coords'][:, np.newaxis, :], a['neighbors'])
        strict = _check_angles(angle1, a['hybridization'], tolerance)
        return a, m, strict
    else:
        return a, m, np.array([], dtype=bool)
Beispiel #14
0
def test_spatial():
    """Test spatial computations"""

    # Angles
    assert_array_almost_equal(angle(np.array((1, 0, 0)),
                                    np.array((0, 0, 0)),
                                    np.array((0, 1, 0))), 90)

    assert_array_almost_equal(angle(np.array((1, 0, 0)),
                                    np.array((0, 0, 0)),
                                    np.array((1, 1, 0))), 45)

    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
    mol.make3D()

    # Check benzene ring angle
    assert_array_almost_equal(angle(mol.coords[0],
                                    mol.coords[1],
                                    mol.coords[2]), 120, decimal=1)

    # Dihedrals
    assert_array_almost_equal(dihedral(np.array((1, 0, 0)),
                                       np.array((0, 0, 0)),
                                       np.array((0, 1, 0)),
                                       np.array((1, 1, 0))), 0)

    assert_array_almost_equal(dihedral(np.array((1, 0, 0)),
                                       np.array((0, 0, 0)),
                                       np.array((0, 1, 0)),
                                       np.array((1, 1, 1))), -45)

    # Check benzene ring dihedral
    assert_array_almost_equal(dihedral(mol.coords[0],
                                       mol.coords[1],
                                       mol.coords[2],
                                       mol.coords[3]), 0, decimal=1)

    mol = oddt.toolkit.readstring('smi', 'c1ccccc1')
    mol.make3D()
    mol2 = mol.clone

    # Test rotation
    assert_almost_equal(mol2.coords, rotate(mol2.coords, np.pi, np.pi, np.pi))

    # Rotate perpendicular to ring
    mol2.coords = rotate(mol2.coords, 0, 0, np.pi)

    # RMSD
    assert_almost_equal(rmsd(mol, mol2, method=None), 2.77, decimal=1)
    # Hungarian must be close to zero (RDKit is 0.3)
    assert_almost_equal(rmsd(mol, mol2, method='hungarian'), 0, decimal=0)

    # pick one molecule from docked poses
    mols = list(oddt.toolkit.readfile('sdf', os.path.join(test_data_dir, 'data/dude/xiap/actives_docked.sdf')))
    mols = list(filter(lambda x: x.title == '312335', mols))

    assert_array_almost_equal([rmsd(mols[0], mol) for mol in mols[1:]],
                              [4.753552, 2.501487, 2.7941732, 1.1281863, 0.74440968,
                               1.6256877, 4.762476, 2.7167852, 2.5504358, 1.9303833,
                               2.6200771, 3.1741529, 3.225431, 4.7784939, 4.8035369,
                               7.8962774, 2.2385094, 4.8625236, 3.2036853])

    assert_array_almost_equal([rmsd(mols[0], mol, method='hungarian') for mol in mols[1:]],
                              [2.5984519, 1.7295024, 1.1268076, 1.0285776, 0.73529714,
                               1.4094033, 2.5195069, 1.7449125, 1.5116163, 1.7796179,
                               2.6064286, 3.1576841, 3.2135022, 3.1675091, 2.7001681,
                               5.1263351, 2.0836117, 3.542397, 3.1873631])