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