Saturday 10 April 2010

Plug cclib into Avogadro

cclib is an open source Python library for parsing and analysing computational chemistry log files.

Avogadro is a cross-platform molecular visualiser with a lot of functionality geared towards setting up and analysing computational chemistry calculations. It is an open source project led by Marcus Hanwell and is built on top of OpenBabel.

Although Avogadro has increasing support for parsing comp chem log files from a variety of packages, there may be times when it chokes on a file. If this happens, it's nice to have a backup option. This is where cclib can come in handy.

If you're on Windows, have Avogadro 1.0.0, cclib 1.0, OpenBabel 2.2.3 and its Python bindings (these latter shouldn't be necessary in a future version of Avogadro), just copy the following code into a .py file and save it in C:\Program Files\Avogadro\bin\extensionScripts.

When you next start Avogadro, it will have an "Open with cclib" Option in the Scripts menu.

from PyQt4.QtCore import *
from PyQt4.QtGui import *

import sys
sys.path.append("C:\\Python26\\Lib\\site-packages")
sys.path.append("C:\\Python26\\lib")

import cclib

import numpy
import Avogadro as avo
import openbabel as ob

class Extension(QObject):
def __init__(self):
QObject.__init__(self)

def name(self): # Recommended
return "Open with cclib"

def description(self): # Recommended
return "Open comp chem files with cclib"

def actions(self): # Required
actions = []

# Actions are just instances of the QAction class from PyQt4
action = QAction(self)
action.setText("Open with cclib")
actions.append(action)

return actions

def performAction(self, action, glwidget): # Required
# Only one action so need to check its identity

filename = str(QFileDialog.getOpenFileName())
if not filename: # You hit cancel
return None

logfile = cclib.parser.ccopen(filename)
data = logfile.parse()

obmol = ob.OBMol()
avomol = avo.molecules.addMolecule()
avoatoms = []
for atomcoord, atomno in zip(data.atomcoords[-1], data.atomnos):
coord = atomcoord.tolist()
obatom = ob.OBAtom()
obatom.SetAtomicNum(int(atomno))
obatom.SetVector(*coord)
obmol.AddAtom(obatom)

newatom = avomol.addAtom()
newatom.atomicNumber = int(atomno)
newatom.pos = atomcoord
avoatoms.append(newatom)

obmol.ConnectTheDots()
obmol.PerceiveBondOrders()
obmol.SetTotalSpinMultiplicity(data.mult)
obmol.SetTotalCharge(data.charge)

for bond in ob.OBMolBondIter(obmol):
newbond = avomol.addBond()
newbond.setBegin(avomol.atom(bond.GetBeginAtomIdx() - 1))
newbond.setEnd(avomol.atom(bond.GetEndAtomIdx() - 1))
newbond.order = bond.GetBO()

avo.GLWidget.current().molecule = avomol

return None

Notes:
  • There should be no need to have the OpenBabel Python bindings installed separately, but there is no way to access the OpenBabel library in Avogadro (at least on Windows). This prevents me, for example, from calling ConnectTheDots (I had to use my own installation of OpenBabel) or to add Conformers (which was what I wanted to do).
  • There are two Script menus after installing this plugin!
  • How do I emit a debug message?
  • The Python prompt in Avogadro requires you to "print" everything to see its value. This should not be necessary.
  • Cutting and pasting multiple lines into the Python prompt works fine, but it looks pretty weird as the prompt (>>>) is missing.

8 comments:

Geoff Hutchison said...

Noel... I asked you about the "print" issue in development. If you have any great ideas, we're open to them. Should the terminal just add "print repr(...)" around every line?

Geoff Hutchison said...

The rest of your questions are better asked on the mailing list for Tim. I don't know why OB isn't available, or why two "Scripts" menus appear, etc.

Noel O'Boyle said...

I've not quite sure exactly how the Python prompt decides what to print in general, but it does use repr for variables and literals.

Nilesh Tawari said...

Heelo Noel,
I have Avagadro version 1.0.1. How to plug cclib in this version.
Thanks
-nilesh

Nilesh Tawari said...

Hello Noel,
Thanks for useful blog.
I have Avogadro 1.0.1, how to plug cclib in it. I tried to save "extensionScripts.py" in C:\Program Files\Avogadro\bin
directory but didn't work.
-nilesh

Noel O'Boyle said...

@Nilesh: You misread the line: "just copy the following code into a .py file and save it in C:\Program Files\Avogadro\bin\extensionScripts."

extensionScripts is a folder. The Python file can be called anything, but it should be placed in this folder.

Nilesh Tawari said...

Ya did the same thing, i copied the script and saved in C:\Program Files\Avogadro\bin\extensionScripts with name extensionScripts.py but could not able to locate the "Open with cclib" Option in the Scripts menu.
-nilesh

Noel O'Boyle said...

I don't know what the problem is.