-
Notifications
You must be signed in to change notification settings - Fork 1
/
turbomole_functions.py
295 lines (229 loc) · 9.96 KB
/
turbomole_functions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
import os, shutil, glob, sys, yaml
import subprocess
#function definitions
def utf8_enc(var):
if sys.version_info >= (3, 0):
return var.encode('utf-8')
else:
return var
def utf8_dec(var):
if sys.version_info >= (3, 0):
return var.decode('utf-8')
else:
return var
def make_define_str(settings,coord):
if settings['use old mos']:
with open('old_results/settings.yml') as infile:
old_settings = yaml.full_load(infile)
same_basis = old_settings['basis set'] == settings['basis set']
if not (settings['use old mos'] and same_basis):
define_string = '\n%s\na %s\n'%(settings['title'],coord)
#implement symmetry
if settings['int coord']:
define_string+='ired\n*\n'
else:
define_string+='*\nno\n'
define_string += 'b all %s\n*\n'%(settings['basis set']) # add options for basis sets (different for different atoms)
if not settings['use old mos']:
define_string += 'eht\n\n'
define_string += '%i\n'%(settings['charge'])
#implement symmetry
if settings['multiplicity'] < 3:
define_string += '\n\n\n'
else:
define_string += 'n\nu %i\n*\n\n'%(settings['multiplicity']-1)
else:
define_string += 'use old_results/control\n\n'
define_string += 'scf\niter\n%i\n\n'%(settings['scf iter'])
if settings['use ri']:
define_string += 'ri\non\nm %i\n\n'%(settings['ricore'])
if settings['functional'] != 'None':
define_string += 'dft\non\nfunc %s\ngrid %s\n\n'%(settings['functional'],settings['grid size'])
if settings['disp'] != 'off':
define_string += 'dsp\n%s\n\n'%(settings['disp'])
if settings['tddft']:
define_string += 'ex\n'
if settings['multiplicity'] > 1:
define_string += 'urpa\n*\n'
else:
define_string += 'rpa%s\n*\n'%(settings['exc state type'][0].lower())
define_string += 'a %i\n*\n'%(settings['num exc states'])
define_string += '*\n\n'
#implement symmetry
define_string += '*\n'
else:
output_files = ['alpha','auxbasis','basis','beta','control','hessapprox','mos']
for filename in output_files:
if os.path.isfile('old_results/%s'%(filename)): os.system('cp old_results/%s .'%(filename))
shutil.copy('coord_0','coord')
define_string = '\n\n\n\n\n'
if settings['use ri']:
define_string += 'ri\non\nm %i\n\n'%(settings['ricore'])
else:
define_string += 'ri\noff\n\n'
if settings['functional'] != 'None': define_string+='dft\non\nfunc %s\ngrid %s\n\n'%(settings['functional'],settings['grid size'])
else: define_string+='dft\noff\n\n'
define_string+='dsp\n%s\n\n'%(settings['disp'])
if not settings['tddft']:
if old_settings['tddft']:
os.system('sed -i \'s/#$max/$max/g\' control')
for dg in 'soes','scfinstab','rpacor','denconv': os.system('kdg %s'%(dg))
elif not old_settings['tddft']:
define_string+='ex\n'
if settings['multiplicity'] > 1: define_string+='urpa\n*\n'
else: define_string+='rpa%s\n*\n'%(settings['exc state type'][0].lower())
define_string+='a %i\n*\n'%(settings['num exc states'])
define_string+='*\n\n'
#implement symmetry
else:
define_string+='ex\n'
if old_settings['exc state type'] != settings['exc state type']:
if settings['multiplicity'] > 1:
define_string+='urpa\n'
else:
define_string+='rpa%s\n'%(settings['exc state type'][0].lower())
define_string+='*\n'
define_string+='a %i\n*\n'%(settings['num exc states'])
define_string+='*\n\n'
define_string+='*\n'
return define_string
def inputprep(program,input_string):
outfilename='%s.out'%(program)
process=subprocess.Popen([program],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate(input=utf8_enc(input_string))
with open(outfilename,'w') as outfile: outfile.write(utf8_dec(out))
if not 'normally' in utf8_dec(err).split():
print('An error occured when running %s:'%(program))
with open(outfilename) as infile:
lines=infile.readlines()
for line in lines: print(line)
def single_point_calc(settings,tmp=False):
scf_program = 'ridft' if settings['use ri'] else 'dscf'
if tmp: suffix='_tmp'
elif settings['opt']: suffix='_0'
else: suffix=''
output=scf_program+suffix+'.out'
num_iter,done=0,False
while not done:
run_turbomole(scf_program,output)
os.system('eiger > eiger.out')
done,err=check_scf(output)
if not done:
if err == 'not converged':
num_iter+=settings['scf iter']
if num_iter > settings['max scf iter']:
print('SCF not converged in maximum number of iterations (%i)'%(settings['max scf iter']))
exit(0)
elif err == 'negative HLG':
print('Attention: negative HOMO-LUMO gap found - please check manually')
exit(0)
if settings['tddft']:
run_turbomole('escf','escf%s.out'%(suffix))
done,err=check_escf(output)
if not done:
print('Problem with escf calculation found - please check manually')
exit(0)
def gradient_calc(settings):
grad_program = 'rdgrad' if settings['use ri'] else 'grad'
run_turbomole(grad_program)
def aoforce():
run_turbomole('aoforce','aoforce.out')
def jobex(settings):
options=''
if settings['use ri']: options+=' -ri'
if settings['tddft']: options+=' -ex %i'%(settings['opt exc state'])
options+=' -c %i'%(settings['opt cyc'])
num_cycles,done=0,False
while not done:
run_turbomole('jobex%s'%(options))
os.system('eiger > eiger.out')
done,err=check_opt()
if not done:
if err == 'opt not converged':
num_cycles+=settings['opt cyc']
if num_cycles > settings['max opt cyc']:
print('Structure optimisation not converged in maximum number of cycles (%i)'%(settings['max opt cyc']))
exit(0)
elif err.startswith('scf problem'):
num_cycles+=int(err.split()[-1])
single_point_calc(settings,tmp=True)
else:
print('An error occurred during the structure optimisation - please check manually')
exit(0)
#implement other errors
elif not settings['tddft']:
scf_done,err=check_scf('job.last')
if not scf_done:
print('The Structure optimisations converged but the last SCF run showed an error.')
exit(0)
def run_turbomole(command,outfile=None):
if outfile == None: outfile=command.split()[0]+'.out'
proc_cmd=['nohup']+command.split()
if not command.startswith('jobex'):
if outfile == None: outfile = command+'.out'
proc_cmd+=['>','outfile']
with open(outfile,'w') as tm_out:
tm_process=subprocess.Popen(proc_cmd,stdout=tm_out,stderr=subprocess.PIPE)
out, err = tm_process.communicate()
err=utf8_dec(err)
if not 'normally' in err.split('\n')[-2].split():
print('Error while running %s:'%(command.split()[0]))
print(err)
exit(0)
def check_scf(output_file):
conv=False
with open(output_file,'r') as infile:
for line in infile.readlines():
if 'convergence criteria cannot be satisfied' in line:
conv=False
break
if 'convergence criteria satisfied' in line:
conv=True
break
if conv == False:
return False, 'not converged'
else:
with open('eiger.out','r') as infile:
for line in infile.readlines():
if 'Gap' in line:
hlg=float(line.split()[-2])
break
if hlg < 0: return False, 'negative HLG'
else: return True,None
def check_escf(output_file):
conv=False
with open(output_file,'r') as infile:
for line in infile.readlines():
if 'all done' in line:
conv=True
break
return conv,None
def check_opt():
conv=os.path.isfile('GEO_OPT_CONVERGED')
if not conv:
if os.path.isfile('GEO_OPT_RUNNING'): err = 'jobex did not end properly'
else:
with open('GEO_OPT_FAILED','r') as infile:
for line in infile.readlines():
if 'OPTIMIZATION DID NOT CONVERGE' in line:
err = 'opt not converged'
break
if 'your energy calculation did not converge' in line:
err = 'scf problem during step nr. %s'%(glob.glob('job.[1-9]*')[0].split('.')[-1])
break
else: err='' # check for problems with last run here, e.g. neg. HLG
return conv,err
def man_occ(occ_vec):
if settings['multiplicity'] == 1:
instring='\n\n\ny\neht\n0\n\n'
define_process=subprocess.Popen(['define'],stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
define_out=define_process.communicate(input=instring)[0].decode('utf-8').split('\n')
for line in define_out:
if 'NUMBER OF ELECTRONS IN YOUR MOLECULE IS' in line:
n_occ=int(line.split()[-1])/2
break
instring+='c 1-%i\n'%(n_occ-len(occ_vec))
for i in len(occ_vec):
if occ_vec[i] == 1: instring+='c %i\n'%(n_occ-len(occ_vec)+1+i)
instring+='*\n\n*\n'
else: raise Error("manual occupation not implemented for open-shell systems")