Belle II Software  release-08-01-10
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 
47 import argparse
48 from caf.strategies import SequentialRunByRun
49 from caf.utils import ExpRun, IoV
50 from caf.backends import LSF
51 from caf.framework import Calibration, CAF
52 from ROOT.Belle2 import PXDHotPixelMaskCalibrationAlgorithm
53 from ROOT.Belle2 import PXDChargeCalibrationAlgorithm
54 from ROOT.Belle2 import PXDGainCalibrationAlgorithm
55 import ROOT
56 import pickle
57 import basf2 as b2
58 b2.set_log_level(b2.LogLevel.INFO)
59 
60 ROOT.gROOT.SetBatch(True)
61 
62 
63 parser = argparse.ArgumentParser(
64  description="Compute gain correction maps for PXD from beam data")
65 parser.add_argument(
66  '--runLow',
67  default=0,
68  type=int,
69  help='Compute mask for specific IoV')
70 parser.add_argument('--runHigh', default=-1, type=int,
71  help='Compute mask for specific IoV')
72 parser.add_argument(
73  '--expNo',
74  default=3,
75  type=int,
76  help='Compute mask for specific IoV')
77 parser.add_argument('--maxSubRuns', default=20, type=int,
78  help='Maximum number of subruns to use')
79 args = parser.parse_args()
80 
81 
82 # input files
83 pxd_ignore_run_list = [ExpRun(3, 484), ExpRun(3, 485), ExpRun(3, 486), ExpRun(3, 524)]
84 
85 # Set the IoV range for this calibration
86 iov_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
94 with 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)
98 input_files = []
99 
100 input_file_iov_set = set(files_to_iovs.values())
101 for 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 
106 print(f'Number selected input files: {len(input_files)}')
107 
108 
109 # Access files_to_iovs for MC runs
110 with open("mc_file_iov_map.pkl", 'br') as map_file:
111  mc_files_to_iovs = pickle.load(map_file)
112 
113 mc_input_files = list(mc_files_to_iovs.keys())
114 
115 
116 print(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
122 hotpixel_collector = b2.register_module("PXDRawHotPixelMaskCollector")
123 hotpixel_collector.param("granularity", "run")
124 
125 # The pre collector path must contain geometry and unpacker
126 pre_hotpixel_collector_path = b2.create_path()
127 pre_hotpixel_collector_path.add_module(
128  "Gearbox", fileName='geometry/Beast2_phase2.xml')
129 pre_hotpixel_collector_path.add_module("Geometry", useDB=False)
130 pre_hotpixel_collector_path.add_module('PXDUnpacker')
131 pre_hotpixel_collector_path.add_module('PXDPostErrorChecker')
132 pre_hotpixel_collector_path.add_module('Progress')
133 # Create and configure the calibration algorithm
134 hotpixel_algo = PXDHotPixelMaskCalibrationAlgorithm()
135 
136 # We can play around with hotpixelkiller parameters
137 # Continue masking even when few/no events were collected
138 hotpixel_algo.forceContinueMasking = False
139 # Minimum number of collected events for masking
140 hotpixel_algo.minEvents = 10000
141 # Only consider dead pixel masking when median number of hits per pixel is
142 # higher
143 hotpixel_algo.minHits = 15
144 # Occupancy threshold is median occupancy x multiplier
145 hotpixel_algo.pixelMultiplier = 7
146 # Set True to allow masking of hot drain lines
147 hotpixel_algo.maskDrains = True
148 # Occupancy threshold is median occupancy x multiplier
149 hotpixel_algo.drainMultiplier = 7
150 # Set True to allow masking of hot rows
151 hotpixel_algo.maskRows = True
152 # Occupancy threshold is median occupancy x multiplier
153 hotpixel_algo.rowMultiplier = 7
154 
155 # We want to use a specific collector collecting from raw hits
156 hotpixel_algo.setPrefix("PXDRawHotPixelMaskCollector")
157 
158 # Create a hotpixel calibration
159 hotpixel_cal = Calibration(
160  name="PXDHotPixelMaskCalibrationAlgorithm",
161  collector=hotpixel_collector,
162  algorithms=hotpixel_algo,
163  input_files=input_files)
164 hotpixel_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
167 hotpixel_cal.files_to_iovs = files_to_iovs
168 
169 # Here we set the AlgorithmStrategy
170 hotpixel_cal.strategies = SequentialRunByRun
171 hotpixel_cal.max_files_per_collector_job = 1
172 hotpixel_cal.use_central_database("Calibration_Offline_Development")
173 
174 hotpixel_cal.ignored_runs = pxd_ignore_run_list
175 hotpixel_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
182 charge_collector = b2.register_module("PXDClusterChargeCollector")
183 charge_collector.param("granularity", "run")
184 charge_collector.param("minClusterCharge", 8)
185 charge_collector.param("minClusterSize", 2)
186 charge_collector.param("maxClusterSize", 6)
187 charge_collector.param("nBinsU", 4)
188 charge_collector.param("nBinsV", 6)
189 
190 
191 # The pre collector path on data
192 pre_charge_collector_path = b2.create_path()
193 pre_charge_collector_path.add_module(
194  "Gearbox", fileName='geometry/Beast2_phase2.xml')
195 pre_charge_collector_path.add_module("Geometry", useDB=False)
196 pre_charge_collector_path.add_module("ActivatePXDPixelMasker")
197 pre_charge_collector_path.add_module("PXDUnpacker")
198 pre_charge_collector_path.add_module('PXDPostErrorChecker')
199 pre_charge_collector_path.add_module("PXDRawHitSorter")
200 pre_charge_collector_path.add_module("PXDClusterizer")
201 
202 
203 landau_algo = PXDChargeCalibrationAlgorithm()
204 
205 # We can play around with algo parameters
206 # Minimum number of collected clusters for estimating gains
207 landau_algo.minClusters = 5000
208 # Artificial noise sigma for smearing cluster charge
209 landau_algo.noiseSigma = 0.6
210 # Force continue algorithm instead of c_notEnoughData
211 landau_algo.forceContinue = False
212 landau_algo.strategy = 1 # 0: medians, 1: landau fit
213 # We want to use a specific collector
214 landau_algo.setPrefix("PXDClusterChargeCollector")
215 
216 # create calibration
217 charge_cal = Calibration(
218  name="PXDChargeCalibrationAlgorithm",
219  collector=charge_collector,
220  algorithms=landau_algo,
221  input_files=input_files)
222 
223 charge_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
226 charge_cal.files_to_iovs = files_to_iovs
227 
228 # Here we set the AlgorithmStrategy
229 charge_cal.strategies = SequentialRunByRun
230 charge_cal.max_files_per_collector_job = 1
231 
232 charge_cal.algorithms[0].params["iov_coverage"] = iov_to_calibrate
233 charge_cal.ignored_runs = pxd_ignore_run_list
234 
235 charge_cal.use_central_database("Calibration_Offline_Development")
236 
237 
238 # gain calibration on mc
239 
240 gain_collector = b2.register_module("PXDClusterChargeCollector")
241 gain_collector.param("granularity", "run")
242 gain_collector.param("minClusterCharge", 8)
243 gain_collector.param("minClusterSize", 2)
244 gain_collector.param("maxClusterSize", 6)
245 gain_collector.param("nBinsU", 4)
246 gain_collector.param("nBinsV", 6)
247 
248 # The pre collector path on mc files
249 pre_gain_collector_path = b2.create_path()
250 pre_gain_collector_path.add_module(
251  "Gearbox", fileName='geometry/Beast2_phase2.xml')
252 pre_gain_collector_path.add_module("Geometry", useDB=False)
253 pre_gain_collector_path.add_module("PXDDigitizer")
254 pre_gain_collector_path.add_module("PXDClusterizer")
255 
256 
257 # Create and configure the calibration algorithm
258 gain_algo = PXDGainCalibrationAlgorithm()
259 
260 # We can play around with algo parameters
261 # Minimum number of collected clusters for estimating gains
262 gain_algo.minClusters = 3000
263 # Artificial noise sigma for smearing cluster charge
264 gain_algo.noiseSigma = 0.6
265 # Force continue algorithm instead of c_notEnoughData
266 gain_algo.forceContinue = False
267 gain_algo.strategy = 1 # 0: median, 1: landau fit
268 # We want to use a specific collector
269 gain_algo.setPrefix("PXDClusterChargeCollector")
270 
271 # Create a charge calibration
272 gain_cal = Calibration(
273  name="PXDGainCalibrationAlgorithm",
274  collector=gain_collector,
275  algorithms=gain_algo,
276  input_files=mc_input_files)
277 
278 gain_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
281 gain_cal.files_to_iovs = mc_files_to_iovs
282 
283 # Here we set the AlgorithmStrategy
284 gain_cal.strategies = SequentialRunByRun
285 gain_cal.max_files_per_collector_job = 1
286 
287 gain_cal.algorithms[0].params["iov_coverage"] = iov_to_calibrate
288 gain_cal.ignored_runs = pxd_ignore_run_list
289 
290 gain_cal.use_central_database("Calibration_Offline_Development")
291 
292 
293 # CAF
294 
295 # Define dependencies. In this case: hotpixel_cal -> charge_cal -> gain_cal
296 charge_cal.depends_on(hotpixel_cal)
297 gain_cal.depends_on(charge_cal)
298 
299 # create a CAF instance and add the calibration
300 cal_fw = CAF()
301 cal_fw.add_calibration(hotpixel_cal)
302 cal_fw.add_calibration(charge_cal)
303 cal_fw.add_calibration(gain_cal)
304 # cal_fw.backend = backends.Local(max_processes=20)
305 cal_fw.backend = LSF()
306 cal_fw.output_dir = f'pxd_calibration_results_range_{args.runLow}_{args.runHigh}_{args.expNo}'
307 cal_fw.run(iov=iov_to_calibrate)