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