Statistiques
| Révision :

root / ase / calculators / mopac.py @ 10

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 10 tkerber
        forces = np.reshape(forces,  (3, nats))
128 10 tkerber
        forces *= kcal_mol
129 10 tkerber
130 10 tkerber
        return forces
131 10 tkerber
132 10 tkerber
    def read_output_forces(self):
133 10 tkerber
        outfile = open('pymopac.in.out')
134 10 tkerber
        lines = outfile.readlines()
135 10 tkerber
        outfile.close()
136 10 tkerber
137 10 tkerber
        nats = len(self.atoms)
138 10 tkerber
        nx = nats * 3
139 10 tkerber
140 10 tkerber
        forces = []
141 10 tkerber
        for i,line in enumerate(lines):
142 10 tkerber
            if line.find('GRADIENT\n') != -1:
143 10 tkerber
                for j in range(nx):
144 10 tkerber
                    gline = lines[i+j+1]
145 10 tkerber
                    forces.append(-float(gline[49:62]))
146 10 tkerber
                break
147 10 tkerber
148 10 tkerber
        return forces
149 10 tkerber
150 10 tkerber
    def get_input_block(self):
151 10 tkerber
        # For restarting I can use 'DENOUT' and 'OLDENS' at some point
152 10 tkerber
        block = ''
153 10 tkerber
        block += '%s '%(self.functional)
154 10 tkerber
        #if self.functional == 'PM6-DH2':
155 10 tkerber
        block += 'NOANCI '
156 10 tkerber
        block += '1SCF GRADIENTS '
157 10 tkerber
        block += 'AUX(0,PRECISION=9) '
158 10 tkerber
        block += 'RELSCF = 0.0001 '
159 10 tkerber
        charge = 0
160 10 tkerber
        if charge != 0:
161 10 tkerber
            block += 'CHARGE=%i '%(charge)
162 10 tkerber
        if self.spin == 1.:
163 10 tkerber
            block += 'DOUBLET '
164 10 tkerber
        elif self.spin == 2.:
165 10 tkerber
            block += 'TRIPLET '
166 10 tkerber
        block += '\n'
167 10 tkerber
        block += 'Title: ASE job\n\n'
168 10 tkerber
169 10 tkerber
        constraints = self.atoms._get_constraints()
170 10 tkerber
        nconstraints = len(constraints)
171 10 tkerber
        for iat in xrange(len(self.atoms)):
172 10 tkerber
            f = [1, 1, 1]
173 10 tkerber
            if iat < nconstraints:
174 10 tkerber
                if constraints[iat] is not None:
175 10 tkerber
                    f = [0, 0, 0]
176 10 tkerber
            atom = self.atoms[iat]
177 10 tkerber
            xyz = atom.position
178 10 tkerber
            block += ' %2s'%atom.symbol
179 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])
180 10 tkerber
181 10 tkerber
        if self.atoms.pbc.any():
182 10 tkerber
            for v in self.atoms.get_cell():
183 10 tkerber
                block += 'Tv %8.3f %8.3f %8.3f\n'%(v[0],v[1],v[2])
184 10 tkerber
        return block
185 10 tkerber
186 10 tkerber
    def update(self, atoms):
187 10 tkerber
        if not (self.atoms.get_positions() == atoms.get_positions()).all() or self.first:
188 10 tkerber
            self.atoms = atoms.copy()
189 10 tkerber
            self.run()