19from simulation
import add_simulation
20from rawdata
import add_packers
21from softwaretrigger
import constants
23from ROOT
import Belle2
27 """Test module for assuring correct data store content"""
30 """reimplementation of Module::event()."""
33 if not sft_trigger.isValid():
34 basf2.B2FATAL(
"SoftwareTriggerResult object not created")
35 elif len(sft_trigger.getResults()) == 0:
36 basf2.B2FATAL(
"SoftwareTriggerResult exists but has no entries")
39 basf2.B2FATAL(
"ROIs are not present")
42def get_file_name(base_path, run_type, location, passthrough, simulate_events_of_doom_buster):
45 mode +=
"_passthrough"
46 if simulate_events_of_doom_buster:
48 return os.path.join(base_path, f
"{location.name}_{run_type.name}{mode}.root")
51def generate_input_file(run_type, location, output_file_name, exp_number, passthrough,
52 simulate_events_of_doom_buster):
54 Generate an input file for usage in the test.
55 Simulate uubar for "beam" and two muons for "cosmic" setting.
57 Only raw data will be stored to the given output file.
58 :param run_type: Whether to simulate cosmic or beam
59 :param location: Whether to simulate expressreco (with ROIs) or hlt (no PXD)
60 :param output_file_name: where to store the result file
61 :param exp_number: which experiment number to simulate
62 :param passthrough: if true don't generate a trigger result in the input file
63 :param simulate_events_of_doom_buster: if true, simulate the effect of the
64 EventsOfDoomBuster module by inflating the number of CDC hits
66 if os.path.exists(output_file_name):
69 basf2.set_random_seed(12345)
72 path.add_module(
'EventInfoSetter', evtNumList=[4], expList=[exp_number])
74 if run_type == constants.RunTypes.beam:
76 elif run_type == constants.RunTypes.cosmic:
80 path.add_module(
"ParticleGun", pdgCodes=[-13, 13], momentumParams=[10, 200])
82 add_simulation(path, usePXDDataReduction=(location == constants.Location.expressreco))
86 if simulate_events_of_doom_buster:
88 class InflateCDCHits(basf2.Module):
89 """Artificially inflate the number of CDC hits."""
94 self.cdc_hits.isRequired()
96 if not eodb_parameters.isValid():
97 basf2.B2FATAL(
"EventsOfDoomParameters is not valid")
98 self.cdc_hits_threshold = eodb_parameters.getNCDCHitsMax() + 1
102 if self.cdc_hits.isValid():
104 for i
in range(self.cdc_hits_threshold):
105 self.cdc_hits.appendNew()
107 path.add_module(InflateCDCHits())
109 if location == constants.Location.hlt:
110 components = DEFAULT_HLT_COMPONENTS
111 elif location == constants.Location.expressreco:
112 components = DEFAULT_EXPRESSRECO_COMPONENTS
114 basf2.B2FATAL(f
"Location {location.name} for test is not supported")
116 components.append(
"TRG")
118 add_packers(path, components=components)
121 if location == constants.Location.expressreco
and not passthrough:
122 class FakeHLTResult(basf2.Module):
123 def initialize(self):
124 self.results =
Belle2.PyStoreObj(Belle2.SoftwareTriggerResult.Class(),
"SoftwareTriggerResult")
125 self.results.registerInDataStore()
130 self.results.create()
132 if (self.EventMetaData.obj().getEvent() == 1):
133 self.results.addResult(
"software_trigger_cut&all&total_result", 1)
134 self.results.addResult(
"software_trigger_cut&filter&total_result", 1)
135 self.results.addResult(
"software_trigger_cut&skim&total_result", 1)
136 self.results.addResult(
"software_trigger_cut&skim&accept_mumutight", 1)
137 self.results.addResult(
"software_trigger_cut&skim&accept_dstar_1", 1)
138 self.results.addResult(
"software_trigger_cut&filter&L1_trigger", 1)
140 elif (self.EventMetaData.obj().getEvent() == 2):
141 self.results.addResult(
"software_trigger_cut&all&total_result", 1)
142 self.results.addResult(
"software_trigger_cut&filter&total_result", 1)
143 self.results.addResult(
"software_trigger_cut&skim&total_result", 0)
144 self.results.addResult(
"software_trigger_cut&filter&L1_trigger", 1)
146 elif (self.EventMetaData.obj().getEvent() == 3):
147 self.results.addResult(
"software_trigger_cut&all&total_result", 1)
148 self.results.addResult(
"software_trigger_cut&filter&total_result", 0)
149 self.results.addResult(
"software_trigger_cut&skim&total_result", 1)
150 self.results.addResult(
"software_trigger_cut&skim&accept_mumutight", 1)
151 self.results.addResult(
"software_trigger_cut&skim&accept_dstar_1", 1)
152 self.results.addResult(
"software_trigger_cut&filter&L1_trigger", 0)
154 elif (self.EventMetaData.obj().getEvent() == 4):
155 self.results.addResult(
"software_trigger_cut&all&total_result", 0)
156 self.results.addResult(
"software_trigger_cut&filter&total_result", 0)
157 self.results.addResult(
"software_trigger_cut&skim&total_result", 1)
158 self.results.addResult(
"software_trigger_cut&skim&accept_mumutight", 1)
159 self.results.addResult(
"software_trigger_cut&skim&accept_dstar_1", 1)
160 self.results.addResult(
"software_trigger_cut&filter&L1_trigger", 0)
162 path.add_module(FakeHLTResult())
165 branch_names = RAWDATA_OBJECTS + [
"EventMetaData",
"TRGSummary"]
167 branch_names += [
"SoftwareTriggerResult"]
169 if location == constants.Location.hlt:
170 branch_names.remove(
"RawPXDs")
171 branch_names.remove(
"ROIs")
174 branch_names.remove(
"RawTRGs")
176 path.add_module(
"RootOutput", outputFileName=output_file_name, branchNames=branch_names)
183def test_script(script_location, input_file_name, temp_dir):
185 Test a script with the given file path using the given input file.
186 Raises an exception if the execution fails or if the needed output is not in
188 The results are stored in the temporary directory location.
190 :param script_location: the script to test
191 :param input_file_name: the file path of the input file
192 :param temp_dir: where to store and run
194 input_buffer =
"UNUSED"
195 output_buffer =
"UNUSED"
198 random_seed =
"".join(random.choices(
"abcdef", k=4))
200 histos_file_name = f
"{random_seed}_histos.root"
201 output_file_name = os.path.join(temp_dir, f
"{random_seed}_output.root")
202 globaltags = list(basf2.conditions.default_globaltags)
208 os.chdir(os.path.dirname(script_location))
209 cmd1 = [sys.executable, script_location,
"--central-db-tag"] + globaltags + [
210 "--input-file", os.path.abspath(input_file_name),
211 "--histo-output-file", os.path.join(temp_dir, f
"{histos_file_name}"),
212 "--output-file", os.path.abspath(output_file_name),
213 "--number-processes", str(num_processes),
214 "--input", input_buffer,
215 "--output", output_buffer,
216 "--dqm", str(histo_port)
218 subprocess.check_call(cmd1)
223 final_histos_file_name = os.path.join(temp_dir, histos_file_name)
224 if os.path.exists(histos_file_name):
225 shutil.copy(histos_file_name, os.path.join(temp_dir, final_histos_file_name))
226 os.unlink(histos_file_name)
231 if "beam_reco" in script_location:
233 if "expressreco" not in script_location:
235 test_path = basf2.Path()
236 test_path.add_module(
"RootInput", inputFileName=output_file_name)
241 cmd2 = [
"hlt-check-dqm-size", final_histos_file_name]
242 subprocess.check_call(cmd2)
245def test_folder(location, run_type, exp_number, event_distribution, passthrough=False,
246 simulate_events_of_doom_buster=False):
248 Run all hlt operation scripts in a given folder
249 and test the outputs of the files.
251 Will call the test_script function on all files in the folder given
252 by the location after having created a suitable input file with the given
255 :param location: hlt or expressreco, depending on which operation files to run
256 and which input to simulate
257 :param run_type: cosmic or beam, depending on which operation files to run
258 and which input to simulate
259 :param exp_number: which experiment number to simulate
260 :param event_distribution: where to look for the operation files (will search in the folder
261 hlt/operation/{event_distribution}/{location}/)
262 :param passthrough: only relevant for express reco: If true don't create a
263 software trigger result in the input file to test running
264 express reco if hlt is in passthrough mode
265 :param simulate_events_of_doom_buster: if true, simulate the effect of the
266 EventsOfDoomBuster module by inflating the number of CDC hits
273 temp_dir = os.getcwd()
274 prepare_path = os.environ[
"BELLE2_PREPARE_PATH"]
275 input_file_name = get_file_name(
276 prepare_path, run_type, location, passthrough, simulate_events_of_doom_buster)
278 script_dir = basf2.find_file(f
"hlt/operation/{event_distribution}/{location.name}/")
279 run_at_least_one =
False
280 for script_location
in glob(os.path.join(script_dir, f
"run_{run_type.name}*.py")):
281 run_at_least_one =
True
282 test_script(script_location, input_file_name=input_file_name, temp_dir=temp_dir)
284 assert run_at_least_one
Class to access a DBObjPtr from Python.
A (simplified) python wrapper for StoreArray.
a (simplified) python wrapper for StoreObjPtr.
skip_test(reason, py_case=None)
safe_process(*args, **kwargs)
add_continuum_generator(path, finalstate, userdecfile='', *, skip_on_failure=True, eventType='')