Statistiques
| Révision :

root / ase / calculators / gaussian.py @ 16

Historique | Voir | Annoter | Télécharger (7,45 ko)

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

5
 @author:       Rosa Bulo
6
 @organization: Vrije Universiteit Amsterdam
7
 @contact:      bulo@few.vu.nl
8

9
Torsten Kerber,  ENS LYON: 2011,  07,  11
10

11
This work is supported by Award No. UK-C0017,  made by King Abdullah
12
University of Science and Technology(KAUST)
13
"""
14
import os,  sys,  string
15

    
16
import numpy as np
17
from ase.units import Hartree,  Bohr
18
from ase.calculators.general import Calculator
19
import os, sys, re, math, commands, subprocess, time
20

    
21
class Gaussian(Calculator):
22
    """
23
    Class for representing the settings of a ReaxffForceJob
24
        
25
    It contains the following variables:
26
                        
27
    basis:  
28
        A string representing the basisset to be used
29

30
    functional:
31
        A string representing the DFT functional or wavefunction
32
        method to be used.
33

34
    """
35

    
36
    def __init__(self, functional='BP86', basis='TZVP', atoms=None, inputfile=None):
37
        self.functional = functional
38
        self.basis = basis
39
        self.restartdata = None
40
        self.forces = None
41
        self.atoms_old = None
42
        if inputfile != None:
43
            self = self.get_settings(inputfile)                
44
        self.atoms = atoms
45

    
46
    def set_functional(self, functional):
47
        self.functional = functional
48

    
49
    def set_basis(self, basis):
50
        self.basis = basis
51

    
52
    def setup_job(self,  type='force'):
53
        ForceJob.setup_job(self, type=type)
54
 
55
        os.chdir(self.dirname)
56
        self.myfiles = GaussianFileManager()
57
        # Add the restart restuls to the filemanager. The checksum will be empty('')
58
        if self.restartdata != None:
59
            self.r_m = GaussianResults(self.myfiles)
60
            self.myfiles.add_results(self.r_m, dir=self.restartdata+'/')
61

    
62
        os.chdir(self.dir)
63

    
64
    def write_parfile(self, filename):
65
        parfile = open(filename, 'w')
66
        parfile.write(self.prm)
67
        parfile.close()
68

    
69
    def write_moldata(self,  type='force'):
70
        out = commands.getoutput('mkdir SETUP')
71
        out = commands.getoutput('ls SETUP/coord.*').split()
72
        pdb = False
73
        psf = False
74
        prm = False
75

    
76
        # Change labels variable if necessary
77
        norderats = 0
78
#        for el in self.labels:
79
#            norderats += 1
80
#            if norderats != self.atoms.pdb.get_number_of_atoms():
81
#                self.labels = self.get_labels()
82

    
83
        self.write_input(type)
84

    
85
    def write_input(self, type):
86
        input = self.get_input_block(type)
87
        pyfile = open('ASE-gaussian.com', 'w')
88
        pyfile.write(input)
89
        pyfile.close()
90

    
91
    def get_inp(self,  filename):
92
        input = None
93
        lis = commands.getoutput('ls %s'%(filename)).split('\n')
94
        if not re.search('ls:', lis[0]):
95
            infile = open(filename)
96
            input = infile.readlines()
97
            infile.close()
98
        return input
99

    
100
    def run(self, type='force'):
101
        startrun = time.time()
102
        # I have to write the input every timestep,  because that is where the coordinates are
103
        # self.write_input(type)
104
        self.write_moldata(type)
105

    
106
        # Make sure that restart data is copied to the current directory
107
#        if self.r_m != None:
108
#            self.r_m.files.copy_job_result_files(self.r_m.fileid)
109

    
110
        out = commands.getoutput('g09 ASE-gaussian.com')
111
        endrun = time.time()
112
        #print 'timings: ', endrun-startrun
113
        # Write the output
114
#        outputfile = open('ASE-gaussian.log')
115
#        outfile = open('ASE-gaussian.out',  'w')
116
#        for line in outputfile:
117
#            outfile.write(line)
118
#        outputfile.close()
119
#        outfile.close()
120
        # End write output
121
        self.energy = self.read_energy()
122
        if type == 'force':
123
            self.forces = self.read_forces()
124
        self.energy_zero = self.energy
125

    
126
        # Change the results object to the new results
127
        input = self.get_input_block(type)
128

    
129
    def read_energy(self,  charges=True):
130
        hartree2kcal = 627.5095
131

    
132
        outfile = open('ASE-gaussian.log')
133
        lines = outfile.readlines()
134
        outfile.close()
135

    
136
        chargelines = 0
137
        if charges:
138
            nats = len(self.atoms)
139
            block = ''
140
        for line in lines:
141
            if re.search('SCF Done', line):
142
                words = line.split()
143
                energy = float(words[4]) * hartree2kcal
144
            if charges:
145
                if re.search(' Mulliken atomic charges:', line):
146
                    chargelines += 1
147
            if chargelines > 0 and chargelines <= nats+2:
148
                chargelines += 1
149
                block += line
150
   
151
        if charges:
152
            chargefile = open('charge.out', 'a')
153
            chargefile.write(block)
154
            chargefile.close()
155

    
156
        return energy
157

    
158
    def read_forces(self):
159
        factor = Hartree / Bohr
160
        factor = 1.0
161

    
162
        outfile = open('ASE-gaussian.log')
163
        lines = outfile.readlines()
164
        outfile.close()
165

    
166
        outputforces = None
167
        forces = None
168
        nats = len(self.atoms)
169

    
170
        for iline, line in enumerate(lines):
171
            if re.search('Forces \(Ha', line):
172
                forces = np.zeros((nats,  3),  float)
173
                for iat in range(nats):
174
                    forceline = lines[iline+iat+3]
175
                    words = forceline.split()
176
                    for idir,  word in enumerate(words[2:5]):
177
                        forces[iat,  idir] = float(word) * factor
178
                break
179
        return forces
180

    
181
    def get_input_block(self, type):
182
        block = ''
183
        block += '%chk=ASE-gaussian.chk\n'
184
        block += '%Mem=256MB\n'
185
        block += '%nproc=32\n'
186
        block += 'MaxDisk=16gb\n'
187

    
188
        block += '#'
189
        block += '%s'%(self.functional)
190
        block += '/'
191
        block += '%s'%(self.basis)
192

    
193
        if type == 'force':
194
            block += 'Force '
195
#        if self.r_m != None:
196
#            block += 'Guess=Read'
197

    
198
        block += '\n\nGaussian job\n\n'
199

    
200
        charge = sum(self.atoms.get_charges())
201
        block += '%i '%(charge)
202
        block += '%i '%(1)
203
        block += '\n'
204

    
205
        coords = self.atoms.get_positions()
206
        for i, at in enumerate(self.atoms.get_chemical_symbols()):
207
            block += ' %2s'%(at)
208
            coord = coords[i]
209
            block += '  %16.5f %16.5f %16.5f'%(coord[0], coord[1], coord[2])
210
            block += '\n'
211

    
212
        if self.atoms.get_pbc().any(): 
213
            cell = self.atoms.get_cell()
214
           
215
            for v in cell: 
216
                block += 'TV %8.3f %8.3f %8.3f\n'%(v[0], v[1], v[2])
217
        block += '\n'
218

    
219
        return block
220

    
221

    
222
    def get_settings(self,  filename=None):
223
        settings = GaussianSettings()
224

    
225
        if filename != None or filename == '':
226
            input = self.get_inp(filename)
227
        else:
228
            settings.set_functional("")
229
            return settings
230
    
231
        if input == None:
232
            settings.set_functional("")
233
            return settings
234

    
235
        for i, line in enumerate(input):
236
            if len(line.strip()) == 0:
237
                continue
238
            if line[0] == '#':
239
                keyline = i
240
                words = line[1:].split()
241
            else:
242
                settings.functional = words[0].split('/')[0]
243
                settings.basis = words[0].split('/')[1]
244
            break
245
            return settings
246
                
247
    def update(self,  atoms):
248
        if self.atoms_old != atoms:
249
            self.atoms = atoms.copy()
250
            self.atoms_old = atoms.copy()
251
            self.run()