Belle II Software  release-08-01-10
mcevent_forwarding.py
1 #!/usr/bin/env python3
2 
3 
10 
11 import sys
12 import basf2
13 from b2test_utils import clean_working_directory, safe_process, show_only_errors
14 from ROOT import Belle2
15 import subprocess
16 import json
17 
18 
19 def check_mc_events(outfile, expect):
20  """Check if the number of MC events reported by the file metadata is what whe expect"""
21  try:
22  metadata = subprocess.check_output(["b2file-metadata-show", "--json", outfile])
23  mcEvents = json.loads(metadata)["mcEvents"]
24  except Exception as e:
25  basf2.B2ERROR(f"Cannot determine number of MC events: {e}")
26  return False
27 
28  if mcEvents != expect:
29  basf2.B2ERROR(f"{outfile} MCEvents not correct: got {mcEvents}, expected {expect}")
30  return False
31  else:
32  basf2.B2INFO(f"{outfile}: MCEvents=={expect} Ok")
33  return True
34 
35 
36 def run_rootio(outfile, infiles, expect, *, N=0, **input_kwargs):
37  """
38  Run RootInput/RootOutput and check that the number of events is what we want
39 
40  Arguments:
41  outfile (str): filename for the output
42  infiles (list): list of input filenames
43  expect (int): numer of MC events we expect in the final file
44  N (int): pass to process() as second argument to limit the number of events
45 
46  All other arguments are passed to RootInput as module parameters
47  """
48 
49  global failures
50  path = basf2.create_path()
51  path.add_module("RootInput", inputFileNames=infiles, **input_kwargs)
52  path.add_module("RootOutput", outputFileName=outfile)
53  # zero counters so we can continue processing even if we already reported
54  # errors before
55  basf2.logging.zero_counters()
56  with show_only_errors():
57  safe_process(path, N)
58 
59  result = check_mc_events(outfile, expect)
60  failures += 0 if result else 1
61  return result
62 
63 
64 # no summary and load dictionaries early
65 basf2.logging.enable_summary(False)
66 Belle2.Environment.Instance().setNumberEventsOverride(0)
67 
68 # so let's go in an empty directory
69 with clean_working_directory():
70  # and create a few files with some empty events
71  all_files = []
72  event_counts = []
73  failures = 0
74  for i in range(1, 16, 7):
75  all_files.append(f"events-{i:03d}.root")
76  event_counts.append(i)
77  generate = basf2.create_path()
78  generate.add_module("EventInfoSetter", evtNumList=i)
79  generate.add_module("RootOutput", outputFileName=all_files[-1])
80  with show_only_errors():
81  safe_process(generate)
82 
83  # now for either one or all of those files run a number of checks:
84  for name, total, filenames, sequence in [
85  ("single", event_counts[-1], all_files[-1:], ["1:3"]),
86  ("total", sum(event_counts), all_files, ["0", "1:2", "2-"]),
87  ]:
88  # simple processing should forward MC events
89  run_rootio(f"{name}.root", filenames, total)
90  # but any skipping should not
91  run_rootio(f"{name}-skip1.root", filenames, 0, skipNEvents=1)
92  run_rootio(f"{name}-skipTo.root", filenames, 0, skipToEvent=[0, 0, 1])
93  run_rootio(f"{name}-sequence.root", filenames, 0, entrySequences=sequence)
94  # and limiting the number of events should only forward if all events
95  # are processed
96  for N in [1, total-1, total, 100000]:
97  Belle2.Environment.Instance().setNumberEventsOverride(N)
98  run_rootio(f"{name}-basf2-n-{N}.root", filenames, 0 if N < total else total)
99  Belle2.Environment.Instance().setNumberEventsOverride(0)
100  run_rootio(f"{name}-proc-{N}.root", filenames, 0 if N < total else total, N=N)
101 
102  # and if some files are processed multiple times we don't want to forward
103  # the number either
104  run_rootio("duplicate.root", all_files*2, 0)
105 
106 if failures > 0:
107  basf2.B2ERROR(f"{failures} tests failed ...")
108  sys.exit(1)
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28