Compute RMSD between two molecules#

Let us compute the root-mean-square deviation (RMSD) of atomic positions between the atoms of two superimposed molecules.

from math import sqrt

def compute_rmsd(mol1_indexer, mol2_indexer):
    """Computes RMSD between two superimposed molecules and returns RMSD in angstrom"""

    # check if indexers are of the same size
    if len(mol1_indexer) != len(mol2_indexer):
        print('Molecules are not the same')
        return -1

    sqrd_sum = SBQuantity.squareLength(0.0)
    # go through all atoms in the indexer
    for i in range(len(mol1_indexer)):
        if mol1_indexer[i].elementType != mol2_indexer[i].elementType:
            print('Atoms are not the same')
            return -1
        # get positions of atoms from indexers
        pos1 = mol1_indexer[i].getPosition()
        pos2 = mol2_indexer[i].getPosition()
        # compute distance between atoms
        # and accumulate squared norm for distances
        sqrd_sum += (pos1 - pos2).norm2()

    # take a square root of the sum of squared distances divided by the number of atoms
    rmsd = SBQuantity.sqrt(sqrd_sum / len(mol1_indexer))

    # return RMSD in angstrom
    return rmsd.angstrom.value

def compute_rmsd_2mol(mol1, mol2):
    """Computes several RMSD between two superimposed molecules:
    1) between all atoms,
    2) between backbone atoms,
    3) between alpha-Carbon atoms.
    """
    # get indexers of all atoms
    mol1_all_indexer      = mol1.getNodes('node.type atom')
    mol2_all_indexer      = mol2.getNodes('n.t a')
    # get indexers of all atoms in the backbone
    mol1_backbone_indexer = mol1.getNodes('node.type atom in node.type backbone')
    mol2_backbone_indexer = mol2.getNodes('n.t a in n.t bb')
    # get indexers of all alpha Carbons in the backbone
    mol1_CA_indexer       = mol1.getNodes('"CA" in node.type backbone')
    mol2_CA_indexer       = mol2.getNodes('"CA" in n.t bb')

    rmsd_all      = compute_rmsd(mol1_all_indexer, mol2_all_indexer);
    rmsd_backbone = compute_rmsd(mol1_backbone_indexer, mol2_backbone_indexer);
    rmsd_CA       = compute_rmsd(mol1_CA_indexer, mol2_CA_indexer);

    if (rmsd_all != -1):      print("RMSD (all atoms): %e Angstrom" % rmsd_all)
    if (rmsd_backbone != -1): print("RMSD (backbone) : %e Angstrom" % rmsd_backbone)
    if (rmsd_CA != -1):       print("RMSD (C_alpha)  : %e Angstrom" % rmsd_CA)

    # return a list of RMSDs
    return [rmsd_all, rmsd_backbone, rmsd_CA]


# get all molecules in the active document
indexer = SAMSON.getNodes('node.type molecule')

if len(indexer) < 2:
    print("Less than two molecules are present in the data graph")
else:
    # we assume here that we need to compute RMSD between the first two molecules in the indexer
    mol1 = indexer[0]    # get the first molecule
    mol2 = indexer[1]    # get the second molecule
    # compute RMSD between the two superimposed molecules
    rmsd = compute_rmsd_2mol(mol1, mol2)