#!/usr/bin/python
#*******************************************************************************
#                                                                              *
#                                   Viewmol                                    *
#                                                                              *
#                                 U F F . P Y                                  *
#                                                                              *
#                 Copyright (c) Joerg-R. Hill, October 2003                    *
#                                                                              *
#*******************************************************************************
#
# $Id: uff.py,v 1.1 2003/11/07 13:20:17 jrh Exp $
# $Log: uff.py,v $
# Revision 1.1  2003/11/07 13:20:17  jrh
# Initial revision
#
#
import os
import string
import viewmol
import molecule
import atom
import label

class uff:
  def writeFiles(self, dir, mol):
    self.writeCoordinateFile(dir, mol)
    self.writeTopologyFile(dir, mol)
    self.writeControlFile(dir)

  def writeCoordinateFile(self, dir, mol):
    coordFile=open(dir+"/coord", "w")
    coordFile.write("$coord\n")
    for i in mol.getAtoms():
      coords=i.coordinates()
      name=i.getElement().getSymbol()
      line="%22.14f%22.14f%22.14f %s\n" % (coords[0]/0.52917706, coords[1]/0.52917706, coords[2]/0.52917706, name)
      coordFile.write(line)
    coordFile.write("$end\n")
    coordFile.close()

  def writeTopologyFile(self, dir, mol):
    # Build connectivity from bonds
    connectivity={}
    for i in mol.getBonds():
      if not connectivity.has_key(i[0]):
        connectivity[i[0]]=[]
      connectivity[i[0]].append(i[1])
      if not connectivity.has_key(i[1]):
        connectivity[i[1]]=[]
      connectivity[i[1]].append(i[0])
    # Write topology file
    topologyFile=open(dir+"/ufftopology", "w")
    topologyFile.write("$ufftopology\nnxtnei12\n")
    # Only the nxtnei12 data group is necessary, Turbomole's
    # UFF module can determine the other ones automatically
    for i in connectivity.keys():
      self.writeList(topologyFile, i, connectivity[i])

  def writeList(self, topologyFile, which, list):
    line=" %5d %5d\n" % (which+1, len(list))
    topologyFile.write(line)
    line="     "
    for i in list:
      word=" %5d" % (i+1)
      line=line + word
    line=line + "\n"
    topologyFile.write(line)

  def writeControlFile(self, dir):
    controlFile=open(dir+"/control", "w")
    controlFile.write("$title\n")
    controlFile.write("Test\n")
    controlFile.write("$operating system unix\n")
    controlFile.write("$symmetry c1\n")
    controlFile.write("$coord file=coord\n")
    controlFile.write("$uff\n")
    controlFile.write("       500         1          1 ! maxcycle,modus,nqeq\n")
    controlFile.write("    111111                      ! iterm\n")
    controlFile.write("  0.10D-07  0.10D-04            ! econv,gconv\n")
    controlFile.write("      0.00  1.10                ! qtot,dfac\n")
    controlFile.write("  0.10D+03  0.10D-04       0.30 ! epssteep,epssearch,dqmax\n")
    controlFile.write("        25      0.10       0.00 ! mxls,dhls,ahls\n")
    controlFile.write("      1.00      0.00       0.00 ! alpha,beta,gamma\n")
    controlFile.write("         F         F          F ! transform,lnumhess,lmd\n")
    controlFile.write("$ufftopology file=ufftopology\n")
    controlFile.write("$end\n")
    controlFile.close()

  def runUFF(self, dir):
    size=viewmol.getWindowSize()
    energy=label.label()
    energy.translate(20, size[1]-20, 0)
    energy.text("UFF energy")
    for line in os.popen("cd "+dir+"; uff").readlines():
      if line[0:10] == "UFF energy":
        energy.text(line)
    os.remove(dir+"/control")
    os.remove(dir+"/ufftopology")
    os.remove(dir+"/uffgradient")
    os.remove(dir+"/uffgradx")
    try:
      os.remove(dir+"/uffconverged")
      os.remove(dir+"/uffhessian0-0")
    except OSError:
      viewmol.write("uff did not converge")
    energy.delete()

  def readResults(self, dir, mol):
    coordFile=open(dir+"/coord", "r")
    line=coordFile.readline()
    for i in mol.getAtoms():
      line=coordFile.readline()
      if line[0:4] != "$end":
        words=string.split(line)
        i.coordinates(float(words[0])*0.52917706, float(words[1])*0.52917706, float(words[2])*0.52917706)
    coordFile.close()
    os.remove(dir+"/coord")

  def run(self):
    dir="/tmp"
    for i in viewmol.getMolecules():
      self.writeFiles(dir, i)
      self.runUFF(dir)
      self.readResults(dir, i)

  def register(self, language):
    viewmol.registerMenuItem("UFF optimization")

#-------------------------
if __name__ == '__main__':
  optimization=uff()
  uff.run(optimization)
