Belle II Software  release-06-01-15
caf_ecms.py
1 # -*- coding: utf-8 -*-
2 
3 
10 
11 """
12 Airflow script to perform eCMS calibration (combination of the had-B and mumu method).
13 """
14 
15 from prompt import CalibrationSettings, INPUT_DATA_FILTERS
16 from prompt.calibrations.caf_boostvector import settings as boostvector
17 from reconstruction import add_pid_module, add_ecl_modules, prepare_cdst_analysis
18 
19 from basf2 import create_path, register_module, B2INFO
20 import modularAnalysis as ma
21 import vertex
22 import stdCharged
23 import stdPi0s
24 
25 
26 
27 settings = CalibrationSettings(
28  name="Ecms Calibrations",
29  expert_username="zlebcr",
30  description=__doc__,
31  input_data_formats=["cdst"],
32  input_data_names=["hadron4S", "mumu4S", "mumuOff"],
33  input_data_filters={
34  "hadron4S": [
35  INPUT_DATA_FILTERS["Data Tag"]["btocharm_calib"],
36  INPUT_DATA_FILTERS["Run Type"]["physics"],
37  INPUT_DATA_FILTERS["Beam Energy"]["4S"],
38  INPUT_DATA_FILTERS["Data Quality Tag"]["Good Or Recoverable"],
39  INPUT_DATA_FILTERS["Magnet"]["On"]],
40  "mumu4S": [
41  INPUT_DATA_FILTERS["Data Tag"]["mumu_tight_or_highm_calib"],
42  INPUT_DATA_FILTERS["Run Type"]["physics"],
43  INPUT_DATA_FILTERS["Beam Energy"]["4S"],
44  INPUT_DATA_FILTERS["Data Quality Tag"]["Good Or Recoverable"],
45  INPUT_DATA_FILTERS["Magnet"]["On"]],
46  "mumuOff": [
47  INPUT_DATA_FILTERS["Data Tag"]["mumu_tight_or_highm_calib"],
48  INPUT_DATA_FILTERS["Run Type"]["physics"],
49  INPUT_DATA_FILTERS["Beam Energy"]["Continuum"],
50  INPUT_DATA_FILTERS['Beam Energy']['Scan'],
51  INPUT_DATA_FILTERS["Data Quality Tag"]["Good Or Recoverable"],
52  INPUT_DATA_FILTERS["Magnet"]["On"]]
53  },
54  expert_config={
55  "outerLoss": "pow(0.000010e0*rawTime, 2) + 1./nEv",
56  "innerLoss": "pow(0.000120e0*rawTime, 2) + 1./nEv",
57  "runHadB": True,
58  "eCMSmumuSpread": 5.2e-3,
59  "eCMSmumuShift": 10e-3},
60  depends_on=[boostvector])
61 
62 
63 
64 
65 def get_hadB_path(isCDST):
66  """ Selects the hadronic B decays, function returns corresponding path """
67 
68  # module to be run prior the collector
69  rec_path_1 = create_path()
70  if isCDST:
71  prepare_cdst_analysis(path=rec_path_1, components=['CDC', 'ECL', 'KLM'])
72 
73  add_pid_module(rec_path_1)
74  add_ecl_modules(rec_path_1)
75 
76  stdCharged.stdPi(listtype='loose', path=rec_path_1)
77  stdCharged.stdK(listtype='good', path=rec_path_1)
78  stdPi0s.stdPi0s(listtype='eff40_May2020', path=rec_path_1)
79 
80  ma.cutAndCopyList("pi+:my", "pi+:loose", "[abs(dz)<2.0] and [abs(dr)<0.5]", path=rec_path_1)
81  ma.cutAndCopyList("K+:my", "K+:good", "[abs(dz)<2.0] and [abs(dr)<0.5]", path=rec_path_1)
82 
83  ma.cutAndCopyList("pi0:my", "pi0:eff40_May2020", "", path=rec_path_1)
84 
85 
88 
89  DcutLoose = '1.7 < M < 2.1'
90  Dcut = '1.830 < M < 1.894'
91  # Reconstructs D0s and sets decay mode identifiers
92  ma.reconstructDecay(decayString='D0:Kpi -> K-:my pi+:my', cut=DcutLoose, dmID=1, path=rec_path_1)
93  ma.reconstructDecay(decayString='D0:Kpipi0 -> K-:my pi+:my pi0:my',
94  cut=DcutLoose, dmID=2, path=rec_path_1)
95  ma.reconstructDecay(decayString='D0:Kpipipi -> K-:my pi+:my pi-:my pi+:my',
96  cut=DcutLoose, dmID=3, path=rec_path_1)
97 
98  # Performs mass constrained fit for all D0 candidates
99  vertex.kFit(list_name='D0:Kpi', conf_level=0.0, fit_type='mass', path=rec_path_1)
100  # vertex.kFit(list_name='D0:Kpipi0', conf_level=0.0, fit_type='mass', path=rec_path_1)
101  vertex.kFit(list_name='D0:Kpipipi', conf_level=0.0, fit_type='mass', path=rec_path_1)
102 
103  ma.applyCuts("D0:Kpi", Dcut, path=rec_path_1)
104  ma.applyCuts("D0:Kpipi0", Dcut, path=rec_path_1)
105  ma.applyCuts("D0:Kpipipi", Dcut, path=rec_path_1)
106 
107  DStarcutLoose = 'massDifference(0) < 0.16'
108 
109  # Reconstructs D*-s and sets decay mode identifiers
110  ma.reconstructDecay(decayString='D*+:D0pi_Kpi -> D0:Kpi pi+:my', cut=DStarcutLoose, dmID=1, path=rec_path_1)
111  ma.reconstructDecay(decayString='D*+:D0pi_Kpipi0 -> D0:Kpipi0 pi+:my',
112  cut=DStarcutLoose, dmID=2, path=rec_path_1)
113  ma.reconstructDecay(decayString='D*+:D0pi_Kpipipi -> D0:Kpipipi pi+:my',
114  cut=DStarcutLoose, dmID=3, path=rec_path_1)
115 
116  BcutLoose = '[ useCMSFrame(p) < 1.6 ] and [abs(dM) < 0.25]'
117  Bcut = '[ useCMSFrame(p) < 1.2 ] and [abs(dM) < 0.05]'
118 
119  # Reconstructs the signal B0 candidates from Dstar
120  ma.reconstructDecay(decayString='B0:Dstpi_D0pi_Kpi -> D*-:D0pi_Kpi pi+:my',
121  cut=BcutLoose,
122  dmID=1, path=rec_path_1)
123  ma.reconstructDecay(decayString='B0:Dstpi_D0pi_Kpipi0 -> D*-:D0pi_Kpipi0 pi+:my',
124  cut=BcutLoose,
125  dmID=2, path=rec_path_1)
126  ma.reconstructDecay(decayString='B0:Dstpi_D0pi_Kpipipi -> D*-:D0pi_Kpipipi pi+:my',
127  cut=BcutLoose,
128  dmID=3, path=rec_path_1)
129 
130  vertex.treeFit('B0:Dstpi_D0pi_Kpi', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
131  vertex.treeFit('B0:Dstpi_D0pi_Kpipi0', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
132  vertex.treeFit('B0:Dstpi_D0pi_Kpipipi', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
133 
134 
137 
138  # Reconstructs charged D mesons and sets decay mode identifiers
139  ma.reconstructDecay(decayString='D-:Kpipi -> K+:my pi-:my pi-:my',
140  cut=DcutLoose, dmID=4, path=rec_path_1)
141 
142  vertex.kFit(list_name='D-:Kpipi', conf_level=0.0, fit_type='mass', path=rec_path_1)
143  ma.applyCuts("D-:Kpipi", '1.844 < M < 1.894', path=rec_path_1)
144 
145  # Reconstructs the signal B candidates
146  ma.reconstructDecay(decayString='B0:Dpi_Kpipi -> D-:Kpipi pi+:my',
147  cut=BcutLoose, dmID=4, path=rec_path_1)
148 
149 
152 
153  # Reconstructs the signal B- candidates
154  ma.reconstructDecay(decayString='B-:D0pi_Kpi -> D0:Kpi pi-:my',
155  cut=BcutLoose,
156  dmID=5, path=rec_path_1)
157  ma.reconstructDecay(decayString='B-:D0pi_Kpipi0 -> D0:Kpipi0 pi-:my',
158  cut=BcutLoose,
159  dmID=6, path=rec_path_1)
160  ma.reconstructDecay(decayString='B-:D0pi_Kpipipi -> D0:Kpipipi pi-:my',
161  cut=BcutLoose,
162  dmID=7, path=rec_path_1)
163 
164  vertex.treeFit('B-:D0pi_Kpi', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
165  vertex.treeFit('B-:D0pi_Kpipi0', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
166  vertex.treeFit('B-:D0pi_Kpipipi', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
167 
168  ma.copyLists(
169  outputListName='B0:merged',
170  inputListNames=[
171  'B0:Dstpi_D0pi_Kpi',
172  'B0:Dstpi_D0pi_Kpipi0',
173  'B0:Dstpi_D0pi_Kpipipi',
174  'B0:Dpi_Kpipi'
175  ],
176  path=rec_path_1)
177 
178  ma.copyLists(
179  outputListName='B-:merged',
180  inputListNames=[
181  'B-:D0pi_Kpi',
182  'B-:D0pi_Kpipi0',
183  'B-:D0pi_Kpipipi',
184  ],
185  path=rec_path_1)
186 
187  # Builds the rest of event object, which contains all particles not used in the reconstruction of B0 candidates.
188  ma.buildRestOfEvent(target_list_name='B0:merged', path=rec_path_1)
189 
190  # Calculates the continuum suppression variables
191  cleanMask = ('cleanMask', 'nCDCHits > 0 and useCMSFrame(p)<=3.2', 'p >= 0.05 and useCMSFrame(p)<=3.2')
192  ma.appendROEMasks(list_name='B0:merged', mask_tuples=[cleanMask], path=rec_path_1)
193  ma.buildContinuumSuppression(list_name='B0:merged', roe_mask='cleanMask', path=rec_path_1)
194 
195  # Builds the rest of event object, which contains all particles not used in the reconstruction of B- candidates.
196  ma.buildRestOfEvent(target_list_name='B-:merged', path=rec_path_1)
197 
198  # Calculates the continuum suppression variables
199  cleanMask = ('cleanMask', 'nCDCHits > 0 and useCMSFrame(p)<=3.2', 'p >= 0.05 and useCMSFrame(p)<=3.2')
200  ma.appendROEMasks(list_name='B-:merged', mask_tuples=[cleanMask], path=rec_path_1)
201  ma.buildContinuumSuppression(list_name='B-:merged', roe_mask='cleanMask', path=rec_path_1)
202 
203  ma.applyCuts("B0:merged", "[R2 < 0.3] and " + Bcut, path=rec_path_1)
204  ma.applyCuts("B-:merged", "[R2 < 0.3] and " + Bcut, path=rec_path_1)
205 
206  return rec_path_1
207 
208 
209 def get_mumu_path(isCDST):
210  """ Selects the ee -> mumu events, function returns corresponding path """
211 
212  # module to be run prior the collector
213  rec_path_1 = create_path()
214  if isCDST:
215  prepare_cdst_analysis(path=rec_path_1, components=['CDC', 'ECL', 'KLM'])
216 
217  muSelection = '[p>1.0]'
218  muSelection += ' and abs(dz)<2.0 and abs(dr)<0.5'
219  muSelection += ' and nPXDHits >=1 and nSVDHits >= 8 and nCDCHits >= 20'
220 
221  ma.fillParticleList('mu+:BV', muSelection, path=rec_path_1)
222  ma.reconstructDecay('Upsilon(4S):BV -> mu+:BV mu-:BV', '9.5<M<11.5', path=rec_path_1)
223  vertex.treeFit('Upsilon(4S):BV', updateAllDaughters=True, ipConstraint=True, path=rec_path_1)
224 
225  return rec_path_1
226 
227 
228 def get_data_info(inData, kwargs):
229  """ Filter the input data and returns the IOVs """
230 
231  # In this script we want to use one sources of input data.
232  # Get the input files from the input_data variable
233  file_to_iov_physics = inData
234 
235  # We might have requested an enormous amount of data across a run range.
236  # There's a LOT more files than runs!
237  # Lets set some limits because this calibration doesn't need that much to run.
238  max_files_per_run = 1000000
239 
240  # We filter out any more than 100 files per run. The input data files are sorted alphabetically by b2caf-prompt-run
241  # already. This procedure respects that ordering
242  from prompt.utils import filter_by_max_files_per_run
243 
244  reduced_file_to_iov_physics = filter_by_max_files_per_run(file_to_iov_physics, max_files_per_run)
245  input_files_physics = list(reduced_file_to_iov_physics.keys())
246  B2INFO(f"Total number of files actually used as input = {len(input_files_physics)}")
247 
248  # Get the overall IoV we our process should cover. Includes the end values that we may want to ignore since our output
249  # IoV should be open ended. We could also use this as part of the input data selection in some way.
250  requested_iov = kwargs.get("requested_iov", None)
251 
252  from caf.utils import IoV
253  # The actual value our output IoV payload should have. Notice that we've set it open ended.
254  output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
255 
256  return input_files_physics, output_iov
257 
258 
259 def get_calibrations(input_data, **kwargs):
260  """
261  Required function used by b2caf-prompt-run tool.
262  This function return a list of Calibration objects we assign to the CAF process.
263 
264  Parameters:
265  input_data (dict): Should contain every name from the 'input_data_names' variable as a key.
266  Each value is a dictionary with {"/path/to/file_e1_r5.root": IoV(1,5,1,5), ...}. Useful for
267  assigning to calibration.files_to_iov
268 
269  **kwargs: Configuration options to be sent in. Since this may change we use kwargs as a way to help prevent
270  backwards compatibility problems. But you could use the correct arguments in b2caf-prompt-run for this
271  release explicitly if you want to.
272 
273  Currently only kwargs["output_iov"] is used. This is the output IoV range that your payloads should
274  correspond to. Generally your highest ExpRun payload should be open ended e.g. IoV(3,4,-1,-1)
275 
276  Returns:
277  list(caf.framework.Calibration): All of the calibration objects we want to assign to the CAF process
278  """
279 
280  from caf.framework import Calibration
281  from caf.strategies import SingleIOV
282 
283  from ROOT.Belle2 import InvariantMassAlgorithm
284  from caf.framework import Collection
285 
286  input_files_Had, output_iov_Had = get_data_info(input_data["hadron4S"], kwargs)
287  input_files_MuMu4S, output_iov_MuMu4S = get_data_info(input_data["mumu4S"], kwargs)
288  input_files_MuMuOff, output_iov_MuMuOff = get_data_info(input_data["mumuOff"], kwargs)
289 
290  isCDST = 'mdst' not in (input_files_MuMu4S + input_files_MuMuOff)[0]
291 
292  rec_path_HadB = get_hadB_path(isCDST)
293  rec_path_MuMu = get_mumu_path(isCDST)
294 
295  collector_HadB = register_module('EcmsCollector')
296  collector_MuMu = register_module('BoostVectorCollector', Y4SPListName='Upsilon(4S):BV')
297 
298  algorithm_ecms = InvariantMassAlgorithm()
299  algorithm_ecms.setOuterLoss(kwargs['expert_config']['outerLoss'])
300  algorithm_ecms.setInnerLoss(kwargs['expert_config']['innerLoss'])
301 
302  algorithm_ecms.includeHadBcalib(kwargs['expert_config']['runHadB'])
303  algorithm_ecms.setMuMuEcmsSpread(kwargs['expert_config']['eCMSmumuSpread'])
304  algorithm_ecms.setMuMuEcmsOffset(kwargs['expert_config']['eCMSmumuShift'])
305 
306  calibration_ecms = Calibration('eCMS',
307  algorithms=algorithm_ecms)
308 
309  collection_HadB = Collection(collector=collector_HadB,
310  input_files=input_files_Had,
311  pre_collector_path=rec_path_HadB)
312  collection_MuMu4S = Collection(collector=collector_MuMu,
313  input_files=input_files_MuMu4S,
314  pre_collector_path=rec_path_MuMu)
315  collection_MuMuOff = Collection(collector=collector_MuMu,
316  input_files=input_files_MuMuOff,
317  pre_collector_path=rec_path_MuMu)
318 
319  calibration_ecms.add_collection(name='dimuon_4S', collection=collection_MuMu4S)
320  calibration_ecms.add_collection(name='dimuon_Off', collection=collection_MuMuOff)
321  calibration_ecms.add_collection(name='hadB_4S', collection=collection_HadB)
322 
323  calibration_ecms.strategies = SingleIOV
324  # calibration_ecms.backend_args = {'extra_lines' : ["RequestRuntime = 6h"]}
325 
326  # Do this for the default AlgorithmStrategy to force the output payload IoV
327  # It may be different if you are using another strategy like SequentialRunByRun
328  for algorithm in calibration_ecms.algorithms:
329  algorithm.params = {"iov_coverage": output_iov_Had}
330 
331  # Most other options like database chain and backend args will be overwritten by b2caf-prompt-run.
332  # So we don't bother setting them.
333 
334  # You must return all calibrations you want to run in the prompt process, even if it's only one
335  return [calibration_ecms]
336 
337 
def stdPi(listtype=_defaultlist, path=None)
Definition: stdCharged.py:126
def stdK(listtype=_defaultlist, path=None)
Definition: stdCharged.py:136
def stdPi0s(listtype="eff60_May2020", path=None, loadPhotonBeamBackgroundMVA=False)
Definition: stdPi0s.py:17
def kFit(list_name, conf_level, fit_type='vertex', constraint='', daughtersUpdate=False, decay_string='', massConstraint=[], smearing=0, path=None)
Definition: vertex.py:121
def treeFit(list_name, conf_level=0.001, massConstraint=[], ipConstraint=False, updateAllDaughters=False, customOriginConstraint=False, customOriginVertex=[0.001, 0, 0.0116], customOriginCovariance=[0.0048, 0, 0, 0, 0.003567, 0, 0, 0, 0.0400], path=None)
Definition: vertex.py:223