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