Belle II Software development
caf_hotpixel_sequential.py
1#!/usr/bin/env python3
2
3
10
11# This steering file computes PXD hotpixel and deadpixel masks from root formatted raw data
12# running the CAF
13#
14# Before running, you have to put a file to IoV mapping called 'file_iov_map.pkl' in your
15# working directory. You can create such a map file by using the tool b2caf-filemap.
16# See also the option --help.
17#
18# b2caf-filemap -m raw -p "/hsm/belle2/bdata/Data/Raw/e0003/r*/**/*.root"
19#
20# This will try to compute hot pixel masks, dead pixel masks and occupancy maps for each run
21# in the given IoV range.
22#
23# The results will be collected in a folder 'pxd_calibration_results_range_XY'. In order to complete the
24# process, the check and uploads the outputdbs to a global tag (GT).
25#
26# b2conditionsdb upload Calibration_Offline_Development ./database.txt
27#
28# The option --help provides extensive help for the b2conditionsdb tool.
29
30import argparse
31from caf.strategies import SequentialRunByRun
32from caf.utils import ExpRun, IoV
33from caf import backends
34from caf.framework import Calibration, CAF
35from ROOT import Belle2 # noqa: make Belle2 namespace accessible
36from ROOT.Belle2 import PXDHotPixelMaskCalibrationAlgorithm
37import pickle
38import basf2 as b2
39b2.set_log_level(b2.LogLevel.INFO)
40
41
42parser = argparse.ArgumentParser(
43 description="Compute hot pixel masks for PXD from rawhit occupancy")
44parser.add_argument(
45 '--runLow',
46 default=0,
47 type=int,
48 help='Compute mask for specific IoV')
49parser.add_argument('--runHigh', default=-1, type=int,
50 help='Compute mask for specific IoV')
51parser.add_argument(
52 '--expNo',
53 default=3,
54 type=int,
55 help='Compute mask for specific IoV')
56parser.add_argument('--maxSubRuns', default=20, type=int,
57 help='Maximum number of subruns to use')
58args = parser.parse_args()
59
60
61# Ignoring runs
62pxd_ignore_run_list = [ExpRun(3, 484), ExpRun(3, 485), ExpRun(3, 486), ExpRun(3, 524)]
63
64# Set the IoV range for this calibration
65iov_to_calibrate = IoV(
66 exp_low=args.expNo,
67 run_low=args.runLow,
68 exp_high=args.expNo,
69 run_high=args.runHigh)
70
71map_file_path = "file_iov_map.pkl"
72with open(map_file_path, 'br') as map_file:
73 files_to_iovs = pickle.load(map_file)
74
75
76input_file_iov_set = set(files_to_iovs.values())
77print(f'Number of distinct iovs {len(input_file_iov_set)}')
78
79
80input_files = []
81
82for file_iov in input_file_iov_set:
83 if iov_to_calibrate.contains(file_iov):
84 subruns = [k for k, v in files_to_iovs.items() if v == file_iov]
85 input_files.extend(subruns[:args.maxSubRuns])
86
87
88print(f'Number selected input files: {len(input_files)}')
89
90# Create and configure the collector and its pre collector path
91hotpixelcollector = b2.register_module("PXDRawHotPixelMaskCollector")
92hotpixelcollector.param("granularity", "run")
93
94# The pre collector path must contain geometry and unpacker
95gearbox = b2.register_module('Gearbox')
96gearbox.param('fileName', 'geometry/Beast2_phase2.xml')
97geometry = b2.register_module('Geometry')
98geometry.param('components', ['PXD'])
99pre_collector_path = b2.create_path()
100pre_collector_path.add_module(gearbox)
101pre_collector_path.add_module(geometry)
102pre_collector_path.add_module('PXDUnpacker')
103
104
105# Create and configure the calibration algorithm
106# Getting a calibration algorithm instance
107hotpixelkiller = PXDHotPixelMaskCalibrationAlgorithm()
108# We can play around with hotpixelkiller parameters
109# Continue masking even when few/no events were collected
110hotpixelkiller.forceContinueMasking = False
111# Minimum number of collected events for masking
112hotpixelkiller.minEvents = 30000
113# Only consider dead pixel masking when median number of hits per pixel is
114# higher
115hotpixelkiller.minHits = 15
116# Occupancy threshold is median occupancy x multiplier
117hotpixelkiller.pixelMultiplier = 7
118# Set True to allow masking of hot drain lines
119hotpixelkiller.maskDrains = True
120# Occupancy threshold is median occupancy x multiplier
121hotpixelkiller.drainMultiplier = 7
122# Set True to allow masking of hot rows
123hotpixelkiller.maskRows = True
124# Occupancy threshold is median occupancy x multiplier
125hotpixelkiller.rowMultiplier = 7
126# We want to use a specific collector collecting from raw hits
127hotpixelkiller.setPrefix("PXDRawHotPixelMaskCollector")
128
129# Create a calibration
130cal = Calibration(
131 name="PXDHotPixelMaskCalibrationAlgorithm",
132 collector=hotpixelcollector,
133 algorithms=hotpixelkiller,
134 input_files=input_files)
135cal.pre_collector_path = pre_collector_path
136
137# Apply the map to this calibration, now the CAF doesn't have to do it
138cal.files_to_iovs = files_to_iovs
139
140# The SequentialRunByRun strategy executes your algorithm over runs
141# individually to give you payloads for each one (if successful)
142cal.strategies = SequentialRunByRun
143
144cal.ignored_runs = pxd_ignore_run_list
145cal.algorithms[0].params["iov_coverage"] = iov_to_calibrate
146
147cal.max_files_per_collector_job = 1
148
149# Create a CAF instance and add the calibration to it.
150cal_fw = CAF()
151cal_fw.add_calibration(cal)
152# cal_fw.backend = backends.LSF()
153cal_fw.backend = backends.Local(max_processes=20)
154# Time between polling checks to the CAF to see if a step (algorithm,
155# collector jobs) is complete
156cal_fw.heartbeat = 30
157# Can change where your calibration runs
158cal_fw.output_dir = f'calibration_results_range_{args.runLow}_{args.runHigh}'
159cal_fw.run(iov=iov_to_calibrate)
160# Should have created a directory called 'calibration_results'