root / ase / calculators / mopac.py @ 13
Historique | Voir | Annoter | Télécharger (5,9 ko)
1 |
"""
|
---|---|
2 |
This module is the MOPAC module for ASE, based on the PyMD MOPAC Module by R. Bulo,
|
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 commands |
11 |
import numpy as np |
12 |
|
13 |
from ase.atoms import Atoms |
14 |
from ase.units import kcal, mol |
15 |
from ase.calculators.general import Calculator |
16 |
|
17 |
kcal_mol = kcal / mol |
18 |
class Mopac(Calculator): |
19 |
def __init__(self, files=None, restart=0, geomopt=False, functional="PM6"): |
20 |
self.restart = restart
|
21 |
self.geomopt = geomopt
|
22 |
self.functional = functional
|
23 |
|
24 |
self.spin = 0 |
25 |
self.occupations = None |
26 |
|
27 |
self.stress = None |
28 |
self.energy_zero = None |
29 |
self.energy_free = None |
30 |
self.forces = None |
31 |
|
32 |
self.atoms_old = None |
33 |
|
34 |
def write_moldata(self): |
35 |
"""
|
36 |
Writes the files that have to be written each timestep
|
37 |
"""
|
38 |
# Change labels variable if necessary
|
39 |
# FIXME: what does norderats stands for????
|
40 |
norderats = 0
|
41 |
for el in self.atoms.get_chemical_symbols(): |
42 |
norderats += 1
|
43 |
if norderats != self.atoms.get_number_of_atoms(): |
44 |
self.labels = self.get_labels() |
45 |
|
46 |
input = self.get_input_block()
|
47 |
pyfile = open('pymopac.in','w') |
48 |
pyfile.write(input)
|
49 |
pyfile.close() |
50 |
|
51 |
def run(self): |
52 |
self.write_moldata()
|
53 |
print '<MOPAC calculation started>' |
54 |
out = commands.getoutput('mopac pymopac.in')
|
55 |
outputfile = open('pymopac.in.out') |
56 |
outfile = open('mopac%02i.out'%(self.restart),'w') |
57 |
for line in outputfile: |
58 |
outfile.write(line) |
59 |
outfile.close() |
60 |
outputfile.close() |
61 |
|
62 |
energy = self.read_energy()
|
63 |
if energy == None: |
64 |
energy = self.rerun()
|
65 |
self.forces = self.read_forces() |
66 |
print '<MOPAC calculation finished>' |
67 |
|
68 |
self.energy_zero = energy
|
69 |
self.energy_free = energy
|
70 |
self.first = False |
71 |
|
72 |
def read_energy(self, charges=True): |
73 |
outfile = open('pymopac.in.out') |
74 |
lines = outfile.readlines() |
75 |
outfile.close() |
76 |
|
77 |
chargelines = 0
|
78 |
if charges:
|
79 |
nats = len(self.atoms) |
80 |
block = ''
|
81 |
for line in lines: |
82 |
if line.find('HEAT OF FORMATION') != -1: |
83 |
words = line.split() |
84 |
energy = float(words[5]) |
85 |
if line.find('H.o.F. per unit cell') != -1: |
86 |
words = line.split() |
87 |
energy = float(words[5]) |
88 |
if line.find('"""""""""""""UNABLE TO ACHIEVE SELF-CONSISTENCE') != -1: |
89 |
energy = None
|
90 |
if charges:
|
91 |
if line.find('NET ATOMIC CHARGES') != -1: |
92 |
chargelines += 1
|
93 |
if chargelines > 0 and chargelines <= nats+3: |
94 |
chargelines += 1
|
95 |
block += line |
96 |
|
97 |
if charges:
|
98 |
chargefile = open('charge%02i.out'%(self.restart),'a') |
99 |
chargefile.write(block) |
100 |
chargefile.close() |
101 |
|
102 |
return energy
|
103 |
|
104 |
def read_forces(self): |
105 |
outfile = open('pymopac.in.aux') |
106 |
lines = outfile.readlines() |
107 |
outfile.close() |
108 |
|
109 |
outputforces = None
|
110 |
nats = len(self.atoms) |
111 |
|
112 |
forces = np.zeros((nats, 3), float) |
113 |
for i,line in enumerate(lines): |
114 |
if line.find('GRADIENTS:') != -1: |
115 |
l = 0
|
116 |
for j in range(nats * 3): |
117 |
if j%10 == 0: |
118 |
l += 1
|
119 |
gline = lines[i+l] |
120 |
k = j -((l-1)*10) |
121 |
|
122 |
try:
|
123 |
f = -float(gline[k*18:(k*18)+18]) |
124 |
except ValueError: |
125 |
if outputforces == None: |
126 |
outputforces = self.read_output_forces()
|
127 |
f = outputforces[j] |
128 |
forces[j/3, j%3] = f |
129 |
break
|
130 |
|
131 |
forces *= kcal_mol |
132 |
return forces
|
133 |
|
134 |
def read_output_forces(self): |
135 |
outfile = open('pymopac.in.out') |
136 |
lines = outfile.readlines() |
137 |
outfile.close() |
138 |
|
139 |
nats = len(self.atoms) |
140 |
|
141 |
forces = np.zeros((nats, 3), float) |
142 |
for i,line in enumerate(lines): |
143 |
if line.find('GRADIENT\n') != -1: |
144 |
for j in range(nats * 3): |
145 |
gline = lines[i+j+1]
|
146 |
forces[j/3, j%3] = -float(gline[49:62]) |
147 |
break
|
148 |
|
149 |
return forces
|
150 |
|
151 |
def get_input_block(self): |
152 |
# For restarting I can use 'DENOUT' and 'OLDENS' at some point
|
153 |
block = ''
|
154 |
block += '%s '%(self.functional) |
155 |
#if self.functional == 'PM6-DH2':
|
156 |
block += 'NOANCI '
|
157 |
block += '1SCF GRADIENTS '
|
158 |
block += 'AUX(0,PRECISION=9) '
|
159 |
block += 'RELSCF = 0.0001 '
|
160 |
charge = 0
|
161 |
if charge != 0: |
162 |
block += 'CHARGE=%i '%(charge)
|
163 |
if self.spin == 1.: |
164 |
block += 'DOUBLET '
|
165 |
elif self.spin == 2.: |
166 |
block += 'TRIPLET '
|
167 |
block += '\n'
|
168 |
block += 'Title: ASE job\n\n'
|
169 |
|
170 |
constraints = self.atoms._get_constraints()
|
171 |
nconstraints = len(constraints)
|
172 |
for iat in xrange(len(self.atoms)): |
173 |
f = [1, 1, 1] |
174 |
if iat < nconstraints:
|
175 |
if constraints[iat] is not None: |
176 |
f = [0, 0, 0] |
177 |
atom = self.atoms[iat]
|
178 |
xyz = atom.position |
179 |
block += ' %2s'%atom.symbol
|
180 |
block += ' %16.5f %i %16.5f %i %16.5f %i \n'%(xyz[0],f[0],xyz[1],f[1],xyz[2],f[2]) |
181 |
|
182 |
if self.atoms.pbc.any(): |
183 |
for v in self.atoms.get_cell(): |
184 |
block += 'Tv %8.3f %8.3f %8.3f\n'%(v[0],v[1],v[2]) |
185 |
return block
|
186 |
|
187 |
def update(self, atoms): |
188 |
if self.atoms_old != atoms: |
189 |
self.atoms = atoms.copy()
|
190 |
self.atoms_old = atoms.copy()
|
191 |
self.run()
|