3 from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
4 from AsgAnalysisAlgorithms.AsgAnalysisConfig
import makeEventCutFlowConfig
7 """ConfigBlock for merging the output of various selection streams"""
10 super(EventSelectionMergerConfig, self).
__init__()
11 self.addOption(
'selections', [], type=list,
12 info=
"the selection decisions (list of strings) to unify into a "
13 "final decision (internally: selection_1 || selection_2 || ...). "
14 "The default is [] (empty list).")
15 self.addOption(
'noFilter',
False, type=bool,
16 info=
"do not apply an event filter. The default is False, i.e. "
17 "remove events not passing the full list of selection cuts.")
20 alg = config.createAlgorithm(
'CP::SaveFilterAlg',
'EventSelectionMerger')
21 alg.FilterDescription =
'events passing at least one EventSelection algorithm'
22 alg.eventDecisionOutputDecoration =
'ignore_anySelection_%SYS%'
23 alg.selection =
'||'.
join([sel+
',as_char' for sel
in self.selections
if sel])
24 alg.noFilter = self.noFilter
25 alg.selectionName =
'pass_anySelection_%SYS%'
26 alg.decorationName =
'ntuplepass_anySelection_%SYS%'
29 """ConfigBlock for interpreting text-based event selections"""
32 super(EventSelectionConfig, self).
__init__()
33 self.addOption(
'name', name, type=str,
35 info=
"the name of the event selection, used to uniquely identify "
36 "the EventSelectionConfig block.")
37 self.addOption(
'electrons',
"", type=str,
38 info=
"the input electron container, with a possible selection, in "
39 "the format container or container.selection. The default is '' "
41 self.addOption(
'muons',
"", type=str,
42 info=
"the input muon container, with a possible selection, in the "
43 "format container or container.selection. The default is '' "
45 self.addOption(
'jets',
"", type=str,
46 info=
"the input jet container, with a possible selection, in the "
47 "format container or container.selection. The default is '' "
49 self.addOption(
'largeRjets',
"", type=str,
50 info=
"the large-R jet container, with a possible selection, in "
51 "the format container or container.selection. The default is '' "
53 self.addOption(
'photons',
"", type=str,
54 info=
"the input photon container, with a possible selection, in "
55 "the format container or container.selection. The default is '' "
57 self.addOption(
'taus',
"", type=str,
58 info=
"the input tau-jet container, with a possible selection, in "
59 "the format container or container.selection. The default is '' "
61 self.addOption(
'met',
"", type=str,
62 info=
"he input MET container. The default is '' (empty string).")
64 self.addOption(
'metTerm',
"Final", type=str,
66 self.addOption(
'btagDecoration',
"", type=str,
67 info=
"the b-tagging decoration to use when defining b-jets. "
68 "The default is '' (empty string).")
69 self.addOption(
'preselection',
"", type=str,
70 info=
"the event-wise selection flag to start this event selection "
71 "from. The default is '' (empty string).")
72 self.addOption(
'selectionCuts',
"", type=str,
74 info=
"a single string listing one selection cut per line.")
75 self.addOption(
'noFilter',
False, type=bool,
76 info=
"do not apply an event filter. The default is False, i.e. "
77 "remove events not passing the full list of selection cuts.")
78 self.addOption(
'debugMode',
False, type=bool,
79 info=
"whether to create an output branch for every single line "
80 "of the selection cuts. The default is False (only saves the"
95 if self.selectionCuts
is None:
96 raise ValueError (
"[EventSelectionConfig] You must provide the 'selectionCuts' option to 'EventSelectionConfig': "
97 "a single string where each line represents a different selection cut to apply in order.")
98 for line
in self.selectionCuts.
split(
"\n"):
106 if text.startswith(
"#"):
109 if "EL_N" in text.split():
111 elif "MU_N" in text.split():
113 elif "SUM_EL_N_MU_N" in text.split():
115 elif "JET_N" in text.split():
117 elif "JET_N_BTAG" in text.split():
119 elif "PH_N" in text.split():
121 elif "TAU_N" in text.split():
123 elif "LJET_N" in text.split():
125 elif "MET" in text.split():
127 elif "MWT" in text.split():
129 elif "MET+MWT" in text.split():
131 elif "MLL" in text.split():
133 elif "MLLWINDOW" in text.split():
135 elif "OS" in text.split():
137 elif "SS" in text.split():
139 elif "MLL_OSSF" in text.split():
141 elif "LJETMASS_N" in text.split():
143 elif "LJETMASSWINDOW_N" in text.split():
145 elif "SAVE" in text.split():
147 elif "IMPORT" in text.split():
149 elif "EVENTFLAG" in text.split():
151 elif "GLOBALTRIGMATCH" in text.split():
154 raise ValueError (f
"[EventSelectionConfig] The following selection cut is not recognised! --> {text}")
157 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Check {keyword} in: {text}")
160 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Missing input collection for {collection}")
165 if not requirePositive
or value >= 0:
168 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Float {test} is not positive!")
170 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be a float, not {type(test)}!")
175 if value ==
float(test):
176 if not requirePositive
or value >= 0:
179 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Int {test} us not positive!")
181 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be an int, not a float!")
183 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be an int, not {type(test)}")
186 if not isinstance(test, str):
187 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be a string, not a number!")
202 raise KeyError (f
"[EventSelectionConfig] Misconfiguration! {test} should be one of {list(mapping.keys())}")
205 test = test.split(
":")
207 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be provided as 'btagger:btagWP'")
216 if algorithm
is not None:
217 algorithm.decorationName = f
'{decoration},as_char'
220 config.addOutputVar(
'EventInfo', decoration, decoration.split(
"_%SYS%")[0])
226 config.addSelection(
'EventInfo',
'', decoration)
232 decoration = decoration.split(
"&&")
233 decoration = [sub +
',as_char' if ',as_char' not in sub
else sub
for sub
in decoration]
234 return '&&'.
join(decoration)
239 if items[0] !=
"IMPORT":
247 self.
currentDecoration = f
'{self.currentDecoration},as_char&&pass_{region}_%SYS%'
249 imported_cuts = [cut
for cut
in config.getSelectionCutFlow(
'EventInfo',
'')
if cut.startswith(region)]
255 if items[0] !=
"EL_N":
257 if len(items) != 4
and len(items) != 5:
259 if not self.electrons:
261 thisalg = f
'{self.name}_NEL_{self.step}'
262 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
263 alg.particles, alg.objectSelection = config.readNameAndSelection(self.electrons)
269 elif len(items) == 5:
271 if alg.objectSelection:
272 alg.objectSelection +=
"&&" + config.getFullSelection(self.electrons.
split(
".")[0], extraSel)
274 alg.objectSelection = config.getFullSelection(self.electrons.
split(
".")[0], extraSel)
283 if items[0] !=
"MU_N":
285 if len(items) != 4
and len(items) != 5:
289 thisalg = f
'{self.name}_NMU_{self.step}'
290 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
291 alg.particles, alg.objectSelection = config.readNameAndSelection(self.muons)
297 elif len(items) == 5:
299 if alg.objectSelection:
300 alg.objectSelection +=
"&&" + config.getFullSelection(self.muons.
split(
".")[0], extraSel)
302 alg.objectSelection = config.getFullSelection(self.muons.
split(
".")[0], extraSel)
311 if items[0] !=
"SUM_EL_N_MU_N":
313 if len(items) != 4
and len(items) != 5:
315 if not self.electrons
and not self.muons:
317 thisalg = f
'{self.name}_SUMNELNMU_{self.step}'
318 alg = config.createAlgorithm(
'CP::SumNElNMuPtSelectorAlg', thisalg)
319 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
320 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
327 elif len(items) == 5:
337 if items[0] !=
"JET_N":
339 if len(items) != 4
and len(items) != 5:
343 thisalg = f
'{self.name}_NJET_{self.step}'
344 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
345 alg.particles, alg.objectSelection = config.readNameAndSelection(self.jets)
351 elif len(items) == 5:
353 if alg.objectSelection:
354 alg.objectSelection +=
"&&" + config.getFullSelection(self.jets.
split(
".")[0], extraSel)
356 alg.objectSelection = config.getFullSelection(self.jets.
split(
".")[0], extraSel)
365 if items[0] !=
"JET_N_BTAG":
367 if len(items) != 3
and len(items) != 4:
371 thisalg = f
'{self.name}_NBJET_{self.step}'
372 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
373 particles, selection = config.readNameAndSelection(self.jets)
374 alg.particles = particles
375 alg.objectSelection = f
'{selection}&&{self.btagDecoration},as_char'
380 elif len(items) == 4:
382 customBtag = f
'ftag_select_{btagger}_{btagWP}'
383 alg.objectSelection = f
'{selection}&&{customBtag},as_char'
391 if items[0] !=
"PH_N":
393 if len(items) != 4
and len(items) != 5:
397 thisalg = f
'{self.name}_NPH_{self.step}'
398 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
399 alg.particles, alg.objectSelection = config.readNameAndSelection(self.photons)
405 elif len(items) == 5:
407 if alg.objectSelection:
408 alg.objectSelection +=
"&&" + config.getFullSelection(self.photons.
split(
".")[0], extraSel)
410 alg.objectSelection = config.getFullSelection(self.photons.
split(
".")[0], extraSel)
419 if items[0] !=
"TAU_N":
421 if len(items) != 4
and len(items) != 5:
425 thisalg = f
'{self.name}_NTAU_{self.step}'
426 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
427 alg.particles, alg.objectSelection = config.readNameAndSelection(self.taus)
433 elif len(items) == 5:
435 if alg.objectSelection:
436 alg.objectSelection +=
"&&" + config.getFullSelection(self.taus.
split(
".")[0], extraSel)
438 alg.objectSelection = config.getFullSelection(self.taus.
split(
".")[0], extraSel)
447 if items[0] !=
"LJET_N":
449 if len(items) != 4
and len(items) != 5:
451 thisalg = f
'{self.name}_NLJET_{self.step}'
452 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
453 alg.particles, alg.objectSelection = config.readNameAndSelection(self.largeRjets)
459 elif len(items) == 5:
461 if alg.objectSelection:
462 alg.objectSelection +=
"&&" + config.getFullSelection(self.largeRjets.
split(
".")[0], extraSel)
464 alg.objectSelection = config.getFullSelection(self.largeRjets.
split(
".")[0], extraSel)
473 if items[0] !=
"LJETMASS_N":
475 if len(items) != 4
and len(items) != 5:
477 thisalg = f
'{self.name}_NLJETMASS_{self.step}'
478 alg = config.createAlgorithm(
'CP::NObjectMassSelectorAlg', thisalg)
479 alg.particles, alg.objectSelection = config.readNameAndSelection(self.largeRjets)
485 elif len(items) == 5:
487 if alg.objectSelection:
488 alg.objectSelection +=
"&&" + config.getFullSelection(self.largeRjets.
split(
".")[0], extraSel)
490 alg.objectSelection = config.getFullSelection(self.largeRjets.
split(
".")[0], extraSel)
499 if items[0] !=
"LJETMASSWINDOW_N":
501 if len(items) != 5
and len(items) != 6
and len(items) != 7:
503 thisalg = f
'{self.name}_NLJETMASSWINDOW_{self.step}'
504 alg = config.createAlgorithm(
'CP::NLargeRJetMassWindowSelectorAlg', thisalg)
505 alg.ljets, alg.ljetSelection = config.readNameAndSelection(self.largeRjets)
506 if len(items) == 5
or (len(items) == 6
and "veto" in items):
511 alg.vetoMode = (len(items) == 6
and self.
check_string(items[5]) ==
"veto")
512 elif (len(items) == 6
and "veto" not in items)
or len(items) == 7:
514 if alg.ljetSelection:
515 alg.ljetSelection +=
"&&" + config.getFullSelection(self.largeRjets.
split(
".")[0], extraSel)
517 alg.ljetSelection = config.getFullSelection(self.largeRjets.
split(
".")[0], extraSel)
522 alg.vetoMode = (len(items) ==7
and self.
check_string(items[6]) ==
"veto")
529 if items[0] !=
"MET":
535 thisalg = f
'{self.name}_MET_{self.step}'
536 alg = config.createAlgorithm(
'CP::MissingETSelectorAlg', thisalg)
537 alg.met = config.readName(self.met)
538 alg.metTerm = self.metTerm
547 if items[0] !=
"MWT":
551 if not self.electrons
and not self.muons:
553 thisalg = f
'{self.name}_MWT_{self.step}'
554 alg = config.createAlgorithm(
'CP::TransverseMassSelectorAlg', thisalg)
555 alg.met = config.readName(self.met)
556 alg.metTerm = self.metTerm
557 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
558 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
567 if items[0] !=
"MET+MWT":
573 if not self.electrons
and not self.muons:
575 thisalg = f
'{self.name}_METMWT_{self.step}'
576 alg = config.createAlgorithm(
'CP::MissingETPlusTransverseMassSelectorAlg', thisalg)
577 alg.met = config.readName(self.met)
578 alg.metTerm = self.metTerm
579 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
580 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
589 if items[0] !=
"MLL":
593 if not self.electrons
and not self.muons:
595 thisalg = f
'{self.name}_MLL_{self.step}'
596 alg = config.createAlgorithm(
'CP::DileptonInvariantMassSelectorAlg', thisalg)
598 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
600 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
609 if items[0] !=
"MLLWINDOW":
611 if len(items) != 3
and len(items) != 4:
613 if not self.electrons
and not self.muons:
615 thisalg = f
'{self.name}_MLLWINDOW_{self.step}'
616 alg = config.createAlgorithm(
'CP::DileptonInvariantMassWindowSelectorAlg', thisalg)
618 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
620 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
623 alg.vetoMode = (len(items) == 4
and self.
check_string(items[3]) ==
"veto")
632 if not self.electrons
and not self.muons:
634 thisalg = f
'{self.name}_OS_{self.step}'
635 alg = config.createAlgorithm(
'CP::ChargeSelectorAlg', thisalg)
637 if "Particle" in self.electrons
or "Truth" in self.electrons:
638 alg.truthElectrons, alg.truthElectronSelection = config.readNameAndSelection(self.electrons)
640 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
642 if "Particle" in self.muons
or "Truth" in self.muons:
643 alg.truthMuons, alg.truthMuonSelection = config.readNameAndSelection(self.muons)
645 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
655 if not self.electrons
and not self.muons:
657 thisalg = f
'{self.name}_SS_{self.step}'
658 alg = config.createAlgorithm(
'CP::ChargeSelectorAlg', thisalg)
660 if "Particle" in self.electrons
or "Truth" in self.electrons:
661 alg.truthElectrons, alg.truthElectronSelection = config.readNameAndSelection(self.electrons)
663 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
665 if "Particle" in self.muons
or "Truth" in self.muons:
666 alg.truthMuons, alg.truthMuonSelection = config.readNameAndSelection(self.muons)
668 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
676 if items[0] !=
"MLL_OSSF":
678 if len(items) != 3
and len(items) != 4:
680 if not self.electrons
and not self.muons:
682 thisalg = f
'{self.name}_MLL_OSSF_{self.step}'
683 alg = config.createAlgorithm(
'CP::DileptonOSSFInvariantMassWindowSelectorAlg', thisalg)
685 if "Particle" in self.electrons
or "Truth" in self.electrons:
686 alg.truthElectrons, alg.truthElectronSelection = config.readNameAndSelection(self.electrons)
688 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.electrons)
690 if "Particle" in self.muons
or "Truth" in self.muons:
691 alg.truthMuons, alg.truthMuonSelection = config.readNameAndSelection(self.muons)
693 alg.muons, alg.muonSelection = config.readNameAndSelection(self.muons)
696 alg.vetoMode = (len(items) == 4
and self.
check_string(items[3]) ==
"veto")
703 if items[0] !=
"EVENTFLAG":
713 if items[0] !=
"GLOBALTRIGMATCH":
717 self.
setDecorationName(
None, config,
"globalTriggerMatch_dontsave_%SYS%,as_char")
722 if items[0] !=
"SAVE":
726 thisalg = f
'{self.name}_SAVE'
727 alg = config.createAlgorithm(
'CP::SaveFilterAlg', thisalg)
728 alg.FilterDescription = f
'events passing < {self.name} >'
729 alg.eventDecisionOutputDecoration = f
'ignore_{self.name}_%SYS%'
731 alg.noFilter = self.noFilter
732 alg.selectionName = f
'pass_{self.name}_%SYS%,as_char'
733 alg.decorationName = f
'ntuplepass_{self.name}_%SYS%'
734 config.addOutputVar(
'EventInfo', f
'ntuplepass_{self.name}_%SYS%', f
'pass_{self.name}')
739 electrons=None, muons=None, jets=None,
741 photons=None, taus=None, met=None, metTerm=None,
742 btagDecoration=None, preselection=None,
743 selectionCuts=None, noFilter=None,
744 debugMode=None, cutFlowHistograms=None):
745 """Create an event selection config block
748 name -- the name defining this selection
749 electrons -- the electron container and selection
750 muons -- the muon container and selection
751 jets -- the jet container and selection
752 largeRjets -- the large-R jet container and selection
753 photons -- the photon container and selection
754 taus -- the tau-jet container and selection
755 met -- the MET container
756 metTerm -- the MET term to use (e.g. 'Final', 'NonInt')
757 btagDecoration -- the b-tagging decoration to use when defining b-jets
758 preselection -- optional event-wise selection flag to start from
759 selectionCuts -- a string listing one selection cut per line
760 noFilter -- whether to disable the event filter
761 debugMode -- enables saving all intermediate decorations
762 cutFlowHistograms -- whether to toggle event cutflow histograms per systematic
766 config.setOptionValue (
'electrons', electrons)
767 config.setOptionValue (
'muons', muons)
768 config.setOptionValue (
'jets', jets)
769 config.setOptionValue (
'largeRjets', largeRjets)
770 config.setOptionValue (
'photons', photons)
771 config.setOptionValue (
'taus', taus)
772 config.setOptionValue (
'met', met)
773 config.setOptionValue (
'metTerm', metTerm)
774 config.setOptionValue (
'btagDecoration', btagDecoration)
775 config.setOptionValue (
'preselection', preselection)
776 config.setOptionValue (
'selectionCuts', selectionCuts)
777 config.setOptionValue (
'noFilter', noFilter)
778 config.setOptionValue (
'debugMode', debugMode)
782 if cutFlowHistograms:
784 customSelections=name)
787 electrons=None, muons=None, jets=None,
789 photons=None, taus=None, met=None, metTerm=None,
790 btagDecoration=None, preselection=None,
791 selectionCutsDict=None, noFilter=None,
792 debugMode=None, cutFlowHistograms=None):
793 """Create multiple event selection config blocks
796 electrons -- the electron container and selection
797 muons -- the muon container and selection
798 jets -- the jet container and selection
799 largeRjets -- the large-R jet container and selection
800 photons -- the photon container and selection
801 taus -- the tau-jet container and selection
802 met -- the MET container
803 metTerm -- the MET term to use (e.g. 'Final', 'NonInt')
804 btagDecoration -- the b-tagging decoration to use when defining b-jets
805 preselection -- optional event-wise selection flag to start from
806 selectionCutsDict -- a dictionary with key the name of the selection and value a string listing one selection cut per line
807 noFilter -- whether to disable the event filter
808 debugMode -- enables saving all intermediate decorations
809 cutFlowHistograms -- whether to toggle event cutflow histograms per region and per systematic
813 if len(
list(selectionCutsDict.keys())) == 1:
814 name, selectionCuts =
list(selectionCutsDict.items())[0]
815 makeEventSelectionConfig(seq, name, electrons, muons, jets, largeRjets, photons, taus, met, metTerm, btagDecoration, preselection, selectionCuts, noFilter=noFilter, debugMode=debugMode, cutFlowHistograms=cutFlowHistograms)
820 for name, selectionCuts
in selectionCutsDict.items():
821 makeEventSelectionConfig(seq, name, electrons, muons, jets, largeRjets, photons, taus, met, metTerm, btagDecoration, preselection, selectionCuts, noFilter=
True, debugMode=debugMode, cutFlowHistograms=cutFlowHistograms)
826 config.setOptionValue (
'selections', [f
'pass_{name}_%SYS%' for name
in selectionCutsDict.keys()
if not name.startswith(
"SUB")])
827 config.setOptionValue (
'noFilter', noFilter)