#
#    This file is part of the CCP1 Graphical User Interface (ccp1gui)
# 
#   (C) 2002-2007 CCLRC Daresbury Laboratory
# 
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
# 
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
# 
#   You should have received a copy of the GNU General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
"""Implements the MOLPRO specific calculation (Calc) and
calculation editor (CalcEd) classes
"""
import os,sys
if __name__ == "__main__":
    # Need to add the gui directory to the python path so 
    # that all the modules can be imported
    gui_path = os.path.split(os.path.dirname( os.path.realpath( __file__ ) ))[0]
    sys.path.append(gui_path)

import string

# may need:
# setenv LD_PRELOAD /usr/lib/libexpat.so
# see  http://sourceforge.net/tracker/index.php?func=detail&aid=1075984&group_id=5470&atid=105470
import xml.sax

# Import our modules
import objects.field
import jobmanager
import viewer.help
import qm
import calc
import objects.file
import qmtools
import tools

from viewer.paths import paths,find_exe
from molproxmlcontenthandler import MolproXMLContentHandler


# Import external modules
import Tkinter
import Pmw
import tkFileDialog


MENU_ENER  = "Energy"
MENU_GRAD  = "Gradient"
MENU_OPT   = "Geometry Optimisation"

class MOLPROCalc(qm.QMCalc):
    """MOLPRO specifics."""
    def __init__(self, **kw):

        qm.QMCalc.__init__(self,**kw)

        self.debug=1

        self.set_parameter("task",MENU_ENER)
        self.set_program('MOLPRO')
        self.set_title('This file was generated by the CCP1 GUI (molpro interface)')
        self.set_name('unnamed')
        #
        # see the basismanager for the form of 
        # the basis structure
        #
        self.set_parameter("default_basis","cc-pVDZ")
        self.set_parameter("basis",None)
        ####self.set_input("basis_atom",{})
        self.set_parameter("ECP",None)

        ####self.set_input("ECP_atom",{})
        self.set_parameter("dft_functional","BLYP")

        #Guess and Restart parameters
        self.set_parameter('restart',0)
        self.set_parameter('restart_type',0)

##         self.set_parameter('ed0_keep',0)
##         self.set_parameter('ed0_path','?')
##         self.set_parameter('ed2_keep',0)
##         self.set_parameter('ed2_specify',0)
##         self.set_parameter('ed2_path','?')
##         self.set_parameter('ed3_keep',0)
##         self.set_parameter('ed3_specify',0)
##         self.set_parameter('ed3_path',0)
##         self.set_parameter('ed7_keep',0)
##         self.set_parameter('ed7_specify',0)
##         self.set_parameter('ed7_path','?')
##         self.set_parameter('ed14_keep',0)
##         self.set_parameter('ed14_path','?')

        self.set_parameter('enter_sect1',0)
        self.set_parameter('enter_sect2',0)
#        self.set_parameter('super','full conventional')
#        self.set_parameter('bypass',0)
        self.set_parameter("guess_method","Compute")
        self.set_parameter("guess_comp","atoms")
        self.set_parameter("guess_sect1",1)
        self.set_parameter("guess_sect2",2)
        self.set_parameter("getq_block1",1)
        self.set_parameter("getq_block2",1)
        self.set_parameter("getq_sect1",1)
        self.set_parameter("getq_sect2",2)
        
        self.set_parameter("scf_method","RHF")
        self.set_parameter("scf_maxcyc",50)
        self.set_parameter("scf_threshold",6)
        self.set_parameter("scf_level_init",1.0)
        self.set_parameter("scf_level_it",10)
        self.set_parameter("scf_level_final",0.1)
        self.set_parameter("scf_bypass",0)
        self.set_parameter("dft_grid","medium")
        self.set_parameter("dft_weights","MHL8SSF")
        self.set_parameter("dft_grid_atom",{}) #This isn't used anywhere yet

        self.set_parameter("dft_radialgrid","default")
        self.set_parameter("dft_angulargrid","default")
        self.set_parameter("dft_radialgridpoints","100")
        self.set_parameter("dft_angulargridpoints","110")
        self.set_parameter("dft_jfit",0)
        self.set_parameter("dft_jbas","A1DGAUSS")
        self.set_parameter("dft_schwarz",6)
        
        self.set_parameter("postscf_method","None")

##         self.set_parameter("predirectives",
##              "#file ed3 ed3 keep\n"+
##              "#memory 20000000\n"+
##              "#time 600\n")
##         self.set_parameter("classidirectives",
##              "#restart new\n#super off nosym\n"+
##              "#integral high\n#accuracy 30 15\n#bypass one two\n"+
##              "#mfile memory\n")
##         self.set_parameter("predirectives","")
        self.set_parameter("basisdirectives","")
##         self.set_parameter("classidirectives","")
##         self.set_parameter("classiidirectives","")

        self.set_parameter("ana_homolumo",0)
        self.set_parameter("ana_homolumo1",0)
        self.set_parameter("ana_homolumo2",0)
        self.set_parameter("ana_homolumo3",0)
        self.set_parameter("ana_homolumo4",0)
        self.set_parameter("ana_homolumo5",0)
        self.set_parameter("ana_orbitals",[])
        self.set_parameter("ana_chargeden",0)
        self.set_parameter("ana_chargedengrad",0)
        self.set_parameter("ana_spinden",0)
        self.set_parameter("ana_frequencies",0)
        self.set_parameter("ana_hessian",0)
        self.set_parameter("ana_potential",0)
        self.set_parameter("ana_diffden",0)

        self.set_parameter('direct_scf',0);
        self.set_parameter('symmetry',1)
        self.set_parameter('adaption',0)
        self.set_parameter('use_ri',0)
        self.set_parameter('accuracy','medium')
        
        #Geometry optimisation parameters
        self.set_parameter('optimiser','Cartesian')
        self.set_parameter('opt_jorgensen',0)
        self.set_parameter('opt_hess_update','default')
        self.set_parameter('opt_powell',0)
        self.set_parameter('opt_min_hess',0)
        self.set_parameter('opt_max_hess',0)
        self.set_parameter('opt_rfo',0)
        self.set_parameter('opt_rfomode','on')

        field = objects.field.Field()
        field.dim[0] = 11
        field.dim[1] = 11
        field.dim[2] = 11
        self.set_parameter('grid',field)
        self.field_sized=0

        self.basis_manager = qmtools.BasisManager()
        
        #Set up the keyword basis sets for MOLPRO
        m = self.basis_manager
        m.define_keyword_basis('sto-3g',['h','he','li',' be','b','c','n','o','f','ne',
                                        'na','mg','al','si','p','s','cl','ar',
                                        'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                        'ga','ge','as','se','br','kr',
                                        'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                        'in','sn','sb','te','i','xe'],ecp=0)
        m.define_keyword_basis('sv 3-21G',['h','he','li','be','b','c','n','o','f','ne',
                                           'na','mg','al','si','p','s','cl','ar',
                                           'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                           'ga','ge','as','se','br','kr',
                                           'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                           'in','sn','sb','te','i','xe'],ecp=0)
        m.define_keyword_basis('sv 4-21G',['h','he','li','be','b','c','n','o','f','ne'],ecp=0)
        m.define_keyword_basis('sv 4-31G',['h','b','c','n','o','f','ne',
                                           'p','s','cl','ar'],ecp=0)#check li & be -see molpro manual-3.12 table3
        m.define_keyword_basis('sv 5-31G',['h','b','c','n','o','f'],ecp=0)#not sure about li & be -see molpro
        m.define_keyword_basis('sv 6-21G',['h','he','li','be','b','c','n','o','f','ne',
                                           'na','mg','al','si','p','s','cl','ar'],ecp=0)
        m.define_keyword_basis('sv 6-31G',['h','li','be','b','c','n','o','f','ne',
                                           'na','mg','al','si','p','s','cl','ar',
                                           'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn'],ecp=0)
        m.define_keyword_basis('sv 6-31G*',['h','li','be','b','c','n','o','f','ne',
                                           'na','mg','al','si','p','s','cl','ar',
                                           'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn'],ecp=0)
        m.define_keyword_basis('midi1',['h','li','be','b','c','n','o','f','ne',
                                        'na','mg','al','si','p','s','cl','ar',
                                        'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                        'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('midi4',['h','li','be','b','c','n','o','f','ne',
                                        'na','mg','al','si','p','s','cl','ar',
                                        'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                        'ga','ge','as','se','br','kr'],ecp=0)

        #not sure about bi&bi for these 2- see MOLPRO manual ch3/node12, table 3
        m.define_keyword_basis('sv dunning',['h','li','be','b','c','n','o','f','ne',
                                             'al','si','p','s','cl',
                                             'sc','ti','v','cr','mn','fe','co','ni','cu',
                                             'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('sv ahlrichs',['h','he','li','be','b','c','n','o','f','ne',
                                              'na','mg','al','si','p','s','cl','ar',
                                              'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                              'ga','ge','as','se','br','kr'],ecp=0)

        m.define_keyword_basis('dz dunning',['h','li','be','b','c','n','o','f','ne',
                                             'al','si','p','s','cl','ar',
                                             'sc','ti','v','cr','mn','fe','co','ni','cu','zn'],ecp=0)
        m.define_keyword_basis('dz ahlrichs',['h','he','li','be','b','c','n','o','f','ne',
                                              'na','mg','al','si','p','s','cl','ar',
                                              'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                              'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('dzp dunning',['h','li','be','b','c','n','o','f','ne',
                                              'al','si','p','s','cl','ar',
                                              'sc','ti','v','cr','mn','fe','co','ni','cu','zn'],ecp=0)
        m.define_keyword_basis('dzp ahlrichs',['h','he','li','be','b','c','n','o','f','ne',
                                              'na','mg','al','si','p','s','cl','ar',
                                              'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                              'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('tzv dunning',['h','be','b','c','n','o','f','ne',
                                              'al','si','p','s','cl','ar',
                                              'sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                              'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('tzv ahlrichs',['h','he','li','be','b','c','n','o','f','ne',
                                               'na','mg','al','si','p','s','cl','ar',
                                               'sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                               'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('tzvp dunning',['h','be','b','c','n','o','f','ne',
                                               'al','si','p','s','cl','ar',
                                               'sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                               'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('tzvp ahlrichs',['h','he','li','be','b','c','n','o','f','ne',
                                                'na','mg','al','si','p','s','cl','ar',
                                                'sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                                'ga','ge','as','se','br','kr'],ecp=0)


        m.define_keyword_basis('tzv 6-311G',['h','he','li','be','b','c','n','o','f','ne',
                                             'na','mg','al','si','p','s','cl','ar'],ecp=0)
        
        m.define_keyword_basis('tzvp 6-311G*',['h','he','li','be','b','c','n','o','f','ne',
                                               'na','mg','al','si','p','s','cl','ar'],ecp=0)

        m.define_keyword_basis('cc-pVDZ',['h','he','li','be','b','c','n','o','f','ne',
                                          'na','al','si','p','s','cl','ar',
                                          'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('cc-pVTZ',['h','he','li','be','b','c','n','o','f','ne',
                                          'na','al','si','p','s','cl','ar',
                                          'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('cc-pVQZ',['h','he','li','be','b','c','n','o','f','ne',
                                          'na','al','si','p','s','cl','ar',
                                          'ga','ge','as','se','br','kr'],ecp=0)
        m.define_keyword_basis('cc-pV5Z',['h','he','li','be','b','c','n','o','f','ne',
                                          'na','al','si','p','s','cl','ar',
                                          'ga','ge','as','se','br','kr'],ecp=0)

        #ECP Basis sets start here:
        m.define_keyword_basis('ecp sbjkc',['li','be','b','c','n','o','f','ne',
                                            'na','mg','al','si','p','s','cl','ar',
                                            'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                            'ga','ge','as','se','br','kr',
                                            'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                            'in','sn','sb','te','i','xe',
                                            'cs','ba','la','ce','pr','nd','pm','sm','eu','gd','tb','dy','ho','er','tm','yb','lu',
                                            'hf','ta','w','re','os','ir','pt','au','hg',
                                            'tl','pb','bi','po','at','rn'],ecp=1)
        
        m.define_keyword_basis('ecp lanl',['li','be','b','c','n','o','f','ne',
                                           'na','mg','al','si','p','s','cl','ar',
                                           'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                           'ga','ge','as','se','br','kr',
                                           'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                           'in','sn','sb','te','i','xe',
                                           'cs','ba','la',
                                           'hf','ta','w','re','os','ir','pt','au','hg',
                                           'tl','pb','bi'],ecp=1)
        
        m.define_keyword_basis('ecp lanl2',['h','li','be','b','c','n','o','f','ne'
                                            'na','mg','al','si','p','s','cl','ar',
                                            'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                            'ga','ge','as','se','br','kr',
                                            'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                            'in','sn','sb','te','i','xe',
                                            'cs','ba','la',
                                            'hf','ta','w','re','os','ir','pt','au','hg',
                                            'pb','bi','u','np','pu'],ecp=1)

        m.define_keyword_basis('ecp crenbl',['li','be','b','c','n','o','f','ne',
                                             'na','mg','al','si','p','s','cl','ar',
                                             'k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                             'ga','ge','as','se','br','kr',
                                             'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                             'in','sn','sb','te','i','xe',
                                             'cs','ba','la','ce','pr','nd','pm','sm','eu','gd','tb','dy','ho','er','tm','yb','lu',
                                             'hf','ta','w','re','os','ir','pt','au',
                                             'pb','bi','po','at','rn',
                                             'fr','ra','ac',
                                             'th','pa','u','np','pu','am','cm','bk','cf','es','fm','md','no','lw'],ecp=1)

        m.define_keyword_basis('ecp crenbs',['sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                             'y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                             'la',
                                             'hf','ta','w','re','os','ir','pt','au','pb','bi','po','at','rn'],ecp=1)

        m.define_keyword_basis('ecp strlc',['li','be','b','c','n','o','f','ne',
                                            'na','mg','al','si','p','s','cl','ar','k','ca',
                                            'zn','ga','ge','as','se','br','kr','rb','sr',
                                            'in','sn','sb','te','i','xe',
                                            'cs','ba','hg','tl','pb','bi','po','at','rn',
                                            'ac','th','pa','u','np','pu','am','cm','bk','cf','es','fm','md','no','lw'],ecp=1)
        
        m.define_keyword_basis('ecp strsc',['k','ca','sc','ti','v','cr','mn','fe','co','ni','cu','zn',
                                            'rb','sr','y','zr','nb','mo','tc','ru','rh','pd','ag','cd',
                                            'cs','ba','ce','pr','nd','pm','sm','eu','gd','tb','dy','ho','er','tm','yb',
                                            'hf','ta','w','re','os','ir','pt','au',
                                            'hg','ac','th','pa','u','np','pu','am','cm','bk','cf','es','fm','md','no','lw'],ecp=1)



    def get_editor_class(self):
        return MOLPROCalcEd

    def WriteInput(self,filename=None):
        """Write the MOLPRO input file"""

        self.GetModel()
        mol_name = self.get_input("mol_name")
        mol_obj  = self.get_input("mol_obj")
        job_name = self.get_name()


        if not filename:
            # see if there is a job object we can query to
        # get any parameters
            job = self.get_job()
            directory=None
            if job:
                directory = job.get_parameter("local_directory")
            if not directory:
                directory = self.get_parameter("directory")
            if not directory:
                directory = paths['user']
                
            filename = directory+os.sep+job_name+'.com'
       
        writeinput_err = self.__WriteInput(mol_obj,filename)
        if writeinput_err:
            return

        # load contents of input for viewing
        file = open(filename,'r')
        input = file.readlines()
        self.set_input("input_file",input)
        file.close()
        
        return filename

    def makejob(self,writeinput=1,graph=None):
        """Prepare the MOLPRO job:
        1) Generate the input-file
        2) Construct the sequence of job steps
        """
        #Get an editor instance to pop up tk-error widgets
        ed = self.get_editor()

        self.GetModel()

        # Set up the names/paths
        mol_name = self.get_input("mol_name")
        job_name = self.get_name()
        directory = self.get_parameter("directory")
        file_ext = '.com'
        infile = directory+os.sep+job_name+file_ext

        # Change to the working directory
        os.chdir( directory )
        print "Running molpro job from: %s" % directory
        
        if writeinput:
            mol_obj  = self.get_input("mol_obj")
            
            writeinput_err = self.__WriteInput(mol_obj,infile)
            if writeinput_err:
                return
            
            # load contents of input for viewing
            file = open(infile,'r')
            input = file.readlines()
            self.set_input("input_file",input)
            file.close()
        else:
            try:
                print directory,os.sep,job_name
                file = open(infile,'r')
            except IOError,e:
                print str(e)
                ed.Error("Trying to run a calculation with no input file!\n"+
                         "Please make sure you have written an input file.")
                return

        #  Get/create job of type specified by the submission parameter
        job = self.get_job()
        if not job:
            job = self.create_job()

        jobtype = job.jobtype
        job.name = job_name
        job.clear_steps()

        # Now we have the jobs, add the steps to it
        job.add_step(jobmanager.job.DELETE_FILE,'remove old output',remote_filename=job_name+'.out',kill_on_error=0)
        job.add_step(jobmanager.job.DELETE_FILE,'remove old XML',remote_filename=job_name+'.xml',kill_on_error=0)
        job.add_step(jobmanager.job.DELETE_FILE,'remove old Molden',remote_filename=job_name+'.molden',kill_on_error=0)
        job.add_step(jobmanager.job.COPY_OUT_FILE,'transfer input',local_filename=job_name+'.in')

        # Block of code to tweak the job depending on how it is being run
        if jobtype == jobmanager.job.LOCALHOST:

            # First see if a default executable was found in the job
            molpro_exe=job.get_parameter('executable')

            # Failing that scan the path
            if not molpro_exe:
                # Look in the path for the molpro executable
                molpro_exe = self.get_executable( job )
                if not molpro_exe:
                    msg='Cannot find an executable to run!\n'+\
                        'Please make sure an executable is in your path or use the\n'+\
                        'the job tab to set the path to the executable.'
                    raise calc.CalcError(msg)
        else:
            raise calc.CalcError("Runing Molpro currently only supported for local resources!")
        
        
        if self.debug: print 'Using MOLPRO path ' + molpro_exe

        stdout_file=None
        # Run with -X to get XML marked up output
        #local_command_args = ['-X',job_name+'.com']
        local_command_args = [job_name+'.com']
        
        if sys.platform[:3] == 'win':
            stdout_file=job_name+'.out'

        job.add_step(jobmanager.job.RUN_APP,
                     'run molpro',
                     local_command=molpro_exe,
                     local_command_args=local_command_args,
                     stdout_file=stdout_file)
        
        job.add_step(jobmanager.job.COPY_BACK_FILE,'recover log',remote_filename=job_name+'.out')
        job.add_tidy(self.endjob)
        return job

    def endjob(self,job_status_code):

        """Load results from Molpro job

        This function is executed in the main thread (rather than the
        job thread) so that it can perform GUI update operations and
        output

        """

        if self.debug:
            print 'running endjob2 code=',job_status_code

        # load contents of listing for viewing
        job_name = self.get_name()
        directory = self.get_parameter("directory")
        filename=directory+'/'+job_name+'.out'
        file = open(filename)
        self.ReadOutput(file)
        file.close()

        # Parse XML output
        xmlfilename=directory+'/'+job_name+'.xml'
        self.results = []
        parser = xml.sax.make_parser()
        parser.setFeature( xml.sax.handler.feature_namespaces, 0 )
        ch = MolproXMLContentHandler(self.results)
        parser.setContentHandler(ch)
        if self.debug:
            print 'Parsing Molpro XML FILE',xmlfilename
        parser.parse(xmlfilename)
        print  'Parsed %s objects' % ( len(self.results) )

        # Add the molden file to the results for orbital viewing
        o = objects.file.File(job_name+'.molden',type=objects.file.MOLDEN_WFN)
        self.results.append(o)

        # Load the results into the gui
        code = self.store_results_to_gui()
        if code:
            raise JobError, "No molecular structure in Punchfile - check output"

    def get_executable(self,job):
        """Return the path to the Molpro Executable"""
        global find_exe

        executable = job.get_parameter( 'executable' )
        if executable:
            return executable

        if sys.platform[:3] == 'win':
            return None
        elif sys.platform[:3] == 'mac':
            return None
        else:
            return find_exe( 'molpro' )
        
    def get_theory(self):
        """Convenience function for ChemShell interface"""
        postscf_method = self.get_parameter("postscf_method")
        print postscf_method
        if postscf_method == "None":
            scf_method = self.get_parameter("scf_method")
            print scf_method
            if scf_method == "Direct DFT" or scf_method == "Direct UDFT":
                theory = self.get_parameter("dft_functional")
            else:
                theory = scf_method
        else:
            print 'else clause'
            theory = postscf_method

        print 'done',theory
        return theory

    def check_direct(self):
        """Convenience function for ChemShell interface"""
        scf_method = self.get_parameter("scf_method")
        if scf_method == "Direct DFT" or scf_method == "Direct UDFT" or \
               scf_method == "Direct RHF" or scf_method == "Direct UHF":
            return 1
        else:
            return 0

##     def __keepfiles(self):
##         """Keep any files the user has selected - for Windoze use environment variables,
##            for unix and its ilk, try runmolpro as default and only use env var if we bum out.
##            Also run a quick check to see if we can use runmolpro with the -V variable.
##         """
##         #dictionary to hold runmolpro command line parameters
##         self.runmolpro_keep = {'ed0' : '',
##                                'ed2' : '',
##                                'ed3' : '',
##                                'ed7' : '',
##                                'ed14' : ''}

##         #Check if runmolpro -V works
##         from jobmanager import subprocess
##         cmd="runmolpro -V"
##         p = subprocess.ForegroundPipe(cmd)
##         code = p.run()
##         dict = {}
##         if p.error:
##             self.userunmolpro = 0
##         else:
##             for l in p.output:
##                 w = l.split()
##                 if len(w) == 2:
##                     dict[w[0]]=w[1]
##             try:
##                 test = dict['MOLPRO_LIB']
##                 self.userunmolpro = 1
##             except KeyError:
##                 print 'got a key error'
##                 self.userunmolpro = 0

##         print 'self.userunmolpro is '+str(self.userunmolpro)
        
##         if self.get_parameter('ed0_keep'):
##             ed0_path = self.get_parameter("ed0_path")
##             os.putenv('ed0',ed0_path)

##         # ed2
##         if self.get_parameter('ed2_keep'):
##             if self.get_parameter('ed2_specify'):
##                 ed2_path = self.get_parameter('ed2_path')
##             else:
##                 dir = self.get_parameter('directory')
##                 stem = self.get_parameter('job_name')
##                 ed2_path = dir+os.sep+stem+'.ed2'
                
##             if sys.platform[:3] == 'win':
##                 os.putenv('ed2',ed2_path)
##             elif sys.platform[:3] == 'mac':
##                 print "Sorry! - Mac still not supported!"
##             else:
##                 if self.userunmolpro:
##                     self.runmolpro_keep['ed2'] = ' -k ed2='+ed2_path
##                 else:
##                     os.putenv('ed2',ed2_path)

##         # ed3
##         if self.get_parameter('ed3_keep') or self.get_parameter("guess_method") == "Dumpfile":
##             if self.get_parameter('ed3_specify'):
##                 ed3_path = self.get_parameter('ed3_path')
##             else:
##                 dir = self.get_parameter('directory')
##                 stem = self.get_parameter('job_name')
##                 ed3_path = dir+os.sep+stem+'.ed3'
                
##             if sys.platform[:3] == 'win':
##                 os.putenv('ed3',ed3_path)
##             elif sys.platform[:3] == 'mac':
##                 print "Sorry! - Mac still not supported!"
##             else:
##                 if self.userunmolpro:
##                     self.runmolpro_keep['ed3'] = ' -k ed3='+ed3_path
##                 else:
##                     os.putenv('ed3',ed3_path)
##         # ed7
##         if self.get_parameter('ed7_keep'):
##             if self.get_parameter('ed7_specify'):
##                 ed7_path = self.get_parameter('ed7_path')
##             else:
##                 dir = self.get_parameter('directory')
##                 stem = self.get_parameter('job_name')
##                 ed7_path = dir+os.sep+stem+'.ed7'
                
##             if sys.platform[:3] == 'win':
##                 os.putenv('ed7',ed7_path)
##             elif sys.platform[:3] == 'mac':
##                 print "Sorry! - Mac still not supported!"
##             else:
##                 if self.userunmolpro:
##                     self.runmolpro_keep['ed7'] = ' -k ed7='+ed7_path
##                 else:
##                     os.putenv('ed7',ed7_path)

##         if self.get_parameter("guess_method") == "GETQ":
##             if not self.get_parameter('ed14_keep') or self.get_parameter('ed14_path')[0] == '?':
##                 ed.Error("Using GETQ for guess but the location of ed14 is unspecified.\n"+
##                          "Please go to the job tab and specify the location of the foreign dumpfile (ed14).")
##                 return
##             else:
##                 if self.get_parameter('ed14_keep'):
##                     if self.get_parameter('ed14_specify'):
##                         ed14_path = self.get_parameter('ed14_path')
##                     else:
##                         dir = self.get_parameter('directory')
##                         stem = self.get_parameter('job_name')
##                         ed14_path = dir+os.sep+stem+'.ed14'

##                     if sys.platform[:3] == 'win':
##                         os.putenv('ed14',ed14_path)
##                     elif sys.platform[:3] == 'mac':
##                         print "Sorry! - Mac still not supported!"
##                     else:
##                         if self.userunmolpro:
##                             self.runmolpro_keep['ed14'] = ' -k ed14='+ed14_path
##                         else:
##                             os.putenv('ed14',ed14_path)

    def __WriteInput(self,mol,filename):

        #Get an editor object so we can pop up tk error widgets
        ed = self.get_editor()

        #Check the spin of the molecule is o.k. before we do owt else.
        if self.CheckSpin(show=1):
            return 1

        task           = self.get_parameter("task")
        scf_method     = self.get_parameter("scf_method")
        postscf_method = self.get_parameter("postscf_method")

        #Set local flag for rhf/uhf
        if (scf_method == "RHF" or scf_method == "DFT" or 
            scf_method == "Direct RHF" or scf_method == "Direct DFT"):
            scftype="rhf"
        elif (scf_method == "UHF" or scf_method == "UDFT" or 
            scf_method == "Direct UHF" or scf_method == "Direct UDFT"):
            scftype="uhf"
        #Set local flag for dft
        if (scf_method == "DFT" or scf_method == "UDFT" or 
            scf_method == "Direct DFT" or scf_method == "Direct UDFT"):
            dft=1
        else:
            dft=0

        file = open(filename,'w') 

        # dynamic memory limit is set to 64 M, so as to allow for large calculations
        job_name = self.get_name()
        title = self.get_title()


        #file.write("***,%s\nmemory,64,m\n" % title)
        file.write("***,%s\n" % title)

        # At this stage, start a new wfu file for each job
        file.write("file,2,%s.wfu,new\n" % job_name)
        
        if self.get_parameter("spin")-1 != 0:
            file.write("set,spin=%d\n" % self.get_parameter("spin")-1)

        request_z = (self.get_parameter('task') == MENU_OPT and self.get_parameter('optimiser') == 'Z-Matrix')
        write_x = 1

        if request_z == 1:

            # MOLPRO CODE NEEDED HERE
            
            # Try to load mixed coordinates from the Z-matrix editor
            z = 0
            for a in mol.atom:
                if a.zorc == 'z':
                    z = 1
            if z:
                # check if the first 3 atoms comply with the
                # zmatrix conventions
                if abs(mol.atom[0].coord[0]) > 0.0001 or \
                   abs(mol.atom[0].coord[1]) > 0.0001 or \
                   abs(mol.atom[0].coord[2]) > 0.0001 or \
                   abs(mol.atom[1].coord[0]) > 0.0001 or \
                   abs(mol.atom[1].coord[1]) > 0.0001 or \
                   abs(mol.atom[2].coord[1]) > 0.0001 :
                    mol.list()
                    ed.Error('Make sure the first 3 atoms obey the zmatrix conventions')
                    raise Exception, "Bad z-matrix"

                else:
                    # check for variables
                    counts = mol.counts()
                    print 'counts',counts
                    if counts[2] == 0:
                        ed.Error('Z-matrix has no variables')
                        raise Exception, "Bad z-matrix"

                    # we can write out and use the internals
                    write_x = 0
                    file.write('zmatrix angstrom\n')

                    txt = mol.output_zmat()
                    #check first line to see if it specifies cartesians
                    tlist = string.split(txt[0])
                    first = tlist[0]
                    if (first[0:4] == 'coor'):
                        file.write('cartesian\n')
                        
                    # skip the zmatrix card as we replaced it
                    txt.pop(0)

                    for field in txt:
                        check = field.split()
                        first = check[0]
                        if (first[0:4] == 'coor'):
                            file.write('cartesian\n')
                        elif (first[0:4] == 'zmat'):
                            file.write('internal\n')
                        else:
                            file.write(field + '\n')

        if write_x:
            # Geometry
            file.write('geomtyp=xyz\n')
            file.write('geometry={\n')
            file.write('angstrom;\n')
            file.write('%d\n' % (len(mol.atom)))
            file.write('%s\n' % ('gui structure'))
            for a in mol.atom:
                if a.get_number() > 0:
                    file.write(
                        a.name + ',' +
                        str(a.coord[0]) + ',' +
                        str(a.coord[1]) + ',' +
                        str(a.coord[2]) + '\n')

## NEED to put partial charges in IN.LAT ?
##                 else:
##                     file.write(str(a.coord[0]) + ' ' +
##                                str(a.coord[1]) + ' ' +
##                                str(a.coord[2]) + ' ' +
##                                str(a.partial_charge) + ' ' +
##                                a.name + '\n')
        file.write('}\n')
        file.write('set,charge='+str(self.get_parameter("charge"))+'\n')

        #
        #  BASIS directive
        #
        self._write_basis(file)

        self._write_ecp(file)

        #  Replacement Class II
##        classii = self.get_parameter("classiidirectives")
##        if classii != "":
##            file.write(classii)
##            return 0

        #
        #  SCFTYPE directive
        #
        #if postscf_method == "MP2":
        #    file.write('scftype mp2\n')
        #elif postscf_method == "MP3":
        #    file.write('scftype mp3\n')
        #elif postscf_method == "Direct MP2":
        #    file.write('scftype direct mp2\n')
        ## Restricted
        #elif (scf_method == "RHF" or scf_method == "DFT"):
        #    file.write('scftype rhf\n')
        #elif (scf_method == "Direct RHF" or scf_method == "Direct DFT"):
        #    file.write('scftype direct rhf\n')
        #Unrestricted
        #elif (scf_method == "UHF" or scf_method == "UDFT"):
        #    file.write('scftype uhf\n')
        #elif (scf_method == "Direct UHF" or scf_method == "Direct UDFT"):
        #    file.write('scftype direct uhf\n')
        #else:
        #    file.write('scftype rhf')

        if dft:
            functional = self.get_parameter("dft_functional")


        if self.check_direct():
            file.write('{');

        if scf_method == "RHF" or scf_method == "Direct RHF":
            file.write('rhf;\n')
        elif scf_method == "DFT" or scf_method == "Direct DFT":
            file.write('rks,%s\n' % (functional))
        elif scf_method == "UHF" or  scf_method == "Direct UHF":
            file.write('uhf;\n')
        elif scf_method == "UDFT" or scf_method == "Direct UDFT":
            file.write('uks,%s\n' %(functional))

        if self.check_direct():
            file.write('direct}\n')

        if postscf_method == 'CISD':
            file.write('cisd\n')
        elif postscf_method == 'CCSD':
            file.write('ccsd;\n')
        elif postscf_method == 'CCSD(T)':
            file.write('ccsd(t);\n')

        #This is where all the DFT directives go
        #        if scf_method == "DFT" or scf_method == "UDFT" or scf_method == "Direct DFT" or scf_method == "Direct UDFT"
        if dft:
            functional = self.get_parameter("dft_functional")
            accuracy   = self.get_parameter("dft_grid")
            weights    = self.get_parameter("dft_weights")
            
            #Map what's written in the menus to MOLPRO directives
            dft_dictionary={"Euler-MacLaurin": "euler",
                            "Mura-Knowles" : "log",
                            "Lebedev-Laikov": "lebedev",
                            "Gauss-Legendre" : "gausslegendre",
                            "Lebedev-Laikov": "lebedev",
                            "Gauss-Legendre" : "gausslegendre"}
            
            radialgrid = self.get_parameter("dft_radialgrid")
            angulargrid = self.get_parameter("dft_angulargrid")
            jfit = self.get_parameter("dft_jfit")
             
            #file.write('dft '+str(functional)+'\n')
            #file.write('dft quadrature '+str(accuracy)+'\n')
            #if weights != "default":
            #    file.write('dft weights '+str(weights)+'\n')

            #if radial & angular grids not default specify type and no. points
            #if radialgrid != "default":
            #    file.write('dft '+dft_dictionary[radialgrid]+
            #               ' '+str(self.get_parameter("dft_radialgridpoints"))+'\n')
            #if angulargrid != "default":
            #    file.write('dft '+dft_dictionary[angulargrid]+
            #               ' '+str(self.get_parameter("dft_angulargridpoints"))+'\n')

            #if coulomb fitting  add aux basis and scwarz cutoff

#             if jfit:
#                 file.write('dft jfit memory \n') #memory is default as MOLPRO will
#                     #recalualte the integrals anyway
#                     #if they don't fit in memory.
#                 file.write('dft schwartz '+str(self.get_parameter("dft_schwarz"))+'\n')
#                 file.write('dft jbas '+str(self.get_parameter("dft_jbas"))+'\n')
#SCF convergence options
#         if (scf_method == "RHF" or scf_method == "DFT" or 
#             scf_method == "Direct RHF" or scf_method == "Direct DFT"):
#         if (scftype == "rhf"):
#             file.write('level '+
#                        str(self.get_parameter("scf_level_init"))+' '+
#                        str(self.get_parameter("scf_level_it"))+' '+
#                        str(self.get_parameter("scf_level_final"))+'\n')
            
#         elif (scf_method == "UHF" or scf_method == "UDFT" or
#               scf_method == "Direct UHF" or scf_method == "Direct UDFT"):
#        elif (scftype == "uhf"):
#             file.write('level '+
#                        str(self.get_parameter("scf_level_init"))+' '+
#                        str(self.get_parameter("scf_level_init"))+' '+
#                        str(self.get_parameter("scf_level_it"))+' '+
#                        str(self.get_parameter("scf_level_final"))+' '+
#                        str(self.get_parameter("scf_level_final"))+'\n')
            
#        file.write('maxcyc '+str(self.get_parameter("scf_maxcyc"))+'\n')
#        file.write('thresh '+str(self.get_parameter("scf_threshold"))+'\n')




        if task == MENU_OPT:
            #if self.get_parameter('optimiser') == 'Z-Matrix':
            #if self.get_parameter('opt_jorgensen'):
            #    file.write('maxjorg '+str(self.get_parameter("max_opt_step"))+'\n')
            #    file.write('minmax '+str(self.get_parameter("max_opt_step"))+' '
            #               +str(self.get_parameter('max_opt_line'))+'\n')
            #file.write('xtol '+str(self.get_parameter('opt_conv_thsld'))+'\n')
            #file.write('stepmax '+str(self.get_parameter("max_opt_step_len"))+'\n')

            file.write('optg\n');

        elif task == MENU_GRAD:
            file.write('grad; FIX ME\n')            

#         elif task == MENU_OPT:
#             if self.get_parameter('optimiser') == 'Z-Matrix':
#                 if self.get_parameter('opt_jorgensen'):
#                     if self.get_parameter('find_ts'):
#                         file.write('runtype saddle jorgensen\n')
#                         powell = self.get_parameter('opt_powell')
#                         if powell:
#                             file.write('powell\n')
#                     else:
#                         file.write('runtype optim jorgensen\n')
#                         hessupdate = self.get_parameter('opt_hess_update')
#                         if hessupdate != 'default':
#                             file.write(str(hessupdate)+'\n')

#                     #Now write out all other jorgensen options:
#                     eigmin = self.get_parameter('opt_min_hess')
#                     if eigmin:
#                         file.write('eigmin '+str(eigmin)+'\n')
#                     eigmax = self.get_parameter('opt_max_hess')
#                     if eigmax:
#                         file.write('eigmin '+str(eigmax)+'\n')
#                     rfo = self.get_parameter('opt_rfo')
#                     if rfo:
#                         file.write('rfo '+str(self.get_parameter('opt_rfomode'))+'\n')
                        
                    
#                 else: # we're not using jorgensen
#                     if self.get_parameter('find_ts'):
#                         file.write('runtype saddle\n')
#                     else:
#                         file.write('runtype optim\n')
#             else:
#                 file.write('runtype optx\n')


        if self.get_parameter("ana_frequencies"):
            file.write('frequencies,finite_difference,FIXME')
            #file.write('nosym\n')
            #file.write('adapt off\n')
            #file.write('punch normal vibr\n')
            #file.write('enter 1\n')

        if self.get_parameter("ana_hessian"):
            file.write('frequencies,analytic\n')
            #file.write('runtype hessian\n')
            #file.write('nosym\n')
            #file.write('adapt off\n')
            #file.write('punch normal vibr\n')
            #file.write('enter 1\n')

        # Output Options
        #file.write('put,xml\n')
        file.write('put,xml,'+job_name+'.xml\n')
        file.write('put,molden,'+job_name+'.molden\n')

        # Input writing finishes here
        file.close()
        return 0

    def get_next_section(self):
        # return the next section to use
        if self.next_section:
            self.next_section = self.next_section + 1
            return self.next_section
        else:
            print "No next_section defined in molprouk.py.__WriteInput!\n"
            return 0


    def _write_basis(self,file):
        """Output the basis specification"""
        basis = self.get_parameter("basisdirectives")
        if basis != "":
            file.write(basis)
        else:
            basis = self.get_parameter("basis")
            if basis:
                # Use the result of the basis manager
                # for more details see the basis manager module
                first=1
                file.write('basis={\n')
                file.write('default=dummy,')
                for entry in basis:
                    (ass_type, tag, b) = entry
                    if self.debug:
                        print 'entry', ass_type, tag, b
                    if ass_type == 'TYPE.KEY':
                        #If b contains 2 fields, need to place element symbol between the two:
                        basis_keyword=string.split(b)
                        length=len(basis_keyword)
                        if not first:
                            file.write(',')
                        first = 0
                        file.write('%s=%s' % (tag,basis_keyword[0])) #  only 1 keyword
                    elif ass_type == 'TYPE.EXPL':
                        # NOT CODED YET FOR MOLPRO
                        raise calc.CalcError("explict basis set input not coded yet")
                        b.list()
                        for shell in b.shells:
                            file.write('%s %s\n' % (shell.type, tag))
                            for p in shell.expansion:
                                print 'expansion',p,len(p)
                                if len(p) == 2:
                                    file.write( '%12.8f %8.4f\n' % (p[1],p[0]))
                                elif len(p) == 3:

                                    file.write( '%12.8f %8.4f %8.4f\n' % (p[1],p[0],p[2]))
                                else:
                                    print 'ELSE'
                file.write('}\n')

            else:
                # Use the default
                basis = self.get_parameter("default_basis")
                file.write('basis=' + basis+'\n')

    def _write_ecp(self,file):
        
        ecp = self.get_parameter("ECP")
        if ecp:
            file.write('pseudo ecp\n')
            for entry in ecp:
                print 'entry:',entry
                (ass_type, tag, b) = entry
                print 'entry', ass_type, tag, b
                if ass_type == 'TYPE.KEY':
                    #The form of the input for MOLPRO is: 'el sym' ecp 'el tag'
                    #so just strip any numbers off 'el tag' to get the symbol
                    basis_keyword=string.split(b)
                    trans = string.maketrans('a','a')
                    el_sym = string.translate(tag,trans,string.digits)
                    file.write('%s %s %s\n' %(el_sym,basis_keyword[1],tag))
                if ass_type == 'TYPE.EXPL':
                    file.write('cards %s\n' % (tag))
                    file.write('%s %s\n' % (b.lmax, b.ncore))
                    b.list()
                    for shell in b.shells:
                        file.write('%d \n' % (len(shell.expansion)))
                        for p in shell.expansion:
                            print 'expansion',p,len(p)
                            file.write( '%d %8.4f %8.4f\n' % (p[0],p[1],p[2]))
                        else:
                            print 'ELSE'

homolumoa = 0

class MOLPROCalcEd(qm.QMCalcEd):

    def __init__(self,root,calc,graph,**kw):
        qm.QMCalcEd.__init__(self,root,calc,graph,**kw)

        # Associate helpfile with widget
        viewer.help.sethelp(self,'MoleculeTab')
        
        self.tasks = [MENU_ENER, MENU_GRAD, MENU_OPT]
            #"numerical force constants",
            #"analytical force constants",
            #"polarisability",
            #"hyper polarisability",
            #"magnetisability",
            #"Raman intensities",
            #"infrared intensities",
            #"UV/Vis intensities"]
        self.theories[MENU_ENER] = [
             "RHF", "UHF", "MP2", "B3LYP", "UB3LYP", 
             "BLYP", "UBLYP", "SVWN", "USVWN", 
             "HCTH", "UHCTH", "FT97", "UFT97"]
        self.theories[MENU_GRAD] = [
             "RHF", "UHF", "MP2", "B3LYP", "UB3LYP", 
             "BLYP", "UBLYP", "SVWN", "USVWN", 
             "HCTH", "UHCTH", "FT97", "UFT97"]
        self.theories[MENU_OPT] = [
             "RHF", "UHF", "MP2", "B3LYP", "UB3LYP", 
             "BLYP", "UBLYP", "SVWN", "USVWN", 
             "HCTH", "UHCTH", "FT97", "UFT97"]
        self.scf_methods = {}
        self.scf_methods[MENU_ENER] = [
             "RHF", "UHF", "GVB", "DFT", "UDFT" ,
             "Direct RHF", "Direct UHF", "Direct GVB", "Direct DFT", "Direct UDFT"]
        self.scf_methods[MENU_GRAD] = [
             "RHF", "UHF", "GVB", "DFT", "UDFT" ,
             "Direct RHF", "Direct UHF", "Direct GVB", "Direct DFT", "Direct UDFT"]
        self.scf_methods[MENU_OPT] = [
             "RHF", "UHF", "GVB", "DFT", "UDFT" ,
             "Direct RHF", "Direct UHF", "Direct GVB", "Direct DFT", "Direct UDFT"]

        #DFT options
        self.dft_functionals = [
             "SVWN", "BLYP", "B3LYP", "B97", "HCTH", "FT97"]
        self.dft_grids = ["low", "medium", "high", "veryhigh"]
        self.dft_radialgrids = ["default","Euler-MacLaurin","Mura-Knowles"]
        self.dft_angulargrids = ["default","Lebedev-Laikov","Gauss-Legendre"]
        # This is the full list of possible points, they are not supported in the
        #standard version of molpro, so not needed here.
        #self.dft_lebedevpoints =[6,14,26,38,50,74,86,110,146,170,194,230,266,
        #                         302,350,434,590,770,974,1202,1454,1730,2030,
        #                         2354,2702,3074,3470,3890,4334,4802,5294,5810]
        self.dft_lebedevpoints =['6','14','26','38','50','74','86','110','146','170',
                                 '194','230','266','302','350','434','590','770','974','1202']
        self.dft_weights = ["Becke","MHL","SSF","MHL4SSF","MHL8SSF"]
        self.dft_jbas = ["A1DGAUSS","A2DGAUSS","DEMON","AHLRICHS"]
        
        self.postscf_methods = {}
        self.postscf_methods[MENU_ENER] = [
             "None", "MCSCF", "MP2", "MP3", 
             "CCSD", "CCSD(T)", "Direct CI", "MRDCI",
             "Direct MP2" ]
        self.postscf_methods[MENU_GRAD] = [
             "None", "MCSCF", "MP2", "MP3", 
             "Direct MP2"]
        self.postscf_methods[MENU_OPT] = [
             "None", "MCSCF", "MP2", "MP3",
             "Direct MP2"]
        self.guess_options = ["Compute","Dumpfile","GETQ"]
        self.compute_options = ["atoms","hcore","minguess","extguess","atorb"]
        scf_rhf = ["RHF","B3LYP" ,"BLYP" ,"SVWN" ,"HCTH" ,"FT97"]
        scf_uhf = ["UHF","UB3LYP","UBLYP","USVWN","UHCTH","UFT97"]

        self.optcoord_opts = [ "Z-Matrix","Cartesian" ]
        self.optbfgs_opts = ["default","BFGS","BFGSX"]
        self.optrfo_opts = ["on","off"]
        
        self.submission_policies = [ jobmanager.job.LOCALHOST, "Globus","Nordugrid" ]


        #Create the tools used in the Molecule tab - spin & charge created in QM.
        self.task_tool = tools.SelectOptionTool(self,'task','Task',self.tasks,command=self.__taskupdate)
        self.balloon.bind( self.task_tool.widget, 'Specify the type of calculation to run.' )
        
        #Used to specify task
        self.tasktoolvalue = self.task_tool.widget.getvalue() 

        self.checkspin_widget = Tkinter.Button(self.interior(),
                                             text = 'Check Spin',
                                             command = self.__CheckSpin)
        self.balloon.bind( self.checkspin_widget, 'Check if the spin is consistent for the molecule' )
        
        self.symmetry_tool = tools.BooleanTool(self,'symmetry','Use Symmetry')
        self.balloon.bind( self.symmetry_tool.widget, 'Turn on the use of symmetry during the calculation' )

        mol_obj = self.calc.get_input('mol_obj')

        # need to propagate the default basis back

        self.basis_manager = self.calc.basis_manager
        
        self.basis_tool = qmtools.BasisTool(self,'basis','ECP','default_basis',
                                    molecule=mol_obj,basis_manager=self.basis_manager)

        #Create the tools used in the Theory tab
        #self.guess_tool = MolproGuessTool(self,self.__guesscommand)
        self.guessoption_tool = tools.SelectOptionTool(self,'guess_method','Vectors',self.guess_options,
                                                 self.__guesstype)
        self.balloon.bind( self.guessoption_tool.widget, 'Determine how the initial vectors for the guess are computed' )
        self.guessatoms_tool = tools.SelectOptionTool(self,'guess_comp',None,self.compute_options)
        self.guesssection1_tool = tools.IntegerTool(self,'guess_sect1','Section a',0)
        self.guesssection2_tool = tools.IntegerTool(self,'guess_sect2','Section b',0)
        self.guessgetqblock1_tool = tools.IntegerTool(self,'getq_block1','File Block a',0)
        self.guessgetqblock2_tool = tools.IntegerTool(self,'getq_block2','File Block b',0)
        self.guessgetqsection1_tool = tools.IntegerTool(self,'getq_sect1','File Section a',0)
        self.guessgetqsection2_tool = tools.IntegerTool(self,'getq_sect2','File Section b',0)
        
        self.scfmethod_tool = tools.SelectOptionTool(self,'scf_method',
                                               'SCF Method',
                                               self.scf_methods[self.tasktoolvalue],
                                               self.__scfmethod)
        self.scfmaxcycles_tool = tools.IntegerTool(self,'scf_maxcyc','Max. Cycles',1)
        self.balloon.bind( self.scfmaxcycles_tool.widget, 'Maximum permitted number of SCF cycles' )
        self.scfthreshold_tool = tools.IntegerTool(self,'scf_threshold','Threshold',3)
        self.balloon.bind( self.scfthreshold_tool.widget, 'Consider the SCF converged when Energy change is less than 10x(-n) this number' )

        self.scfbypass_tool = tools.BooleanTool(self,'scf_bypass', 'Bypass SCF')
        self.balloon.bind( self.scfbypass_tool.widget, 'Eschew SCF calculation. Read integrals and vectors from dumpfile instead' )

        self.scflevelinit_tool = tools.FloatTool(self,'scf_level_init','Initial Levelshifter Value',0.0)
        self.scflevelit_tool = tools.IntegerTool(self,'scf_level_it','Cycle to change on',1)
        self.scflevelfinal_tool = tools.FloatTool(self,'scf_level_final','Final Levelshifter Value',0.0)
        

        self.postscfmethod_tool = tools.SelectOptionTool(self,'postscf_method',
                                                   'Method',
                                                   self.postscf_methods[self.tasktoolvalue])


        #Create the tools for the DFT tab
        self.dftfunctional_tool = tools.SelectOptionTool(self,'dft_functional','Functional',self.dft_functionals)
        self.dftaccuracy_tool = tools.SelectOptionTool(self,'dft_grid','Grid setting',self.dft_grids)
        self.balloon.bind( self.dftaccuracy_tool.widget, 'Specify a quadrature grid designed to achieve a particular accuracy' )
        self.dftweightscheme_tool = tools.SelectOptionTool(self,'dft_weights',
                                                     'DFT weighting scheme',
                                                     self.dft_weights)

        self.dftradial_tool = tools.MenuCounterTool(self,
                                              'dft_radialgrid',
                                             'Radial Grid',
                                             self.dft_radialgrids,
                                             'dft_radialgridpoints',
                                             'Number of points',
                                             command = self.__dftradialgridpoints
                                             )
        self.radialgrid = self.dftradial_tool.firstmenu.getvalue()
        
        self.dftangular_tool = tools.MenuCounterMenuTool(self,
                                                   'dft_angulargrid',
                                                   'Angular Grid',
                                                   self.dft_angulargrids,
                                                   'dft_angulargridpoints',
                                                   'Number of points',
                                                   'dft_angulargridpoints',
                                                   'Number of points',
                                                   self.dft_lebedevpoints,
                                                   command = self.__dftangulargridpoints
                                                   )
        self.angulargrid = self.dftangular_tool.firstmenu.getvalue()

        self.dftjfit_tool = tools.BooleanTool(self,'dft_jfit','Use Coulomb Fitting',self.__dftjbasselect)
        self.balloon.bind( self.dftjfit_tool.widget, 'Evaluate the Coulomb energy with an auxilary basis set' )
        self.dftjbas_tool = tools.SelectOptionTool(self,'dft_jbas','Fitting Basis',self.dft_jbas)
        self.balloon.bind( self.dftjbas_tool.widget, 'Select the auxilary fitting basis' )
        self.dftschwarz_tool = tools.IntegerTool(self,'dft_schwarz','Schwarz cutoff')
        self.balloon.bind( self.dftschwarz_tool.widget, 'Reduce the number of 3e integrals by setting Schwarz tolerance to 10x-(n)' )

        #Create the tools used in the Properties tab
        self.homolumo_tool = tools.BooleanTool(self, 'ana_homolumo', 'HOMO/LUMO')
        self.homolumo1_tool = tools.BooleanTool(self, 'ana_homolumo1', 'HOMO1/LUMO1')
        self.homolumo2_tool = tools.BooleanTool(self, 'ana_homolumo2', 'HOMO2/LUMO2')
        self.homolumo3_tool = tools.BooleanTool(self, 'ana_homolumo2', 'HOMO3/LUMO3')
        self.homolumo4_tool = tools.BooleanTool(self, 'ana_homolumo4', 'HOMO4/LUMO4') 
        self.homolumo5_tool = tools.BooleanTool(self, 'ana_homolumo5', 'HOMO5/LUMO5')
       
        self.chargeden_tool = tools.BooleanTool(self, 'ana_chargeden', 'Charge Density')
        self.balloon.bind ( self.chargeden_tool.widget, 'Calculate the charge density and import the results back for display' )
        self.diffden_tool = tools.BooleanTool(self, 'ana_diffden', 'Difference Density')
        self.potential_tool = tools.BooleanTool(self, 'ana_potential', 'Potential')
        self.balloon.bind ( self.potential_tool.widget, 'Calculate the electrostatic potential and import the results back for display' )                
        self.chargedengrad_tool = tools.BooleanTool(self, 'ana_chargedengrad', 'Gradient Density')
        self.spinden_tool = tools.BooleanTool(self, 'ana_spinden', 'Spin Density')
        self.frequencies_tool = tools.BooleanTool(self, 'ana_frequencies', 'Finite Difference')
        self.balloon.bind( self.frequencies_tool.widget, 'Calculate force constants numerically' )
        self.hessian_tool = tools.BooleanTool(self, 'ana_hessian', "Analytic")
        self.balloon.bind( self.hessian_tool.widget, 'Calculate the force constants analytically' )

        #Create the tools used in the Optimisation tab
        self.optcoords_tool = tools.SelectOptionTool(self,'optimiser', 'Opt. Coords',
                                               self.optcoord_opts, self.__selectcoords)
        self.find_ts_tool = tools.BooleanTool(self,"find_ts","Locate Transition State",self.__findts)
 #       self.optmethod_tool = tools.SelectOptionTool(self,'optimiser_method','Method',self.optmethodopts)

        self.optmaxcyc1_tool = tools.IntegerTool(self,'max_opt_step','Energy evaluations',0)
        self.optmaxcyc2_tool = tools.IntegerTool(self,'max_opt_line','Line searches',0)
        self.optxtol_tool = tools.FloatTool(self,'opt_conv_thsld','Convergence Thresh.',0.0)        
        self.optstepmax_tool = tools.FloatTool(self,'max_opt_step_len','Max. Step size',0.0)        
        self.optvalue_tool = tools.FloatTool(self,'opt_value','Turning Point Accuracy',0.0)

        self.optjorg_tool = tools.BooleanTool(self,'opt_jorgensen','Use Jorgensen-Simons Algorithm',
                                        self.__optjorgensen)
        self.optpowell_tool = tools.BooleanTool(self,'opt_powell','Use Powell Hessian update')
        self.optbfgs_tool = tools.SelectOptionTool(self,'opt_hess_update', 'Hessian Update Procedure',
                                             self.optbfgs_opts)
        self.optminhess_tool = tools.FloatTool(self,'opt_min_hess','Min. Hessian Eigenvalue')
        self.optmaxhess_tool = tools.FloatTool(self,'opt_max_hess','Max. Hessian Eigenvalue')
        self.optrfo_tool = tools.MenuAndBooleanTool(self,'opt_rfo','opt_rfomode',
                                              'Use Rational Function Optimisation',
                                              'RFO Mode',self.optrfo_opts)

        #Create the tools used for the Job tab
        self.jobname_tool = tools.TextFieldTool(self,'name','Job Name')
        self.balloon.bind( self.jobname_tool.widget, 'Specify the prefix for all output files' )
        # See LayoutTK for the job submission tools
        self.LayoutToolsTk()

        self.__initialisetools()
        
#        self.menu.addmenuitem('View','command',
#                     'View a summary of results',
#                     command = lambda s=self: s.summarise_results(),
#                     label = 'Results Summary')

        # flag to check if we already have a summary editor open
        self.summaryeditor=None


    def __initialisetools(self):
        """Initialise any tools and variables that effect the defaults that are displayed.
        """
        self.task_tool.widget.invoke(self.calc.get_parameter('task'))
        self.scfmethod_tool.widget.invoke(self.calc.get_parameter('scf_method'))
        self.guessoption_tool.widget.invoke(self.calc.get_parameter('guess_method'))
        self.jobname_tool.UpdateWidget()
        self.__getenvironment()
###        self.ed0path_tool.UpdateWidget()
 
    def __taskupdate(self,task):
        """Update the SCF and post-SCF methods for the task that has been selected
           and hide the optimisation tab
        """
        self.scfmethod_tool.SetItems(self.scf_methods[task])
        self.postscfmethod_tool.SetItems(self.postscf_methods[task])
        if task != 'Geometry Optimisation':
            self.notebook.tab('Optimisation').configure(state="disabled")
        else:
            self.notebook.tab('Optimisation').configure(state="active")

    def __CheckSpin(self):
        for tool in self.tools:
            tool.ReadWidget()
        self.calc.CheckSpin()

    def __scfmethod(self,scf):
        """Configure all widgets and variables that depend on the SCF type.
        """
        self.scfmethod_tool.ReadWidget()
        if (scf == 'DFT') or (scf == 'UDFT') or (scf == 'Direct DFT') or (scf == 'Direct UDFT'):
            self.notebook.tab('DFT').configure(state="active")
        else:
            self.notebook.tab('DFT').configure(state="disabled")
            
        # REM the default 'enter' and 'vectors' sections are configured in the __guesstype
        #  method as this is always run after the __scfmethod is invoked
        #guess = self.calc.get_parameter("guess_method")
        self.__guesstype("")

    def __guesstype(self,value):
        """Display the relevant tools depending on where we are going to be getting the
           vectors from for this calculation.
        """
        # 1st 3 lines a bit daft but need in case we called from __scfmethod
        self.guessoption_tool.ReadWidget() 
        guess = self.calc.get_parameter('guess_method')
        scf = self.calc.get_parameter('scf_method')
        
        self.guessatoms_tool.Forget()
        self.guesssection1_tool.Forget()
        self.guesssection2_tool.Forget()
        self.guessgetqblock1_tool.Forget()
        self.guessgetqblock2_tool.Forget()
        self.guessgetqsection1_tool.Forget()
        self.guessgetqsection2_tool.Forget()
        
        # configure the default 'enter' and 'vectors' sections
        if (scf == "RHF") or (scf == "DFT") or (scf == "Direct RHF") or (scf == "Direct DFT") :
            #if self.calc.get_parameter("postscf_method") == "MCSCF":
            #    self.calc.set_parameter("enter_sect1","6")
            #    self.calc.set_parameter("enter_sect1","7")
            #else:
            self.calc.set_parameter("enter_sect1","1")
            self.calc.set_parameter("guess_sect1","1")
            self.calc.set_parameter("getq_sect1","1")
        if (scf == "UHF") or (scf == "UDFT") or (scf == "Direct UHF") or (scf == "Direct UDFT") :
            #if self.calc.get_parameter("postscf_method") == "MCSCF":
            #    self.calc.set_parameter("enter_sect1","6")
            #    self.calc.set_parameter("enter_sect1","7")
            #else:
            self.calc.set_parameter("enter_sect1","2")
            self.calc.set_parameter("enter_sect2","3")
            self.calc.set_parameter("guess_sect1","2")
            self.calc.set_parameter("guess_sect2","3")
            self.calc.set_parameter("getq_sect1","2")
            self.calc.set_parameter("getq_sect2","3")
            
        if (scf == "GVB") or (scf == "Direct GVB"):
            #if self.calc.get_parameter("postscf_method") == "MCSCF":
            #    self.calc.set_parameter("enter_sect1","6")
            #    self.calc.set_parameter("enter_sect1","7")
            #else:
            self.calc.set_parameter("enter_sect1","4")
            self.calc.set_parameter("enter_sect2","5")
            self.calc.set_parameter("guess_sect1","4")
            self.calc.set_parameter("guess_sect2","5")
            self.calc.set_parameter("getq_sect1","4")
            self.calc.set_parameter("getq_sect2","5")
             
        if (guess == 'Compute'):
            self.guessatoms_tool.Pack()
        elif (guess == 'Dumpfile'):
            if (scf == "RHF") or (scf == "DFT") or (scf == "Direct RHF") or (scf == "Direct DFT"):  
                self.guesssection1_tool.UpdateWidget()
                self.guesssection1_tool.Pack()
            else:
                self.guesssection1_tool.Pack()
                self.guesssection2_tool.Pack()
                self.guesssection1_tool.UpdateWidget()
                self.guesssection2_tool.UpdateWidget()
        elif (guess == 'GETQ'):
            if (scf == "RHF") or (scf == "DFT") or (scf == "Direct RHF") or (scf == "Direct DFT"):  
                self.guessgetqblock1_tool.UpdateWidget()
                self.guessgetqsection1_tool.UpdateWidget()
                self.guessgetqblock1_tool.Pack()
                self.guessgetqsection1_tool.Pack()
                Pmw.alignlabels([self.guessgetqblock1_tool.widget,
                                 self.guessgetqsection1_tool.widget])
                
            else:
                self.guessgetqblock1_tool.UpdateWidget()
                self.guessgetqsection1_tool.UpdateWidget()
                self.guessgetqblock2_tool.UpdateWidget()
                self.guessgetqsection2_tool.UpdateWidget()
                self.guessgetqblock1_tool.Pack()
                self.guessgetqsection1_tool.Pack()
                self.guessgetqblock2_tool.Pack()
                self.guessgetqsection2_tool.Pack()
                Pmw.alignlabels([self.guessgetqblock1_tool.widget,
                                 self.guessgetqblock2_tool.widget,
                                 self.guessgetqsection1_tool.widget,
                                 self.guessgetqsection2_tool.widget])
                
 
    def __dftradialgridpoints(self,choice):
        """Select the number of gridpoints dependant on the radial grid selected
        """
        print "choice is: " + choice
        if (choice == 'Euler-MacLaurin' or choice == 'Mura-Knowles'):
            self.dftradial_tool.ShowCounter()
        else:
            self.dftradial_tool.HideCounter()
       
    def __dftangulargridpoints(self,choice):
        """Select the number of gridpoints dependant on the angular grid selected
        """
        if (choice == 'Gauss-Legendre'):
            self.dftangular_tool.ShowCounter()
            self.dftangular_tool.HideMenu()
        if (choice == 'Lebedev-Laikov'):
            self.dftangular_tool.ShowMenu()
            self.dftangular_tool.HideCounter()
        if (choice == 'default'):
            self.dftangular_tool.HideCounter()
            self.dftangular_tool.HideMenu()

    def __dftjbasselect(self):
        """Configure the tools to be displayed depending on whether we are using
           Coulomb fitting in a DFT calculation.
        """
        self.dftjfit_tool.ReadWidget()

        if self.calc.get_parameter('dft_jfit'):
            self.dftjbas_tool.Pack()
            self.dftschwarz_tool.Pack()
        else:
            self.dftjbas_tool.Forget()
            self.dftschwarz_tool.Forget()
            
    #Optimisation methods are here
    def __selectcoords(self,choice):
        """Display the tools suitable for the coordinate scheme selected
           and with their default values.
        """
        #Read this, the findts and jorgensen widgets to see where we are at:
        self.find_ts_tool.ReadWidget()
        self.optjorg_tool.ReadWidget()
        self.optcoords_tool.ReadWidget()
        
        if (self.calc.get_parameter('optimiser') == 'Cartesian'):
            self.optxtol_tool.UpdateWidget()
            if (self.calc.get_parameter('find_ts')):
                self.Error('Transistion state location requires internal coordinates!\n'
                           +'Make sure the z-matrix for your molecule is suitable.')
                self.calc.set_parameter('find_ts',0)
                #self.find_ts_tool.UpdateWidget()
                #self.__findts()
                return
                
            if (self.calc.get_parameter('opt_jorgensen')):
                self.Error('Use of the Jorgensen-Simons algorithm requires internal coordinates!\n'
                           +'Make sure the z-matrix for your molecule is suitable.')
                #self.calc.set_parameter('opt_jorgensen',0)
                #self.optjorg_tool.UpdateWidget()
                #self.__optjorgensen()
                return
                
            self.optvalue_tool.Forget()
            self.calc.set_parameter('opt_conv_thsld',0.001)

                
        elif (self.calc.get_parameter('optimiser') == 'Z-Matrix'):
            self.calc.set_parameter('opt_value',0.3)
            self.optvalue_tool.UpdateWidget()
            self.optvalue_tool.Pack()
            self.calc.set_parameter('opt_conv_thsld',0.003)
            self.optxtol_tool.UpdateWidget()

    def __findts(self):
        """Configure the optimisation widget with the tools suitable for
           finding a transition state and with their default values.
        """
        self.find_ts_tool.ReadWidget()
        self.optjorg_tool.ReadWidget()
        self.optcoords_tool.ReadWidget()
        
        #Warn if not using internal coordiantes
        if self.calc.get_parameter('find_ts')== 1:
            if self.calc.get_parameter('optimiser') == 'Cartesian':
                self.__selectcoords('Cartesian') #this triggers the warning
                self.calc.set_parameter('optimiser','Z-Matrix')
                self.optcoords_tool.UpdateWidget()
                self.__selectcoords('Z-Matrix')
            if (self.calc.get_parameter('opt_jorgensen')):
                self.__optjorgensen()
                
            self.calc.set_parameter('opt_conv_thsld',0.001)
            self.optxtol_tool.UpdateWidget()
            self.calc.set_parameter('opt_value',0.3)
            self.optvalue_tool.UpdateWidget()

        if self.calc.get_parameter('find_ts')== 0: #update coord and jorg tools accordingly
            self.__selectcoords(self.calc.get_parameter('optimiser'))
            self.__optjorgensen()

    def __optjorgensen(self):
        """If we are undertaking a geometry optimisation using the Jorgensen/Simmons algorithm
           display the tools required for the type of calculation.
        """
        self.find_ts_tool.ReadWidget()
        self.optcoords_tool.ReadWidget()
        self.optjorg_tool.ReadWidget()
        
        opttype = self.calc.get_parameter('find_ts')#type of optimisation
        
        #forget everything unless we need it
        self.optpowell_tool.Forget()
        self.optbfgs_tool.Forget()
        self.optminhess_tool.Forget()
        self.optmaxhess_tool.Forget()
        self.optrfo_tool.Forget()

        if self.calc.get_parameter('opt_jorgensen'):
            if self.calc.get_parameter('optimiser') == 'Cartesian':
                self.__selectcoords('Cartesian') #Trigger the warning
                self.calc.set_parameter('optimiser','Z-Matrix')
                self.optcoords_tool.UpdateWidget()
                self.__selectcoords('Z-Matrix')
                
            if  self.calc.get_parameter('find_ts'):
                self.optpowell_tool.Pack()
            else:
                self.optbfgs_tool.Pack()
                
            self.optminhess_tool.Pack()
            self.optmaxhess_tool.Pack()
            self.optrfo_tool.Pack()
                
    def __restartcalc(self):
        """If this is a restart calculation, display the relevant widgets.
        """
        self.restartcalc_tool.ReadWidget()
        if self.calc.get_parameter('restart'):
            self.restarttype_tool.Pack()
            self.restartbypass_tool.Pack()
        else:
            self.restarttype_tool.Forget()
            self.restartbypass_tool.Forget()

    def __getenvironment(self):
        """Work out some sensible defaults for the locations of things
           - currently just the lib directory.
        """
        if sys.platform[:3] == 'win':
            try:
                ed0_path = os.environ('MOLPRO_LIB')
            except:
                ed0_path = os.getcwd()
                
        elif sys.platform[:3] == 'mac':
            print "Help!  - still havent got round to supporting the Mac yet!"
            
        else:
            try:
                from jobmanager import ccp1gui_subprocess
                cmd="runmolpro -V"
                p = ccp1gui_subprocess.ForegroundPipe(cmd)
                code = p.run()
                dict = {}
                for l in p.output:
                    w = l.split()
                    dict[w[0]]=w[1]
                ed0_path = dict['MOLPRO_LIB']
            except:
                ed0_path = os.getcwd()

        self.calc.set_parameter('ed0_path',ed0_path)
            
    def summarise_results(self):
        """ Use John Kendrick's output reader to scan a molprouk
            output file and summarise the results.
        """
        print 'scanning output...'


    def LayoutToolsTk(self):
        """Place the widgets belonging to the tools (ChargeTool etc)
        This will generally be replaced by a more specific function
        for a particular code interface.
        """
        #Add Molecule tab
        page = self.notebook.add('Molecule',tab_text='Molecule')
        
        # Associate helpfile with notebook frame
        tab = self.notebook.tab('Molecule')
        viewer.help.sethelp(tab,'Molecule Tab')
        
        page.optgroup = Pmw.Group(page,tag_text="Options")
        page.optgroup.pack(expand='yes',fill='both')
        page.basisgroup = Pmw.Group(page,tag_text="Basis Selector")
        page.basisgroup.pack(expand='yes',fill='both')

        self.title_tool.widget.pack(in_=page.optgroup.interior())
        self.task_tool.widget.pack(in_=page.optgroup.interior())
        self.scfmethod_tool.widget.pack(in_=page.optgroup.interior())
        self.charge_tool.widget.pack(in_=page.optgroup.interior())
        self.spin_tool.widget.pack(in_=page.optgroup.interior())
        self.checkspin_widget.pack(in_=page.optgroup.interior())
        self.symmetry_tool.widget.pack(in_=page.optgroup.interior())

        Pmw.alignlabels([self.charge_tool.widget, self.spin_tool.widget])
        self.basis_tool.widget.pack(in_=page.basisgroup.interior())

        #Add Theory tab
        page = self.notebook.add('Theory',tab_text='Theory')
        # Associate helpfile with notebook frame
        tab = self.notebook.tab('Theory')
        viewer.help.sethelp(tab,'Theory Tab')
        
        page.guessgroup = Pmw.Group(page,tag_text="Guess")
        page.guessgroup.pack(expand='yes',fill='both')
        self.guessoption_tool.widget.pack(in_=page.guessgroup.interior(),side='left')
        page.guessframe = Tkinter.Frame(page.guessgroup.interior())
        page.guessframe.pack(in_=page.guessgroup.interior(),side='left')
        self.guessatoms_tool.SetParent(page.guessframe)
        self.guesssection1_tool.SetParent(page.guessframe)
        self.guesssection2_tool.SetParent(page.guessframe)
        self.guessgetqblock1_tool.SetParent(page.guessframe)
        self.guessgetqsection1_tool.SetParent(page.guessframe)
        self.guessgetqblock2_tool.SetParent(page.guessframe)
        self.guessgetqsection2_tool.SetParent(page.guessframe)

        page.scfgroup = Pmw.Group(page,tag_text="SCF")
        page.scfgroup.pack(expand='yes',fill='both')
        self.scfmethod_tool.widget.pack(in_=page.scfgroup.interior())
        self.scfmaxcycles_tool.widget.pack(in_=page.scfgroup.interior())
        self.scfthreshold_tool.widget.pack(in_=page.scfgroup.interior())
        self.scfbypass_tool.widget.pack(in_=page.scfgroup.interior())

        page.scflevelgroup = Pmw.Group(page,tag_text="SCF Level Shifters")
        page.scflevelgroup.pack(in_=page.scfgroup.interior(),
                                expand='yes',
                                fill='both',
                                padx=10,
                                pady=10)
        self.scflevelinit_tool.widget.pack(in_=page.scflevelgroup.interior())
        self.scflevelit_tool.widget.pack(in_=page.scflevelgroup.interior())
        self.scflevelfinal_tool.widget.pack(in_=page.scflevelgroup.interior())

        page.postscfgroup = Pmw.Group(page,tag_text="Post SCF")
        page.postscfgroup.pack(expand='yes',fill='both')

        self.postscfmethod_tool.widget.pack(in_=page.postscfgroup.interior())

        
        #Add DFT tab
        page = self.notebook.add('DFT',tab_text='DFT')
        # Associate helpfile with notebook frame
        tab = self.notebook.tab('DFT')
        viewer.help.sethelp(tab,'DFT Tab')
        
        page.dftgroup1 = Pmw.Group(page,tag_text="Functional")
        page.dftgroup1.pack(expand='yes',fill='both')
        page.dftgroup2 = Pmw.Group(page,tag_text="Accuracy")
        page.dftgroup2.pack(expand='yes',fill='both')
        page.dftgroup3 = Pmw.Group(page,tag_text="Quadrature Types")
        page.dftgroup3.pack(expand='yes',fill='both')
        #page.dftgroup4 = Pmw.Group(page,tag_text="DFT Options4")
        #page.dftgroup4.pack(expand='yes',fill='both')
        page.dftgroup5 = Pmw.Group(page,tag_text="Coulomb Fitting")
        page.dftgroup5.pack(expand='yes',fill='both')


        self.dftfunctional_tool.widget.pack(in_=page.dftgroup1.interior())
        self.dftaccuracy_tool.widget.pack(in_=page.dftgroup2.interior())
        self.dftweightscheme_tool.widget.pack(in_=page.dftgroup2.interior())        
        self.dftradial_tool.widget.pack(in_=page.dftgroup3.interior(),side='top')
        self.dftangular_tool.widget.pack(in_=page.dftgroup3.interior(),side='top')
        
        self.dftjfit_tool.SetParent(page.dftgroup5.interior())
        self.dftjfit_tool.Pack()
        self.dftjbas_tool.SetParent(page.dftgroup5.interior())
        self.dftschwarz_tool.SetParent(page.dftgroup5.interior())

        # Add Properties tab
        page = self.notebook.add('Properties',tab_text='Properties')
        
        # Associate helpfile with notebook frame
        tab = self.notebook.tab('Properties')
        viewer.help.sethelp(tab,'Properties Tab')
        
        page.grgroup = Pmw.Group(page,tag_text="Graphical options")

        page.grgroup.pack(expand='yes',fill='x')

        page.mogroup = Pmw.Group(page.grgroup.interior(),tag_text="Orbital Plots")
        page.mogroup.pack(expand='yes',fill='x',side='right')
        self.homolumo_tool.widget.pack(in_=page.mogroup.interior())
        self.homolumo1_tool.widget.pack(in_=page.mogroup.interior())
        self.homolumo2_tool.widget.pack(in_=page.mogroup.interior())
        self.homolumo3_tool.widget.pack(in_=page.mogroup.interior())
        self.homolumo4_tool.widget.pack(in_=page.mogroup.interior())
        self.homolumo5_tool.widget.pack(in_=page.mogroup.interior())

        f = Tkinter.Frame(page.grgroup.interior())
        f.pack(expand='yes',fill='x',side='left')
        page.group2 = Pmw.Group(f,tag_text="Density and Potential")
        page.group2.pack(expand='yes',fill='x',side='top')
        self.chargeden_tool.widget.pack(in_=page.group2.interior())
        self.diffden_tool.widget.pack(in_=page.group2.interior())
        self.potential_tool.widget.pack(in_=page.group2.interior())
        self.chargedengrad_tool.widget.pack(in_=page.group2.interior())
        self.spinden_tool.widget.pack(in_=page.group2.interior())

        page.editgrid_button = Tkinter.Button(f,command=self.edit_grid)
        page.editgrid_button.config(text="Edit Grid")
        page.editgrid_button.pack(side='bottom',padx=10,pady=20)

        page.vgroup = Pmw.Group(page,tag_text="Frequencies")
        page.vgroup.pack(expand='yes',fill='x')
        self.frequencies_tool.widget.pack(in_=page.vgroup.interior())
        self.hessian_tool.widget.pack(in_=page.vgroup.interior())

        Pmw.alignlabels([self.homolumo_tool.widget,
                         self.homolumo1_tool.widget,
                         self.homolumo2_tool.widget,
                         self.homolumo3_tool.widget,
                         self.homolumo4_tool.widget,
                         self.homolumo5_tool.widget])

        Pmw.alignlabels([self.potential_tool.widget,
                         self.chargeden_tool.widget,
                         self.diffden_tool.widget,
                         self.chargedengrad_tool.widget,
                         self.spinden_tool.widget,
                         page.editgrid_button])


        #Add Optimisation tab
        page = self.notebook.add('Optimisation',tab_text='Optimisation')
        
        # Associate helpfile with notebook frame
        tab = self.notebook.tab('Optimisation')
        viewer.help.sethelp(tab,'Optimisation Tab')
        
        page.rungroup = Pmw.Group(page,tag_text="Runtype")
        page.rungroup.pack(expand='yes',fill='both')
        self.optcoords_tool.widget.pack(in_=page.rungroup.interior())
        self.find_ts_tool.widget.pack(in_=page.rungroup.interior())

        page.searchgroup = Pmw.Group(page,tag_text="Search Procedure")
        page.searchgroup.pack(expand='yes',fill='both')
        self.optmaxcyc1_tool.SetParent(page.searchgroup.interior())
        self.optmaxcyc1_tool.Pack()
        self.optmaxcyc2_tool.SetParent(page.searchgroup.interior())
        self.optmaxcyc2_tool.Pack()
        self.optxtol_tool.SetParent(page.searchgroup.interior())
        self.optxtol_tool.Pack()
        self.optstepmax_tool.SetParent(page.searchgroup.interior())
        self.optstepmax_tool.Pack()
        self.optvalue_tool.SetParent(page.searchgroup.interior())
        self.optvalue_tool.Pack()
        Pmw.alignlabels([self.optmaxcyc1_tool.widget, self.optmaxcyc2_tool.widget,
                         self.optxtol_tool.widget, self.optstepmax_tool.widget,
                         self.optvalue_tool.widget])
        
        page.jorggroup = Pmw.Group(page,tag_text="Jorgensen-Simons Algorithm")
        page.jorggroup.pack(expand='yes',fill='both')
        self.optjorg_tool.SetParent(page.jorggroup.interior())
        self.optjorg_tool.Pack()
        self.optpowell_tool.SetParent(page.jorggroup.interior())
        self.optbfgs_tool.SetParent(page.jorggroup.interior())
        self.optminhess_tool.SetParent(page.jorggroup.interior())
        self.optmaxhess_tool.SetParent(page.jorggroup.interior())
        self.optrfo_tool.SetParent(page.jorggroup.interior())
        Pmw.alignlabels([self.optjorg_tool.widget, self.optpowell_tool.widget,
                         self.optbfgs_tool.widget, self.optminhess_tool.widget,
                         self.optmaxhess_tool.widget, self.optrfo_tool.widget])

        #Add Job tab
        page = self.notebook.add('Job',tab_text='Job')

        # Associate helpfile with notebook frame
        tab = self.notebook.tab('Job')
        viewer.help.sethelp(tab,'Job Tab')
        
        page.jobgroup = Pmw.Group(page,tag_text="Job Group")
        page.jobgroup.pack(side='top',expand='yes',fill='both')

        self.jobname_tool.widget.pack(in_=page.jobgroup.interior())

        # Job submission
        self.submission_frame = Tkinter.Frame(page.jobgroup.interior())
        self.submission_frame.pack()
        self.submission_tool = tools.SelectOptionTool(self,
                                                'submission',
                                                'Job Submission',
                                                self.submission_policies,
                                                )
        self.submission_config_button = Tkinter.Button(self.submission_frame,
                                                       text='Configure...',
                                                       command=self.open_jobsub_editor)
        self.submission_tool.widget.pack(in_=self.submission_frame,side='left')
        self.submission_config_button.pack(side='left')#
        

    def EditCoordinates(self,model=None):
        """Open a coordinate editor window
        This differs from the generic one only in that the variables can
        have keywords associated (e.g. type 3)
        """
        if self.calc.editing:
            print 'Calculation is already being edited'
        else:
            self.calc.editing = 1
            mol_name = self.calc.get_input('mol_name')
            mol_obj = self.calc.get_input('mol_obj')
            self.zme = ZME(self.root,
                           model=mol_obj,
                           reload_func=self.reload_for_zme,
                           update_func=self.update_for_zme,
                           v_key=1)


def copycontents(to,fro):
    """Used to update an object by copying in the contents from another"""
    c = to.__class__
    d1 = c.__dict__
    try:
        d2 = fro.__dict__
    except AttributeError:
        d2 = {}
    for k in d2.keys():
        to.__dict__[k] = fro.__dict__[k]


def prdict(obj,name,depth):

    try:
        myclass = obj.__class__
    except:
        myclass = ""

    for i in range(depth):
        print "   ",
    print name, obj, myclass

    try:
        dicts = obj.__dict__.keys()
    except AttributeError:
        dicts = []

    for y in dicts:
        o = obj.__dict__[y]
        prdict(o,y,depth+1)


def pickler(obj):

    obj.g = None

    prdict(obj,'TOP',0)

    sfile='junk.pkl'
    fobj = open(sfile,'w')

    p = pickle.Pickler(fobj)
        
    try:
        p.dump(obj)
    except pickle.PicklingError, e:
        print 'X'
        print e.__class__
        print e.args

    fobj.close()
    

if __name__ == "__main__":
    from interfaces.molpro import *
    from objects.zmatrix import *

    if 1:
        calc = MOLPROCalc()
        calc.set_parameter('ana_hessian',1)
        calc.set_input('mol_obj',Zmatrix(file='../examples/water.zmt'))
        job = calc.makejob()
        job.debug = 1
        job.run()
        calc.endjob()

    if 0:
        root = Tk()
        calc = MOLPROCalc()
        calc.set_input('mol_obj',Zmatrix(file='../examples/water.zmt'))
        jm = JobManager()
        je = JobEditor(root,jm)
        vt = MOLPROCalcEd(root,calc,None,job_editor=je)
        # invoke via calculation editor
        vt.Run()
        root.mainloop()
