1# Pizza.py toolkit, www.cs.sandia.gov/~sjplimp/pizza.html
2# Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories
3#
4# Copyright (2005) Sandia Corporation.  Under the terms of Contract
5# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
6# certain rights in this software.  This software is distributed under
7# the GNU General Public License.
8
9# vmd tool
10
11# Minimalistic VMD embedding for Pizza.py
12# (c) 2010 Axel Kohlmeyer <akohlmey@gmail.com>
13# This class will replace the VMD startup script,
14#   open a pipe to the executable,
15#   and feed it Tcl command lines one at a time
16
17oneline = "Control VMD from python"
18
19docstr = """
20v = vmd()		       start up VMD
21v.stop()		       shut down VMD instance
22v.clear()		       delete all visualizations
23
24v.rep(style)		       set default representation style. One of
25			       (Lines|VDW|Licorice|DynamicBonds|Points|CPK)
26v.new(file[,type])   	       load new file (default file type 'liggghtstrj')
27v.data(file[,atomstyle])       load new data file (default atom style 'full')
28v.replace(file[,type])	       replace current frames with new file
29v.append(file[,type]) 	       append file to current frame(s)
30v.set(snap,x,y,z,(True|False)) set coordinates from a pizza.py snapshot to new or current frame
31
32v.frame(frame)		       set current frame
33v.flush()		       flush pending input to VMD and update GUI
34v.read(file)		       read Tcl script file (e.g. saved state)
35
36v.enter()		       enter interactive shell
37v.debug([True|False])	       display generated VMD script commands?
38"""
39
40# History
41#   11/10, Axel Kohlmeyer (Temple U): original version
42
43# Imports and external programs
44
45import types, os
46import numpy
47
48try: from DEFAULTS import PIZZA_VMDNAME
49except: PIZZA_VMDNAME = "vmd"
50try: from DEFAULTS import PIZZA_VMDDIR
51except: PIZZA_VMDDIR = "/usr/local/lib/vmd"
52try: from DEFAULTS import PIZZA_VMDDEV
53except: PIZZA_VMDDEV = "win"
54try: from DEFAULTS import PIZZA_VMDARCH
55except: PIZZA_VMDARCH = "LINUX"
56
57# try these settings for a Mac
58#PIZZA_VMDNAME = "vmd"
59#PIZZA_VMDDIR = "/Applications/VMD\ 1.8.7.app/Contents/vmd"
60#PIZZA_VMDDEV = "win"
61#PIZZA_VMDARCH = "MACOSXX86"
62
63try: import pexpect
64except:
65  print "pexpect from http://pypi.python.org/pypi/pexpect", \
66      "is required for vmd tool"
67  raise
68
69# Class definition
70
71class vmd:
72
73  # --------------------------------------------------------------------
74
75  def __init__(self):
76    self.vmddir = PIZZA_VMDDIR
77    self.vmdexe = PIZZA_VMDDIR + '/' + PIZZA_VMDNAME + '_' + PIZZA_VMDARCH
78    # these are all defaults copied from the vmd launch script
79    os.environ['VMDDIR'] = PIZZA_VMDDIR
80    os.environ['VMDDISPLAYDEVICE'] = PIZZA_VMDDEV
81    os.environ['VMDSCRPOS']    = "596 190"
82    os.environ['VMDSCRSIZE']   = "669 834"
83    os.environ['VMDSCRHEIGHT'] = "6.0"
84    os.environ['VMDSCRDIST']   = "-2.0"
85    os.environ['VMDTITLE']     = "on"
86    os.environ['TCL_LIBRARY'] = PIZZA_VMDDIR + "/scripts/tcl"
87    os.environ['STRIDE_BIN']  = PIZZA_VMDDIR + "/stride_" + PIZZA_VMDARCH
88    os.environ['SURF_BIN']    = PIZZA_VMDDIR + "/surf_" + PIZZA_VMDARCH
89    os.environ['TACHYON_BIN'] = PIZZA_VMDDIR + "/tachyon_" + PIZZA_VMDARCH
90    ldpath = os.environ.get('LD_LIBRARY_PATH','')
91    if ldpath == '':
92      os.environ['LD_LIBRARY_PATH'] = PIZZA_VMDDIR
93    else:
94      os.environ['LD_LIBRARY_PATH'] = ldpath + ':' + PIZZA_VMDDIR
95    ldpath = os.environ.get('LD_LIBRARY_PATH','')
96    if ldpath == '':
97      os.environ['PYTHONPATH'] = PIZZA_VMDDIR
98    else:
99      os.environ['PYTHONPATH'] = PIZZA_VMDDIR + "/scripts/python"
100    self.debugme = False
101    # open pipe to vmd and wait until we have a prompt
102    self.VMD = pexpect.spawn(self.vmdexe)
103    self.VMD.expect('vmd >')
104
105  # --------------------------------------------------------------------
106  # post command to vmd and wait until the prompt returns.
107  def __call__(self,command):
108    if self.VMD.isalive():
109      self.VMD.sendline(command)
110      self.VMD.expect('vmd >')
111      if self.debugme:
112        print "call+result:"+self.VMD.before
113    return
114
115  # --------------------------------------------------------------------
116  # exit VMD
117  def stop(self):
118    self.__call__("quit")
119    del self.VMD
120
121  # --------------------------------------------------------------------
122  # force VMD display and GUI update.
123  def flush(self):
124    self.__call__('display update ui')
125
126  # --------------------------------------------------------------------
127  # turn on debugging info
128  def debug(self,status=True):
129    if status and not self.debugme:
130      print 'Turning vmd.py debugging ON.'
131    if not status and self.debugme:
132      print 'Turning vmd.py debugging OFF.'
133    self.debugme = status
134
135  # --------------------------------------------------------------------
136  # emulate a regular tcl command prompt
137  def enter(self,mode='tcl'):
138    self.__call__('menu main off')
139    self.__call__('menu main on')
140    while 1:
141      try:
142        command = raw_input("vmd > ")
143      except EOFError:
144        print "(EOF)"
145        self.__call__('menu main off')
146        return
147      if command == "quit" or command == "exit":
148        self.__call__('menu main off')
149        return
150      if command == "gopython":
151        print "gopython not supported here"
152        continue
153      self.__call__(command)
154
155  # --------------------------------------------------------------------
156  # read and execute tcl script file (e.g. a saved state)
157  def read(self,filename):
158    self.__call__('play ' + filename)
159    self.flush()
160
161  # --------------------------------------------------------------------
162  # remove all molecules, data and visualizations
163  def clear(self):
164    self.__call__("mol delete all")
165
166  # --------------------------------------------------------------------
167  # navigate to a given frame
168  def rep(self,style='Lines'):
169    if style == 'Lines' or style == 'VDW' or style == 'Licorice' \
170       or style == 'DynamicBonds' or style == 'Points' or style == 'CPK':
171      self.__call__('mol default style ' + style)
172  # --------------------------------------------------------------------
173  # navigate to a given frame
174  def frame(self,framespec):
175    self.__call__('animate goto ' + str(framespec))
176
177  # --------------------------------------------------------------------
178  # load a new molecule from a file supported by a molfile plugin
179  def new(self,filename,filetype='liggghtstrj'):
180    self.__call__('mol new ' + filename + ' type ' + filetype + ' waitfor all')
181    self.flush()
182
183  # --------------------------------------------------------------------
184  # load a new molecule from a data file via the topotools plugin
185  def data(self,filename,atomstyle='full'):
186    self.__call__('package require topotools 1.0')
187    self.__call__('topo readliggghtsdata ' + filename + ' ' + atomstyle)
188    self.flush()
189
190  # --------------------------------------------------------------------
191  # append all frames from a given file to the current molecule
192  def append(self,filename,filetype='liggghtstrj'):
193    self.__call__('set tmol [molinfo top]')
194    self.__call__('array set viewpoints {}')
195    self.__call__('foreach mol [molinfo list] { set viewpoints($mol) [molinfo $mol get { center_matrix rotate_matrix scale_matrix global_matrix}]}')
196    self.__call__('mol addfile ' + filename + ' mol $tmol type ' + filetype + ' waitfor all')
197    self.__call__('foreach mol [molinfo list] { molinfo $mol set {center_matrix rotate_matrix scale_matrix global_matrix} $viewpoints($mol)}')
198    self.flush()
199
200  # --------------------------------------------------------------------
201  # replace all frames of a molecule with those from a given file
202  def update(self,filename,filetype='liggghtstrj'):
203    self.__call__('set tmol [molinfo top]')
204    self.__call__('array set viewpoints {}')
205    self.__call__('foreach mol [molinfo list] {set viewpoints($mol) [molinfo $mol get { center_matrix rotate_matrix scale_matrix global_matrix}]}')
206    self.__call__('animate delete all $tmol')
207    self.__call__('mol addfile ' + filename + ' mol $tmol type ' + filetype + ' waitfor all')
208    self.__call__('foreach mol [molinfo list] {molinfo $mol set {center_matrix rotate_matrix scale_matrix global_matrix} $viewpoints($mol)}')
209    self.flush()
210
211  # --------------------------------------------------------------------
212  # add or overwrite coordinates with coordinates in a snapshot
213  def set(self,snap,x,y,z,append=True):
214    self.__call__('set vmdsel [atomselect top all]')
215    if append:
216      self.__call__('animate dup [molinfo top]')
217    cmd = '$vmdsel set {x y z} {'
218    for idx in range(0,snap.natoms):
219      cmd += ' {'+str(snap[idx,x])+' '+str(snap[idx,y])+' '+str(snap[idx,z])+'}'
220    cmd += '}'
221    self.__call__(cmd)
222    self.__call__('$vmdsel delete ; unset vmdsel')
223    self.flush()
224