ChimeraX Recipes

Find closest pair of atoms

Here is Python code defining a command “closest” that finds the closest pair of atoms between two set of atoms. Opening the closest.py code in ChimeraX adds the command

open closest.py

then use the command on two sets of atoms

open 7LUP
closest /A to /B show true

Minimum distance 2.27 between /A LYS 45 NZ and /B ASP 522 OD1

Here is the closest.py code:

#
# Add command "closest" that finds the closest pair of atoms given two
# sets of atoms.
#
# open 7LUP
# closest /A to /B
#
#  Minimum distance 2.27 between /A LYS 45 NZ and /B ASP 522 OD1
#

def closest(session, atoms, to_atoms, max_dist = 10, show = False):
    xyz1, xyz2 = atoms.scene_coords, to_atoms.scene_coords
    from chimerax.geometry import find_closest_points
    i1, i2, nearest1 = find_closest_points(xyz1, xyz2, max_dist)
    if len(nearest1) == 0:
        d = a1 = a2 = None
    else:
        v = xyz2[nearest1] - xyz1[i1]
        d2 = (v*v).sum(axis=1)
        c = d2.argmin()
        c1, c2 = i1[c], nearest1[c]
        a1, a2 = atoms[c1], to_atoms[c2]
        from math import sqrt
        d = sqrt(d2[c])
    report_closest(session, d, a1, a2, show, max_dist)
    return d, a1, a2

def report_closest(session, d, a1, a2, show, max_dist):
    if d is None:
        msg = 'No atom pairs within distance %.3g of each other' % max_dist
    else:
        msg = 'Minimum distance %.2f between %s and %s' % (d, str(a1), str(a2))
    session.logger.status(msg, log = True)

    if show and a1 and a2:
        from chimerax.core.commands import run
        run(session, 'distance %s %s' % (a1.atomspec, a2.atomspec))
        run(session, 'view %s %s' % (a1.atomspec, a2.atomspec))

def closest_slow(session, atoms, to_atoms, max_dist = 10, show = False):
    '''Loop through every pair of atoms in Python.  This is slow.'''
    dmin = amin1 = amin2 = None
    from chimerax.geometry import distance
    for a1 in atoms:
        for a2 in to_atoms:
            d = distance(a1.scene_coord, a2.scene_coord)
            if (dmin is None or d < dmin) and d <= max_dist:
                dmin, amin1, amin2 = d, a1, a2
    report_closest(session, dmin, amin1, amin2, show, max_dist)
    return dmin, amin1, amin2

def register_command(session):
    from chimerax.core.commands import CmdDesc, register, FloatArg, BoolArg
    from chimerax.atomic import AtomsArg
    desc = CmdDesc(required= [('atoms', AtomsArg)],
                   keyword = [('to_atoms', AtomsArg),
                              ('max_dist', FloatArg),
                              ('show', BoolArg)],
                   required_arguments = ['to_atoms'],
                   synopsis = 'find closest pair of atoms')
    register('closest', desc, closest, logger=session.logger)

register_command(session)

Tom Goddard, Sptember 28, 2021