Tuesday 17 July 2007

ccWeb - A lightweight web service for parsing computational chemistry


cclib is a Python library for enabling package-independent computational chemistry algorithms. At its core is a parser for comp chem output files. The latest release, cclib 0.7, can extract information which can be used, for example, to implement charge decomposition analysis, or population analysis, or to convolute the Raman spectrum.

Let's imagine that you cannot or don't want to install cclib, but you would like to be able to access the parsed data from a comp chem output file (e.g. using a different programming language, or in a workflow environment like Taverna). The solution is ccWeb, a web service that you can send your comp chem file to, and it will send you back the result.

Specifically, you need to POST to http://www.redbrick.dcu.ie/~noel/cclib/ccWeb.py with the contents of your logfile in the parameter 'logfile'. In Python, this is done as follows:

import urllib

myurl = "http://www.redbrick.dcu.ie/~noel/cclib/ccWeb.py"
logfiletext = open("mylogfile.log", "r").read()
params = urllib.urlencode({'logfile': logfiletext})
webconnection = urllib.urlopen(myurl, params)
result = webconnection.read()
The results are returned in JSON format as a dictionary of parsed attributes, which can be directly evaluated as an expression in Python and Javascript, or more securely, parsed using a third-party library. Here's how to process the result in Python. If the third-party library, simplejson, is installed, it will be used to safely parse the results:

try:
import simplejson
except:
simplejson = None

if simplejson:
data = simplejson.loads(result)
else:
result = result.strip()
assert result[0] == '{' and result[-1] == '}', \
"Don't trust this JSON!"
data = eval(result)

The actual code for the webservice is as follows:

#!/usr/bin/env python

import cgitb; cgitb.enable() # For traceback information
import os
import cgi
import tempfile
import logging

import simplejson

from cclib.parser import ccopen

fields = cgi.FieldStorage()


if fields.has_key("logfile"):

handle, filename = tempfile.mkstemp()
tmpfile = open(filename, "w")
print >> tmpfile, fields.getfirst("logfile")
tmpfile.close()

failed = False
try:
a = ccopen(filename)
a.logger.setLevel(logging.ERROR)
data = a.parse()
except:
failed = True
os.close(handle)
os.remove(filename)

if not failed:
print "Content-Type: application/json; charset=utf-8"
print "Status: 200 Ok"
print
print data.writejson()
else:
print "Content-Type: application/json; charset=utf-8"
print "Status: 500 Internal Server Error"
print
print simplejson.dumps({'error': 'cclib was not able \
to parse this logfile without errors. Please \
send an email to cclib-users@lists.sf.net.'})
else:
print "Content-Type: application/json; charset=utf-8"
print "Status: 400 Bad Request"
print
print simplejson.dumps({'error': 'You need to set the \
value of the logfile parameter to the contents of \
a logfile'})
Note: ccWeb is based on the development version of the forthcoming cclib 0.8.

No comments: