root / ase / calculators / turbomole.py @ 3
Historique | Voir | Annoter | Télécharger (6,27 ko)
1 | 1 | tkerber | """This module defines an ASE interface to Turbomole
|
---|---|---|---|
2 | 1 | tkerber |
|
3 | 1 | tkerber | http://www.turbomole.com/
|
4 | 1 | tkerber | """
|
5 | 1 | tkerber | import os, sys, string |
6 | 1 | tkerber | |
7 | 1 | tkerber | from ase.units import Hartree, Bohr |
8 | 1 | tkerber | from ase.io.turbomole import write_turbomole |
9 | 3 | tkerber | from ase.calculators.general import Calculator |
10 | 1 | tkerber | |
11 | 1 | tkerber | import numpy as np |
12 | 1 | tkerber | |
13 | 2 | tkerber | class Turbomole(Calculator): |
14 | 1 | tkerber | """Class for doing Turbomole calculations.
|
15 | 1 | tkerber | """
|
16 | 3 | tkerber | def __init__(self, label='turbomole', calculate_energy="dscf", calculate_forces="grad", post_HF = False): |
17 | 1 | tkerber | """Construct TURBOMOLE-calculator object.
|
18 | 1 | tkerber |
|
19 | 1 | tkerber | Parameters
|
20 | 1 | tkerber | ==========
|
21 | 1 | tkerber | label: str
|
22 | 1 | tkerber | Prefix to use for filenames (label.txt, ...).
|
23 | 1 | tkerber | Default is 'turbomole'.
|
24 | 1 | tkerber |
|
25 | 1 | tkerber | Examples
|
26 | 1 | tkerber | ========
|
27 | 1 | tkerber | This is poor man's version of ASE-Turbomole:
|
28 | 1 | tkerber |
|
29 | 1 | tkerber | First you do a normal turbomole preparation using turbomole's
|
30 | 1 | tkerber | define-program for the initial and final states.
|
31 | 1 | tkerber |
|
32 | 1 | tkerber | (for instance in subdirectories Initial and Final)
|
33 | 1 | tkerber |
|
34 | 1 | tkerber | Then relax the initial and final coordinates with desired constraints
|
35 | 1 | tkerber | using standard turbomole.
|
36 | 1 | tkerber |
|
37 | 1 | tkerber | Copy the relaxed initial and final coordinates
|
38 | 1 | tkerber | (initial.coord and final.coord)
|
39 | 1 | tkerber | and the turbomole related files (from the subdirectory Initial)
|
40 | 1 | tkerber | control, coord, alpha, beta, mos, basis, auxbasis etc to the directory
|
41 | 1 | tkerber | you do the diffusion run.
|
42 | 1 | tkerber |
|
43 | 1 | tkerber | For instance:
|
44 | 1 | tkerber | cd $My_Turbomole_diffusion_directory
|
45 | 1 | tkerber | cd Initial; cp control alpha beta mos basis auxbasis ../;
|
46 | 1 | tkerber | cp coord ../initial.coord;
|
47 | 1 | tkerber | cd ../;
|
48 | 1 | tkerber | cp Final/coord ./final.coord;
|
49 | 1 | tkerber | mkdir Gz ; cp * Gz ; gzip -r Gz
|
50 | 1 | tkerber |
|
51 | 1 | tkerber | from ase.io import read
|
52 | 1 | tkerber | from ase.calculators.turbomole import Turbomole
|
53 | 1 | tkerber | a = read('coord', index=-1, format='turbomole')
|
54 | 1 | tkerber | calc = Turbomole()
|
55 | 1 | tkerber | a.set_calculator(calc)
|
56 | 1 | tkerber | e = a.get_potential_energy()
|
57 | 1 | tkerber |
|
58 | 1 | tkerber | """
|
59 | 3 | tkerber | |
60 | 1 | tkerber | self.label = label
|
61 | 1 | tkerber | self.converged = False |
62 | 3 | tkerber | |
63 | 3 | tkerber | # set calculators for energy and forces
|
64 | 3 | tkerber | self.calculate_energy = calculate_energy
|
65 | 3 | tkerber | self.calculate_forces = calculate_forces
|
66 | 1 | tkerber | |
67 | 3 | tkerber | # turbomole has no stress
|
68 | 1 | tkerber | self.stress = np.empty((3, 3)) |
69 | 1 | tkerber | |
70 | 3 | tkerber | # storage for energy and forces
|
71 | 3 | tkerber | self.e_total = None |
72 | 3 | tkerber | self.forces = None |
73 | 3 | tkerber | self.updated = False |
74 | 3 | tkerber | |
75 | 3 | tkerber | # atoms must be set
|
76 | 3 | tkerber | self.atoms = None |
77 | 3 | tkerber | |
78 | 3 | tkerber | # POST-HF method
|
79 | 3 | tkerber | self.post_HF = post_HF
|
80 | 1 | tkerber | |
81 | 1 | tkerber | def initialize(self, atoms): |
82 | 1 | tkerber | self.numbers = atoms.get_atomic_numbers().copy()
|
83 | 1 | tkerber | self.species = []
|
84 | 1 | tkerber | for a, Z in enumerate(self.numbers): |
85 | 1 | tkerber | self.species.append(Z)
|
86 | 1 | tkerber | self.converged = False |
87 | 1 | tkerber | |
88 | 3 | tkerber | def execute(self, command): |
89 | 3 | tkerber | from subprocess import Popen, PIPE |
90 | 3 | tkerber | try:
|
91 | 3 | tkerber | proc = Popen([command], shell=True, stderr=PIPE)
|
92 | 3 | tkerber | error = proc.communicate()[1]
|
93 | 3 | tkerber | if "abnormally" in error: |
94 | 3 | tkerber | raise OSError(error) |
95 | 3 | tkerber | print "TM command: ", command, "successfully executed" |
96 | 3 | tkerber | except OSError, e: |
97 | 3 | tkerber | print >>sys.stderr, "Execution failed:", e |
98 | 3 | tkerber | sys.exit(1)
|
99 | 3 | tkerber | |
100 | 1 | tkerber | def get_potential_energy(self, atoms): |
101 | 3 | tkerber | # update atoms
|
102 | 3 | tkerber | self.set_atoms(atoms)
|
103 | 3 | tkerber | # if update of energy is neccessary
|
104 | 3 | tkerber | if self.update_energy: |
105 | 3 | tkerber | # calculate energy
|
106 | 3 | tkerber | self.execute(self.calculate_energy + " > ASE.TM.energy.out") |
107 | 3 | tkerber | # check for convergence of dscf cycle
|
108 | 3 | tkerber | if os.path.isfile('dscf_problem'): |
109 | 3 | tkerber | print 'Turbomole scf energy calculation did not converge' |
110 | 3 | tkerber | raise RuntimeError, \ |
111 | 3 | tkerber | 'Please run Turbomole define and come thereafter back'
|
112 | 3 | tkerber | # read energy
|
113 | 3 | tkerber | self.read_energy()
|
114 | 3 | tkerber | else :
|
115 | 3 | tkerber | print "taking old values (E)" |
116 | 3 | tkerber | self.update_energy = False |
117 | 3 | tkerber | return self.e_total |
118 | 1 | tkerber | |
119 | 1 | tkerber | def get_forces(self, atoms): |
120 | 3 | tkerber | # update atoms
|
121 | 3 | tkerber | self.set_atoms(atoms)
|
122 | 3 | tkerber | # complete energy calculations
|
123 | 3 | tkerber | if self.update_energy: |
124 | 3 | tkerber | self.get_potential_energy(atoms)
|
125 | 3 | tkerber | # if update of forces is neccessary
|
126 | 3 | tkerber | if self.update_forces: |
127 | 3 | tkerber | # calculate forces
|
128 | 3 | tkerber | self.execute(self.calculate_forces + " > ASE.TM.forces.out") |
129 | 3 | tkerber | # read forces
|
130 | 3 | tkerber | self.read_forces()
|
131 | 3 | tkerber | else :
|
132 | 3 | tkerber | print "taking old values (F)" |
133 | 3 | tkerber | self.update_forces = False |
134 | 1 | tkerber | return self.forces.copy() |
135 | 1 | tkerber | |
136 | 1 | tkerber | def get_stress(self, atoms): |
137 | 1 | tkerber | return self.stress.copy() |
138 | 3 | tkerber | |
139 | 3 | tkerber | def set_atoms(self, atoms): |
140 | 3 | tkerber | if self.atoms == atoms: |
141 | 3 | tkerber | return
|
142 | 3 | tkerber | # performs an update of the atoms
|
143 | 3 | tkerber | super(Turbomole, self).set_atoms(atoms) |
144 | 1 | tkerber | write_turbomole('coord', atoms)
|
145 | 3 | tkerber | # energy and forces must be re-calculated
|
146 | 3 | tkerber | self.update_energy = True |
147 | 3 | tkerber | self.update_forces = True |
148 | 1 | tkerber | |
149 | 1 | tkerber | def read_energy(self): |
150 | 1 | tkerber | """Read Energy from Turbomole energy file."""
|
151 | 1 | tkerber | text = open('energy', 'r').read().lower() |
152 | 1 | tkerber | lines = iter(text.split('\n')) |
153 | 1 | tkerber | |
154 | 1 | tkerber | # Energy:
|
155 | 1 | tkerber | for line in lines: |
156 | 1 | tkerber | if line.startswith('$end'): |
157 | 1 | tkerber | break
|
158 | 1 | tkerber | elif line.startswith('$'): |
159 | 1 | tkerber | pass
|
160 | 1 | tkerber | else:
|
161 | 3 | tkerber | # print 'LINE',line
|
162 | 1 | tkerber | energy_tmp = float(line.split()[1]) |
163 | 3 | tkerber | if self.post_HF: |
164 | 3 | tkerber | energy_tmp += float(line.split()[4]) |
165 | 3 | tkerber | self.e_total = energy_tmp * Hartree
|
166 | 3 | tkerber | |
167 | 1 | tkerber | |
168 | 3 | tkerber | def read_forces(self): |
169 | 1 | tkerber | """Read Forces from Turbomole gradient file."""
|
170 | 1 | tkerber | file = open('gradient','r') |
171 | 3 | tkerber | lines=file.readlines()
|
172 | 3 | tkerber | file.close()
|
173 | 1 | tkerber | |
174 | 3 | tkerber | forces = np.array([[0, 0, 0]]) |
175 | 3 | tkerber | |
176 | 3 | tkerber | nline = len(lines)
|
177 | 3 | tkerber | iline = -1
|
178 | 3 | tkerber | |
179 | 3 | tkerber | for i in xrange(nline): |
180 | 3 | tkerber | if 'cycle' in lines[i]: |
181 | 3 | tkerber | iline = i |
182 | 3 | tkerber | |
183 | 3 | tkerber | if iline < 0: |
184 | 3 | tkerber | print 'Gradients not found' |
185 | 3 | tkerber | raise RuntimeError("Please check TURBOMOLE gradients") |
186 | 1 | tkerber | |
187 | 3 | tkerber | iline += len(self.atoms) + 1 |
188 | 3 | tkerber | nline -= 1
|
189 | 3 | tkerber | for i in xrange(iline, nline): |
190 | 3 | tkerber | line = string.replace(lines[i],'D','E') |
191 | 3 | tkerber | #tmp=np.append(forces_tmp,np.array\
|
192 | 3 | tkerber | # ([[float(f) for f in line.split()[0:3]]]))
|
193 | 3 | tkerber | tmp=np.array([[float(f) for f in line.split()[0:3]]]) |
194 | 3 | tkerber | forces=np.concatenate((forces,tmp)) |
195 | 3 | tkerber | #note the '-' sign for turbomole, to get forces
|
196 | 3 | tkerber | self.forces = (-np.delete(forces, np.s_[0:1], axis=0))*Hartree/Bohr |