Statistiques
| Révision :

root / ase / calculators / turbomole.py @ 2

Historique | Voir | Annoter | Télécharger (6,99 ko)

1
"""This module defines an ASE interface to Turbomole
2

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

    
6

    
7
import os, sys, string
8

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

    
14
import numpy as np
15

    
16
class Turbomole(Calculator):
17
    """Class for doing Turbomole calculations.
18
    """
19
    def __init__(self, label='turbomole'):
20
        """Construct TURBOMOLE-calculator object.
21

22
        Parameters
23
        ==========
24
        label: str
25
            Prefix to use for filenames (label.txt, ...).
26
            Default is 'turbomole'.
27

28
        Examples
29
        ========
30
        This is poor man's version of ASE-Turbomole:
31

32
        First you do a normal turbomole preparation using turbomole's
33
        define-program for the initial and final states.
34

35
        (for instance in subdirectories Initial and Final)
36

37
        Then relax the initial and final coordinates with desired constraints
38
        using standard turbomole.
39

40
        Copy the relaxed initial and final coordinates 
41
        (initial.coord and final.coord)
42
        and the turbomole related files (from the subdirectory Initial) 
43
        control, coord, alpha, beta, mos, basis, auxbasis etc to the directory
44
        you do the diffusion run.
45
        
46
        For instance:
47
        cd $My_Turbomole_diffusion_directory
48
        cd Initial; cp control alpha beta mos basis auxbasis ../;
49
        cp coord ../initial.coord;
50
        cd ../;
51
        cp Final/coord ./final.coord;
52
        mkdir Gz ; cp * Gz ; gzip -r Gz
53
        
54
        from ase.io import read
55
        from ase.calculators.turbomole import Turbomole
56
        a = read('coord', index=-1, format='turbomole')
57
        calc = Turbomole()
58
        a.set_calculator(calc)
59
        e = a.get_potential_energy()
60
        
61
        """
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

    
89
        self.label = label
90
        self.converged = False
91
        #clean up turbomole energy file
92
        os.system('rm -f energy; touch energy')
93

    
94
        #turbomole has no stress
95
        self.stress = np.empty((3, 3))
96
        
97

    
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
    def initialize(self, atoms):
113
        self.numbers = atoms.get_atomic_numbers().copy()
114
        self.species = []
115
        for a, Z in enumerate(self.numbers):
116
            self.species.append(Z)
117
        self.converged = False
118
        
119
    def get_potential_energy(self, atoms):
120
        self.update(atoms)
121
        return self.etotal
122

    
123
    def get_forces(self, atoms):
124
        self.update(atoms)
125
        return self.forces.copy()
126
    
127
    def get_stress(self, atoms):
128
        self.update(atoms)
129
        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
140
        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

    
168
        
169
    def read_energy(self):
170
        """Read Energy from Turbomole energy file."""
171
        text = open('energy', 'r').read().lower()
172
        lines = iter(text.split('\n'))
173

    
174
        # Energy:
175
        for line in lines:
176
            if line.startswith('$end'):
177
                break
178
            elif line.startswith('$'):
179
                pass
180
            else:
181
                #print 'LINE',line
182
                energy_tmp = float(line.split()[1])
183
        #print 'energy_tmp',energy_tmp
184
        self.etotal = energy_tmp * Hartree
185

    
186

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

    
190
        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
            
209

    
210
        #note the '-' sign for turbomole, to get forces
211
        self.forces = (-np.delete(tmpforces, np.s_[0:1], axis=0))*Hartree/Bohr
212

    
213
        #print 'forces', self.forces
214

    
215
    def read(self):
216
        """Dummy stress for turbomole"""
217
        self.stress = np.empty((3, 3))