10Airflow script to perform eCMS calibration (combination of the had-B and mumu method).
13from prompt
import CalibrationSettings, INPUT_DATA_FILTERS
14from prompt.calibrations.caf_boostvector
import settings
as boostvector
16from basf2
import create_path, register_module, get_file_metadata, B2INFO, B2WARNING
17from reconstruction
import prepare_cdst_analysis
18import modularAnalysis
as ma
26settings = CalibrationSettings(
27 name=
"Ecms Calibrations",
28 expert_username=
"zlebcr",
30 input_data_formats=[
"cdst"],
31 input_data_names=[
"hadron4S",
"mumu4S",
"mumuOff"],
34 INPUT_DATA_FILTERS[
"Data Tag"][
"btocharm_calib"],
35 INPUT_DATA_FILTERS[
"Run Type"][
"physics"],
36 INPUT_DATA_FILTERS[
"Beam Energy"][
"4S"],
37 INPUT_DATA_FILTERS[
"Data Quality Tag"][
"Good Or Recoverable"],
38 INPUT_DATA_FILTERS[
"Magnet"][
"On"]],
40 INPUT_DATA_FILTERS[
"Data Tag"][
"mumu_tight_or_highm_calib"],
41 INPUT_DATA_FILTERS[
"Run Type"][
"physics"],
42 INPUT_DATA_FILTERS[
"Beam Energy"][
"4S"],
43 INPUT_DATA_FILTERS[
"Data Quality Tag"][
"Good Or Recoverable"],
44 INPUT_DATA_FILTERS[
"Magnet"][
"On"]],
46 INPUT_DATA_FILTERS[
"Data Tag"][
"mumu_tight_or_highm_calib"],
47 INPUT_DATA_FILTERS[
"Run Type"][
"physics"],
48 INPUT_DATA_FILTERS[
"Beam Energy"][
"Continuum"],
49 INPUT_DATA_FILTERS[
'Beam Energy'][
'Scan'],
50 INPUT_DATA_FILTERS[
"Data Quality Tag"][
"Good Or Recoverable"],
51 INPUT_DATA_FILTERS[
"Magnet"][
"On"]]
54 "outerLoss":
"pow(0.000010e0*rawTime, 2) + 1./nEv",
55 "innerLoss":
"pow(0.000120e0*rawTime, 2) + 1./nEv",
57 "eCMSmumuSpread": 5.2e-3,
58 "eCMSmumuShift": 10e-3,
60 depends_on=[boostvector])
65def get_hadB_path(isCDST):
66 """ Selects the hadronic B decays, function returns corresponding path """
69 rec_path_1 = create_path()
71 prepare_cdst_analysis(path=rec_path_1, components=[
'SVD',
'CDC',
'ECL',
'KLM'])
77 ma.cutAndCopyList(
"pi+:my",
"pi+:loose",
"[abs(dz)<2.0] and [abs(dr)<0.5]", path=rec_path_1)
78 ma.cutAndCopyList(
"K+:my",
"K+:good",
"[abs(dz)<2.0] and [abs(dr)<0.5]", path=rec_path_1)
80 ma.cutAndCopyList(
"pi0:my",
"pi0:eff40_May2020",
"", path=rec_path_1)
86 DcutLoose =
'1.7 < M < 2.1'
87 Dcut =
'1.830 < M < 1.894'
89 ma.reconstructDecay(decayString=
'D0:Kpi -> K-:my pi+:my', cut=DcutLoose, dmID=1, path=rec_path_1)
90 ma.reconstructDecay(decayString=
'D0:Kpipi0 -> K-:my pi+:my pi0:my',
91 cut=DcutLoose, dmID=2, path=rec_path_1)
92 ma.reconstructDecay(decayString=
'D0:Kpipipi -> K-:my pi+:my pi-:my pi+:my',
93 cut=DcutLoose, dmID=3, path=rec_path_1)
96 vertex.kFit(list_name=
'D0:Kpi', conf_level=0.0, fit_type=
'mass', path=rec_path_1)
98 vertex.kFit(list_name=
'D0:Kpipipi', conf_level=0.0, fit_type=
'mass', path=rec_path_1)
100 ma.applyCuts(
"D0:Kpi", Dcut, path=rec_path_1)
101 ma.applyCuts(
"D0:Kpipi0", Dcut, path=rec_path_1)
102 ma.applyCuts(
"D0:Kpipipi", Dcut, path=rec_path_1)
104 DStarcutLoose =
'massDifference(0) < 0.16'
107 ma.reconstructDecay(decayString=
'D*+:D0pi_Kpi -> D0:Kpi pi+:my', cut=DStarcutLoose, dmID=1, path=rec_path_1)
108 ma.reconstructDecay(decayString=
'D*+:D0pi_Kpipi0 -> D0:Kpipi0 pi+:my',
109 cut=DStarcutLoose, dmID=2, path=rec_path_1)
110 ma.reconstructDecay(decayString=
'D*+:D0pi_Kpipipi -> D0:Kpipipi pi+:my',
111 cut=DStarcutLoose, dmID=3, path=rec_path_1)
113 BcutLoose =
'[ useCMSFrame(p) < 1.6 ] and [abs(dM) < 0.25]'
114 Bcut =
'[ useCMSFrame(p) < 1.2 ] and [abs(dM) < 0.05]'
117 ma.reconstructDecay(decayString=
'B0:Dstpi_D0pi_Kpi -> D*-:D0pi_Kpi pi+:my',
119 dmID=1, path=rec_path_1)
120 ma.reconstructDecay(decayString=
'B0:Dstpi_D0pi_Kpipi0 -> D*-:D0pi_Kpipi0 pi+:my',
122 dmID=2, path=rec_path_1)
123 ma.reconstructDecay(decayString=
'B0:Dstpi_D0pi_Kpipipi -> D*-:D0pi_Kpipipi pi+:my',
125 dmID=3, path=rec_path_1)
127 vertex.treeFit(
'B0:Dstpi_D0pi_Kpi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
128 vertex.treeFit(
'B0:Dstpi_D0pi_Kpipi0', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
129 vertex.treeFit(
'B0:Dstpi_D0pi_Kpipipi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
136 ma.reconstructDecay(decayString=
'D-:Kpipi -> K+:my pi-:my pi-:my',
137 cut=DcutLoose, dmID=4, path=rec_path_1)
139 vertex.kFit(list_name=
'D-:Kpipi', conf_level=0.0, fit_type=
'mass', path=rec_path_1)
140 ma.applyCuts(
"D-:Kpipi",
'1.844 < M < 1.894', path=rec_path_1)
143 ma.reconstructDecay(decayString=
'B0:Dpi_Kpipi -> D-:Kpipi pi+:my',
144 cut=BcutLoose, dmID=4, path=rec_path_1)
151 ma.reconstructDecay(decayString=
'B-:D0pi_Kpi -> D0:Kpi pi-:my',
153 dmID=5, path=rec_path_1)
154 ma.reconstructDecay(decayString=
'B-:D0pi_Kpipi0 -> D0:Kpipi0 pi-:my',
156 dmID=6, path=rec_path_1)
157 ma.reconstructDecay(decayString=
'B-:D0pi_Kpipipi -> D0:Kpipipi pi-:my',
159 dmID=7, path=rec_path_1)
161 vertex.treeFit(
'B-:D0pi_Kpi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
162 vertex.treeFit(
'B-:D0pi_Kpipi0', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
163 vertex.treeFit(
'B-:D0pi_Kpipipi', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
166 outputListName=
'B0:merged',
169 'B0:Dstpi_D0pi_Kpipi0',
170 'B0:Dstpi_D0pi_Kpipipi',
176 outputListName=
'B-:merged',
185 ma.buildRestOfEvent(target_list_name=
'B0:merged', path=rec_path_1)
188 cleanMask = (
'cleanMask',
'nCDCHits > 0 and useCMSFrame(p)<=3.2',
'p >= 0.05 and useCMSFrame(p)<=3.2')
189 ma.appendROEMasks(list_name=
'B0:merged', mask_tuples=[cleanMask], path=rec_path_1)
190 ma.buildContinuumSuppression(list_name=
'B0:merged', roe_mask=
'cleanMask', path=rec_path_1)
193 ma.buildRestOfEvent(target_list_name=
'B-:merged', path=rec_path_1)
196 cleanMask = (
'cleanMask',
'nCDCHits > 0 and useCMSFrame(p)<=3.2',
'p >= 0.05 and useCMSFrame(p)<=3.2')
197 ma.appendROEMasks(list_name=
'B-:merged', mask_tuples=[cleanMask], path=rec_path_1)
198 ma.buildContinuumSuppression(list_name=
'B-:merged', roe_mask=
'cleanMask', path=rec_path_1)
200 ma.applyCuts(
"B0:merged",
"[R2 < 0.3] and " + Bcut, path=rec_path_1)
201 ma.applyCuts(
"B-:merged",
"[R2 < 0.3] and " + Bcut, path=rec_path_1)
206def get_mumu_path(isCDST, kwargs):
207 """ Selects the ee -> mumu events, function returns corresponding path """
210 rec_path_1 = create_path()
212 prepare_cdst_analysis(path=rec_path_1, components=[
'SVD',
'CDC',
'ECL',
'KLM'])
214 minPXDhits = kwargs[
'expert_config'][
'minPXDhits']
215 muSelection =
'[p>1.0]'
216 muSelection +=
' and abs(dz)<2.0 and abs(dr)<0.5'
217 muSelection += f
' and nPXDHits >= {minPXDhits} and nSVDHits >= 8 and nCDCHits >= 20'
219 ma.fillParticleList(
'mu+:BV', muSelection, path=rec_path_1)
220 ma.reconstructDecay(
'Upsilon(4S):BV -> mu+:BV mu-:BV',
'9.5<M<11.5', path=rec_path_1)
221 vertex.treeFit(
'Upsilon(4S):BV', updateAllDaughters=
True, ipConstraint=
True, path=rec_path_1)
226def get_data_info(inData, kwargs):
227 """ Filter the input data and returns the IOVs """
231 file_to_iov_physics = inData
236 max_files_per_run = 1000000
242 reduced_file_to_iov_physics = filter_by_max_files_per_run(file_to_iov_physics, max_files_per_run)
243 input_files_physics = list(reduced_file_to_iov_physics.keys())
244 B2INFO(f
"Total number of files actually used as input = {len(input_files_physics)}")
248 requested_iov = kwargs.get(
"requested_iov",
None)
250 from caf.utils
import IoV
252 output_iov = IoV(requested_iov.exp_low, requested_iov.run_low, -1, -1)
254 return input_files_physics, output_iov
257def is_cDST_file(fName):
258 """ Check if the file is cDST based on the metadata """
260 metaData = get_file_metadata(fName)
261 description = metaData.getDataDescription()
264 if 'dataLevel' not in description:
265 B2WARNING(
'The cdst/mdst info is not stored in file metadata')
266 return (
'cdst' in os.path.basename(fName))
268 return (description[
'dataLevel'] ==
'cdst')
271def get_calibrations(input_data, **kwargs):
273 Required function used by b2caf-prompt-run tool.
274 This function return a list of Calibration objects we assign to the CAF process.
277 input_data (dict): Should contain every name
from the
'input_data_names' variable
as a key.
278 Each value
is a dictionary
with {
"/path/to/file_e1_r5.root": IoV(1,5,1,5), ...}. Useful
for
279 assigning to calibration.files_to_iov
281 **kwargs: Configuration options to be sent
in. Since this may change we use kwargs
as a way to help prevent
282 backwards compatibility problems. But you could use the correct arguments
in b2caf-prompt-run
for this
283 release explicitly
if you want to.
285 Currently only kwargs[
"output_iov"]
is used. This
is the output IoV range that your payloads should
286 correspond to. Generally your highest ExpRun payload should be open ended e.g. IoV(3,4,-1,-1)
289 list(caf.framework.Calibration): All of the calibration objects we want to assign to the CAF process
292 from caf.framework
import Calibration
293 from caf.strategies
import SingleIOV
295 from ROOT
import Belle2
296 from ROOT.Belle2
import InvariantMassAlgorithm
297 from caf.framework
import Collection
299 input_files_Had, output_iov_Had = get_data_info(input_data[
"hadron4S"], kwargs)
300 input_files_MuMu4S, output_iov_MuMu4S = get_data_info(input_data[
"mumu4S"], kwargs)
301 input_files_MuMuOff, output_iov_MuMuOff = get_data_info(input_data[
"mumuOff"], kwargs)
304 isCDST_had = is_cDST_file(input_files_Had[0])
if len(input_files_Had) > 0
else True
305 isCDST_mumu = is_cDST_file((input_files_MuMu4S + input_files_MuMuOff)[0])
307 rec_path_HadB = get_hadB_path(isCDST_had)
308 rec_path_MuMu = get_mumu_path(isCDST_mumu, kwargs)
310 collector_HadB = register_module(
'EcmsCollector')
311 collector_MuMu = register_module(
'BoostVectorCollector', Y4SPListName=
'Upsilon(4S):BV')
313 algorithm_ecms = InvariantMassAlgorithm()
314 algorithm_ecms.setOuterLoss(kwargs[
'expert_config'][
'outerLoss'])
315 algorithm_ecms.setInnerLoss(kwargs[
'expert_config'][
'innerLoss'])
317 algorithm_ecms.includeHadBcalib(kwargs[
'expert_config'][
'runHadB'])
318 algorithm_ecms.setMuMuEcmsSpread(kwargs[
'expert_config'][
'eCMSmumuSpread'])
319 algorithm_ecms.setMuMuEcmsOffset(kwargs[
'expert_config'][
'eCMSmumuShift'])
321 calibration_ecms =
Calibration(
'eCMS', algorithms=algorithm_ecms)
323 collection_HadB =
Collection(collector=collector_HadB,
324 input_files=input_files_Had,
325 pre_collector_path=rec_path_HadB)
326 collection_MuMu4S =
Collection(collector=collector_MuMu,
327 input_files=input_files_MuMu4S,
328 pre_collector_path=rec_path_MuMu)
329 collection_MuMuOff =
Collection(collector=collector_MuMu,
330 input_files=input_files_MuMuOff,
331 pre_collector_path=rec_path_MuMu)
333 calibration_ecms.add_collection(name=
'dimuon_4S', collection=collection_MuMu4S)
334 calibration_ecms.add_collection(name=
'dimuon_Off', collection=collection_MuMuOff)
335 calibration_ecms.add_collection(name=
'hadB_4S', collection=collection_HadB)
337 calibration_ecms.strategies = SingleIOV
341 for algorithm
in calibration_ecms.algorithms:
342 algorithm.params = {
"iov_coverage": output_iov_Had}
348 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, massConstraintDecayString='', massConstraintMassValues=[], 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)