Statistiques
| Révision :

root / ase / calculators / mopac.py @ 10

Historique | Voir | Annoter | Télécharger (5,68 ko)

1
"""
2
This module is the MOPAC module for ASE, 
3
based on the PyMD MOPAC Module by R. Bulo, 
4
implemented by T. Kerber
5

6
2011, ENS Lyon
7
"""
8
import commands
9
import numpy as np
10

    
11
from ase.atoms import Atoms
12
from ase.units import kcal, mol
13
from ase.calculators.general import Calculator
14

    
15
kcal_mol = kcal / mol
16
class Mopac(Calculator):
17
    def __init__(self, files=None, restart=0, geomopt=False, functional="PM6"):
18
        self.restart = restart
19
        self.geomopt = geomopt
20
        self.functional = functional
21

    
22
        self.spin = 0
23
        self.occupations = None
24

    
25
        self.first = True
26
        self.stress = None
27
        self.energy_zero = None
28
        self.energy_free = None
29
        self.forces = None
30
        
31
    def write_moldata(self):
32
        """
33
        Writes the files that have to be written each timestep
34
        """
35
        # Change labels variable if necessary
36
        # FIXME: what does norderats stands for????
37
        norderats = 0
38
        for el in self.atoms.get_chemical_symbols():
39
            norderats += 1
40
        if norderats != self.atoms.get_number_of_atoms():
41
            self.labels = self.get_labels()
42

    
43
        input = self.get_input_block()
44
        pyfile = open('pymopac.in','w')
45
        pyfile.write(input)
46
        pyfile.close()
47

    
48
    def run(self):
49
        self.write_moldata()
50
        out = commands.getoutput('mopac pymopac.in')
51
        
52
        outputfile = open('pymopac.in.out')
53
        outfile = open('mopac%02i.out'%(self.restart),'w')
54
        for line in outputfile:
55
            outfile.write(line)
56
        outfile.close()
57
        outputfile.close()
58

    
59
        energy = self.read_energy()
60
        if energy == None:
61
            energy = self.rerun()
62
        self.forces = self.read_forces()
63
        
64
        self.energy_zero = energy
65
        self.energy_free = energy
66
        self.first = False
67

    
68
    def read_energy(self, charges=True):
69
        outfile = open('pymopac.in.out')
70
        lines = outfile.readlines()
71
        outfile.close()
72

    
73
        chargelines = 0
74
        if charges:
75
            nats = len(self.atoms)
76
            block = ''
77
        for line in lines:
78
            if line.find('HEAT OF FORMATION') != -1:
79
                words = line.split()
80
                energy = float(words[5])
81
            if line.find('H.o.F. per unit cell') != -1:
82
                words = line.split()
83
                energy = float(words[5])
84
            if line.find('"""""""""""""UNABLE TO ACHIEVE SELF-CONSISTENCE') != -1:
85
                energy = None
86
            if charges:
87
                if line.find('NET ATOMIC CHARGES') != -1:
88
                    chargelines += 1
89
            if chargelines > 0 and chargelines <= nats+3:
90
                chargelines += 1
91
                block += line
92
             
93
        if charges:
94
            chargefile = open('charge%02i.out'%(self.restart),'a')
95
            chargefile.write(block)
96
            chargefile.close()
97
 
98
        return energy
99

    
100
    def read_forces(self):
101

    
102
        outfile = open('pymopac.in.aux')
103
        lines = outfile.readlines()
104
        outfile.close()
105

    
106
        outputforces = None
107
        nats = len(self.atoms)
108
        nx = nats * 3
109

    
110
        for i,line in enumerate(lines):
111
            if line.find('GRADIENTS:') != -1:
112
                forces = []
113
                l = 0
114
                for j in range(nx):
115
                    if j%10 == 0:
116
                        l += 1
117
                        gline = lines[i+l]
118
                    k = j -((l-1)*10)
119
                    try:
120
                        forces.append(-float(gline[k*18:(k*18)+18]))
121
                    except ValueError:
122
                        if outputforces == None:
123
                            outputforces = self.read_output_forces()
124
                        forces.append(outputforces[j])
125
                break
126

    
127
        forces = np.reshape(forces,  (3, nats))
128
        forces *= kcal_mol
129

    
130
        return forces
131

    
132
    def read_output_forces(self):
133
        outfile = open('pymopac.in.out')
134
        lines = outfile.readlines()
135
        outfile.close()
136

    
137
        nats = len(self.atoms)
138
        nx = nats * 3
139

    
140
        forces = []
141
        for i,line in enumerate(lines):
142
            if line.find('GRADIENT\n') != -1:
143
                for j in range(nx):
144
                    gline = lines[i+j+1]
145
                    forces.append(-float(gline[49:62]))
146
                break
147
        
148
        return forces
149
        
150
    def get_input_block(self):
151
        # For restarting I can use 'DENOUT' and 'OLDENS' at some point 
152
        block = ''
153
        block += '%s '%(self.functional)
154
        #if self.functional == 'PM6-DH2':
155
        block += 'NOANCI '
156
        block += '1SCF GRADIENTS '
157
        block += 'AUX(0,PRECISION=9) '
158
        block += 'RELSCF = 0.0001 '
159
        charge = 0
160
        if charge != 0:
161
            block += 'CHARGE=%i '%(charge)
162
        if self.spin == 1.:
163
            block += 'DOUBLET '
164
        elif self.spin == 2.:
165
            block += 'TRIPLET '
166
        block += '\n'
167
        block += 'Title: ASE job\n\n'
168

    
169
        constraints = self.atoms._get_constraints()
170
        nconstraints = len(constraints)
171
        for iat in xrange(len(self.atoms)):
172
            f = [1, 1, 1]
173
            if iat < nconstraints:
174
                if constraints[iat] is not None:
175
                    f = [0, 0, 0]
176
            atom = self.atoms[iat]
177
            xyz = atom.position
178
            block += ' %2s'%atom.symbol
179
            block += '    %16.5f %i    %16.5f %i    %16.5f %i \n'%(xyz[0],f[0],xyz[1],f[1],xyz[2],f[2])
180

    
181
        if self.atoms.pbc.any():
182
            for v in self.atoms.get_cell(): 
183
                block += 'Tv %8.3f %8.3f %8.3f\n'%(v[0],v[1],v[2])
184
        return block
185

    
186
    def update(self, atoms):
187
        if not (self.atoms.get_positions() == atoms.get_positions()).all() or self.first:
188
            self.atoms = atoms.copy()
189
            self.run()