Statistiques
| Révision :

root / ase / calculators / mopac.py @ 16

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