8 parser = argparse.ArgumentParser()
9 subparser = parser.add_subparsers(dest=
'command')
11 create = subparser.add_parser(
'create', help=
'Create condor submission directory.')
12 status = subparser.add_parser(
'status', help=
'Check the status of the condor submission.')
13 hadd = subparser.add_parser(
'hadd', help=
'Merge completed condor jobs.')
15 create.add_argument(
'-e',
'--executable', type=str, default=
'scripts/genFun4All.sh', help=
'Job script to execute. Default: scripts/genFun4All.sh')
16 create.add_argument(
'-a',
'--macros', type=str, default=
'current/macro', help=
'Directory of input macros. Directory containing Fun4All_G4_sPHENIX.C and G4Setup_sPHENIX.C. Default: current/macro')
17 create.add_argument(
'-b',
'--bin-dir', type=str, default=
'current/bin', help=
'Directory containing Fun4All_G4_sPHENIX executable. Default: current/bin')
18 create.add_argument(
'-n',
'--events', type=int, default=1, help=
'Number of events to generate. Default: 1.')
19 create.add_argument(
'-d',
'--output', type=str, default=
'test', help=
'Output Directory. Default: Current Directory.')
20 create.add_argument(
'-m',
'--jobs-per-submission', type=int, default=20000, help=
'Maximum number of jobs per condor submission. Default: 20000.')
21 create.add_argument(
'-j',
'--events-per-job', type=int, default=100, help=
'Number of events to generate per job. Default: 100.')
22 create.add_argument(
'-s',
'--memory', type=int, default=6, help=
'Memory (units of GB) to request per condor submission. Default: 6 GB.')
23 create.add_argument(
'-u',
'--build-tag', type=str, default=
'unknown', help=
'Specify build tag. Ex: ana.xxx, Default: unknown')
25 status.add_argument(
'-d',
'--condor-dir', type=str, help=
'Condor submission directory.', required=
True)
27 hadd.add_argument(
'-i',
'--job-dir-list', type=str, help=
'List of directories containing condor jobs to be merged.', required=
True)
28 hadd.add_argument(
'-o',
'--output', type=str, default=
'test.root', help=
'Output root file. Default: test.root.')
29 hadd.add_argument(
'-n',
'--jobs-per-hadd', type=int, default=5000, help=
'Number of jobs to merge per hadd call. Default: 5000.')
30 hadd.add_argument(
'-j',
'--jobs-open', type=int, default=50, help=
'Number of jobs to load at once. Default: 50.')
31 hadd.add_argument(
'-m',
'--multiple-submit-dir', type=bool, default=
False,help=
'If merging condor jobs over multiple directories. Default: False')
33 args = parser.parse_args()
37 jobs_per_submission = args.jobs_per_submission
38 output_dir = os.path.realpath(args.output)
39 bin_dir = os.path.realpath(args.bin_dir)
40 executable = os.path.realpath(args.executable)
41 events_per_job =
min(args.events_per_job, events)
43 macros_dir = os.path.realpath(args.macros)
44 jobs = events//events_per_job
45 submissions = int(np.ceil(jobs/jobs_per_submission))
48 print(f
'Events: {events}')
49 print(f
'Events per job: {events_per_job}')
50 print(f
'Jobs: {jobs}')
51 print(f
'Maximum jobs per condor submission: {jobs_per_submission}')
52 print(f
'Submissions: {submissions}')
53 print(f
'Requested memory per job: {memory}GB')
54 print(f
'Output Directory: {output_dir}')
55 print(f
'Macros Directory: {macros_dir}')
56 print(f
'Bin Directory: {bin_dir}')
57 print(f
'Executable: {executable}')
58 print(f
'Build Tag: {tag}')
60 os.makedirs(output_dir,exist_ok=
True)
61 with
open(f
'{output_dir}/log.txt', mode=
'w')
as file:
62 file.write(f
'Events: {events}\n')
63 file.write(f
'Events per job: {events_per_job}\n')
64 file.write(f
'Jobs: {jobs}\n')
65 file.write(f
'Maximum jobs per condor submission: {jobs_per_submission}\n')
66 file.write(f
'Submissions: {submissions}\n')
67 file.write(f
'Requested memory per job: {memory}GB\n')
68 file.write(f
'Output Directory: {output_dir}\n')
69 file.write(f
'Macros Directory: {macros_dir}\n')
70 file.write(f
'Bin Directory: {bin_dir}\n')
71 file.write(f
'Executable: {executable}\n')
72 file.write(f
'Build Tag: {tag}\n')
75 condor_file = f
'{output_dir}/genFun4All.sub'
76 with
open(condor_file, mode=
"w")
as file:
77 file.write(f
'executable = bin/{os.path.basename(executable)}\n')
78 file.write(f
'arguments = $(myPid) $(initialSeed) {events_per_job}\n')
79 file.write(
'log = log/job-$(myPid).log\n')
80 file.write(
'output = stdout/job-$(myPid).out\n')
81 file.write(
'error = error/job-$(myPid).err\n')
82 file.write(f
'request_memory = {memory}GB\n')
83 file.write(
'should_transfer_files = YES\n')
84 file.write(
'when_to_transfer_output = ON_EXIT\n')
86 file.write(
'transfer_input_files = bin/Fun4All_G4_sPHENIX\n')
87 file.write(
'transfer_output_files = G4sPHENIX_g4cemc_eval-$(myPid).root\n')
88 file.write(
'transfer_output_remaps = "G4sPHENIX_g4cemc_eval-$(myPid).root = output/G4sPHENIX_g4cemc_eval-$(myPid).root"\n')
89 file.write(
'queue myPid,initialSeed from seed.txt')
91 for i
in range(submissions):
92 print(f
'Submission: {i}')
94 submit_dir = f
'{output_dir}/submission-{i}'
95 print(f
'Submission Directory: {submit_dir}')
97 os.makedirs(f
'{submit_dir}/stdout',exist_ok=
True)
98 os.makedirs(f
'{submit_dir}/error',exist_ok=
True)
99 os.makedirs(f
'{submit_dir}/log',exist_ok=
True)
100 os.makedirs(f
'{submit_dir}/output',exist_ok=
True)
101 os.makedirs(f
'{submit_dir}/bin',exist_ok=
True)
102 os.makedirs(f
'{submit_dir}/src',exist_ok=
True)
104 shutil.copy(condor_file, submit_dir)
105 shutil.copy(executable, f
'{submit_dir}/bin')
106 shutil.copy(f
'{bin_dir}/Fun4All_G4_sPHENIX', f
'{submit_dir}/bin')
107 shutil.copy(f
'{macros_dir}/Fun4All_G4_sPHENIX.C', f
'{submit_dir}/src')
108 shutil.copy(f
'{macros_dir}/G4Setup_sPHENIX.C', f
'{submit_dir}/src')
110 file_name = f
'{submit_dir}/seed.txt'
111 with
open(file_name, mode=
"w")
as file:
112 for j
in range(
min(jobs,jobs_per_submission)):
113 file.write(f
'{j} {i*jobs_per_submission+100}\n')
115 jobs -=
min(jobs,jobs_per_submission)
116 print(f
'Written {file_name}')
119 condor_dir = os.path.realpath(args.condor_dir)
120 submit_dirs =
next(os.walk(condor_dir))[1]
121 print(f
'Condor Directory: {condor_dir}')
124 for submit_dir
in submit_dirs:
125 jobs_done = len(os.listdir(f
'{condor_dir}/{submit_dir}/output'))
126 jobs_total = len(os.listdir(f
'{condor_dir}/{submit_dir}/log'))
128 print(f
'Condor submission dir: {condor_dir}/{submit_dir}, done: {jobs_done}, {jobs_done/jobs_total*100:.2f} %')
129 jobs_done_total += jobs_done
133 print(f
'Total jobs done: {jobs_done_total}, {jobs_done_total/total*100:.2f} %')
136 output = os.path.realpath(args.output)
137 jobs_per_hadd = args.jobs_per_hadd
138 jobs_open = args.jobs_open+1
139 print(f
'jobs directory: {jobs_dir}')
140 print(f
'output: {output}')
141 print(f
'jobs per hadd: {jobs_per_hadd}')
142 print(f
'jobs open at once: {jobs_open-1}')
144 jobs = os.listdir(jobs_dir)
145 jobs = [f
'{jobs_dir}/{job}' for job
in jobs]
147 total_jobs = len(jobs)
148 hadd_calls = int(np.ceil(total_jobs/jobs_per_hadd))
150 print(f
'total jobs: {total_jobs}')
151 print(f
'hadd calls: {hadd_calls}')
153 for i
in range(hadd_calls):
154 subprocess.run([
'echo',
'#######################'])
155 subprocess.run([
'echo', f
'working on hadd: {i}'])
156 command = f
'hadd -a -n {jobs_open} {output}'.split()
157 i_start = jobs_per_hadd*i
158 i_end =
min(jobs_per_hadd*(i+1), total_jobs)
159 subprocess.run([
'echo', f
'i_start: {i_start}, i_end: {i_end}'])
160 command.extend(jobs[i_start:i_end])
161 subprocess.run(command)
162 subprocess.run([
'echo', f
'done with hadd: {i}'])
163 subprocess.run([
'echo',
'#######################'])
165 if __name__ ==
'__main__':
166 if(args.command ==
'create'):
168 elif(args.command ==
'status'):
170 elif(args.command ==
'hadd'):
171 if(args.multiple_submit_dir):
172 job_dir_list = os.path.realpath(args.job_dir_list)
173 with
open(job_dir_list)
as f:
175 jobs_dir = jobs_dir.strip()
178 job_dir = args.job_dir_list