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