Statistiques
| Révision :

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()