#!/usr/bin/python
#*******************************************************************************
#                                                                              *
#                                   Viewmol                                    *
#                                                                              *
#                            A U T O T E S T . P Y                             *
#                                                                              *
#                 Copyright (c) Joerg-R. Hill, October 2003                    *
#                                                                              *
#*******************************************************************************
#
# $Id: autotest.py,v 1.1 2003/11/07 13:21:02 jrh Exp $
# $Log: autotest.py,v $
# Revision 1.1  2003/11/07 13:21:02  jrh
# Initial revision
#
#

import fnmatch
import os
import sys
import string
import viewmol
import molecule
import label
import light
import energylevels
import history
import spectrum
import time

class autotest:
  label1=None
  label2=None
  mol=[]
  xPos=0
  yPos=0

  def run(self):
    viewmol.showWarnings(viewmol.__dict__['OFF'])
    self.label1=label.label()
    size=viewmol.getWindowSize()
    self.xPos=20
    self.yPos=size[1]-20
    self.label1.text("Automatic tests")
    self.label1.setColor(0.0, 0.0, 1.0, 0.0)
    self.label2=label.label()
    viewmolpath=os.getenv("VIEWMOLPATH")
    for file in ["examples/turbomole/control", "examples/gulp/urea.out", "examples/discover/benzene.cor", "examples/dmol/quartz.outmol", "examples/gamess/c10h8n2.out", "examples/gaussian/mmdc1.log", "examples/mopac/adamantane.out", "examples/pqs/cpcpm.out", "examples/pdb/gpc.pdb"]:
      self.testMolecule(viewmolpath + "/" + file)
    self.createMolecule()
    self.thermodynamics()
    self.label2.delete()
    self.label1.delete()
    fps=viewmol.getFramesPerSecond()
    viewmol.write("On average " + str(fps) + " frames per second were drawn.\n")
    viewmol.write("Viewmol will be terminated in 5 seconds ...")
    self.redrawWait(5)
    viewmol.quit()

  def testMolecule(self, file):
    try:
      viewmol.load(file)
    except ValueError:
      return

    labels=viewmol.getLabels()
    if (len(labels) != 2):
      viewmol.quit()

    mol=viewmol.getMolecules()
    if (len(mol) == 1):
      self.label1.translate(self.xPos, self.yPos, 0)
      self.label2.translate(self.xPos, self.yPos-20, 0)
      self.label1.text("Automatic tests: " + file)
      self.drawingModeTest(mol[0])
      self.moleculeTest(mol[0])
      self.label1.translate(20, 40, 0)
      self.label2.translate(20, 20 ,0)
      spect=mol[0].getSpectrum()
      if (spect != None):
        self.spectrumTest(mol[0], spect)
        del spect
      levels=mol[0].getEnergyLevels()
      if (levels != None):
        self.energyLevelsTest(mol[0], levels)
        del levels
      hist=mol[0].getHistory()
      if (hist != None):
        self.historyTest(mol[0], hist)
        del hist
      self.atomTest(mol[0])
      self.elementTest(mol[0])
      for i in ['car', 'arc', 'mol', 'tm']:
        viewmol.save(mol[0], "test.file", i)
        os.unlink("test.file")
      self.testSaving(viewmol, "molecule.test")
      viewmol.delete(mol[0])

  def drawingModeTest(self, mol):
    self.label2.text("Drawing mode tests")
    for i in ['WIREMODEL', 'STICKMODEL', 'BALLMODEL', 'CPKMODEL']:
      viewmol.model(viewmol.__dict__[i])
      viewmol.redraw()
    for i in ['DOT', 'LINE', 'SURFACE']:
      viewmol.drawingMode(viewmol.__dict__[i])
      viewmol.redraw()
    for i in ['PERSPECTIVE', 'ORTHO']:
      viewmol.projection(viewmol.__dict__[i])
      viewmol.redraw()
    self.label2.text("Drawing mode tests" + ": " + "Sphere resolution")
    light=viewmol.getLights()
    light[0].switch(viewmol.__dict__['OFF'])
    for i in range(4, 30, 2):
      viewmol.sphereResolution(i)
      light[1].rotate(0, 10*i, 0)
      viewmol.redraw()
    light[0].switch(viewmol.__dict__['ON'])
    self.label2.text("Drawing mode tests" + ": " + "Line width")
    viewmol.model(viewmol.__dict__['WIREMODEL'])
    for i in range(1, 5):
      viewmol.lineWidth(i)
      viewmol.redraw()
    viewmol.lineWidth(0)
#   viewmol.projection(viewmol.__dict__['PERSPECTIVE'])
    self.label2.text("Drawing mode tests" + ": " + "Colors and labels")
    viewmol.labelAtoms(viewmol.__dict__['ON'])
    color=viewmol.groundColor()
    viewmol.groundColor(0.0, 1.0, 0.0)
    self.redrawWait(2)
    viewmol.groundColor(color[0], color[1], color[2])
    color=viewmol.backgroundColor()
    viewmol.backgroundColor(0.0, 0.0, 0.0)
    self.redrawWait(2)
    viewmol.backgroundColor(color[0], color[1], color[2])
    viewmol.labelAtoms(viewmol.__dict__['OFF'])
    viewmol.redraw()

  def moleculeTest(self, mol):
    self.label2.text("Molecule tests" + ": " + "Rotation")
    for i in range(0, 360, 5):
      mol.rotate(i, 0, 0)
    for i in range(0, 360, 5):
      mol.rotate(0, i, 0)
    for i in range(0, 360, 5):
      mol.rotate(0, 0, i)
    mol.rotate(0, 0, 0)
    self.label2.text("Molecule tests" + ": " + "Translation and forces")
    mol.showForces(viewmol.__dict__['ON'])
    for i in range(0, 5):
      mol.translate(i, 0, 0)
    for i in range(0, 5):
      mol.translate(0, i, 0)
    for i in range(0, 2):
      mol.translate(0, 0, -i)
    hasCell=1
    try:
      mol.unitCell(viewmol.__dict__['OFF'])
    except ValueError:
      hasCell=0
    if hasCell == 1:
      mol.unitCell(viewmol.__dict__['ON'], 2, 2, 2)
      self.redrawWait(2)
      mol.unitCell(viewmol.__dict__['ON'], 1, 1, 1)
      mol.millerPlane(viewmol.__dict__['ON'], 1, 1, 1)
      self.redrawWait(2)
      mol.millerPlane(viewmol.__dict__['OFF'])
    mol.showForces(viewmol.__dict__['OFF'])
    mol.translate(-5, -5, 2)
    atoms=mol.getAtoms()
    bonds=mol.getBonds()
    title=mol.title()
    self.label2.text("Molecule tests" + ": " + str(len(atoms)) + " atoms and " + str(len(bonds)) + " bonds found in molecule " + title)
    self.redrawWait(2)
    l=mol.bondAverage(atoms[0])
    self.label2.text("Molecule tests" + ": " + "The average bond length for atom 1 is " + str("%.3f" % l) + " Å.")
    self.redrawWait(2)
    l=mol.bondLength(atoms[bonds[0][0]], atoms[bonds[0][1]])
    self.label2.text("Molecule tests" + ": " + "The bond between atom " + str(bonds[0][0]+1) + " and " + str(bonds[0][1]+1) + " is " + str("%.3f" % l) + " Å long.")
    self.redrawWait(2)
    self.label2.text("Molecule tests" + ": " + "The bond between atom " + str(bonds[0][0]+1) + " and " + str(bonds[0][1]+1) + " is now " + str("%.3f" % (l+1.0)) + " Å long.")
    mol.bondLength(atoms[bonds[0][0]], atoms[bonds[0][1]], l+1.0, 'Ang')
    self.redrawWait(2)
    mol.bondLength(atoms[bonds[0][0]], atoms[bonds[0][1]], l, 'Ang')
    found=0
    for i in range(1, len(bonds)):
      for j in range(i+1, len(bonds)):
        if bonds[i][0] == bonds[j][0] or bonds[i][1] == bonds[j][1] or bonds[i][0] == bonds[j][1] or bonds[i][1] == bonds[j][0]:
          if bonds[i][0] == bonds[j][0]:
            l=mol.bondAngle(atoms[bonds[i][1]], atoms[bonds[i][0]], atoms[bonds[j][1]])
            self.label2.text("Molecule tests" + ": " + "The bond angle formed by atoms " + str(bonds[i][1]+1) + ", " + str(bonds[i][0]+1) + " and " + str(bonds[j][1]+1) + " is " + str("%.1f" % l) + " deg.")
          elif bonds[i][1] == bonds[j][1]:
            l=mol.bondAngle(atoms[bonds[i][0]], atoms[bonds[i][1]], atoms[bonds[j][0]])
            self.label2.text("Molecule tests" + ": " + "The bond angle formed by atoms " + str(bonds[i][0]+1) + ", " + str(bonds[i][1]+1) + " and " + str(bonds[j][0]+1) + " is " + str("%.1f" % l) + " deg.")
          elif bonds[i][0] == bonds[j][1]:
            l=mol.bondAngle(atoms[bonds[i][1]], atoms[bonds[i][0]], atoms[bonds[j][0]])
            self.label2.text("Molecule tests" + ": " + "The bond angle formed by atoms " + str(bonds[i][1]+1) + ", " + str(bonds[i][0]+1) + " and " + str(bonds[j][0]+1) + " is " + str("%.1f" % l) + " deg.")
          else:
            l=mol.bondAngle(atoms[bonds[i][0]], atoms[bonds[i][1]], atoms[bonds[j][1]])
            self.label2.text("Molecule tests" + ": " + "The bond angle formed by atoms " + str(bonds[i][0]+1) + ", " + str(bonds[i][1]+1) + " and " + str(bonds[j][1]+1) + " is " + str("%.1f" % l) + " deg.")
          self.redrawWait(2)
	  found=1
          break
      if found == 1:
        break
    for i in range(1, len(bonds)):
      torsion=[-1, bonds[i][0], bonds[i][1], -1]
      for j in range(1, len(bonds)):
        if (bonds[i][0] == bonds[j][0]):
          torsion[0]=bonds[j][1]
        if (bonds[i][0] == bonds[j][1]):
          torsion[0]=bonds[j][0]
        if (bonds[i][1] == bonds[j][0]):
          torsion[3]=bonds[j][1]
        if (bonds[i][1] == bonds[j][1]):
          torsion[3]=bonds[j][0]
      if torsion[0] != -1 and torsion[3] != -1:
        break
    l=mol.torsionAngle(atoms[torsion[0]], atoms[torsion[1]], atoms[torsion[2]], atoms[torsion[3]])
    if l <= 360.0:
      self.label2.text("Molecule tests" + ": " + "The torsion angle formed by atoms " + str(torsion[0]+1) + ", " + str(torsion[1]+1) + ", " + str(torsion[2]+1) + ", and " + str(torsion[3]+1) + " is " + str("%.1f" % l) + " deg.")
      self.redrawWait(2)
      mol.torsionAngle(atoms[torsion[0]], atoms[torsion[1]], atoms[torsion[2]], atoms[torsion[3]], l+90.)
      self.label2.text("Molecule tests" + ": " + "The torsion angle formed by atoms " + str(torsion[0]+1) + ", " + str(torsion[1]+1) + ", " + str(torsion[2]+1) + ", and " + str(torsion[3]+1) + " is now " + str("%.1f" % (l+90.)) + " deg.")
      self.redrawWait(2)
      mol.torsionAngle(atoms[torsion[0]], atoms[torsion[1]], atoms[torsion[2]], atoms[torsion[3]], l)

    for i in ['ENTHALPY', 'ENTROPY', 'GIBBS_ENERGY', 'HEAT_CAPACITY']:
      t=mol.getThermodynamics(molecule.__dict__[i], molecule.__dict__['TRANSLATION'])
      r=mol.getThermodynamics(molecule.__dict__[i], molecule.__dict__['ROTATION'])
      if i == 'ENTHALPY' or i == 'GIBBS_ENERGY':
        p=mol.getThermodynamics(molecule.__dict__[i], molecule.__dict__['PV'])
      else:
        p=0
      v=mol.getThermodynamics(molecule.__dict__[i], molecule.__dict__['VIBRATION'])
      total=mol.getThermodynamics(molecule.__dict__[i], molecule.__dict__['TOTAL'])
      self.label2.text("Molecule tests" + ": " + str(i) + " = " +str(t) + " + " + str(r) + " + " + str(p) + " + " + str(v) + " = " + str(total))

  def spectrumTest(self, mol, spect):
    waveNumbers=mol.getWavenumbers()
    max=0
    j=0
    for i in range(1, len(waveNumbers)):
      if waveNumbers[i][1] > max:
        max=waveNumbers[i][1]
	j=i
    title=mol.title()
    self.label2.text("Spectrum tests" + ": " + str(len(waveNumbers)) + " wave numbers found in molecule " + title)
    spect.show()
    spect.zoom(0, 0, 5000, 100)
    spect.display(spectrum.__dict__['ARROWS'])
    self.redrawWait(2)
    self.label2.text("Spectrum tests")
    spect.mode(j)
    self.redrawWait(1)
    for atom in mol.getAtoms():
      if (atom.getElement().getSymbol() == 'H'):
        atom.neutronScatteringFactor(1.0)
    for i in ['ALLMODES', 'IRMODES', 'RAMANMODES', 'INSMODES', 'IRMODES']:
      spect.type(spectrum.__dict__[i])
      self.redrawWait(2)
    for i in ['ANIMATE', 'ARROWS', 'DISTORT', 'ARROWS']:
      spect.display(spectrum.__dict__[i])
      amplitude=spect.amplitude()
      for j in range(1, 3):
        spect.amplitude(j*0.3)
        self.redrawWait(2)
      spect.amplitude(amplitude)
    spect.deselect()
    for i in ['LINES', 'GAUSSIANS']:
      spect.style(spectrum.__dict__[i])
      self.redrawWait(2)
    sf=spect.scaleFactor()
    spect.scaleFactor(0.9)
    self.redrawWait(2)
    spect.scaleFactor(sf)
    for i in range(50, 1000, 50):
      spect.zoom(i, 0, 5000-i, 100)
    self.testSaving(spect, "spectrum.test")
    spect.style(spectrum.__dict__['LINES'])

  def energyLevelsTest(self, mol, levels):
    self.label2.text("Energy level tests")
    levels.show()
    for i in ['HARTREE', 'KJ/MOL', 'EV', '1/CM']:
      levels.unit(energylevels.__dict__[i])
      self.redrawWait(2)
    levels.mode(energylevels.__dict__['DENSITY_OF_STATES'])
    viewmol.redraw()
    r=levels.resolution()
    levels.resolution(0.5)
    self.redrawWait(2)
    levels.resolution(r)
    levels.mode(energylevels.__dict__['ENERGY_LEVELS'])
    atoms=mol.getAtoms()
    try:
      self.label2.text("Energy level tests" + ": 1s basis function on atom 1")
      mol.selectBasisfunction(atoms[0], "s", 1)
      mol.showElectrons(molecule.__dict__['BASIS_FUNCTION'], 20, molecule.__dict__['IP_LINEAR'])
      hasBasis=1
    except ValueError:
      self.label2.text("Energy level tests" + ": No basis functions found")
      hasBasis=0
    self.redrawWait(2)
    energies=mol.getMOEnergies()
    j=0
    for i in energies:
      if i[0] > 0.0:
        break
      j=j+1
    levels.selectMO(j-1)
    self.label2.text("Energy level tests" + ": HOMO: " + str(energies[j-1][0]) + " Hartrees")
    if hasBasis == 1:
      viewmol.isosurface(0.05)
      mol.showElectrons(molecule.__dict__['MO'], 10, molecule.__dict__['IP_LINEAR'])
      self.redrawWait(2)
    levels.deselect()
    self.label2.text("Energy level tests" + ": Testing saving")
    self.testSaving(levels, "mo.test")

  def historyTest(self, mol, hist):
    self.label2.text("Optimization history tests")
    hist.show()
    hist.showEnergy(viewmol.__dict__['OFF'])
    self.redrawWait(2)
    hist.showGradient(viewmol.__dict__['OFF'])
    hist.showEnergy(viewmol.__dict__['ON'])
    self.redrawWait(2)
    hist.showGradient(viewmol.__dict__['ON'])
    hist.showScales(viewmol.__dict__['OFF'])
    self.redrawWait(2)
    hist.showScales(viewmol.__dict__['ON'])
    nhist=hist.iteration()
    for i in range(1, nhist):
      hist.iteration(i)
      self.redrawWait(1)
    hist.animate(viewmol.__dict__['ON'])
    hist.animate(viewmol.__dict__['OFF'])
    hist.iteration(nhist)
    self.testSaving(hist, "history.test")

  def atomTest(self, mol):
    atoms=mol.getAtoms()
    name=atoms[0].getElement().getSymbol()
    coord=atoms[0].coordinates()
    line="%10.6f, %10.6f, %10.6f" % (coord[0], coord[1], coord[2])
    self.label2.text("Atom tests" + ": Atom 1 is " + name + " at " + line)
    viewmol.model(viewmol.__dict__['CPKMODEL'])
    rad=atoms[0].radius()
    atoms[0].radius(rad+1.0)
    self.redrawWait(2)
    atoms[0].radius(rad)
    radScale=atoms[0].radiusScaleFactor()
    for i in range(1, 5):
      atoms[0].radiusScaleFactor(radScale+i*0.1)
      self.redrawWait(2)
    atoms[0].radiusScaleFactor(radScale)
    atoms[0].replace('Fe')
    self.redrawWait(2)
    atoms[0].delete()
    viewmol.model(viewmol.__dict__['WIREMODEL'])

  def elementTest(self, mol):
    atoms=mol.getAtoms()
    elem=atoms[0].getElement()
    symbol=elem.getSymbol()
    self.label2.text("Element tests" + ": Changing colors for element " + symbol)
    color=elem.darkColor()
    elem.darkColor(0.0, 0.0, 0.0)
    self.redrawWait(1)
    elem.darkColor(color[0], color[1], color[2])
    color=elem.lightColor()
    elem.lightColor(1.0, 1.0, 1.0)
    self.redrawWait(1)
    elem.lightColor(color[0], color[1], color[2])
    color=elem.emissionColor()
    elem.emissionColor(0.0, 1.0, 0.0)
    self.redrawWait(1)
    elem.emissionColor(color[0], color[1], color[2])
    color=elem.ambientColor()
    elem.ambientColor(1.0, 1.0, 1.0)
    self.redrawWait(1)
    elem.ambientColor(color[0], color[1], color[2])
    color=elem.specularColor()
    elem.specularColor(1.0, 0.0, 0.0)
    self.redrawWait(1)
    elem.specularColor(color[0], color[1], color[2])
    shin=elem.shininess()
    elem.shininess(0)
    self.redrawWait(1)
    elem.shininess(shin)
    tp=elem.transperancy()
    elem.transperancy(0.5)
    self.redrawWait(1)
    elem.transperancy(tp)
    del elem
    del atoms

  def createMolecule(self):
    self.label1.text("Building new molecule")
    mol=molecule.molecule()
    mol.addAtom('C')
    atoms=mol.getAtoms()
    mol.addAtom('O', atoms[0])
    mol.addAtom('H', atoms[0])
    mol.addAtom('H', atoms[0])
    mol.addAtom('H', atoms[0])
    atoms=mol.getAtoms()
    mol.addAtom('H', atoms[1])
    for i in range(0, 360, 5):
      mol.rotate(i, 0, 0)
    viewmol.delete(mol)

  def thermodynamics(self):
    self.label1.text("Thermodynamics")
    viewmolpath=os.getenv("VIEWMOLPATH")
    molecule1=viewmol.load(viewmolpath + "/examples/reaction/hio3.outmol")
    molecule1.reaction(molecule.__dict__['PRODUCT'])
    molecule1.translate(-1.0, 1.0, 0.0)
    molecule2=viewmol.load(viewmolpath + "/examples/reaction/i2.outmol")
    molecule2.reaction(molecule.__dict__['REACTANT'])
    molecule2.rotate(90.0, 0.0, 0.0)
    molecule2.translate(1.0, 1.0, 0.0)
    molecule3=viewmol.load(viewmolpath + "/examples/reaction/hno3.outmol")
    molecule3.reaction(molecule.__dict__['REACTANT'])
    molecule3.translate(-1.0, -1.0, 0.0)
    molecule4=viewmol.load(viewmolpath + "/examples/reaction/no.outmol")
    molecule4.reaction(molecule.__dict__['PRODUCT'])
    molecule4.rotate(90.0, 0.0, 0.0)
    molecule4.translate(1.0, -1.0, 0.0)
    molecule5=viewmol.load(viewmolpath + "/examples/reaction/h2o.outmol")
    molecule5.reaction(molecule.__dict__['PRODUCT'])
    viewmol.showThermodynamics(viewmol.__dict__['REACTION'])
    self.redrawWait(5)
    for i in viewmol.getMolecules():
      viewmol.delete(i)

  def testSaving(self, object, file):
    for i in ['TIFF', 'PNG', 'HPGL', 'POSTSCRIPT']:
      self.label2.text("Save tests" + ": Saving as " + i)
      try:
        object.saveDrawing(viewmol.__dict__[i], file)
      except IOError:
        pass
      os.unlink(file)

  def redrawWait(self, duration):
    viewmol.redraw()
    time.sleep(duration)

  def register(self, language):
    viewmol.registerMenuItem("Automatic test")

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