On Jan 9, 2008, at 11:56 AM, Buz Barstow wrote:
Does anyone have a python routine that can be used to calculate the moment
of inertia matrix and principal axes of a selection of atoms?


I compulsively write python code sometimes--its that fun of a language...

If you can get the x, y, z, and mass of your atoms, then you can use the little module below (moi.py). It approximates atomic nuclei as dimensionless ;-). An example usage is at the bottom. "JTools" is my own PDB library, but it gives an idea of use. Once you have the moi tensor, I think Eigenvalue decomposition gets the principle axes, so this becomes a 1-op with numpy. Please let me know if you find errors.

James


========================================================================

#! /usr/bin/env python

"""
moi.py

(c) 2008, James Stroud
This module is released under the GNU Public License 3.0.
See <http://www.gnu.org/licenses/gpl.html>.

A module to find the moment of inertia of some atoms.

See <http://en.wikipedia.org/wiki/Moment_of_inertia> for
a mathematical discussion.

Anywhere "ref" is optional defaults to the center of mass
except where indicated.
The "sel" argument is always a list of Atoms.
"""
import math

class Atom(object):
  def __init__(self, x, y, z, mass):
    self.x = float(x)
    self.y = float(y)
    self.z = float(z)
    self.mass = float(mass)
  def __str__(self):
    return "%s @ (%s, %s, %s)" % (self.x, self.y, self.z, self.mass)

class Point(object):
  def __init__(self, x, y, z):
    self.x = x
    self.y = y
    self.z = z
  def __str__(self):
    return "(%s, %s, %s)" % (self.x, self.y, self.z)

def dist(atom, ref=None):
  """
  Calculates distance between an atom and a ref.
  If ref is not given, then the origin is assumed.
  """
  if ref is None:
    d = math.sqrt(atom.x**2 + atom.y**2 + atom.z**2)
  else:
    x = atom.x - ref.x
    y = atom.y - ref.y
    z = atom.z - ref.z
    d = math.sqrt(x**2 + y**2 + z**2)
  return d

def com(sel):
  """
  Calculates the center of mass of a list of atoms.
  """
  m = sum([atom.mass for atom in sel])
  c = []
  for i in 'xyz':
    mr = []
    for atom in sel:
      mr.append(atom.mass * getattr(atom, i))
    c.append(sum(mr)/m)
  return Point(*c)

def kd(i, j):
  """
  The Kronaker delta.
  """
  return int(i==j)

def moi_element(i, j, sel, ref):
  """
  Generalized moment of inertia element--both diagonal and off
  diagonal. Coordinate axes i and j should be 'x', 'y', or 'z'.
  The sel argument is a list of Atoms.
  The ref arguemnt is a Point.
  """
  delta = kd(i, j)
  refi = getattr(ref, i)
  refj = getattr(ref, j)
  el = []
  for atom in sel:
    r2d = (dist(atom, ref)**2) * delta
    ri = getattr(atom, i) - refi
    rj = getattr(atom, j) - refj
    el.append(atom.mass*(r2d - ri*rj))
  return sum(el)

def tensor_moi(sel, ref=None):
  """
  Calculates the moment of inertia tensor.
  """
  if ref is None:
    ref = com(sel)
  indices = [(i,j) for i in 'xyz' for j in 'xyz']
  tensor = [moi_element(i, j, sel, ref) for (i,j) in indices]
  return [tensor[0:3], tensor[3:6], tensor[6:9]]

def scalar_moi(sel, ref=None):
  """
  Calculates the scalar moment of inertia.
  """
  if ref is None:
    ref = com(sel)
  i = []
  for atom in sel:
    i.append(atom.mass * dist(atom, ref)**2)
  return sum(i)

def test():
  """
  You will want to construct your own test.
  """
  import JTools
  import numpy

  s = JTools.build_pdb('1ass.pdb')
  sel = []
  for p in s[0]:
    for a in p:
      sel.append(Atom(a.x, a.y, a.z, a.get_weight()))

  print "Center of mass of chain 0:"
  print com(sel)

  print
  print "The moi as tensor:"
  tensor = numpy.array(tensor_moi(sel))
  print tensor
  print

  print "The eigenvalue decomposition:"
  decomp = numpy.linalg.eig(tensor)
  print "The eigenvalues:"
  print decomp[0]
  print "The eigenvectors:"
  print decomp[1]
  print

  print "The moi as scalar:"
  print scalar_moi(sel)
  print

  print "The moi as scalar around ori:"
  print scalar_moi(sel, Point(0, 0, 0))
  print

if __name__ == "__main__":
  test()


========================================================================



Thanks! and all the best,

--Buz

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
611 Charles E. Young Dr. S.
Los Angeles, CA  90095

http://www.jamesstroud.com



Reply via email to