root / ase / calculators / turbomole.py @ 10
Historique | Voir | Annoter | Télécharger (5,14 ko)
1 | 1 | tkerber | """This module defines an ASE interface to Turbomole
|
---|---|---|---|
2 | 1 | tkerber | http://www.turbomole.com/
|
3 | 1 | tkerber | """
|
4 | 1 | tkerber | import os, sys, string |
5 | 1 | tkerber | |
6 | 1 | tkerber | from ase.units import Hartree, Bohr |
7 | 1 | tkerber | from ase.io.turbomole import write_turbomole |
8 | 3 | tkerber | from ase.calculators.general import Calculator |
9 | 1 | tkerber | |
10 | 1 | tkerber | import numpy as np |
11 | 1 | tkerber | |
12 | 2 | tkerber | class Turbomole(Calculator): |
13 | 3 | tkerber | def __init__(self, label='turbomole', calculate_energy="dscf", calculate_forces="grad", post_HF = False): |
14 | 1 | tkerber | self.label = label
|
15 | 1 | tkerber | self.converged = False |
16 | 3 | tkerber | |
17 | 3 | tkerber | # set calculators for energy and forces
|
18 | 3 | tkerber | self.calculate_energy = calculate_energy
|
19 | 3 | tkerber | self.calculate_forces = calculate_forces
|
20 | 1 | tkerber | |
21 | 3 | tkerber | # turbomole has no stress
|
22 | 1 | tkerber | self.stress = np.empty((3, 3)) |
23 | 1 | tkerber | |
24 | 3 | tkerber | # storage for energy and forces
|
25 | 3 | tkerber | self.e_total = None |
26 | 3 | tkerber | self.forces = None |
27 | 3 | tkerber | self.updated = False |
28 | 3 | tkerber | |
29 | 3 | tkerber | # atoms must be set
|
30 | 3 | tkerber | self.atoms = None |
31 | 3 | tkerber | |
32 | 3 | tkerber | # POST-HF method
|
33 | 3 | tkerber | self.post_HF = post_HF
|
34 | 1 | tkerber | |
35 | 1 | tkerber | def initialize(self, atoms): |
36 | 1 | tkerber | self.numbers = atoms.get_atomic_numbers().copy()
|
37 | 1 | tkerber | self.species = []
|
38 | 1 | tkerber | for a, Z in enumerate(self.numbers): |
39 | 1 | tkerber | self.species.append(Z)
|
40 | 1 | tkerber | self.converged = False |
41 | 1 | tkerber | |
42 | 3 | tkerber | def execute(self, command): |
43 | 3 | tkerber | from subprocess import Popen, PIPE |
44 | 3 | tkerber | try:
|
45 | 5 | tkerber | # the sub process gets started here
|
46 | 3 | tkerber | proc = Popen([command], shell=True, stderr=PIPE)
|
47 | 3 | tkerber | error = proc.communicate()[1]
|
48 | 8 | tkerber | # check the control file for "actual step" keyword
|
49 | 8 | tkerber | file = open("control") |
50 | 8 | tkerber | data = file.read()
|
51 | 8 | tkerber | if "$actual step" in data: |
52 | 8 | tkerber | raise OSError(error) |
53 | 7 | tkerber | # print "TM command: ", command, "successfully executed"
|
54 | 3 | tkerber | except OSError, e: |
55 | 5 | tkerber | print >>sys.stderr, "Execution failed: ", e |
56 | 3 | tkerber | sys.exit(1)
|
57 | 3 | tkerber | |
58 | 1 | tkerber | def get_potential_energy(self, atoms): |
59 | 3 | tkerber | # update atoms
|
60 | 3 | tkerber | self.set_atoms(atoms)
|
61 | 3 | tkerber | # if update of energy is neccessary
|
62 | 3 | tkerber | if self.update_energy: |
63 | 3 | tkerber | # calculate energy
|
64 | 3 | tkerber | self.execute(self.calculate_energy + " > ASE.TM.energy.out") |
65 | 3 | tkerber | # check for convergence of dscf cycle
|
66 | 3 | tkerber | if os.path.isfile('dscf_problem'): |
67 | 3 | tkerber | print 'Turbomole scf energy calculation did not converge' |
68 | 3 | tkerber | raise RuntimeError, \ |
69 | 3 | tkerber | 'Please run Turbomole define and come thereafter back'
|
70 | 3 | tkerber | # read energy
|
71 | 3 | tkerber | self.read_energy()
|
72 | 3 | tkerber | else :
|
73 | 3 | tkerber | print "taking old values (E)" |
74 | 3 | tkerber | self.update_energy = False |
75 | 3 | tkerber | return self.e_total |
76 | 1 | tkerber | |
77 | 1 | tkerber | def get_forces(self, atoms): |
78 | 3 | tkerber | # update atoms
|
79 | 3 | tkerber | self.set_atoms(atoms)
|
80 | 3 | tkerber | # complete energy calculations
|
81 | 3 | tkerber | if self.update_energy: |
82 | 3 | tkerber | self.get_potential_energy(atoms)
|
83 | 3 | tkerber | # if update of forces is neccessary
|
84 | 3 | tkerber | if self.update_forces: |
85 | 3 | tkerber | # calculate forces
|
86 | 10 | tkerber | if self.calculate_forces is not None: |
87 | 10 | tkerber | self.execute(self.calculate_forces + " > ASE.TM.forces.out") |
88 | 3 | tkerber | # read forces
|
89 | 3 | tkerber | self.read_forces()
|
90 | 3 | tkerber | else :
|
91 | 3 | tkerber | print "taking old values (F)" |
92 | 3 | tkerber | self.update_forces = False |
93 | 1 | tkerber | return self.forces.copy() |
94 | 1 | tkerber | |
95 | 1 | tkerber | def get_stress(self, atoms): |
96 | 5 | tkerber | return self.stress |
97 | 3 | tkerber | |
98 | 3 | tkerber | def set_atoms(self, atoms): |
99 | 3 | tkerber | if self.atoms == atoms: |
100 | 3 | tkerber | return
|
101 | 3 | tkerber | # performs an update of the atoms
|
102 | 3 | tkerber | super(Turbomole, self).set_atoms(atoms) |
103 | 1 | tkerber | write_turbomole('coord', atoms)
|
104 | 3 | tkerber | # energy and forces must be re-calculated
|
105 | 3 | tkerber | self.update_energy = True |
106 | 3 | tkerber | self.update_forces = True |
107 | 1 | tkerber | |
108 | 1 | tkerber | def read_energy(self): |
109 | 1 | tkerber | """Read Energy from Turbomole energy file."""
|
110 | 1 | tkerber | text = open('energy', 'r').read().lower() |
111 | 1 | tkerber | lines = iter(text.split('\n')) |
112 | 1 | tkerber | |
113 | 1 | tkerber | # Energy:
|
114 | 1 | tkerber | for line in lines: |
115 | 1 | tkerber | if line.startswith('$end'): |
116 | 1 | tkerber | break
|
117 | 1 | tkerber | elif line.startswith('$'): |
118 | 1 | tkerber | pass
|
119 | 1 | tkerber | else:
|
120 | 3 | tkerber | # print 'LINE',line
|
121 | 1 | tkerber | energy_tmp = float(line.split()[1]) |
122 | 3 | tkerber | if self.post_HF: |
123 | 3 | tkerber | energy_tmp += float(line.split()[4]) |
124 | 5 | tkerber | # update energy units
|
125 | 3 | tkerber | self.e_total = energy_tmp * Hartree
|
126 | 3 | tkerber | |
127 | 1 | tkerber | |
128 | 3 | tkerber | def read_forces(self): |
129 | 1 | tkerber | """Read Forces from Turbomole gradient file."""
|
130 | 1 | tkerber | file = open('gradient','r') |
131 | 3 | tkerber | lines=file.readlines()
|
132 | 3 | tkerber | file.close()
|
133 | 1 | tkerber | |
134 | 3 | tkerber | forces = np.array([[0, 0, 0]]) |
135 | 3 | tkerber | |
136 | 3 | tkerber | nline = len(lines)
|
137 | 3 | tkerber | iline = -1
|
138 | 3 | tkerber | |
139 | 3 | tkerber | for i in xrange(nline): |
140 | 3 | tkerber | if 'cycle' in lines[i]: |
141 | 3 | tkerber | iline = i |
142 | 3 | tkerber | |
143 | 3 | tkerber | if iline < 0: |
144 | 3 | tkerber | print 'Gradients not found' |
145 | 3 | tkerber | raise RuntimeError("Please check TURBOMOLE gradients") |
146 | 1 | tkerber | |
147 | 5 | tkerber | # next line
|
148 | 3 | tkerber | iline += len(self.atoms) + 1 |
149 | 5 | tkerber | # $end line
|
150 | 3 | tkerber | nline -= 1
|
151 | 5 | tkerber | # read gradients
|
152 | 3 | tkerber | for i in xrange(iline, nline): |
153 | 3 | tkerber | line = string.replace(lines[i],'D','E') |
154 | 3 | tkerber | #tmp=np.append(forces_tmp,np.array\
|
155 | 3 | tkerber | # ([[float(f) for f in line.split()[0:3]]]))
|
156 | 3 | tkerber | tmp=np.array([[float(f) for f in line.split()[0:3]]]) |
157 | 3 | tkerber | forces=np.concatenate((forces,tmp)) |
158 | 3 | tkerber | #note the '-' sign for turbomole, to get forces
|
159 | 3 | tkerber | self.forces = (-np.delete(forces, np.s_[0:1], axis=0))*Hartree/Bohr |