Belle II Software  release-06-01-15
systematics.py
1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*-
3 
4 
11 
12 """ Skim list building functions for systematics studies """
13 
14 __authors__ = [
15  "Sam Cunliffe",
16  "Torben Ferber",
17  "Ilya Komarov",
18  "Yuji Kato"
19 ]
20 
21 import basf2 as b2
22 import modularAnalysis as ma
23 import vertex
24 from skim import BaseSkim, CombinedSkim, fancy_skim_header
25 from stdCharged import stdE, stdK, stdMu, stdPi, stdPr
26 from stdPhotons import stdPhotons
27 from stdPi0s import stdPi0s
28 from stdV0s import stdKshorts, stdLambdas
29 from variables import variables as vm
30 
31 # TODO: Add liaison name and email address
32 __liaison__ = ""
33 __liaison_leptonID__ = "Marcel Hohmann"
34 _VALIDATION_SAMPLE = "mdst14.root"
35 
36 
37 @fancy_skim_header
39  """
40  Primarily used for hadron and lepton ID studies.
41  Lists in this skim are those defined in `PiKFromDstarList`.
42  """
43  __authors__ = ["Sam Cunliffe", "Torben Ferber", "Ilya Komarov", "Yuji Kato", "Racha Cheaib"]
44  __description__ = ""
45  __contact__ = __liaison__
46  __category__ = "systematics"
47 
48  def load_standard_lists(self, path):
49  stdK("all", path=path)
50  stdPi("all", path=path)
51 
52  TestSampleProcess = "ccbar"
53 
54  def build_lists(self, path):
55  return self.PiKFromDstarListPiKFromDstarList(path)
56 
57  def PiKFromDstarList(self, path):
58  """Build PiKFromDstarList lists for systematics skims."""
59  D0Cuts = "1.75 < M < 2.0"
60  DstarCuts = "massDifference(0)<0.16 and useCMSFrame(p) > 1.5"
61 
62  ma.cutAndCopyList("K-:syst", "K-:all", "dr<2 and abs(dz)<4", path=path)
63  ma.cutAndCopyList("pi+:syst", "pi+:all", "dr<2 and abs(dz)<4", path=path)
64 
65  D0Channel = ["K-:syst pi+:syst"]
66 
67  D0List = []
68  for chID, channel in enumerate(D0Channel):
69  ma.reconstructDecay(f"D0:syst{chID} -> {channel}", D0Cuts, chID, path=path)
70  D0List.append(f"D0:syst{chID}")
71 
72  DstarChannel = []
73  for channel in D0List:
74  DstarChannel.append(f"{channel} pi+:syst")
75 
76  DstarList = []
77  for chID, channel in enumerate(DstarChannel):
78  ma.reconstructDecay(f"D*+:syst{chID} -> {channel}", DstarCuts, chID, path=path)
79  DstarList.append(f"D*+:syst{chID}")
80 
81  return DstarList
82 
83 
84 @fancy_skim_header
86  """
87  Lists in this skim are those defined in `BtoDStarPiList` and `DstarToD0PiPartList`.
88  """
89  __authors__ = ["Sam Cunliffe", "Torben Ferber", "Ilya Komarov", "Yuji Kato"]
90  __description__ = ""
91  __contact__ = __liaison__
92  __category__ = "systematics"
93 
94  def load_standard_lists(self, path):
95  stdK("loose", path=path)
96  stdPi("loose", path=path)
97  stdPi0s("eff40_May2020", path=path, loadPhotonBeamBackgroundMVA=False)
98 
99  def build_lists(self, path):
100  return self.BtoDStarPiListBtoDStarPiList(path) + self.DstarToD0PiPartListDstarToD0PiPartList(path)
101 
102  def BtoDStarPiList(self, path):
103  """Build BtoDStarPiList lists for systematics skims."""
104  D0Cuts = "1.835 < M < 1.895"
105  DstarCuts = "massDifference(0)<0.16"
106  B0Cuts = "Mbc > 5.2 and abs(deltaE) < 0.3"
107 
108  # D0
109  D0Channel = ["K+:loose pi-:loose", "K+:loose pi-:loose pi-:loose pi+:loose", "K+:loose pi-:loose pi0:eff40_May2020"]
110 
111  D0List = []
112  for chID, channel in enumerate(D0Channel):
113  resonanceName = "anti-D0:loose" + str(chID)
114  ma.reconstructDecay(resonanceName + " -> " + channel, D0Cuts, chID, path=path)
115  # vertex.raveFit(resonanceName, 0.0, path=path)
116  ma.copyLists("anti-D0:loose", ["anti-D0:loose0", "anti-D0:loose1", "anti-D0:loose2"], path=path)
117  D0List.append("anti-D0:loose")
118 
119  # Dstar
120  DstarChannel = []
121  for channel in D0List:
122  DstarChannel.append(channel + " pi-:loose")
123 
124  DstarList = []
125  for chID, channel in enumerate(DstarChannel):
126  resonanceName = "D*-:loose" + str(chID)
127  ma.reconstructDecay(resonanceName + " -> " + channel, DstarCuts, chID, path=path)
128  # vertex.raveFit(resonanceName, 0.0)
129  DstarList.append(resonanceName)
130 
131  # B0
132  B0Channel = []
133  for channel in DstarList:
134  B0Channel.append(channel + " pi+:loose")
135 
136  B0List = []
137  for chID, channel in enumerate(B0Channel):
138  resonanceName = "B0:sys" + str(chID)
139  ma.reconstructDecay(resonanceName + " -> " + channel, B0Cuts, chID, path=path)
140  B0List.append(resonanceName)
141  # vertex.raveFit(resonanceName, 0.0)
142 
143  return B0List
144 
145  def DstarToD0PiPartList(self, path):
146  """Build DstarToD0PiPartList lists for systematics skims."""
147  ma.fillParticleList("pi+:fromks", "chiProb > 0.001 and pionID > 0.1 and d0 > 0.1", path=path)
148 
149  # D-
150  DminusCuts = "1.0 < M < 1.75"
151  DminusChannel = ["pi-:fromks pi+:loose pi-:loose"]
152 
153  for chID, channel in enumerate(DminusChannel):
154  resonanceName = "D-:loose" + str(chID)
155  ma.reconstructDecay(resonanceName + " -> " + channel, DminusCuts, chID, path=path)
156 
157  # Dstar
158  DstarCuts = "massDifference(0)<0.2 and useCMSFrame(p) > 2.0"
159  DstarChannel = []
160  DstarChannel.append("D-:loose0" + " pi+:loose")
161 
162  DstarList = []
163  for chID, channel in enumerate(DstarChannel):
164  resonanceName = "D*0:loose" + str(chID)
165  ma.reconstructDecay(resonanceName + " -> " + channel, DstarCuts, chID, path=path)
166  DstarList.append(resonanceName)
167 
168  return DstarList
169 
170 
171 @fancy_skim_header
173  """
174  Lists in this skim are those defined in `getDsList`, `getDstarList`,
175  `getSigmacList`, `getmumugList`, `getBZeroList`, and `getBPlusList`.
176  """
177  __authors__ = ["Sam Cunliffe", "Torben Ferber", "Ilya Komarov", "Yuji Kato"]
178  __description__ = ""
179  __contact__ = __liaison__
180  __category__ = "systematics"
181 
182  def load_standard_lists(self, path):
183  stdK("loose", path=path)
184  stdMu("loose", path=path)
185  stdPi("loose", path=path)
186  stdPr("loose", path=path)
187  stdPi0s("eff40_May2020Fit", path=path, loadPhotonBeamBackgroundMVA=False)
188 
189  def build_lists(self, path):
190  return (
191  self.getDsListgetDsList(path)
192  + self.getDstarListgetDstarList(path)
193  + self.getSigmacListgetSigmacList(path)
194  + self.getmumugListgetmumugList(path)
195  + self.getBZeroListgetBZeroList(path)
196  + self.getBPlusListgetBPlusList(path)
197  )
198 
199  def getDsList(self, path):
200  """Build Ds list for systematics skims."""
201  DsCuts = "1.90 < M < 2.04"
202 
203  ma.reconstructDecay("phi:res -> K+:loose K-:loose", "1.01 < M < 1.03", path=path)
204  ma.reconstructDecay("K*0:res -> K+:loose pi-:loose", "0.7 < M < 1.1", path=path)
205 
206  DsChannel = ["phi:res pi+:loose"]
207  DsList = []
208  for chID, channel in enumerate(DsChannel):
209  particlename = "D_s+:Resonance%d" % (chID)
210  ma.reconstructDecay(particlename + " -> " + channel, DsCuts, chID, path=path)
211  DsList.append(particlename)
212 
213  return DsList
214 
215  def getDstarList(self, path):
216  """Build Dstar list for systematics skims."""
217  DplusCuts = "1.8 < M < 1.93"
218  DstarCuts = "massDifference(0)<0.16 and useCMSFrame(p)>2.0"
219 
220  DplusChannel = ["K-:loose pi+:loose pi+:loose"]
221 
222  DplusList = []
223  for chID, channel in enumerate(DplusChannel):
224  ma.reconstructDecay("D+:resonance" + str(chID) + " -> " + channel, DplusCuts, chID, path=path)
225  vertex.raveFit("D+:resonance" + str(chID), 0.0, path=path)
226  DplusList.append("D+:resonance" + str(chID))
227 
228  DstarChannel = []
229  for channel in DplusList:
230  DstarChannel.append(channel + " pi0:eff40_May2020")
231 
232  DstarList = []
233  for chID, channel in enumerate(DstarChannel):
234  ma.reconstructDecay("D*+:resonance" + str(chID) + " -> " + channel, DstarCuts, chID, path=path)
235  DstarList.append("D*+:resonance" + str(chID))
236 
237  return DstarList
238 
239  def getSigmacList(self, path):
240  """Build Sigmac list for systematics skims."""
241  LambdacCuts = "2.24 < M < 2.33"
242  SigmacCuts = "massDifference(0)<0.28 and useCMSFrame(p) > 2.5"
243 
244  LambdacChannel = ["p+:loose K-:loose pi+:loose"]
245  LambdacList = []
246  for chID, channel in enumerate(LambdacChannel):
247  ma.reconstructDecay("Lambda_c+:resonance" + str(chID) + " -> " + channel, LambdacCuts, chID, path=path)
248  vertex.raveFit("Lambda_c+:resonance" + str(chID), 0.0, path=path)
249  LambdacList.append("Lambda_c+:resonance" + str(chID))
250 
251  SigmacList = []
252  SigmacPlusChannel = []
253  # Sigma_c++
254  for channel in LambdacList:
255  SigmacPlusChannel.append(channel + " pi+:loose")
256 
257  for chID, channel in enumerate(SigmacPlusChannel):
258  ma.reconstructDecay("Sigma_c++:resonance" + str(chID) + " -> " + channel, SigmacCuts, chID, path=path)
259  SigmacList.append("Sigma_c++:resonance" + str(chID))
260 
261  # Sigma_c0
262  Sigmac0Channel = []
263  for channel in LambdacList:
264  Sigmac0Channel.append(channel + " pi-:loose")
265 
266  Sigmac0List = []
267  for chID, channel in enumerate(Sigmac0Channel):
268  ma.reconstructDecay("Sigma_c0:resonance" + str(chID) + " -> " + channel, SigmacCuts, chID, path=path)
269  Sigmac0List.append("Sigma_c0:resonance" + str(chID))
270 
271  return SigmacList
272 
273  def getmumugList(self, path):
274  """Build mumug list for systematics skims."""
275  vphoChannel = ["mu+:loose mu-:loose"]
276  vphocuts = ""
277  vphoList = []
278  for chID, channel in enumerate(vphoChannel):
279  resonanceName = "vpho:resonance" + str(chID)
280  ma.reconstructDecay("vpho:resonance" + str(chID) + " -> " + channel, vphocuts, chID, path=path)
281  ma.applyCuts(resonanceName, "nTracks == 2 and M < formula(Ecms*0.9877)", path=path)
282  vertex.raveFit(resonanceName, 0.0, path=path)
283  ma.applyCuts(resonanceName, "M < formula(Ecms*0.9877)", path=path)
284  vphoList.append(resonanceName)
285 
286  return vphoList
287 
288  def getBZeroList(self, path):
289  """Build BZero list for systematics skims."""
290  BZeroCuts = "Mbc > 5.2 and abs(deltaE) < 0.3"
291  BZeroChannel = ["D-:resonance0 pi+:loose"]
292  BZeroList = []
293 
294  for chID, channel in enumerate(BZeroChannel):
295  resonanceName = "B0:resonance" + str(chID)
296  ma.reconstructDecay(resonanceName + " -> " + channel, BZeroCuts, chID, path=path)
297  BZeroList.append(resonanceName)
298 
299  return BZeroList
300 
301  def getBPlusList(self, path):
302  """Build Bplus list for systematics skims."""
303  antiDZeroCut = "1.82 < M < 1.90"
304  antiDZeroChannel = ["K+:loose pi-:loose"]
305  antiDZeroList = []
306 
307  for chID, channel in enumerate(antiDZeroChannel):
308  resonanceName = "anti-D0:resonance" + str(chID)
309  ma.reconstructDecay(resonanceName + " -> " + channel, antiDZeroCut, chID, path=path)
310  vertex.raveFit(resonanceName, 0.0, path=path)
311  antiDZeroList.append(resonanceName)
312 
313  BPlusChannel = []
314  for channel in antiDZeroList:
315  BPlusChannel.append(channel + " pi+:loose")
316 
317  BPlusCuts = "Mbc > 5.2 and abs(deltaE) < 0.3"
318  BPlusList = []
319  for chID, channel in enumerate(BPlusChannel):
320  ma.reconstructDecay("B+:resonance" + str(chID) + " -> " + channel, BPlusCuts, chID, path=path)
321  BPlusList.append("B+:resonance" + str(chID))
322 
323  return BPlusList
324 
325 
326 @fancy_skim_header
328  """
329  We require one cluster-matched electron (the other is not required to match a
330  cluster). No selection on the photon as the sample must be unbiased.
331  """
332  __authors__ = ["Torben Ferber"]
333  __description__ = (
334  "Skim of radiative muon pairs (:math:`ee\\to\\mu\\mu(\\gamma)`) "
335  "for photon systematics."
336  )
337  __contact__ = __liaison__
338  __category__ = "systematics, photon calibration"
339 
340  def load_standard_lists(self, path):
341  stdMu("all", path=path)
342 
343  def build_lists(self, path):
344  # the tight selection starts with all muons, but they must be cluster-matched and not be an electron
345  MuonTightSelection = ("abs(dz) < 2.0 and abs(dr) < 0.5 and nCDCHits > 0 and "
346  "clusterE > 0.0 and clusterE < 1.0")
347  ma.cutAndCopyList("mu+:skimtight", "mu+:all", MuonTightSelection, path=path)
348 
349  # for the loose selection starts with all muons, but we accept tracks that
350  # are not matched to a cluster, but if they are, they must not be an
351  # electron
352  MuonLooseSelection = "abs(dz) < 2.0 and abs(dr) < 0.5 and nCDCHits > 0 and clusterE < 1.0"
353  ma.cutAndCopyList("mu+:skimloose", "mu+:all", MuonLooseSelection, path=path)
354 
355  # create a list of possible selections
356  radmumulist = []
357 
358  # selection ID0:
359  # the radiative muon pair must be selected without looking at the photon.
360  # exclude events with more than two good tracks
361  RadMuMuSelection = "pRecoil > 0.075 and pRecoilTheta > 0.296706 and pRecoilTheta < 2.61799"
362  RadMuMuPairChannel = "mu+:skimtight mu-:skimloose"
363  chID = 0
364  ma.reconstructDecay("vpho:radmumu" + str(chID) + " -> " + RadMuMuPairChannel,
365  RadMuMuSelection, chID, path=path)
366  eventCuts = "nCleanedTracks(abs(dz) < 2.0 and abs(dr) < 0.5) == 2"
367  ma.applyCuts("vpho:radmumu" + str(chID), eventCuts, path=path)
368  radmumulist.append("vpho:radmumu" + str(chID))
369 
370  # selection Id1:
371  # todo: include pair conversions?
372 
373  return radmumulist
374 
375 
376 @fancy_skim_header
378  __authors__ = ["Ilya Komarov"]
379  __description__ = "Systematics skim of :math:`ee\\to ee\\ell\\ell`"
380  __contact__ = __liaison__
381  __category__ = "systematics, lepton ID"
382 
383  def load_standard_lists(self, path):
384  stdE("all", path=path)
385 
386  def build_lists(self, path):
387  # At skim level we avoid any PID-like requirements and just select events
388  # with two good tracks coming from the interavtion region.
389  eLooseSelection = "abs(dz) < 2.0 and abs(dr) < 0.5 and p > 0.3"
390  ma.cutAndCopyList("e+:skimloose", "e+:all", eLooseSelection, path=path)
391 
392  # create a list of possible selections
393  eelllist = []
394 
395  # Lepon pair tracks are back-to-back-like
396  EELLSelection = "useCMSFrame(pt)<0.3"
397  eventCuts = "nCleanedTracks(abs(dz) < 2.0 and abs(dr) < 0.5) < 4"
398  ma.reconstructDecay("gamma:eell -> e+:skimloose e-:skimloose",
399  EELLSelection + " and " + eventCuts, path=path)
400  eelllist.append("gamma:eell")
401 
402  return eelllist
403 
404 
405 @fancy_skim_header
407  """
408  Constructed skim list contains radiative electron pairs for photon systematics. In
409  particular this is for the endcaps where we have no track triggers, we require one
410  cluster-matched electron (the other is not required to match a cluster). No
411  selection on the photon as the sample must be unbiased.
412 
413  As this retains a lot of bhabha events (by construction) we allow for prescaling
414  (and prefer prescaled rather than a biased sampe by requiring any selection on the
415  photon or too much of a cut on the recoil momentum).
416 
417  Prescales are given in standard trigger terms (reciprocal), so prescale of 100 is 1%
418  of events kept, *etc*.
419  """
420 
421  __authors__ = ["Sam Cunliffe"]
422  __description__ = "Radiative electron pairs for photon systematics"
423  __contact__ = __liaison__
424  __category__ = "systematics, photon calibration"
425 
426  def load_standard_lists(self, path):
427  stdE("all", path=path)
428 
429  def __init__(self, prescale_all=1, prescale_fwd_electron=1, **kwargs):
430  """
431  Parameters:
432  prescale_all (int): the global prescale for this skim
433  prescale_fwd_electron (int): the prescale electrons (e-) in
434  the forward endcap
435  **kwargs: Passed to constructor of `BaseSkim`.
436  """
437  # Redefine __init__ to allow for additional optional arguments
438  super().__init__(**kwargs)
439  self.prescale_allprescale_all = prescale_all
440  self.prescale_fwd_electronprescale_fwd_electron = prescale_fwd_electron
441 
442  def build_lists(self, path):
443  # convert prescales from trigger convention
444  prescale_all = str(float(1.0 / self.prescale_allprescale_all))
445  prescale_fwd_electron = str(float(1.0 / self.prescale_fwd_electronprescale_fwd_electron))
446 
447  # require a pair of good electrons one of which must be cluster-matched
448  # with 3 GeV of energy
449  goodtrack = "abs(dz) < 2.0 and abs(dr) < 0.5 and nCDCHits > 0"
450  goodtrackwithcluster = "%s and clusterE > 3.0" % goodtrack
451  ma.cutAndCopyList("e+:skimtight", "e+:all", goodtrackwithcluster, path=path)
452  ma.cutAndCopyList("e+:skimloose", "e+:all", goodtrack, path=path)
453 
454  # a minimum momentum of 75 MeV/c recoiling against the pair,
455  # and require that the recoil is within the CDC acceptance
456  recoil = "pRecoil > 0.075 and 0.296706 < pRecoilTheta < 2.61799" # GeV/c, rad
457  ma.reconstructDecay("vpho:radee -> e+:skimtight e-:skimloose", recoil, path=path)
458 
459  # apply event cuts (exactly two clean tracks in the event, and prescale
460  # the whole event regardless of where the electron went)
461  event_cuts = "[nCleanedTracks(abs(dz) < 2.0 and abs(dr) < 0.5) == 2]" # cm, cm
462  event_cuts += " and [eventRandom <= %s]" % prescale_all
463 
464  # now prescale the *electron* (e-) in the forward endcap (for bhabhas)
465  # note this is all done with cut strings to circumnavigate BII-3607
466  fwd_encap_border = "0.5480334" # rad (31.4 deg)
467  electron_is_first = "daughter(0, charge) < 0"
468  first_in_fwd_endcap = "daughter(0, theta) < %s" % fwd_encap_border
469  first_not_in_fwd_endcap = "daughter(0, theta) > %s" % fwd_encap_border
470  electron_is_second = "daughter(1, charge) < 0"
471  second_in_fwd_endcap = "daughter(1, theta) < %s" % fwd_encap_border
472  second_not_in_fwd_endcap = "daughter(1, theta) > %s" % fwd_encap_border
473  passes_prescale = "eventRandom <= %s" % prescale_fwd_electron
474  #
475  # four possible scenarios:
476  # 1) electron first in the decaystring and in fwd endcap: prescale these
477  prescale_logic = "[%s and %s and %s]" \
478  % (electron_is_first, first_in_fwd_endcap, passes_prescale)
479  # 2) electron second in string and in fwd endcap: prescale these
480  prescale_logic += " or [%s and %s and %s]" \
481  % (electron_is_second, second_in_fwd_endcap, passes_prescale)
482  # 3) electron first in string and not in fwd endcap (no prescale)
483  prescale_logic += " or [%s and %s]" % (electron_is_first, first_not_in_fwd_endcap)
484  # 4) electron second in string and not in fwd endcap (no prescale)
485  prescale_logic += " or [%s and %s]" % (electron_is_second, second_not_in_fwd_endcap)
486 
487  # final candidate building with cuts and prescales
488  prescale_logic = "[%s]" % prescale_logic
489  ma.applyCuts("vpho:radee", event_cuts + " and " + prescale_logic, path=path)
490 
491  return ["vpho:radee"]
492 
493 
494 @fancy_skim_header
496  __authors__ = ["Sam Cunliffe", "Torben Ferber", "Ilya Komarov", "Yuji Kato", "Jake Bennett"]
497  __description__ = ""
498  __contact__ = __liaison__
499  __category__ = "systematics"
500 
501  def load_standard_lists(self, path):
502  stdLambdas(path=path)
503 
504  def build_lists(self, path):
505  vm.addAlias("fsig", "formula(flightDistance/flightDistanceErr)")
506  vm.addAlias("pMom", "daughter(0,p)")
507  vm.addAlias("piMom", "daughter(1,p)")
508  vm.addAlias("daughtersPAsym", "formula((pMom-piMom)/(pMom+piMom))")
509 
510  LambdaList = []
511  ma.cutAndCopyList("Lambda0:syst0", "Lambda0:merged", "fsig>10 and daughtersPAsym>0.41", path=path)
512  LambdaList.append("Lambda0:syst0")
513 
514  return LambdaList
515 
516 
517 @fancy_skim_header
519  """
520  Uses the ``gamma:loose`` list and a cut on the number of tracks.
521 
522  Cuts applied:
523 
524  * :math:`E_{\\gamma}> 3\\,\\text{GeV}` AND
525  * :math:`E_{\\gamma}< 8\\,\\text{GeV}`
526  * :math:`n_{\\text{tracks}} \\geq 2` AND :math:`n_{\\text{tracks}} \\leq 4`
527  * at least 1 candidate in the K_S0:merged or in the phi->K+:all K-:all lists
528  """
529  __authors__ = ["Giuseppe Finocchiaro", "Benjamin Oberhof"]
530  __description__ = (
531  "Skim for ISR - phi gamma analyses, "
532  ":math:`e^+ e^- \\to \\phi \\gamma ` and "
533  ":math:`\\phi` decays into two charged tracks "
534  "(:math:`K^+K^-` or :math:`K_S K_L` with :math:`K_S\\to \\pi^+\\pi^-`)"
535  )
536  __contact__ = "Giuseppe Finocchiaro <giuseppe.finocchiaro@lnf.infn.it>"
537  __category__ = "systematics"
538 
539  TestSampleProcess = "ccbar"
540  validation_sample = _VALIDATION_SAMPLE
541 
542  def load_standard_lists(self, path):
543  stdPhotons("loose", path=path, loadPhotonBeamBackgroundMVA=False)
544  stdK("all", path=path)
545  stdKshorts(path=path)
546 
547  def build_lists(self, path):
548  EventCuts = [
549  "[nTracks>=2] and [nTracks<=4]",
550  "[nParticlesInList(gamma:PhiSystematics) > 0]",
551  "[[nParticlesInList(phi:charged) > 0] or [nParticlesInList(K_S0:PhiSystematics) > 0]]"
552  ]
553 
554  ma.cutAndCopyList("gamma:PhiSystematics", "gamma:loose", "3 < E < 8", writeOut=True, path=path)
555  ma.reconstructDecay('phi:charged -> K+:all K-:all', '0.9 < M < 1.2', path=path)
556  ma.copyList('K_S0:PhiSystematics', 'K_S0:merged', writeOut=True, path=path)
557 
558  path = self.skim_event_cutsskim_event_cuts(" and ".join(EventCuts), path=path)
559  return ["gamma:PhiSystematics"]
560 
561  def validation_histograms(self, path):
562  stdKshorts(path=path)
563  ma.fillParticleList('K+:all', "", writeOut=True, path=path)
564  ma.fillParticleList('K_L0:all', "", writeOut=True, path=path)
565  ma.fillParticleList('gamma:sig', 'nTracks > 1 and 3. < E < 8.', writeOut=True, path=path,
566  loadPhotonBeamBackgroundMVA=False)
567 
568  ma.reconstructDecay('phi:KK -> K+:all K-:all', '0.9 < M < 1.2', writeOut=True, path=path)
569 
570  vm.addAlias("gamma_E_CMS", "useCMSFrame(E)")
571  vm.addAlias("gamma_E", "E")
572  vm.addAlias("K_S0_mass", "M")
573  vm.addAlias("phi_mass", "M")
574 
575  histoRootFile = f'{self}_Validation.root'
576  variableshisto = [('gamma_E', 120, 2.5, 8.5),
577  ('gamma_E_CMS', 100, 2.0, 7.0),
578  ('nTracks', 15, 0, 15),
579  ]
580  variableshistoKS = [('K_S0_mass', 200, 0.4, 0.6),
581  ]
582  variableshistoPhi = [('phi_mass', 200, 0.8, 1.2),
583  ]
584 
585  ma.variablesToHistogram('gamma:sig', variableshisto, filename=histoRootFile, path=path)
586  ma.variablesToHistogram('K_S0:merged', variableshistoKS, filename=histoRootFile, path=path)
587  ma.variablesToHistogram('phi:KK', variableshistoPhi, filename=histoRootFile, path=path)
588 
589 
590 @fancy_skim_header
592  __authors__ = "Phil Grace"
593  __contact__ = "Phil Grace <philip.grace@adelaide.edu.au>"
594  __description__ = "Random skim to select a fixed fraction of events."
595  __category__ = "systematics, random"
596 
597  def __init__(self, KeepPercentage=10, seed=None, **kwargs):
598  """
599  Parameters:
600  KeepPercentage (float): Percentage of events to be kept.
601  seed (int): Set random seed to given number. If this argument is not given,
602  this skim will not alter the random seed.
603  **kwargs: Passed to constructor of `BaseSkim`.
604  """
605  super().__init__(**kwargs)
606  self.KeepPercentageKeepPercentage = KeepPercentage
607  self.seedseed = seed
608 
609  def additional_setup(self, path):
610  if self.seedseed is not None:
611  b2.set_random_seed(int(self.seedseed))
612 
613  def load_standard_lists(self, path):
614  stdPi("all", path=path)
615  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
616 
617  def build_lists(self, path):
618  # Select one photon/track per event with no other cuts, so that all events are
619  # captured in the skim list if KeepPercentage=100.
620  label = "RandomSkim"
621  ma.copyList(f"pi+:{label}", "pi+:all", path=path)
622  ma.copyList(f"gamma:{label}", "gamma:all", path=path)
623  ma.applyRandomCandidateSelection(f"pi+:{label}", path=path)
624  ma.applyRandomCandidateSelection(f"gamma:{label}", path=path)
625 
626  # Select fraction of events
627  path = self.skim_event_cutsskim_event_cuts(
628  f"eventRandom <= {self.KeepPercentage/100}", path=path
629  )
630 
631  return [f"pi+:{label}", f"gamma:{label}"]
632 
633 
634 @fancy_skim_header
636  __authors__ = "Marcel Hohmann"
637  __contact__ = __liaison_leptonID__
638  __description__ = "Skim to select all events that pass the HLT Four Lepton skim for lepton ID studies"
639  __category__ = "systematics, leptonID"
640  ApplyHLTHadronCut = False
641 
642  def load_standard_lists(self, path):
643  stdPi("all", path=path)
644 
645  def build_lists(self, path):
646  label = "FourLeptonHLT"
647  ma.copyList(f"pi+:{label}", "pi+:all", path=path)
648  ma.rankByLowest(f"pi+:{label}", "random", 1, "systematicsFourLeptonHLT_randomRank", path=path)
649 
650  path = self.skim_event_cutsskim_event_cuts(
651  "SoftwareTriggerResult(software_trigger_cut&skim&accept_fourlep) == 1", path=path
652  )
653 
654  return [f"pi+:{label}"]
655 
656 
657 @fancy_skim_header
659  __authors__ = "Marcel Hohmann"
660  __contact__ = __liaison_leptonID__
661  __description__ = "Skim to select all events that pass the HLT RadMuMu skim for lepton ID studies"
662  __category__ = "systematics, leptonID"
663  ApplyHLTHadronCut = False
664 
665  def load_standard_lists(self, path):
666  stdPi("all", path=path)
667 
668  def build_lists(self, path):
669  label = "RadMuMuLeptonID"
670  ma.copyList(f"pi+:{label}", "pi+:all", path=path)
671  ma.rankByLowest(f"pi+:{label}", "random", 1, "systematicsRadMuMuLeptonID_randomRank", path=path)
672 
673  path = self.skim_event_cutsskim_event_cuts(
674  "SoftwareTriggerResult(software_trigger_cut&skim&accept_radmumu) == 1", path=path
675  )
676  return [f"pi+:{label}"]
677 
678 
679 @fancy_skim_header
681  """
682  J/psi skim for lepton ID systematics studies. Lists in this skim are those defined in `JpsimumuTagProbe`, `JpsieeTagProbe`.
683  """
684  __authors__ = ["Sam Cunliffe", "Torben Ferber", "Ilya Komarov", "Yuji Kato", "Racha Cheaib", "Marcel Hohmann"]
685  __description__ = ""
686  __contact__ = __liaison_leptonID__
687  __category__ = "systematics, leptonID"
688 
689  def load_standard_lists(self, path):
690  stdMu("all", path=path)
691  stdE("all", path=path)
692  stdPhotons("all", path=path, loadPhotonBeamBackgroundMVA=False)
693 
694  TestSampleProcess = "ccbar"
695  ApplyHLTHadronCut = True
696 
697  def build_lists(self, path):
698  return [
699  self.JpsimumuTagProbeJpsimumuTagProbe(path),
700  self.JpsieeTagProbeJpsieeTagProbe(path),
701  ]
702 
703  def JpsimumuTagProbe(self, path):
704  """Build JpsimumuTagProbe lists for systematics skims."""
705  Cuts = "2.7 < M < 3.4"
706  ma.reconstructDecay(
707  "J/psi:systematics_mumu -> mu+:all mu-:all",
708  f'{Cuts} and [daughter(0,muonID)>0.1 or daughter(1,muonID)>0.1]',
709  path=path)
710  return "J/psi:systematics_mumu"
711 
712  def JpsieeTagProbe(self, path):
713  """Build JpsieeTagProbe lists for systematics skims."""
714 
715  Cuts = "2.7 < M < 3.4"
716  ma.cutAndCopyList('gamma:brems', 'gamma:all', 'E<1', path=path)
717  ma.correctBrems('e+:brems_corrected', 'e+:all', 'gamma:brems', path=path)
718  ma.reconstructDecay(
719  "J/psi:systematics_ee -> e+:brems_corrected e-:brems_corrected",
720  f'{Cuts} and [daughter(0,electronID_noTOP)>0.1 or daughter(1,electronID_noTOP)>0.1]',
721  path=path)
722  return "J/psi:systematics_ee"
723 
724 
725 @fancy_skim_header
727  """
728  K-short skim for hadron and lepton ID systematics studies.
729  As K-short candidates are abundant this skim has a high retention.
730  To meet the retention criteria a prescale is added. The prescale is given in standard trigger terms (reciprocal).
731  A prescale of 50 will keep 2% of events, etc.
732  """
733  __authors__ = ["Marcel Hohmann"]
734  __description__ = "Skim for K-short events for performance studies"
735  __contact__ = __liaison_leptonID__
736  __category__ = "performance, leptonID"
737 
738  ApplyHLTHadronCut = True
739 
740  def __init__(self, prescale=4, **kwargs):
741  """
742  Parameters:
743  prescale (int): the global prescale for this skim.
744  **kwargs: Passed to constructor of `BaseSkim`.
745  """
746  self.prescaleprescale = prescale
747  super().__init__(**kwargs)
748 
749  def load_standard_lists(self, path):
750  stdPi("all", path=path)
751 
752  def build_lists(self, path):
753 
754  ma.reconstructDecay(
755  'K_S0:reco -> pi+:all pi-:all',
756  '[0.30 < M < 0.70]',
757  path=path)
758 
759  vertex.treeFit('K_S0:reco', 0.0, path=path)
760  ma.applyCuts('K_S0:reco', '0.4 < M < 0.6', path=path)
761 
762  ma.fillParticleList('K_S0:v0 -> pi+ pi-',
763  '[0.30 < M < 0.70]',
764  True,
765  path=path)
766  vertex.treeFit('K_S0:v0', 0.0, path=path)
767  ma.applyCuts('K_S0:v0', '0.4 < M < 0.6', path=path)
768 
769  ma.mergeListsWithBestDuplicate('K_S0:merged', ['K_S0:v0', 'K_S0:reco'],
770  variable='particleSource', preferLowest=True, path=path)
771 
772  KS_cut = '[[cosAngleBetweenMomentumAndVertexVector>0.998] or '\
773  ' [formula(flightDistance/flightDistanceErr)>11] or '\
774  ' [flightTime>0.007]]' # and '\
775  # '[useAlternativeDaughterHypothesis(M, 0:p+) > 1.13068 and useAlternativeDaughterHypothesis(M, 0:pi-, 1:p+) > 1.13068]'
776 
777  ma.cutAndCopyList("K_S0:skim", "K_S0:merged", KS_cut, path=path)
778  path = self.skim_event_cutsskim_event_cuts(f'eventRandom < {(1/self.prescale):.6f}', path=path)
779  return ['K_S0:skim']
780 
781 
782 @fancy_skim_header
784  """
785  Skim for selecting Bhabha events for leptonID studies.
786  In case the retention exceeds 10% a prescale can be added.
787  The prescale is given in standard trigger terms (reciprocal).
788  """
789  __authors__ = ["Justin Skorupa"]
790  __description__ = "Skim for Bhabha events for lepton ID study"
791  __contact__ = __liaison_leptonID__
792  __category__ = "performance, leptonID"
793 
794  ApplyHLTHadronCut = False
795 
796  def __init__(self, prescale=1, **kwargs):
797  """
798  Parameters:
799  prescale (int): the global prescale for this skim.
800  **kwargs: Passed to constructor of `BaseSkim`.
801  """
802  self.prescaleprescale = prescale
803  super().__init__(**kwargs)
804 
805  def load_standard_lists(self, path):
806  stdE("all", path=path)
807 
808  def build_lists(self, path):
809  goodtrack = "abs(dz) < 5 and abs(dr) < 2"
810  goodtrackwithPID = f"{goodtrack} and electronID_noTOP > 0.95 and clusterTheta > 0.59"\
811  " and clusterTheta < 2.15 and useCMSFrame(clusterE) > 2"
812  ma.cutAndCopyList("e+:tight", "e+:all", goodtrackwithPID, path=path)
813  ma.cutAndCopyList("e+:loose", "e+:all", goodtrack, path=path)
814 
815  ma.reconstructDecay(
816  "vpho:bhabha -> e+:tight e-:loose", "", path=path)
817 
818  event_cuts = "[nCleanedTracks(abs(dz) < 5 and abs(dr) < 2) == 2]"\
819  f" and eventRandom < {(1/self.prescale):.6f}"
820 
821  ma.applyCuts("vpho:bhabha", event_cuts, path=path)
822 
823  return ["vpho:bhabha"]
824 
825 
826 @fancy_skim_header
828  """
829  Combined systematics skim for the four hadronic channels:
830  SystematicsKshort,
831  SystematicsJpsi,
832  SystematicsDstar,
833  SystemmaticsLambda.
834 
835  This is required for technical (data production) reasons, as it keeps the number of files low.
836  See the definitions of the individual skims for the details.
837  """
838  __authors__ = ["Marcel Hohmann"]
839  __description__ = "Combined Skim of the systematic hadronic skims: Kshort, Jpsi, Dstar, Lambda."
840  __contact__ = __liaison_leptonID__
841  __category__ = "performance, leptonID"
842  __name__ = "SystematicsCombinedHadronic"
843 
844  produces_mdst_by_default = True
845 
846  def __init__(self, prescale_kshort=4, mdstOutput=True, **kwargs):
847  """ Initialiser.
848 
849  Args:
850  prescale_kshort (Optional[int]): offline prescale factor for KS skim.
851  **kwargs: key-worded arguments. See CombinedSkim.__init__()
852  """
853 
854  kwargs.update(mdstOutput=mdstOutput, CombinedSkimName=self.__name____name____name____name__)
855  kwargs.setdefault('udstOutput', False)
856 
857  skims_list = [SystematicsKshort(prescale=prescale_kshort), SystematicsDstar(), SystematicsLambda(), SystematicsJpsi()]
858  super().__init__(*skims_list, **kwargs)
859 
860 
861 @fancy_skim_header
863  """
864  Combined systematics skim for the four low multi channels:
865  SystematicsFourLeptonFromHLTFlag,
866  SystematicsRadmumuFromHLTFlag,
867  SystematicsBhabha,
868  TauThrust.
869 
870  This is required for technical (data production) reasons, as it keeps the number of files low.
871  See the definitions of the individual skims for the details.
872  """
873  __authors__ = ["Marcel Hohmann"]
874  __description__ = "Combined Skim of the systematic low multi skims: FourLepton, Radmumu, Bhabha, TauThrust."
875  __contact__ = __liaison_leptonID__
876  __category__ = "performance, leptonID"
877  __name__ = "SystematicsCombinedLowMulti"
878 
879  produces_mdst_by_default = True
880 
881  def __init__(self, mdstOutput=True, **kwargs):
882  """ Initialiser.
883 
884  Args:
885  **kwargs: key-worded arguments. See CombinedSkim.__init__()
886  """
887 
888  kwargs.update(mdstOutput=mdstOutput, CombinedSkimName=self.__name____name____name____name__)
889  kwargs.setdefault('udstOutput', False)
890 
891  from skim.WGs.taupair import TauThrust
893  super().__init__(*skims_list, **kwargs)
def skim_event_cuts(self, cut, *path)
Definition: core.py:272
def __name__(self)
Definition: core.py:396
def __name__(self)
Definition: core.py:578
def additional_setup(self, path)
Definition: systematics.py:609
def __init__(self, KeepPercentage=10, seed=None, **kwargs)
Definition: systematics.py:597
def build_lists(self, path)
Definition: systematics.py:617
def load_standard_lists(self, path)
Definition: systematics.py:613
def getmumugList(self, path)
Definition: systematics.py:273
def build_lists(self, path)
Definition: systematics.py:189
def getSigmacList(self, path)
Definition: systematics.py:239
def getDsList(self, path)
Definition: systematics.py:199
def getBPlusList(self, path)
Definition: systematics.py:301
def getBZeroList(self, path)
Definition: systematics.py:288
def load_standard_lists(self, path)
Definition: systematics.py:182
def getDstarList(self, path)
Definition: systematics.py:215
def __init__(self, prescale=1, **kwargs)
Definition: systematics.py:796
def load_standard_lists(self, path)
Definition: systematics.py:805
def __init__(self, prescale_kshort=4, mdstOutput=True, **kwargs)
Definition: systematics.py:846
def __init__(self, mdstOutput=True, **kwargs)
Definition: systematics.py:881
def build_lists(self, path)
Definition: systematics.py:54
def PiKFromDstarList(self, path)
Definition: systematics.py:57
def load_standard_lists(self, path)
Definition: systematics.py:48
def build_lists(self, path)
Definition: systematics.py:386
def load_standard_lists(self, path)
Definition: systematics.py:383
def JpsieeTagProbe(self, path)
Definition: systematics.py:712
def JpsimumuTagProbe(self, path)
Definition: systematics.py:703
def build_lists(self, path)
Definition: systematics.py:697
def load_standard_lists(self, path)
Definition: systematics.py:689
def __init__(self, prescale=4, **kwargs)
Definition: systematics.py:740
def load_standard_lists(self, path)
Definition: systematics.py:749
def load_standard_lists(self, path)
Definition: systematics.py:501
def validation_histograms(self, path)
Definition: systematics.py:561
def load_standard_lists(self, path)
Definition: systematics.py:542
def build_lists(self, path)
Definition: systematics.py:442
def __init__(self, prescale_all=1, prescale_fwd_electron=1, **kwargs)
Definition: systematics.py:429
def load_standard_lists(self, path)
Definition: systematics.py:426
def load_standard_lists(self, path)
Definition: systematics.py:340
def DstarToD0PiPartList(self, path)
Definition: systematics.py:145
def load_standard_lists(self, path)
Definition: systematics.py:94
def raveFit(list_name, conf_level, fit_type='vertex', decay_string='', constraint='', daughtersUpdate=False, path=None, silence_warning=False)
Definition: vertex.py:159
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