Statistiques
| Révision :

root / ase / calculators / turbomole.py @ 20

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

1
"""
2
This module is the EMBED module for ASE
3
implemented by T. Kerber
4

5
Torsten Kerber, ENS LYON: 2011, 07, 11
6

7
This work is supported by Award No. UK-C0017, made by King Abdullah
8
University of Science and Technology (KAUST)
9
"""
10
import os, sys, string
11

    
12
from ase.units import Hartree, Bohr
13
from ase.io.turbomole import write_turbomole
14
from ase.calculators.general import Calculator
15

    
16
import numpy as np
17

    
18
class Turbomole(Calculator):
19
    def __init__(self, label='turbomole', calculate_energy="dscf", calculate_forces="grad", post_HF = False):
20
        self.label = label
21
        self.converged = False
22
        
23
        # set calculators for energy and forces
24
        self.calculate_energy = calculate_energy
25
        self.calculate_forces = calculate_forces
26

    
27
        # turbomole has no stress
28
        self.stress = np.empty((3, 3))
29
        
30
        # storage for energy and forces
31
        self.e_total = None
32
        self.forces = None
33
        self.updated = False
34
        
35
        # atoms must be set
36
        self.atoms = None
37
        
38
        # POST-HF method 
39
        self.post_HF  = post_HF
40

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

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

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

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

    
134
    def read_forces(self):
135
        """Read Forces from Turbomole gradient file."""
136
        file = open('gradient','r')
137
        lines=file.readlines()
138
        file.close()
139

    
140
        forces = np.array([[0, 0, 0]])
141
        
142
        nline = len(lines)
143
        iline = -1
144
        
145
        for i in xrange(nline):
146
            if 'cycle' in lines[i]:
147
                iline = i
148
        
149
        if iline < 0:
150
            print 'Gradients not found'
151
            raise RuntimeError("Please check TURBOMOLE gradients")
152

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