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