325 def main(argv = None):
326 """Main routine of the script.
329 - `argv`: arguments passed to the main routine
335 parser = argparse.ArgumentParser(
336 description=(
"A universal script that merges multiple LHE files for all possible conditions and in the most "
338 "A detailed description of the merging step (in the default mode):\n"
340 " a. assert consistency of the headers (allow difference for the info of e.g. #event, seed);\n"
341 " b. if not MG LO LHEs, will simply use the header from the first LHE; otherwise, reset the "
342 "<MGGenerationInfo> from the headers by merging the #event & xsec info;\n"
343 " 2. Init block: if all <init> blocks are the same, use the same as output; otherwise (the MG LO "
344 "case), merge them by recalculating the # of subprocess (LRPUP) and XSECUP, XERRUP, XMAXUP per "
346 " 3. Event block: concatenate all event blocks. If for MG LO LHEs, recalculate the per-event "
347 "XWGTUP and all <wgt> tags based on the new XSECUP, #event, and 'event_norm' read from the MG "
349 "For further development of this script please always validate the merging result on the test "
350 "routines: https://github.com/colizz/mergelhe_validate\n"
352 " mergeLHE.py -i 'thread*/*.lhe,another_file/another.lhe' -o output.lhe"),
353 formatter_class=argparse.RawTextHelpFormatter)
354 parser.add_argument(
"-i",
"--input-files", type=str,
355 help=
"Input LHE file paths separated by commas. Shell-type wildcards are supported.")
356 parser.add_argument(
"-o",
"--output-file",
357 default=
'output.lhe', type=str,
358 help=
"Output LHE file path.")
359 parser.add_argument(
"--force-mglo-merger", action=
'store_true',
360 help=(
"Force to use the merger script dedicated for MG5 LO LHEs, as introduced in "
361 "https://github.com/cms-sw/genproductions/blob/master/bin/MadGraph5_aMCatNLO/Utilities/merge.pl"))
362 parser.add_argument(
"--force-cpp-merger", action=
'store_true',
363 help=(
"Force to use the external mergeLheFiles.cpp file to merge LHE files, as introduced in "
364 "https://twiki.cern.ch/twiki/bin/view/CMSPublic/SWGuideSubgroupMC#1_2_Using_pLHE_campaigns"))
365 parser.add_argument(
"-b",
"--bypass-check", action=
'store_true',
366 help=(
"Bypass the compatibility check for the headers. If true, the header and init block "
367 "will be just a duplicate from the first input file, and events are concatenated without "
369 parser.add_argument(
"--debug", action=
'store_true',
370 help=
"Use the debug mode.")
371 args = parser.parse_args(argv)
374 format=
'[%(levelname)s] %(message)s',
375 level=logging.INFO
if not args.debug
else DEBUG)
376 logging.info(
'>>> launch mergeLHE.py in %s' % os.path.abspath(os.getcwd()))
379 assert len(args.input_files), \
380 (
'Please specify your input LHE files by -i/--input-files. '
381 'Run \'mergeLHE.py -h\' for details.')
383 for path
in args.input_files.split(
','):
384 find_files = glob.glob(path)
385 if len(find_files) == 0:
386 logging.info(
'Warning: cannot find files in %s' % path)
387 input_files += find_files
389 logging.info(
'>>> Merge %d files: [%s]' % (len(input_files),
', '.
join(input_files)))
390 logging.info(
'>>> Write to output: %s ' % args.output_file)
392 if not os.path.exists(os.path.dirname(os.path.realpath(args.output_file))):
393 os.makedirs(os.path.dirname(os.path.realpath(args.output_file)))
396 assert len(input_files) > 0,
'Input LHE files should be more than 0.'
397 if len(input_files) == 1:
398 logging.warning(
'Input LHE only has 1 file. Will copy this file to the destination.')
400 shutil.copy(input_files[0], args.output_file)
402 assert [args.force_mglo_merger, args.force_cpp_merger].
count(
True) <= 1, \
403 "Can only specify at most one from --force-mglo-merger or --force-cpp-merger."
406 if args.force_mglo_merger:
407 lhe_merger = MG5LOLHEMerger(input_files, args.output_file)
408 elif args.force_cpp_merger:
409 lhe_merger = ExternalCppLHEMerger(input_files, args.output_file)
411 lhe_merger = DefaultLHEMerger(input_files, args.output_file, bypass_check=args.bypass_check)