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
17import reconstruction
as re
19from basf2
import create_path, register_module, get_file_metadata, B2INFO, B2WARNING
20import modularAnalysis
as ma
28settings = 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])
67def 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)
210def 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)
232def 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
263def 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')
277def 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
import Belle2
302 from ROOT.Belle2
import InvariantMassAlgorithm
303 from caf.framework
import Collection
305 input_files_Had, output_iov_Had = get_data_info(input_data[
"hadron4S"], kwargs)
306 input_files_MuMu4S, output_iov_MuMu4S = get_data_info(input_data[
"mumu4S"], kwargs)
307 input_files_MuMuOff, output_iov_MuMuOff = get_data_info(input_data[
"mumuOff"], kwargs)
310 isCDST_had = is_cDST_file(input_files_Had[0])
if len(input_files_Had) > 0
else True
311 isCDST_mumu = is_cDST_file((input_files_MuMu4S + input_files_MuMuOff)[0])
313 rec_path_HadB = get_hadB_path(isCDST_had)
314 rec_path_MuMu = get_mumu_path(isCDST_mumu, kwargs)
316 collector_HadB = register_module(
'EcmsCollector')
317 collector_MuMu = register_module(
'BoostVectorCollector', Y4SPListName=
'Upsilon(4S):BV')
319 algorithm_ecms = InvariantMassAlgorithm()
320 algorithm_ecms.setOuterLoss(kwargs[
'expert_config'][
'outerLoss'])
321 algorithm_ecms.setInnerLoss(kwargs[
'expert_config'][
'innerLoss'])
323 algorithm_ecms.includeHadBcalib(kwargs[
'expert_config'][
'runHadB'])
324 algorithm_ecms.setMuMuEcmsSpread(kwargs[
'expert_config'][
'eCMSmumuSpread'])
325 algorithm_ecms.setMuMuEcmsOffset(kwargs[
'expert_config'][
'eCMSmumuShift'])
327 calibration_ecms =
Calibration(
'eCMS', algorithms=algorithm_ecms)
329 collection_HadB =
Collection(collector=collector_HadB,
330 input_files=input_files_Had,
331 pre_collector_path=rec_path_HadB)
332 collection_MuMu4S =
Collection(collector=collector_MuMu,
333 input_files=input_files_MuMu4S,
334 pre_collector_path=rec_path_MuMu)
335 collection_MuMuOff =
Collection(collector=collector_MuMu,
336 input_files=input_files_MuMuOff,
337 pre_collector_path=rec_path_MuMu)
339 calibration_ecms.add_collection(name=
'dimuon_4S', collection=collection_MuMu4S)
340 calibration_ecms.add_collection(name=
'dimuon_Off', collection=collection_MuMuOff)
341 calibration_ecms.add_collection(name=
'hadB_4S', collection=collection_HadB)
343 calibration_ecms.strategies = SingleIOV
347 for algorithm
in calibration_ecms.algorithms:
348 algorithm.params = {
"iov_coverage": output_iov_Had}
354 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)