10 Airflow script to perform eCMS calibration (combination of the had-B and mumu method).
13 from prompt
import CalibrationSettings, INPUT_DATA_FILTERS
14 from prompt.calibrations.caf_boostvector
import settings
as boostvector
17 import reconstruction
as re
19 from basf2
import create_path, register_module, get_file_metadata, B2INFO, B2WARNING
20 import modularAnalysis
as ma
28 settings = CalibrationSettings(
29 name=
"Ecms Calibrations",
30 expert_username=
"zlebcr",
32 input_data_formats=[
"cdst"],
33 input_data_names=[
"hadron4S",
"mumu4S",
"mumuOff"],
36 INPUT_DATA_FILTERS[
"Data Tag"][
"btocharm_calib"],
37 INPUT_DATA_FILTERS[
"Run Type"][
"physics"],
38 INPUT_DATA_FILTERS[
"Beam Energy"][
"4S"],
39 INPUT_DATA_FILTERS[
"Data Quality Tag"][
"Good Or Recoverable"],
40 INPUT_DATA_FILTERS[
"Magnet"][
"On"]],
42 INPUT_DATA_FILTERS[
"Data Tag"][
"mumu_tight_or_highm_calib"],
43 INPUT_DATA_FILTERS[
"Run Type"][
"physics"],
44 INPUT_DATA_FILTERS[
"Beam Energy"][
"4S"],
45 INPUT_DATA_FILTERS[
"Data Quality Tag"][
"Good Or Recoverable"],
46 INPUT_DATA_FILTERS[
"Magnet"][
"On"]],
48 INPUT_DATA_FILTERS[
"Data Tag"][
"mumu_tight_or_highm_calib"],
49 INPUT_DATA_FILTERS[
"Run Type"][
"physics"],
50 INPUT_DATA_FILTERS[
"Beam Energy"][
"Continuum"],
51 INPUT_DATA_FILTERS[
'Beam Energy'][
'Scan'],
52 INPUT_DATA_FILTERS[
"Data Quality Tag"][
"Good Or Recoverable"],
53 INPUT_DATA_FILTERS[
"Magnet"][
"On"]]
56 "outerLoss":
"pow(0.000010e0*rawTime, 2) + 1./nEv",
57 "innerLoss":
"pow(0.000120e0*rawTime, 2) + 1./nEv",
59 "eCMSmumuSpread": 5.2e-3,
60 "eCMSmumuShift": 10e-3,
62 depends_on=[boostvector])
67 def get_hadB_path(isCDST):
68 """ Selects the hadronic B decays, function returns corresponding path """
71 rec_path_1 = create_path()
73 rec_path_1.add_module(
"RootInput", branchNames=ALWAYS_SAVE_OBJECTS + RAWDATA_OBJECTS)
74 rd.add_unpackers(rec_path_1)
75 re.add_reconstruction(rec_path_1)
81 ma.cutAndCopyList(
"pi+:my",
"pi+:loose",
"[abs(dz)<2.0] and [abs(dr)<0.5]", path=rec_path_1)
82 ma.cutAndCopyList(
"K+:my",
"K+:good",
"[abs(dz)<2.0] and [abs(dr)<0.5]", path=rec_path_1)
84 ma.cutAndCopyList(
"pi0:my",
"pi0:eff40_May2020",
"", path=rec_path_1)
90 DcutLoose =
'1.7 < M < 2.1'
91 Dcut =
'1.830 < M < 1.894'
93 ma.reconstructDecay(decayString=
'D0:Kpi -> K-:my pi+:my', cut=DcutLoose, dmID=1, path=rec_path_1)
94 ma.reconstructDecay(decayString=
'D0:Kpipi0 -> K-:my pi+:my pi0:my',
95 cut=DcutLoose, dmID=2, path=rec_path_1)
96 ma.reconstructDecay(decayString=
'D0:Kpipipi -> K-:my pi+:my pi-:my pi+:my',
97 cut=DcutLoose, dmID=3, path=rec_path_1)
100 vertex.kFit(list_name=
'D0:Kpi', conf_level=0.0, fit_type=
'mass', path=rec_path_1)
102 vertex.kFit(list_name=
'D0:Kpipipi', conf_level=0.0, fit_type=
'mass', path=rec_path_1)
104 ma.applyCuts(
"D0:Kpi", Dcut, path=rec_path_1)
105 ma.applyCuts(
"D0:Kpipi0", Dcut, path=rec_path_1)
106 ma.applyCuts(
"D0:Kpipipi", Dcut, path=rec_path_1)
108 DStarcutLoose =
'massDifference(0) < 0.16'
111 ma.reconstructDecay(decayString=
'D*+:D0pi_Kpi -> D0:Kpi pi+:my', cut=DStarcutLoose, dmID=1, path=rec_path_1)
112 ma.reconstructDecay(decayString=
'D*+:D0pi_Kpipi0 -> D0:Kpipi0 pi+:my',
113 cut=DStarcutLoose, dmID=2, path=rec_path_1)
114 ma.reconstructDecay(decayString=
'D*+:D0pi_Kpipipi -> D0:Kpipipi pi+:my',
115 cut=DStarcutLoose, dmID=3, path=rec_path_1)
117 BcutLoose =
'[ useCMSFrame(p) < 1.6 ] and [abs(dM) < 0.25]'
118 Bcut =
'[ useCMSFrame(p) < 1.2 ] and [abs(dM) < 0.05]'
121 ma.reconstructDecay(decayString=
'B0:Dstpi_D0pi_Kpi -> D*-:D0pi_Kpi pi+:my',
123 dmID=1, path=rec_path_1)
124 ma.reconstructDecay(decayString=
'B0:Dstpi_D0pi_Kpipi0 -> D*-:D0pi_Kpipi0 pi+:my',
126 dmID=2, path=rec_path_1)
127 ma.reconstructDecay(decayString=
'B0:Dstpi_D0pi_Kpipipi -> D*-:D0pi_Kpipipi pi+:my',
129 dmID=3, path=rec_path_1)
131 vertex.treeFit(
'B0:Dstpi_D0pi_Kpi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
132 vertex.treeFit(
'B0:Dstpi_D0pi_Kpipi0', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
133 vertex.treeFit(
'B0:Dstpi_D0pi_Kpipipi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
140 ma.reconstructDecay(decayString=
'D-:Kpipi -> K+:my pi-:my pi-:my',
141 cut=DcutLoose, dmID=4, path=rec_path_1)
143 vertex.kFit(list_name=
'D-:Kpipi', conf_level=0.0, fit_type=
'mass', path=rec_path_1)
144 ma.applyCuts(
"D-:Kpipi",
'1.844 < M < 1.894', path=rec_path_1)
147 ma.reconstructDecay(decayString=
'B0:Dpi_Kpipi -> D-:Kpipi pi+:my',
148 cut=BcutLoose, dmID=4, path=rec_path_1)
155 ma.reconstructDecay(decayString=
'B-:D0pi_Kpi -> D0:Kpi pi-:my',
157 dmID=5, path=rec_path_1)
158 ma.reconstructDecay(decayString=
'B-:D0pi_Kpipi0 -> D0:Kpipi0 pi-:my',
160 dmID=6, path=rec_path_1)
161 ma.reconstructDecay(decayString=
'B-:D0pi_Kpipipi -> D0:Kpipipi pi-:my',
163 dmID=7, path=rec_path_1)
165 vertex.treeFit(
'B-:D0pi_Kpi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
166 vertex.treeFit(
'B-:D0pi_Kpipi0', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
167 vertex.treeFit(
'B-:D0pi_Kpipipi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
170 outputListName=
'B0:merged',
173 'B0:Dstpi_D0pi_Kpipi0',
174 'B0:Dstpi_D0pi_Kpipipi',
180 outputListName=
'B-:merged',
189 ma.buildRestOfEvent(target_list_name=
'B0:merged', path=rec_path_1)
192 cleanMask = (
'cleanMask',
'nCDCHits > 0 and useCMSFrame(p)<=3.2',
'p >= 0.05 and useCMSFrame(p)<=3.2')
193 ma.appendROEMasks(list_name=
'B0:merged', mask_tuples=[cleanMask], path=rec_path_1)
194 ma.buildContinuumSuppression(list_name=
'B0:merged', roe_mask=
'cleanMask', path=rec_path_1)
197 ma.buildRestOfEvent(target_list_name=
'B-:merged', path=rec_path_1)
200 cleanMask = (
'cleanMask',
'nCDCHits > 0 and useCMSFrame(p)<=3.2',
'p >= 0.05 and useCMSFrame(p)<=3.2')
201 ma.appendROEMasks(list_name=
'B-:merged', mask_tuples=[cleanMask], path=rec_path_1)
202 ma.buildContinuumSuppression(list_name=
'B-:merged', roe_mask=
'cleanMask', path=rec_path_1)
204 ma.applyCuts(
"B0:merged",
"[R2 < 0.3] and " + Bcut, path=rec_path_1)
205 ma.applyCuts(
"B-:merged",
"[R2 < 0.3] and " + Bcut, path=rec_path_1)
210 def get_mumu_path(isCDST, kwargs):
211 """ Selects the ee -> mumu events, function returns corresponding path """
214 rec_path_1 = create_path()
216 rec_path_1.add_module(
"RootInput", branchNames=ALWAYS_SAVE_OBJECTS + RAWDATA_OBJECTS)
217 rd.add_unpackers(rec_path_1)
218 re.add_reconstruction(rec_path_1)
220 minPXDhits = kwargs[
'expert_config'][
'minPXDhits']
221 muSelection =
'[p>1.0]'
222 muSelection +=
' and abs(dz)<2.0 and abs(dr)<0.5'
223 muSelection += f
' and nPXDHits >= {minPXDhits} and nSVDHits >= 8 and nCDCHits >= 20'
225 ma.fillParticleList(
'mu+:BV', muSelection, path=rec_path_1)
226 ma.reconstructDecay(
'Upsilon(4S):BV -> mu+:BV mu-:BV',
'9.5<M<11.5', path=rec_path_1)
227 vertex.treeFit(
'Upsilon(4S):BV', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
232 def get_data_info(inData, kwargs):
233 """ Filter the input data and returns the IOVs """
237 file_to_iov_physics = inData
242 max_files_per_run = 1000000
248 reduced_file_to_iov_physics = filter_by_max_files_per_run(file_to_iov_physics, max_files_per_run)
249 input_files_physics = list(reduced_file_to_iov_physics.keys())
250 B2INFO(f
"Total number of files actually used as input = {len(input_files_physics)}")
254 requested_iov = kwargs.get(
"requested_iov",
None)
256 from caf.utils
import IoV
258 output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
260 return input_files_physics, output_iov
263 def is_cDST_file(fName):
264 """ Check if the file is cDST based on the metadata """
266 metaData = get_file_metadata(fName)
267 description = metaData.getDataDescription()
270 if 'dataLevel' not in description:
271 B2WARNING(
'The cdst/mdst info is not stored in file metadata')
272 return (
'cdst' in os.path.basename(fName))
274 return (description[
'dataLevel'] ==
'cdst')
277 def get_calibrations(input_data, **kwargs):
279 Required function used by b2caf-prompt-run tool.
280 This function return a list of Calibration objects we assign to the CAF process.
283 input_data (dict): Should contain every name from the 'input_data_names' variable as a key.
284 Each value is a dictionary with {"/path/to/file_e1_r5.root": IoV(1,5,1,5), ...}. Useful for
285 assigning to calibration.files_to_iov
287 **kwargs: Configuration options to be sent in. Since this may change we use kwargs as a way to help prevent
288 backwards compatibility problems. But you could use the correct arguments in b2caf-prompt-run for this
289 release explicitly if you want to.
291 Currently only kwargs["output_iov"] is used. This is the output IoV range that your payloads should
292 correspond to. Generally your highest ExpRun payload should be open ended e.g. IoV(3,4,-1,-1)
295 list(caf.framework.Calibration): All of the calibration objects we want to assign to the CAF process
298 from caf.framework
import Calibration
299 from caf.strategies
import SingleIOV
301 from ROOT.Belle2
import InvariantMassAlgorithm
302 from caf.framework
import Collection
304 input_files_Had, output_iov_Had = get_data_info(input_data[
"hadron4S"], kwargs)
305 input_files_MuMu4S, output_iov_MuMu4S = get_data_info(input_data[
"mumu4S"], kwargs)
306 input_files_MuMuOff, output_iov_MuMuOff = get_data_info(input_data[
"mumuOff"], kwargs)
309 isCDST_had = is_cDST_file(input_files_Had[0])
if len(input_files_Had) > 0
else True
310 isCDST_mumu = is_cDST_file((input_files_MuMu4S + input_files_MuMuOff)[0])
312 rec_path_HadB = get_hadB_path(isCDST_had)
313 rec_path_MuMu = get_mumu_path(isCDST_mumu, kwargs)
315 collector_HadB = register_module(
'EcmsCollector')
316 collector_MuMu = register_module(
'BoostVectorCollector', Y4SPListName=
'Upsilon(4S):BV')
318 algorithm_ecms = InvariantMassAlgorithm()
319 algorithm_ecms.setOuterLoss(kwargs[
'expert_config'][
'outerLoss'])
320 algorithm_ecms.setInnerLoss(kwargs[
'expert_config'][
'innerLoss'])
322 algorithm_ecms.includeHadBcalib(kwargs[
'expert_config'][
'runHadB'])
323 algorithm_ecms.setMuMuEcmsSpread(kwargs[
'expert_config'][
'eCMSmumuSpread'])
324 algorithm_ecms.setMuMuEcmsOffset(kwargs[
'expert_config'][
'eCMSmumuShift'])
326 calibration_ecms =
Calibration(
'eCMS', algorithms=algorithm_ecms)
328 collection_HadB =
Collection(collector=collector_HadB,
329 input_files=input_files_Had,
330 pre_collector_path=rec_path_HadB)
331 collection_MuMu4S =
Collection(collector=collector_MuMu,
332 input_files=input_files_MuMu4S,
333 pre_collector_path=rec_path_MuMu)
334 collection_MuMuOff =
Collection(collector=collector_MuMu,
335 input_files=input_files_MuMuOff,
336 pre_collector_path=rec_path_MuMu)
338 calibration_ecms.add_collection(name=
'dimuon_4S', collection=collection_MuMu4S)
339 calibration_ecms.add_collection(name=
'dimuon_Off', collection=collection_MuMuOff)
340 calibration_ecms.add_collection(name=
'hadB_4S', collection=collection_HadB)
342 calibration_ecms.strategies = SingleIOV
346 for algorithm
in calibration_ecms.algorithms:
347 algorithm.params = {
"iov_coverage": output_iov_Had}
353 return [calibration_ecms]
def stdK(listtype=_defaultlist, path=None, writeOut=True)
def stdPi(listtype=_defaultlist, path=None, writeOut=True)
def stdPi0s(listtype="eff60_May2020", path=None, beamBackgroundMVAWeight="", fakePhotonMVAWeight="", biasCorrectionTable="")
def kFit(list_name, conf_level, fit_type='vertex', constraint='', daughtersUpdate=False, decay_string='', massConstraint=[], recoilMass=0, smearing=0, path=None)
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], originDimension=3, treatAsInvisible='', ignoreFromVertexFit='', path=None)