Révision 3 ase/calculators/turbomole.py

turbomole.py (revision 3)
2 2

  
3 3
http://www.turbomole.com/
4 4
"""
5

  
6

  
7 5
import os, sys, string
8 6

  
9
from ase.data import chemical_symbols
10 7
from ase.units import Hartree, Bohr
11 8
from ase.io.turbomole import write_turbomole
12
from general import Calculator
9
from ase.calculators.general import Calculator
13 10

  
14 11
import numpy as np
15 12

  
16 13
class Turbomole(Calculator):
17 14
    """Class for doing Turbomole calculations.
18 15
    """
19
    def __init__(self, label='turbomole'):
16
    def __init__(self, label='turbomole', calculate_energy="dscf", calculate_forces="grad", post_HF = False):
20 17
        """Construct TURBOMOLE-calculator object.
21 18

  
22 19
        Parameters
......
59 56
        e = a.get_potential_energy()
60 57
        
61 58
        """
62
        
63
        # get names of executables for turbomole energy and forces
64
        # get the path
65

  
66
        os.system('rm -f sysname.file; sysname > sysname.file')
67
        f = open('sysname.file')
68
        architechture = f.readline()[:-1]
69
        f.close()
70
        tmpath = os.environ['TURBODIR']
71
        pre = tmpath + '/bin/' + architechture + '/'
72

  
73

  
74
        if os.path.isfile('control'):
75
            f = open('control')
76
        else:
77
            print 'File control is missing'
78
            raise RuntimeError, \
79
                'Please run Turbomole define and come thereafter back'
80
        lines = f.readlines()
81
        f.close()
82
        self.tm_program_energy=pre+'dscf'
83
        self.tm_program_forces=pre+'grad'        
84
        for line in lines:
85
            if line.startswith('$ricore'):
86
                self.tm_program_energy=pre+'ridft'
87
                self.tm_program_forces=pre+'rdgrad'
88

  
59
       
89 60
        self.label = label
90 61
        self.converged = False
91
        #clean up turbomole energy file
92
        os.system('rm -f energy; touch energy')
62
        
63
        # set calculators for energy and forces
64
        self.calculate_energy = calculate_energy
65
        self.calculate_forces = calculate_forces
93 66

  
94
        #turbomole has no stress
67
        # turbomole has no stress
95 68
        self.stress = np.empty((3, 3))
96 69
        
70
        # storage for energy and forces
71
        self.e_total = None
72
        self.forces = None
73
        self.updated = False
74
        
75
        # atoms must be set
76
        self.atoms = None
77
        
78
        # POST-HF method 
79
        self.post_HF  = post_HF
97 80

  
98
    def update(self, atoms):
99
        """Energy and forces are calculated when atoms have moved
100
        by calling self.calculate
101
        """
102
        if (not self.converged or
103
            len(self.numbers) != len(atoms) or
104
            (self.numbers != atoms.get_atomic_numbers()).any()):
105
            self.initialize(atoms)
106
            self.calculate(atoms)
107
        elif ((self.positions != atoms.get_positions()).any() or
108
              (self.pbc != atoms.get_pbc()).any() or
109
              (self.cell != atoms.get_cell()).any()):
110
            self.calculate(atoms)
111

  
112 81
    def initialize(self, atoms):
113 82
        self.numbers = atoms.get_atomic_numbers().copy()
114 83
        self.species = []
......
116 85
            self.species.append(Z)
117 86
        self.converged = False
118 87
        
88
    def execute(self, command):
89
        from subprocess import Popen, PIPE
90
        try:
91
            proc = Popen([command], shell=True, stderr=PIPE)
92
            error = proc.communicate()[1]
93
            if "abnormally" in error:
94
                raise OSError(error)
95
            print "TM command: ", command, "successfully executed"
96
        except OSError, e:
97
            print >>sys.stderr, "Execution failed:", e
98
            sys.exit(1)
99

  
119 100
    def get_potential_energy(self, atoms):
120
        self.update(atoms)
121
        return self.etotal
101
        # update atoms
102
        self.set_atoms(atoms)
103
        # if update of energy is neccessary
104
        if self.update_energy:
105
            # calculate energy
106
            self.execute(self.calculate_energy + " > ASE.TM.energy.out")
107
            # check for convergence of dscf cycle
108
            if os.path.isfile('dscf_problem'):
109
                print 'Turbomole scf energy calculation did not converge'
110
                raise RuntimeError, \
111
                    'Please run Turbomole define and come thereafter back'
112
            # read energy
113
            self.read_energy()
114
        else :
115
            print "taking old values (E)"
116
        self.update_energy = False
117
        return self.e_total
122 118

  
123 119
    def get_forces(self, atoms):
124
        self.update(atoms)
120
        # update atoms
121
        self.set_atoms(atoms)
122
        # complete energy calculations
123
        if self.update_energy:
124
            self.get_potential_energy(atoms)
125
        # if update of forces is neccessary
126
        if self.update_forces:
127
            # calculate forces
128
            self.execute(self.calculate_forces + " > ASE.TM.forces.out")
129
            # read forces
130
            self.read_forces()
131
        else :
132
            print "taking old values (F)"
133
        self.update_forces = False
125 134
        return self.forces.copy()
126 135
    
127 136
    def get_stress(self, atoms):
128
        self.update(atoms)
129 137
        return self.stress.copy()
130

  
131
    def calculate(self, atoms):
132
        """Total Turbomole energy is calculated (to file 'energy'
133
        also forces are calculated (to file 'gradient')
134
        """
135
        self.positions = atoms.get_positions().copy()
136
        self.cell = atoms.get_cell().copy()
137
        self.pbc = atoms.get_pbc().copy()
138

  
139
        #write current coordinates to file 'coord' for Turbomole
138
        
139
    def set_atoms(self, atoms):
140
        if self.atoms == atoms:
141
            return
142
        # performs an update of the atoms 
143
        super(Turbomole, self).set_atoms(atoms)
140 144
        write_turbomole('coord', atoms)
141

  
142

  
143
        #Turbomole energy calculation
144
        os.system('rm -f output.energy.dummy; \
145
                      '+ self.tm_program_energy +'> output.energy.dummy')
146

  
147
        #check that the energy run converged
148
        if os.path.isfile('dscf_problem'):
149
            print 'Turbomole scf energy calculation did not converge'
150
            print 'issue command t2x -c > last.xyz'
151
            print 'and check geometry last.xyz and job.xxx or statistics'
152
            raise RuntimeError, \
153
                'Please run Turbomole define and come thereafter back'
154

  
155

  
156
        self.read_energy()
157

  
158
        #Turbomole atomic forces calculation
159
        #killing the previous gradient file because 
160
        #turbomole gradients are affected by the previous values
161
        os.system('rm -f gradient; rm -f output.forces.dummy; \
162
                      '+ self.tm_program_forces +'> output.forces.dummy')
163

  
164
        self.read_forces(atoms)
165

  
166
        self.converged = True
167

  
145
        # energy and forces must be re-calculated
146
        self.update_energy = True
147
        self.update_forces = True
168 148
        
169 149
    def read_energy(self):
170 150
        """Read Energy from Turbomole energy file."""
......
178 158
            elif line.startswith('$'):
179 159
                pass
180 160
            else:
181
                #print 'LINE',line
161
                # print 'LINE',line
182 162
                energy_tmp = float(line.split()[1])
183
        #print 'energy_tmp',energy_tmp
184
        self.etotal = energy_tmp * Hartree
163
                if self.post_HF:
164
                    energy_tmp += float(line.split()[4])
165
        self.e_total = energy_tmp * Hartree
166
        
185 167

  
186

  
187
    def read_forces(self,atoms):
168
    def read_forces(self):
188 169
        """Read Forces from Turbomole gradient file."""
189

  
190 170
        file = open('gradient','r')
191
        line=file.readline()
192
        line=file.readline()
193
        tmpforces = np.array([[0, 0, 0]])
194
        while line:
195
            if 'cycle' in line:
196
                for i, dummy in enumerate(atoms):
197
                            line=file.readline()
198
                forces_tmp=[]
199
                for i, dummy in enumerate(atoms):
200
                            line=file.readline()
201
                            line2=string.replace(line,'D','E')
202
                            #tmp=np.append(forces_tmp,np.array\
203
                            #      ([[float(f) for f in line2.split()[0:3]]]))
204
                            tmp=np.array\
205
                                ([[float(f) for f in line2.split()[0:3]]])
206
                            tmpforces=np.concatenate((tmpforces,tmp))  
207
            line=file.readline()
208
            
171
        lines=file.readlines()
172
        file.close()
209 173

  
210
        #note the '-' sign for turbomole, to get forces
211
        self.forces = (-np.delete(tmpforces, np.s_[0:1], axis=0))*Hartree/Bohr
174
        forces = np.array([[0, 0, 0]])
175
        
176
        nline = len(lines)
177
        iline = -1
178
        
179
        for i in xrange(nline):
180
            if 'cycle' in lines[i]:
181
                iline = i
182
        
183
        if iline < 0:
184
            print 'Gradients not found'
185
            raise RuntimeError("Please check TURBOMOLE gradients")
212 186

  
213
        #print 'forces', self.forces
214

  
215
    def read(self):
216
        """Dummy stress for turbomole"""
217
        self.stress = np.empty((3, 3))
187
        iline += len(self.atoms) + 1
188
        nline -= 1
189
        for i in xrange(iline, nline):
190
            line = string.replace(lines[i],'D','E')
191
            #tmp=np.append(forces_tmp,np.array\
192
            #      ([[float(f) for f in line.split()[0:3]]]))
193
            tmp=np.array([[float(f) for f in line.split()[0:3]]])
194
            forces=np.concatenate((forces,tmp))  
195
        #note the '-' sign for turbomole, to get forces
196
        self.forces = (-np.delete(forces, np.s_[0:1], axis=0))*Hartree/Bohr

Formats disponibles : Unified diff