Belle II Software development
caf_pxd_landau.py
1
8
9# This steering file computes PXD calibrations for hot pixels, dead pixels, hit occupancy and
10# energy loss (gain). The script uses the CAF framework. This script uses by default the
11# SequentialRunByRun strategy and is designed to try to compute new calibration constants
12# regularly to follow temporal changes of the PXD.
13#
14# The script allows you to create a list of runs that will be ignored in the calibration.
15# Use this list for known bad runs.
16#
17# Before calibration, you have to put a file to IoV mapping called 'file_iov_map.pkl' in your
18# working directory. The mapping file should map file locations to IoV ranges and allows to
19# logically address data by experiment and run numbers. You can create such a map file by using
20# the tool b2caf-filemap. See also the option --help.
21#
22# b2caf-filemap -m raw -p "/hsm/belle2/bdata/Data/Raw/e0003/r*/**/*.root"
23#
24# The next step is to prepare mc runs containing PXDSimHits. That setup for the simulation
25# should mimik the situation of beam data as closely as possible.
26#
27# basf2 submit_create_mcruns.py -- --backend='local' --outputdir='pxd_mc_phase2' --runLow=4000 --runHigh=6522 --expNo=3
28#
29# The scripts submits the creation of mc runs to a CAF.backend (here local) for all for given run range. Runs in the
30# specified runs but not found in 'file_iov_map.pkl' will be skipped. The simulated runs will be collected in the folder
31# outputdir. It is best to create another mapping file for the mc data.
32#
33# b2caf-filemap -m metadata -p --output-file "dummy_mc_file_iov_map.pkl" "pxd_mc_phase2/*.root"
34#
35# Finally, a CAF script for the calibration needs to be started:
36#
37# basf2 caf_pxd_landau.py -- --runLow=5613 --runHigh=5613 --expNo=3
38#
39# The results will be collected in a folder 'pxd_calibration_results_range_XY'. In order to complete the
40# process, the check and uploads the outputdbs to a global tag (GT).
41#
42# b2conditionsdb upload Calibration_Offline_Development ./database.txt
43#
44# The option --help provides extensive help for the b2conditionsdb tool.
45
46
47import argparse
48from caf.strategies import SequentialRunByRun
49from caf.utils import ExpRun, IoV
50from caf.backends import LSF
51from caf.framework import Calibration, CAF
52import ROOT # noqa (makes ROOT.Belle2 accessible)
53from ROOT.Belle2 import PXDHotPixelMaskCalibrationAlgorithm
54from ROOT.Belle2 import PXDChargeCalibrationAlgorithm
55from ROOT.Belle2 import PXDGainCalibrationAlgorithm
56import pickle
57import basf2 as b2
58b2.set_log_level(b2.LogLevel.INFO)
59
60ROOT.gROOT.SetBatch(True)
61
62
63parser = argparse.ArgumentParser(
64 description="Compute gain correction maps for PXD from beam data")
65parser.add_argument(
66 '--runLow',
67 default=0,
68 type=int,
69 help='Compute mask for specific IoV')
70parser.add_argument('--runHigh', default=-1, type=int,
71 help='Compute mask for specific IoV')
72parser.add_argument(
73 '--expNo',
74 default=3,
75 type=int,
76 help='Compute mask for specific IoV')
77parser.add_argument('--maxSubRuns', default=20, type=int,
78 help='Maximum number of subruns to use')
79args = parser.parse_args()
80
81
82# input files
83pxd_ignore_run_list = [ExpRun(3, 484), ExpRun(3, 485), ExpRun(3, 486), ExpRun(3, 524)]
84
85# Set the IoV range for this calibration
86iov_to_calibrate = IoV(
87 exp_low=args.expNo,
88 run_low=args.runLow,
89 exp_high=args.expNo,
90 run_high=args.runHigh)
91
92
93# Access files_to_iovs for beam runs
94with open("file_iov_map.pkl", 'br') as map_file:
95 files_to_iovs = pickle.load(map_file)
96
97# Get list of input files (beam data)
98input_files = []
99
100input_file_iov_set = set(files_to_iovs.values())
101for file_iov in input_file_iov_set:
102 if iov_to_calibrate.contains(file_iov):
103 subruns = [k for k, v in files_to_iovs.items() if v == file_iov]
104 input_files.extend(subruns[:args.maxSubRuns])
105
106print(f'Number selected input files: {len(input_files)}')
107
108
109# Access files_to_iovs for MC runs
110with open("mc_file_iov_map.pkl", 'br') as map_file:
111 mc_files_to_iovs = pickle.load(map_file)
112
113mc_input_files = list(mc_files_to_iovs.keys())
114
115
116print(f'Number selected mc input files: {len(mc_input_files)}')
117
118
119# HOTPIXEl CALIBRATION
120
121# Create and configure the collector and its pre collector path
122hotpixel_collector = b2.register_module("PXDRawHotPixelMaskCollector")
123hotpixel_collector.param("granularity", "run")
124
125# The pre collector path must contain geometry and unpacker
126pre_hotpixel_collector_path = b2.create_path()
127pre_hotpixel_collector_path.add_module(
128 "Gearbox", fileName='geometry/Beast2_phase2.xml')
129pre_hotpixel_collector_path.add_module("Geometry", useDB=False)
130pre_hotpixel_collector_path.add_module('PXDUnpacker')
131pre_hotpixel_collector_path.add_module('PXDPostErrorChecker')
132pre_hotpixel_collector_path.add_module('Progress')
133# Create and configure the calibration algorithm
134hotpixel_algo = PXDHotPixelMaskCalibrationAlgorithm()
135
136# We can play around with hotpixelkiller parameters
137# Continue masking even when few/no events were collected
138hotpixel_algo.forceContinueMasking = False
139# Minimum number of collected events for masking
140hotpixel_algo.minEvents = 10000
141# Only consider dead pixel masking when median number of hits per pixel is
142# higher
143hotpixel_algo.minHits = 15
144# Occupancy threshold is median occupancy x multiplier
145hotpixel_algo.pixelMultiplier = 7
146# Set True to allow masking of hot drain lines
147hotpixel_algo.maskDrains = True
148# Occupancy threshold is median occupancy x multiplier
149hotpixel_algo.drainMultiplier = 7
150# Set True to allow masking of hot rows
151hotpixel_algo.maskRows = True
152# Occupancy threshold is median occupancy x multiplier
153hotpixel_algo.rowMultiplier = 7
154
155# We want to use a specific collector collecting from raw hits
156hotpixel_algo.setPrefix("PXDRawHotPixelMaskCollector")
157
158# Create a hotpixel calibration
159hotpixel_cal = Calibration(
160 name="PXDHotPixelMaskCalibrationAlgorithm",
161 collector=hotpixel_collector,
162 algorithms=hotpixel_algo,
163 input_files=input_files)
164hotpixel_cal.pre_collector_path = pre_hotpixel_collector_path
165
166# Apply the map to this calibration, now the CAF doesn't have to do it
167hotpixel_cal.files_to_iovs = files_to_iovs
168
169# Here we set the AlgorithmStrategy
170hotpixel_cal.strategies = SequentialRunByRun
171hotpixel_cal.max_files_per_collector_job = 1
172hotpixel_cal.use_central_database("Calibration_Offline_Development")
173
174hotpixel_cal.ignored_runs = pxd_ignore_run_list
175hotpixel_cal.algorithms[0].params["iov_coverage"] = iov_to_calibrate
176
177
178# Landau Fit on DATA
179
180
181# Create and configure the collector on beam data and its pre collector path
182charge_collector = b2.register_module("PXDClusterChargeCollector")
183charge_collector.param("granularity", "run")
184charge_collector.param("minClusterCharge", 8)
185charge_collector.param("minClusterSize", 2)
186charge_collector.param("maxClusterSize", 6)
187charge_collector.param("nBinsU", 4)
188charge_collector.param("nBinsV", 6)
189
190
191# The pre collector path on data
192pre_charge_collector_path = b2.create_path()
193pre_charge_collector_path.add_module(
194 "Gearbox", fileName='geometry/Beast2_phase2.xml')
195pre_charge_collector_path.add_module("Geometry", useDB=False)
196pre_charge_collector_path.add_module("ActivatePXDPixelMasker")
197pre_charge_collector_path.add_module("PXDUnpacker")
198pre_charge_collector_path.add_module('PXDPostErrorChecker')
199pre_charge_collector_path.add_module("PXDRawHitSorter")
200pre_charge_collector_path.add_module("PXDClusterizer")
201
202
203landau_algo = PXDChargeCalibrationAlgorithm()
204
205# We can play around with algo parameters
206# Minimum number of collected clusters for estimating gains
207landau_algo.minClusters = 5000
208# Artificial noise sigma for smearing cluster charge
209landau_algo.noiseSigma = 0.6
210# Force continue algorithm instead of c_notEnoughData
211landau_algo.forceContinue = False
212landau_algo.strategy = 1 # 0: medians, 1: landau fit
213# We want to use a specific collector
214landau_algo.setPrefix("PXDClusterChargeCollector")
215
216# create calibration
217charge_cal = Calibration(
218 name="PXDChargeCalibrationAlgorithm",
219 collector=charge_collector,
220 algorithms=landau_algo,
221 input_files=input_files)
222
223charge_cal.pre_collector_path = pre_charge_collector_path
224
225# Apply the map to this calibration, now the CAF doesn't have to do it
226charge_cal.files_to_iovs = files_to_iovs
227
228# Here we set the AlgorithmStrategy
229charge_cal.strategies = SequentialRunByRun
230charge_cal.max_files_per_collector_job = 1
231
232charge_cal.algorithms[0].params["iov_coverage"] = iov_to_calibrate
233charge_cal.ignored_runs = pxd_ignore_run_list
234
235charge_cal.use_central_database("Calibration_Offline_Development")
236
237
238# gain calibration on mc
239
240gain_collector = b2.register_module("PXDClusterChargeCollector")
241gain_collector.param("granularity", "run")
242gain_collector.param("minClusterCharge", 8)
243gain_collector.param("minClusterSize", 2)
244gain_collector.param("maxClusterSize", 6)
245gain_collector.param("nBinsU", 4)
246gain_collector.param("nBinsV", 6)
247
248# The pre collector path on mc files
249pre_gain_collector_path = b2.create_path()
250pre_gain_collector_path.add_module(
251 "Gearbox", fileName='geometry/Beast2_phase2.xml')
252pre_gain_collector_path.add_module("Geometry", useDB=False)
253pre_gain_collector_path.add_module("PXDDigitizer")
254pre_gain_collector_path.add_module("PXDClusterizer")
255
256
257# Create and configure the calibration algorithm
258gain_algo = PXDGainCalibrationAlgorithm()
259
260# We can play around with algo parameters
261# Minimum number of collected clusters for estimating gains
262gain_algo.minClusters = 3000
263# Artificial noise sigma for smearing cluster charge
264gain_algo.noiseSigma = 0.6
265# Force continue algorithm instead of c_notEnoughData
266gain_algo.forceContinue = False
267gain_algo.strategy = 1 # 0: median, 1: landau fit
268# We want to use a specific collector
269gain_algo.setPrefix("PXDClusterChargeCollector")
270
271# Create a charge calibration
272gain_cal = Calibration(
273 name="PXDGainCalibrationAlgorithm",
274 collector=gain_collector,
275 algorithms=gain_algo,
276 input_files=mc_input_files)
277
278gain_cal.pre_collector_path = pre_gain_collector_path
279
280# Apply the map to this calibration, now the CAF doesn't have to do it
281gain_cal.files_to_iovs = mc_files_to_iovs
282
283# Here we set the AlgorithmStrategy
284gain_cal.strategies = SequentialRunByRun
285gain_cal.max_files_per_collector_job = 1
286
287gain_cal.algorithms[0].params["iov_coverage"] = iov_to_calibrate
288gain_cal.ignored_runs = pxd_ignore_run_list
289
290gain_cal.use_central_database("Calibration_Offline_Development")
291
292
293# CAF
294
295# Define dependencies. In this case: hotpixel_cal -> charge_cal -> gain_cal
296charge_cal.depends_on(hotpixel_cal)
297gain_cal.depends_on(charge_cal)
298
299# create a CAF instance and add the calibration
300cal_fw = CAF()
301cal_fw.add_calibration(hotpixel_cal)
302cal_fw.add_calibration(charge_cal)
303cal_fw.add_calibration(gain_cal)
304# cal_fw.backend = backends.Local(max_processes=20)
305cal_fw.backend = LSF()
306cal_fw.output_dir = f'pxd_calibration_results_range_{args.runLow}_{args.runHigh}_{args.expNo}'
307cal_fw.run(iov=iov_to_calibrate)