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)) |