root / ase / calculators / gaussian.py @ 16
Historique | Voir | Annoter | Télécharger (7,45 ko)
1 | 16 | tkerber | """
|
---|---|---|---|
2 | 16 | tkerber | This module is the Gaussian module for ASE, based on the PyMD Gaussian Module by R. Bulo,
|
3 | 16 | tkerber | implemented by T. Kerber
|
4 | 16 | tkerber |
|
5 | 16 | tkerber | @author: Rosa Bulo
|
6 | 16 | tkerber | @organization: Vrije Universiteit Amsterdam
|
7 | 16 | tkerber | @contact: bulo@few.vu.nl
|
8 | 16 | tkerber |
|
9 | 16 | tkerber | Torsten Kerber, ENS LYON: 2011, 07, 11
|
10 | 16 | tkerber |
|
11 | 16 | tkerber | This work is supported by Award No. UK-C0017, made by King Abdullah
|
12 | 16 | tkerber | University of Science and Technology(KAUST)
|
13 | 16 | tkerber | """
|
14 | 16 | tkerber | import os, sys, string |
15 | 16 | tkerber | |
16 | 16 | tkerber | import numpy as np |
17 | 16 | tkerber | from ase.units import Hartree, Bohr |
18 | 16 | tkerber | from ase.calculators.general import Calculator |
19 | 16 | tkerber | import os, sys, re, math, commands, subprocess, time |
20 | 16 | tkerber | |
21 | 16 | tkerber | class Gaussian(Calculator): |
22 | 16 | tkerber | """
|
23 | 16 | tkerber | Class for representing the settings of a ReaxffForceJob
|
24 | 16 | tkerber |
|
25 | 16 | tkerber | It contains the following variables:
|
26 | 16 | tkerber |
|
27 | 16 | tkerber | basis:
|
28 | 16 | tkerber | A string representing the basisset to be used
|
29 | 16 | tkerber |
|
30 | 16 | tkerber | functional:
|
31 | 16 | tkerber | A string representing the DFT functional or wavefunction
|
32 | 16 | tkerber | method to be used.
|
33 | 16 | tkerber |
|
34 | 16 | tkerber | """
|
35 | 16 | tkerber | |
36 | 16 | tkerber | def __init__(self, functional='BP86', basis='TZVP', atoms=None, inputfile=None): |
37 | 16 | tkerber | self.functional = functional
|
38 | 16 | tkerber | self.basis = basis
|
39 | 16 | tkerber | self.restartdata = None |
40 | 16 | tkerber | self.forces = None |
41 | 16 | tkerber | self.atoms_old = None |
42 | 16 | tkerber | if inputfile != None: |
43 | 16 | tkerber | self = self.get_settings(inputfile) |
44 | 16 | tkerber | self.atoms = atoms
|
45 | 16 | tkerber | |
46 | 16 | tkerber | def set_functional(self, functional): |
47 | 16 | tkerber | self.functional = functional
|
48 | 16 | tkerber | |
49 | 16 | tkerber | def set_basis(self, basis): |
50 | 16 | tkerber | self.basis = basis
|
51 | 16 | tkerber | |
52 | 16 | tkerber | def setup_job(self, type='force'): |
53 | 16 | tkerber | ForceJob.setup_job(self, type=type) |
54 | 16 | tkerber | |
55 | 16 | tkerber | os.chdir(self.dirname)
|
56 | 16 | tkerber | self.myfiles = GaussianFileManager()
|
57 | 16 | tkerber | # Add the restart restuls to the filemanager. The checksum will be empty('')
|
58 | 16 | tkerber | if self.restartdata != None: |
59 | 16 | tkerber | self.r_m = GaussianResults(self.myfiles) |
60 | 16 | tkerber | self.myfiles.add_results(self.r_m, dir=self.restartdata+'/') |
61 | 16 | tkerber | |
62 | 16 | tkerber | os.chdir(self.dir)
|
63 | 16 | tkerber | |
64 | 16 | tkerber | def write_parfile(self, filename): |
65 | 16 | tkerber | parfile = open(filename, 'w') |
66 | 16 | tkerber | parfile.write(self.prm)
|
67 | 16 | tkerber | parfile.close() |
68 | 16 | tkerber | |
69 | 16 | tkerber | def write_moldata(self, type='force'): |
70 | 16 | tkerber | out = commands.getoutput('mkdir SETUP')
|
71 | 16 | tkerber | out = commands.getoutput('ls SETUP/coord.*').split()
|
72 | 16 | tkerber | pdb = False
|
73 | 16 | tkerber | psf = False
|
74 | 16 | tkerber | prm = False
|
75 | 16 | tkerber | |
76 | 16 | tkerber | # Change labels variable if necessary
|
77 | 16 | tkerber | norderats = 0
|
78 | 16 | tkerber | # for el in self.labels:
|
79 | 16 | tkerber | # norderats += 1
|
80 | 16 | tkerber | # if norderats != self.atoms.pdb.get_number_of_atoms():
|
81 | 16 | tkerber | # self.labels = self.get_labels()
|
82 | 16 | tkerber | |
83 | 16 | tkerber | self.write_input(type) |
84 | 16 | tkerber | |
85 | 16 | tkerber | def write_input(self, type): |
86 | 16 | tkerber | input = self.get_input_block(type) |
87 | 16 | tkerber | pyfile = open('ASE-gaussian.com', 'w') |
88 | 16 | tkerber | pyfile.write(input)
|
89 | 16 | tkerber | pyfile.close() |
90 | 16 | tkerber | |
91 | 16 | tkerber | def get_inp(self, filename): |
92 | 16 | tkerber | input = None
|
93 | 16 | tkerber | lis = commands.getoutput('ls %s'%(filename)).split('\n') |
94 | 16 | tkerber | if not re.search('ls:', lis[0]): |
95 | 16 | tkerber | infile = open(filename)
|
96 | 16 | tkerber | input = infile.readlines() |
97 | 16 | tkerber | infile.close() |
98 | 16 | tkerber | return input |
99 | 16 | tkerber | |
100 | 16 | tkerber | def run(self, type='force'): |
101 | 16 | tkerber | startrun = time.time() |
102 | 16 | tkerber | # I have to write the input every timestep, because that is where the coordinates are
|
103 | 16 | tkerber | # self.write_input(type)
|
104 | 16 | tkerber | self.write_moldata(type) |
105 | 16 | tkerber | |
106 | 16 | tkerber | # Make sure that restart data is copied to the current directory
|
107 | 16 | tkerber | # if self.r_m != None:
|
108 | 16 | tkerber | # self.r_m.files.copy_job_result_files(self.r_m.fileid)
|
109 | 16 | tkerber | |
110 | 16 | tkerber | out = commands.getoutput('g09 ASE-gaussian.com')
|
111 | 16 | tkerber | endrun = time.time() |
112 | 16 | tkerber | #print 'timings: ', endrun-startrun
|
113 | 16 | tkerber | # Write the output
|
114 | 16 | tkerber | # outputfile = open('ASE-gaussian.log')
|
115 | 16 | tkerber | # outfile = open('ASE-gaussian.out', 'w')
|
116 | 16 | tkerber | # for line in outputfile:
|
117 | 16 | tkerber | # outfile.write(line)
|
118 | 16 | tkerber | # outputfile.close()
|
119 | 16 | tkerber | # outfile.close()
|
120 | 16 | tkerber | # End write output
|
121 | 16 | tkerber | self.energy = self.read_energy() |
122 | 16 | tkerber | if type == 'force': |
123 | 16 | tkerber | self.forces = self.read_forces() |
124 | 16 | tkerber | self.energy_zero = self.energy |
125 | 16 | tkerber | |
126 | 16 | tkerber | # Change the results object to the new results
|
127 | 16 | tkerber | input = self.get_input_block(type) |
128 | 16 | tkerber | |
129 | 16 | tkerber | def read_energy(self, charges=True): |
130 | 16 | tkerber | hartree2kcal = 627.5095
|
131 | 16 | tkerber | |
132 | 16 | tkerber | outfile = open('ASE-gaussian.log') |
133 | 16 | tkerber | lines = outfile.readlines() |
134 | 16 | tkerber | outfile.close() |
135 | 16 | tkerber | |
136 | 16 | tkerber | chargelines = 0
|
137 | 16 | tkerber | if charges:
|
138 | 16 | tkerber | nats = len(self.atoms) |
139 | 16 | tkerber | block = ''
|
140 | 16 | tkerber | for line in lines: |
141 | 16 | tkerber | if re.search('SCF Done', line): |
142 | 16 | tkerber | words = line.split() |
143 | 16 | tkerber | energy = float(words[4]) * hartree2kcal |
144 | 16 | tkerber | if charges:
|
145 | 16 | tkerber | if re.search(' Mulliken atomic charges:', line): |
146 | 16 | tkerber | chargelines += 1
|
147 | 16 | tkerber | if chargelines > 0 and chargelines <= nats+2: |
148 | 16 | tkerber | chargelines += 1
|
149 | 16 | tkerber | block += line |
150 | 16 | tkerber | |
151 | 16 | tkerber | if charges:
|
152 | 16 | tkerber | chargefile = open('charge.out', 'a') |
153 | 16 | tkerber | chargefile.write(block) |
154 | 16 | tkerber | chargefile.close() |
155 | 16 | tkerber | |
156 | 16 | tkerber | return energy
|
157 | 16 | tkerber | |
158 | 16 | tkerber | def read_forces(self): |
159 | 16 | tkerber | factor = Hartree / Bohr |
160 | 16 | tkerber | factor = 1.0
|
161 | 16 | tkerber | |
162 | 16 | tkerber | outfile = open('ASE-gaussian.log') |
163 | 16 | tkerber | lines = outfile.readlines() |
164 | 16 | tkerber | outfile.close() |
165 | 16 | tkerber | |
166 | 16 | tkerber | outputforces = None
|
167 | 16 | tkerber | forces = None
|
168 | 16 | tkerber | nats = len(self.atoms) |
169 | 16 | tkerber | |
170 | 16 | tkerber | for iline, line in enumerate(lines): |
171 | 16 | tkerber | if re.search('Forces \(Ha', line): |
172 | 16 | tkerber | forces = np.zeros((nats, 3), float) |
173 | 16 | tkerber | for iat in range(nats): |
174 | 16 | tkerber | forceline = lines[iline+iat+3]
|
175 | 16 | tkerber | words = forceline.split() |
176 | 16 | tkerber | for idir, word in enumerate(words[2:5]): |
177 | 16 | tkerber | forces[iat, idir] = float(word) * factor
|
178 | 16 | tkerber | break
|
179 | 16 | tkerber | return forces
|
180 | 16 | tkerber | |
181 | 16 | tkerber | def get_input_block(self, type): |
182 | 16 | tkerber | block = ''
|
183 | 16 | tkerber | block += '%chk=ASE-gaussian.chk\n'
|
184 | 16 | tkerber | block += '%Mem=256MB\n'
|
185 | 16 | tkerber | block += '%nproc=32\n'
|
186 | 16 | tkerber | block += 'MaxDisk=16gb\n'
|
187 | 16 | tkerber | |
188 | 16 | tkerber | block += '#'
|
189 | 16 | tkerber | block += '%s'%(self.functional) |
190 | 16 | tkerber | block += '/'
|
191 | 16 | tkerber | block += '%s'%(self.basis) |
192 | 16 | tkerber | |
193 | 16 | tkerber | if type == 'force': |
194 | 16 | tkerber | block += 'Force '
|
195 | 16 | tkerber | # if self.r_m != None:
|
196 | 16 | tkerber | # block += 'Guess=Read'
|
197 | 16 | tkerber | |
198 | 16 | tkerber | block += '\n\nGaussian job\n\n'
|
199 | 16 | tkerber | |
200 | 16 | tkerber | charge = sum(self.atoms.get_charges()) |
201 | 16 | tkerber | block += '%i '%(charge)
|
202 | 16 | tkerber | block += '%i '%(1) |
203 | 16 | tkerber | block += '\n'
|
204 | 16 | tkerber | |
205 | 16 | tkerber | coords = self.atoms.get_positions()
|
206 | 16 | tkerber | for i, at in enumerate(self.atoms.get_chemical_symbols()): |
207 | 16 | tkerber | block += ' %2s'%(at)
|
208 | 16 | tkerber | coord = coords[i] |
209 | 16 | tkerber | block += ' %16.5f %16.5f %16.5f'%(coord[0], coord[1], coord[2]) |
210 | 16 | tkerber | block += '\n'
|
211 | 16 | tkerber | |
212 | 16 | tkerber | if self.atoms.get_pbc().any(): |
213 | 16 | tkerber | cell = self.atoms.get_cell()
|
214 | 16 | tkerber | |
215 | 16 | tkerber | for v in cell: |
216 | 16 | tkerber | block += 'TV %8.3f %8.3f %8.3f\n'%(v[0], v[1], v[2]) |
217 | 16 | tkerber | block += '\n'
|
218 | 16 | tkerber | |
219 | 16 | tkerber | return block
|
220 | 16 | tkerber | |
221 | 16 | tkerber | |
222 | 16 | tkerber | def get_settings(self, filename=None): |
223 | 16 | tkerber | settings = GaussianSettings() |
224 | 16 | tkerber | |
225 | 16 | tkerber | if filename != None or filename == '': |
226 | 16 | tkerber | input = self.get_inp(filename)
|
227 | 16 | tkerber | else:
|
228 | 16 | tkerber | settings.set_functional("")
|
229 | 16 | tkerber | return settings
|
230 | 16 | tkerber | |
231 | 16 | tkerber | if input == None: |
232 | 16 | tkerber | settings.set_functional("")
|
233 | 16 | tkerber | return settings
|
234 | 16 | tkerber | |
235 | 16 | tkerber | for i, line in enumerate(input): |
236 | 16 | tkerber | if len(line.strip()) == 0: |
237 | 16 | tkerber | continue
|
238 | 16 | tkerber | if line[0] == '#': |
239 | 16 | tkerber | keyline = i |
240 | 16 | tkerber | words = line[1:].split()
|
241 | 16 | tkerber | else:
|
242 | 16 | tkerber | settings.functional = words[0].split('/')[0] |
243 | 16 | tkerber | settings.basis = words[0].split('/')[1] |
244 | 16 | tkerber | break
|
245 | 16 | tkerber | return settings
|
246 | 16 | tkerber | |
247 | 16 | tkerber | def update(self, atoms): |
248 | 16 | tkerber | if self.atoms_old != atoms: |
249 | 16 | tkerber | self.atoms = atoms.copy()
|
250 | 16 | tkerber | self.atoms_old = atoms.copy()
|
251 | 16 | tkerber | self.run() |