4
|
1 #!/usr/bin/env python
|
|
2
|
|
3 """
|
|
4 Copyright 2012 Oleksandr Moskalenko <om@hpc.ufl.edu>
|
|
5
|
|
6 Runs BEAST on an input XML file.
|
|
7 For use with BEAST version 1.7.1
|
|
8
|
|
9 usage: beast.py inputxml
|
|
10
|
|
11 Produces:
|
|
12 output log file
|
|
13 mcmc.operators file
|
|
14 A variable number of '.tree' files depending on the XML input
|
|
15 """
|
|
16 import os, shutil, subprocess, sys, optparse, glob, string
|
|
17 from xml.dom.minidom import parse, Node
|
|
18
|
|
19 def stop_err(msg):
|
|
20 sys.stderr.write("%s\n" % msg)
|
|
21 sys.exit()
|
|
22
|
|
23 def parseFnames(nodelist):
|
|
24 filenames = []
|
|
25 for node in nodelist:
|
|
26 if node.hasAttributes():
|
|
27 fname = node.getAttribute('fileName')
|
|
28 if fname != "":
|
|
29 filenames.append(fname)
|
|
30 else:
|
|
31 pass
|
|
32 return filenames
|
|
33
|
|
34 def __main__():
|
|
35 usage = "usage: %prog inputXML"
|
|
36 parser = optparse.OptionParser(usage = usage)
|
|
37 parser.add_option("-T", "--threads", action="store", type="string", dest="threads", help="Number of threads")
|
|
38 parser.add_option("-s", "--seed", action="store", type="string",
|
|
39 dest="seed", help="Random seed")
|
|
40 parser.add_option("-r", "--strict", action="store_true", dest="strict", help="Strict XML parsing")
|
|
41 parser.add_option("-e", "--errors", action="store", type="string",
|
|
42 dest="errors", help="Maximum number of errors allowed")
|
|
43 parser.add_option("-i", "--inputxml", action="store", type="string", dest="inputxml", help="Input XML")
|
|
44 parser.add_option("-o", "--operators", action="store", type="string", dest="operators", help="Operators")
|
|
45 parser.add_option("-l", "--logs", action="store", type="string", dest="logs", help="Logs")
|
|
46 parser.add_option("-t", "--trees", action="store", type="string", dest="trees", help="Trees")
|
|
47 parser.add_option("-d", "--id", action="store", type="string", dest="treeid", help="Tree ID")
|
|
48 parser.add_option("-p", "--path", action="store", type="string", dest="path", help="New file path")
|
|
49 (options, args) = parser.parse_args()
|
|
50 if options.threads == None:
|
|
51 threads = 1
|
|
52 else:
|
|
53 threads = int(options.threads)
|
|
54 if options.seed != None:
|
|
55 seed = int(options.seed)
|
|
56 else:
|
|
57 seed = 12345
|
|
58 if options.strict == "-strict":
|
|
59 print "Strict XML check was chosen\n"
|
|
60 strict = True
|
|
61 print "No strict XML check was chosen\n"
|
|
62 else:
|
|
63 strict = False
|
|
64 inputxml = options.inputxml
|
|
65 operators = options.operators
|
|
66 logs = options.logs
|
|
67 trees = options.trees
|
|
68 errors = options.errors
|
|
69 treefile_id = options.treeid
|
|
70 newfilepath = options.path
|
|
71 sys.stdout.write("The following parameters have been provided:\n")
|
|
72 sys.stdout.write("Input XML: %s\n" % inputxml)
|
|
73 sys.stdout.write("Operators: %s\n" % operators)
|
|
74 sys.stdout.write("Logs: %s\n" % logs)
|
|
75 sys.stdout.write("Trees: %s\n" % trees)
|
|
76 sys.stdout.write("Strict: %s\n" % strict)
|
|
77 sys.stdout.write("New file path: %s\n" % newfilepath)
|
|
78 sys.stdout.write("Tree file ID: %s\n" % treefile_id)
|
|
79 if errors != None:
|
|
80 sys.stdout.write("Errors: %s\n" % errors)
|
|
81 cmd = []
|
|
82 cmd.append('beast')
|
|
83 if strict == True:
|
|
84 cmd.append('-strict')
|
|
85 thread_opt = "-threads %d" % threads
|
|
86 sys.stdout.write("Threads: %s\n" % thread_opt)
|
|
87 cmd.append(thread_opt)
|
|
88 cmd.append('-seed %d' % int(seed))
|
|
89 if errors != None:
|
|
90 cmd.append('-errors %d' % int(errors))
|
|
91 cmd.append(inputxml)
|
|
92 try:
|
|
93 proc = subprocess.Popen(args=cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
94 except Exception, err:
|
|
95 sys.stderr.write("Error invoking command: \n%s\n\n%s\n" % (cmd, err))
|
|
96 sys.exit(1)
|
|
97 stdout, stderr = proc.communicate()
|
|
98 return_code = proc.returncode
|
|
99 if return_code:
|
|
100 sys.stdout.write(stdout)
|
|
101 sys.stderr.write(stderr)
|
|
102 sys.stderr.write("Return error code %i from command:\n" % return_code)
|
|
103 sys.stderr.write("%s\n" % cmd)
|
|
104 sys.exit(1)
|
|
105 else:
|
|
106 sys.stdout.write(stdout)
|
|
107 sys.stdout.write(stderr)
|
|
108 #2012-04-24 - 2nd approach, parse the .xml file:
|
|
109 xml_file = os.path.abspath(inputxml)
|
|
110 if not os.path.exists(inputxml):
|
|
111 sys.stderr.write("Cannot find the input XML file for parsing.\n")
|
|
112 dom = parse(inputxml)
|
|
113 xml_logs = dom.getElementsByTagName('log')
|
|
114 xml_trees = dom.getElementsByTagName('logTree')
|
|
115 logfiles_orig = parseFnames(xml_logs)
|
|
116 treefiles_orig = parseFnames(xml_trees)
|
|
117 try:
|
|
118 if len(logfiles_orig) == 0:
|
|
119 logfiles_orig = glob.glob("*.log*")
|
|
120 if len(logfiles_orig) == 0:
|
|
121 logfiles_orig.append('Error_no_log')
|
|
122 dummy_file = open('Error_no_log','w')
|
|
123 dummy_file.write("BEAST run has not produced a log or it's named in such a way that I can't locate it. Configure BEAST to produce .log files without spaces in their names and rerun the analysis.\n")
|
|
124 dummy_file.close()
|
|
125 logfiles = []
|
|
126 if os.path.isdir(newfilepath):
|
|
127 for filename in logfiles_orig:
|
|
128 if os.path.isfile(filename):
|
|
129 name = string.replace(os.path.splitext(filename)[0], "_", "-")
|
|
130 filestring = "primary_%s_%s_visible_nexus" % (treefile_id, name)
|
|
131 newpath = os.path.join(newfilepath,filestring)
|
|
132 logfiles.append(newpath)
|
|
133 # else:
|
|
134 # sys.stderr.write("Can't find the log file to rename.\n")
|
|
135 logfiles[0] = logs
|
|
136 for i in range(len(logfiles_orig)):
|
|
137 src = logfiles_orig[i]
|
|
138 dst = logfiles[i]
|
|
139 if os.path.exists(src):
|
|
140 shutil.copy(src, dst)
|
|
141 # else:
|
|
142 # print "File '%s' can't be found.\n" % src
|
|
143 except Exception, err:
|
|
144 sys.stderr.write("Error copying log file: \n%s\n" % err)
|
|
145 try:
|
|
146 if not os.path.exists('mcmc.operators'):
|
|
147 bat = open('mcmc.operators','w')
|
|
148 bat.write('The mcmc.operators file did not have any output.\n')
|
|
149 bat.close()
|
|
150 except Exception, err:
|
|
151 sys.stderr.write("Error copying mcmc.operators file: \n%s\n" % err)
|
|
152 try:
|
|
153 if len(treefiles_orig) == 0:
|
|
154 print "No tree files found by the xml file parser.\n"
|
|
155 treefiles_orig = glob.glob("*.trees*")
|
|
156 # print "Original tree files from the directory:\n\t%s" % " ".join(treefiles_orig)
|
|
157 if len(treefiles_orig) == 0:
|
|
158 treefiles_orig.append('Error_no_tree')
|
|
159 dummy_file = open('Error_no_tree','w')
|
|
160 dummy_file.write("BEAST run has not produced an output tree or it's named in such a way that I can't locate it. Configure BEAST to produce .tree files without spaces in their names and rerun the analysis.\n")
|
|
161 dummy_file.close()
|
|
162 treefiles = []
|
|
163 if os.path.isdir(newfilepath):
|
|
164 for filename in treefiles_orig:
|
|
165 if os.path.isfile(filename):
|
|
166 name = string.replace(os.path.splitext(filename)[0], "_", "-")
|
|
167 filestring = "primary_%s_%s_visible_nexus" % (treefile_id, name)
|
|
168 newpath = os.path.join(newfilepath,filestring)
|
|
169 treefiles.append(newpath)
|
|
170 treefiles[0] = trees
|
|
171 for i in range(len(treefiles_orig)):
|
|
172 src = treefiles_orig[i]
|
|
173 dst = treefiles[i]
|
|
174 if os.path.exists(src):
|
|
175 shutil.copy(src, dst)
|
|
176 except Exception, err:
|
|
177 sys.stderr.write("Error copying trees file(s): \n%s\n" % err)
|
|
178 if __name__=="__main__": __main__()
|