Statistiques
| Révision :

root / ase / calculators / turbomole.py @ 10

Historique | Voir | Annoter | Télécharger (5,14 ko)

1
"""This module defines an ASE interface to Turbomole
2
http://www.turbomole.com/
3
"""
4
import os, sys, string
5

    
6
from ase.units import Hartree, Bohr
7
from ase.io.turbomole import write_turbomole
8
from ase.calculators.general import Calculator
9

    
10
import numpy as np
11

    
12
class Turbomole(Calculator):
13
    def __init__(self, label='turbomole', calculate_energy="dscf", calculate_forces="grad", post_HF = False):
14
        self.label = label
15
        self.converged = False
16
        
17
        # set calculators for energy and forces
18
        self.calculate_energy = calculate_energy
19
        self.calculate_forces = calculate_forces
20

    
21
        # turbomole has no stress
22
        self.stress = np.empty((3, 3))
23
        
24
        # storage for energy and forces
25
        self.e_total = None
26
        self.forces = None
27
        self.updated = False
28
        
29
        # atoms must be set
30
        self.atoms = None
31
        
32
        # POST-HF method 
33
        self.post_HF  = post_HF
34

    
35
    def initialize(self, atoms):
36
        self.numbers = atoms.get_atomic_numbers().copy()
37
        self.species = []
38
        for a, Z in enumerate(self.numbers):
39
            self.species.append(Z)
40
        self.converged = False
41
        
42
    def execute(self, command):
43
        from subprocess import Popen, PIPE
44
        try:
45
            # the sub process gets started here
46
            proc = Popen([command], shell=True, stderr=PIPE)
47
            error = proc.communicate()[1]
48
            # check the control file for "actual step" keyword
49
            file = open("control")
50
            data = file.read()
51
            if "$actual step" in data:
52
                raise OSError(error)
53
            # print "TM command: ", command, "successfully executed"
54
        except OSError, e:
55
            print >>sys.stderr, "Execution failed: ", e
56
            sys.exit(1)
57

    
58
    def get_potential_energy(self, atoms):
59
        # update atoms
60
        self.set_atoms(atoms)
61
        # if update of energy is neccessary
62
        if self.update_energy:
63
            # calculate energy
64
            self.execute(self.calculate_energy + " > ASE.TM.energy.out")
65
            # check for convergence of dscf cycle
66
            if os.path.isfile('dscf_problem'):
67
                print 'Turbomole scf energy calculation did not converge'
68
                raise RuntimeError, \
69
                    'Please run Turbomole define and come thereafter back'
70
            # read energy
71
            self.read_energy()
72
        else :
73
            print "taking old values (E)"
74
        self.update_energy = False
75
        return self.e_total
76

    
77
    def get_forces(self, atoms):
78
        # update atoms
79
        self.set_atoms(atoms)
80
        # complete energy calculations
81
        if self.update_energy:
82
            self.get_potential_energy(atoms)
83
        # if update of forces is neccessary
84
        if self.update_forces:
85
            # calculate forces
86
            if self.calculate_forces is not None:
87
                self.execute(self.calculate_forces + " > ASE.TM.forces.out")
88
            # read forces
89
            self.read_forces()
90
        else :
91
            print "taking old values (F)"
92
        self.update_forces = False
93
        return self.forces.copy()
94
    
95
    def get_stress(self, atoms):
96
        return self.stress
97
        
98
    def set_atoms(self, atoms):
99
        if self.atoms == atoms:
100
            return
101
        # performs an update of the atoms 
102
        super(Turbomole, self).set_atoms(atoms)
103
        write_turbomole('coord', atoms)
104
        # energy and forces must be re-calculated
105
        self.update_energy = True
106
        self.update_forces = True
107
        
108
    def read_energy(self):
109
        """Read Energy from Turbomole energy file."""
110
        text = open('energy', 'r').read().lower()
111
        lines = iter(text.split('\n'))
112

    
113
        # Energy:
114
        for line in lines:
115
            if line.startswith('$end'):
116
                break
117
            elif line.startswith('$'):
118
                pass
119
            else:
120
                # print 'LINE',line
121
                energy_tmp = float(line.split()[1])
122
                if self.post_HF:
123
                    energy_tmp += float(line.split()[4])
124
        # update energy units
125
        self.e_total = energy_tmp * Hartree
126
        
127

    
128
    def read_forces(self):
129
        """Read Forces from Turbomole gradient file."""
130
        file = open('gradient','r')
131
        lines=file.readlines()
132
        file.close()
133

    
134
        forces = np.array([[0, 0, 0]])
135
        
136
        nline = len(lines)
137
        iline = -1
138
        
139
        for i in xrange(nline):
140
            if 'cycle' in lines[i]:
141
                iline = i
142
        
143
        if iline < 0:
144
            print 'Gradients not found'
145
            raise RuntimeError("Please check TURBOMOLE gradients")
146

    
147
        # next line
148
        iline += len(self.atoms) + 1
149
        # $end line
150
        nline -= 1
151
        # read gradients
152
        for i in xrange(iline, nline):
153
            line = string.replace(lines[i],'D','E')
154
            #tmp=np.append(forces_tmp,np.array\
155
            #      ([[float(f) for f in line.split()[0:3]]]))
156
            tmp=np.array([[float(f) for f in line.split()[0:3]]])
157
            forces=np.concatenate((forces,tmp))  
158
        #note the '-' sign for turbomole, to get forces
159
        self.forces = (-np.delete(forces, np.s_[0:1], axis=0))*Hartree/Bohr