-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
executable file
·360 lines (324 loc) · 18.6 KB
/
main.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
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
#!/usr/bin/python
import logging
import classes
import argparse
from ConfigParser import SafeConfigParser
def main():
"""Quantum Chemistry Interface - Fesigned to simplify the use of QC packages
Quantum Chemistry Interface has been designed to simplify quantum chemistry
calculations for organic chemists, it provides a common interface to quantum
chemistry packages, automatically handles creating input file and reading
output files, furthermore it is capable of automatically calculating
reaction thermodynamic quantities given basic reaction path info. QCI
understands the PBS system so is ideal for use on many clusters
When the script is run you must call it with the 3 positional arguments
described below, these tell the script how to name your job, and where the
files relating to each job are found. Both the job and step names can accept
a list of names to automatically create batch jobs. Warning: Batch modes can
radpidly create a large number of job, be careful if there is limits to job
submission on your cluster.
Furthermore you must provide a flag indicating which mode the script should
run in. Currently the options are new (creates a new job, no batch mode),
submit (submits jobs to the queue), analyse (extracts data from jobs),
reaction, (extracts thermochemistry for reactions)
It is invisioned that the project name should hold a braod description of
a series of calulations, the job name should hold a description of the
substitution pattern, and the step name should hold a description of the
reaction step.
For example in a series of calculations studying H atom loss from
substituted methane moecules you might start with the starting material,
methane.
projectName: - Hloss
jobName: - H
stepname: - SM
qci Hloss H SM -n -c 0 -m 1 -x methane.xyz
The values not specifically passed are taken from the config file
Next you would calculate the transition state for loss of H atom
projectName: - Hloss
jobName: - H
stepName -HlossTS
qci Hloss H HlossTS -n -ts -c 0 -m 1 -x HlossTS.xyz
Notice we have to explictly tell qci we are looking for a TS state
Next we need to make the product job for methyl radical
projectName: - Hloss
jobName: - H
stepName: - Product
qci Hloss H Product -n -c 0 -m 2 -x methylradical.xyz
We have now created the input files for this reaction, we can submit to the
queue using a batch mode by passing a list of stepnames
qci Hloss H "SM HlossTS Product" -s -w 4:00:00
This will submit the jobs we created in the previous commands.
Once this jobs are complete we can analyse the job to check the geometery
has converged to the correct structure, again we can use a batch mode here
qci Hloss H "SM HlossTS Product" -a
This will print the most important infomaition from the output file
If all the jobs have finished correctly, and freqency calculations
were requested it is now possible to calculate reaction paramters.
qci Hloss H "SM HlossTS Product+H" -re
Reaction mode requires a list of reaction steps, it is assumed that odd
numbered steps are starting materials and products, and that even steps are
transition states connecting them. If a step has more than one molecule you
ask qci to sum their enthalpies by giving a list seperated by + signs, with
no spaces.
Positional Args:
projectName -- Set name of project
jobName -- Set name of job. Accepts a list of names for batch modes
stepName -- Set name of Step. Accepts a list of name for batch modes
Optional Args:
Modes:
new/-n -- Creates inputfile files from options selected
submit/-s -- Creates pbsfile and submits job to queue. Batch mode
analyse/-a -- Reads output file with cclib to extract chemical data.
Batch mode
reaction/-re -- Calculates therodynamics quantites for reaction
given list in form "SM TS Prod TS2 Prod2 ... TSN
ProdN" where each word is a step name
Chemical Options:
tstate/-ts -- Mark job as a transition state. Default = False
charge/-c -- Set charge for molecule. Default from config file
mult/-m -- Set multiplicity for moecule. Default from config file
basis/-b -- Set basis set for calculation. Default from config file
functional/-f -- Set functional for system. Default from config file
xyz/-x -- Set location to read .xyz file for coordinates. No default
pcm/-p -- Set PCM simulation on and select solvent. Deafult = false
type/-t -- Set type of job, currently either OPT and FREQ.
Default = OPT
engine/-e -- Set which QC packake to use for calculation.
Default from config file
PBS Options:
walltime/-w -- Set allowed excution time. Default from config file
nodes/-n -- Set number of nodes to be used. Default from config file
cpus/-cp -- Set number of cpus per node. Default from config file
ram/-r -- Set amount of ram per node. Default from config file
queue/-q -- Set queue for job. Default from config file
"""
logging.basicConfig(filename='qcfoc.log', level=logging.DEBUG)
logging.info('Started')
confparser = SafeConfigParser()
confparser.read('conf/qcfoc.conf')
argparser = argparse.ArgumentParser(
description='Quantum Chemistry Interface', version='0.1')
argparser.add_argument('projectName', action='store',
help='Set name of project')
argparser.add_argument('jobName', action='store',
help= ('Set name of job. Accepts a list '
'of names for batch modes'))
argparser.add_argument('stepName', action='store', help=
('Set name of Step. Accepts a list'
'of name for batch modes'))
argparser.add_argument('--new', '-n', action='store_true', default=False,
help='Creates inputfile files from options selecte')
argparser.add_argument('--submit', '-s', action='store_true', default=False,
help= ('Creates pbsfile and submits'
'job to queue. Batch mode'))
argparser.add_argument('--analyse', '-a', action='store_true',
default=False, help= ('Creates pbsfile and submits '
'job to queue. Batch mode'))
argparser.add_argument('--reaction', '-re', action='store_true', default=False,
help=('Calcuates reaction thermochem given reaction'
'profile in stepname in form of'
'SM TS Prod1+Prod2'))
argparser.add_argument('--irc', '-irc', action='store_true', default=False,
help='Checks if IRC jobs give correct SM + Prod')
argparser.add_argument('--fragment', '-fr', action='store',
default=None, help= ('Automatically subtitute'
'atom with fragment. pass'
'as "AtomNo Frag"'))
argparser.add_argument('--tstate', '-ts', action='store_true',
default=False, help= ('Flag to mark job as a '
'transition state. Default = False'))
argparser.add_argument('--charge', '-c', action='store',
default=confparser.get('default_options','charge'),
help= ('Set charge for molecule. Default from config'
'file'), type=int)
argparser.add_argument('--mult', '-m', action='store',
default=confparser.get('default_options', 'mult'),
help=('Set multiplicity for moecule. Default'
'from config file'), type=int)
argparser.add_argument('--basis', '-b', action='store',
default=confparser.get('default_options','basis'),
help=('Set basis set for calculation. Default'
'from config file'))
argparser.add_argument('--functional', '-f', action='store',
default=confparser.get('default_options','functional'),
help=('Set functional for calculation. Default'
'from config file'))
argparser.add_argument('--xyz', '-x', action='store', help=
('Set location to read .xyz file for coordinates.'
'No default'))
argparser.add_argument('--symmetry', '-sym', action='store',
default=confparser.get('default_options','sym'),
help=('Molecular point group. Default'
'from config file'))
argparser.add_argument('--pcm', '-p', action='store', default=None, help=
('Set PCM solvent simulation on and select solvent.'
'Deafult = false'))
argparser.add_argument('--type', '-t', action='store', default='OPT',
choices=('OPT', 'FREQ', 'IRC'), help=('Set type of job, '
'currently supported'
'OPT and FREQ.'
'Default = OPT'))
argparser.add_argument('--engine', '-e', action='store',
default=confparser.get('default_options','engine'),
choices=('GAU','GAMESS'), help=('Set which quantum '
'chemistry packake to '
'use for calculation. '
'Default from config '
'file'))
argparser.add_argument('--walltime', '-w', action='store',
default=confparser.get('default_options','walltime'),
help=('Set max allowed excution time. Default '
'from config file'))
argparser.add_argument('--nodes', '-no', action='store',
default=confparser.get( 'default_options','nodes'),
help=('Set number of nodes to be used.'
'Default from config file'))
argparser.add_argument('--cpus', '-cp', action='store',
default=confparser.get('default_options','cpus'),
help=('Set number of cpus per node. Default '
'from config file'))
argparser.add_argument('--ram', '-r', action='store',
default=confparser.get('default_options','ram'),
help=('Set amount of ram per node. Default'
'from config file'))
argparser.add_argument('--queue', '-q', action='store',
default=confparser.get('default_options','queue'),
help='Set queue for job. Default from config file')
args = argparser.parse_args()
#Call subroutines for making Gaussian new jobs
if args.new is True:
if args.engine == 'GAU':
try:
if args.fragment is not None:
j = classes.gau_step(args.projectName, args.jobName, args.stepName,
ts=args.tstate,charge=args.charge,
mult=args.mult,xyz=args.xyz,
fragatom=args.fragment.split()[0],
frag=args.fragment.split()[1] )
else:
j = classes.gau_step(args.projectName, args.jobName, args.stepName,
ts=args.tstate,charge=args.charge,
mult=args.mult,xyz=args.xyz)
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, args.jobName, args.stepName))
try:
j.write_inputfile(args.basis, args.functional, args.nodes,
args.cpus, args.ram, args.pcm, args.type)
print 'Wrote inputfile for: %s-%s-%s' % (args.projectName, args.jobName, args.stepName)
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, args.jobName, args.stepName))
elif args.engine == 'GAMESS':
try:
if args.fragment is not None:
j = classes.gamess_step(args.projectName, args.jobName, args.stepName,
ts=args.tstate,charge=args.charge,
mult=args.mult,xyz=args.xyz,
fragatom=args.fragment.split()[0],
frag=args.fragment.split()[1] )
else:
j = classes.gamess_step(args.projectName, args.jobName, args.stepName,
ts=args.tstate,charge=args.charge,
mult=args.mult,xyz=args.xyz)
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, args.jobName, args.stepName))
try:
j.write_inputfile(args.basis, args.functional, args.nodes,
args.cpus, args.ram, args.pcm, args.type,
args.symmetry)
print 'Wrote inputfile for: %s-%s-%s' % (args.projectName, args.jobName, args.stepName)
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, args.jobName, args.stepName))
#Call subroutines for sumbitting jobs
if args.submit is True:
for job in args.jobName.split():
for step in args.stepName.split():
if args.engine == 'GAU':
j = classes.gau_step(args.projectName, job, step)
elif args.engine == 'GAMESS':
j = classes.gamess_step(args.projectName, job, step)
try:
j.write_pbsfile(args.walltime, args.nodes,
args.cpus, args.queue)
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, job, step))
j.submit_job()
#Call subroutines for Analysing job
if args.analyse is True:
for job in args.jobName.split():
for step in args.stepName.split():
if args.engine == 'GAU':
j = classes.gau_step(args.projectName, job, step)
elif args.engine == 'GAMESS':
j = classes.gamess_step(args.projectName, job, step)
try:
j.analyse_job()
print j
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, job, step))
#Call subroutines for calculating reaction parmaters
if args.reaction is True:
print 'Project: %s' % args.projectName
print 'Reaction %s' % args.stepName
print
for job in args.jobName.split():
enthalpies = []
print 'Substitution: %s' % job
print
for step in args.stepName.split('=>'): #Makes a list of anthaplies
step = step.strip()
jobs = []
for sub in step.split('+'):
sub = sub.strip()
if args.engine == 'GAU':
jobs.append(classes.gau_step(args.projectName, job, sub))
elif args.engine == 'GAMESS':
jobs.append(classes.gamess_step(args.projectName, job, sub))
try:
jobs[-1].analyse_job()
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, job, sub))
try:
enthalpies.append(sum(a.enthalpy for a in jobs))
except AttributeError:
exit("AttributeError: Missing Enthalpy for job %s-%s-%s" % (a.projectName, a.jobName, a.stepName))
activation = []
reaction = []
total_reaction = 0
for count in xrange(0, len(enthalpies)-2, 2):#calcautes thermochem
activation.append(enthalpies[count+1] - enthalpies[count])
reaction.append(enthalpies[count+2] - enthalpies[count])
total_reaction = enthalpies[-1] - enthalpies[0]
for count in xrange(len(activation)):#outputs therochem
if len(activation) > 1:
print "Reaction Number: %d" % (count+1,)
print "\tActivation energy = %f kcal/mol" % (float(activation[count])*float(627.509),)
print "\tReaction enthalpy = %f kcal/mol" % (float(reaction[count])*float(627.509),)
print
if len(activation) > 1:
print "Total reaction enthalpy = %f kcal/mol" % (float(total_reaction)*float(627.509),)
print
logging.info('Finished')
if args.irc is True:
jobs = []
for job in args.jobName.split():
for step in args.stepName.split():
if args.engine == 'GAU':
jobs.append(classes.gau_step(args.projectName, job, step))
elif args.engine == 'GAMESS':
jobs.append(classes.gamess_step(args.projectName, job, step))
try:
jobs[-1].analyse_job()
except IOError, error:
exit("IOError: %s for job %s-%s-%s" % (error, args.projectName, job, step))
print "Optimized Starting Material Coordinates"
print jobs[0].format_coords(jobs[0].mol)
print "IRC Starting Material Coordinates"
print jobs[1].format_coords(jobs[1].irccoords[0])
print
print "Optimized Product Coordinates"
print jobs[2].format_coords(jobs[2].mol)
print "IRC Product Coordinates"
print jobs[1].format_coords(jobs[1].irccoords[-1])
#run if not being imported
if __name__ == '__main__':
main()