3from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
4from AnalysisAlgorithmsConfig.ConfigSequence
import groupBlocks
5from AsgAnalysisAlgorithms.AsgAnalysisConfig
import EventCutFlowBlock
6from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType
10 """ConfigBlock for merging the output of various selection streams"""
13 super(EventSelectionMergerConfig, self).
__init__()
15 self.setBlockName(
'EventSelectionMerger')
16 self.addDependency(
'EventSelection', required=
True)
17 self.addOption(
'noFilter',
False, type=bool,
18 info=
"do not apply an event filter, i.e. setting it to `False` "
19 "removes events not passing the full list of selection cuts.")
22 """Return the instance name for this block"""
30 selections = config.getContainerMeta(
'EventInfo',
'eventSelectionNames',
32 selections = [sel
for sel
in selections
if not sel.startswith(
"pass_SUB")]
34 alg = config.createAlgorithm(
'CP::SaveFilterAlg',
35 'EventSelectionMerger' + selections[0].
split(
"_%SYS%")[0])
36 alg.FilterDescription =
'events passing at least one EventSelection'
37 alg.eventDecisionOutputDecoration =
'ignore_anySelection_%SYS%'
38 alg.selection =
'||'.join([sel +
',as_char' for sel
in selections])
39 alg.noFilter = self.noFilter
40 alg.selectionName =
'pass_anySelection_%SYS%'
41 alg.decorationName =
'ntuplepass_anySelection_%SYS%'
44 """ConfigBlock for interpreting text-based event selections"""
47 super(EventSelectionConfig, self).
__init__()
48 self.setBlockName(
'EventSelection')
49 self.addOption(
'selectionName',
'', type=str,
51 info=
"the name of the event selection, used to uniquely identify "
52 "the `EventSelectionConfig` block.")
53 self.addOption(
'electrons',
"", type=str,
54 info=
"the input electron container, with a possible selection, in "
55 "the format `container` or `container.selection`.")
56 self.addOption(
'muons',
"", type=str,
57 info=
"the input muon container, with a possible selection, in the "
58 "format `container` or `container.selection`.")
59 self.addOption(
'jets',
"", type=str,
60 info=
"the input jet container, with a possible selection, in the "
61 "format `container` or `container.selection`.")
62 self.addOption(
'largeRjets',
"", type=str,
63 info=
"the large-R jet container, with a possible selection, in "
64 "the format `container` or `container.selection`.")
65 self.addOption(
'photons',
"", type=str,
66 info=
"the input photon container, with a possible selection, in "
67 "the format `container` or `container.selection`.")
68 self.addOption(
'taus',
"", type=str,
69 info=
"the input tau-jet container, with a possible selection, in "
70 "the format `container` or `container.selection`.")
71 self.addOption(
'met',
"", type=str,
72 info=
"the input MET container.")
73 self.addOption(
'metTerm',
"Final", type=str,
74 info=
"the MET term to use when computing MET-based quantities.")
75 self.addOption(
'btagDecoration',
"", type=str,
76 info=
"the b-tagging decoration to use when defining b-jets.")
77 self.addOption(
'preselection',
"", type=str,
78 info=
"the event-wise selection flag to start this event selection "
80 self.addOption(
'selectionCuts',
"", type=str,
82 info=
"a single string listing one selection cut per line. "
83 "See [available keywords](https://topcptoolkit.docs.cern.ch/latest/settings/eventselection/#available-keywords).")
84 self.addOption(
'debugMode',
False, type=bool,
85 info=
"whether to create an output branch for every single line "
86 "of the selection cuts. Setting it to `False` only saves the"
88 self.addOption(
'useDressedProperties',
True, type=bool,
89 info=
"whether to use dressed truth electron and truth muon "
90 "kinematics rather than simple 4-vector kinematics.")
96 """Return the instance name for this block"""
100 existing = config.getContainerMeta(
'EventInfo',
'eventSelectionNames', defaultValue=[])
101 config.setContainerMeta(
'EventInfo',
'eventSelectionNames',
102 existing + [f
'pass_{self.selectionName}_%SYS%'], allowOverwrite=
True)
111 if self.selectionCuts
is None:
112 raise ValueError (
"[EventSelectionConfig] You must provide the 'selectionCuts' option to 'EventSelectionConfig': "
113 "a single string where each line represents a different selection cut to apply in order.")
114 for line
in self.selectionCuts.
split(
"\n"):
123 if text.startswith(
"#"):
126 if "EL_N" in text.split():
128 elif "MU_N" in text.split():
130 elif "SUM_EL_N_MU_N" in text.split():
132 elif "SUM_EL_N_MU_N_TAU_N" in text.split():
134 elif "JET_N_GHOST" in text.split():
136 elif "JET_N" in text.split():
138 elif "JET_N_BTAG" in text.split():
140 elif "PH_N" in text.split():
142 elif "TAU_N" in text.split():
144 elif "LJET_N_GHOST" in text.split():
146 elif "LJET_N" in text.split():
148 elif "OBJ_N" in text.split():
150 elif "MET" in text.split():
152 elif "MWT" in text.split():
154 elif "MET+MWT" in text.split():
156 elif "MLL" in text.split():
158 elif "MLLWINDOW" in text.split():
160 elif "OS" in text.split():
162 elif "SS" in text.split():
164 elif "MLL_OSSF" in text.split():
166 elif "LJETMASS_N" in text.split():
168 elif "LJETMASSWINDOW_N" in text.split():
170 elif "SAVE" in text.split():
172 elif "IMPORT" in text.split():
174 elif "EVENTFLAG" in text.split():
176 elif "GLOBALTRIGMATCH" in text.split():
178 elif "RUN_NUMBER" in text.split():
181 raise ValueError (f
"[EventSelectionConfig] The following selection cut is not recognised! --> {text}")
184 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Check {keyword} in: {text}")
187 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Missing input collection for {collection}")
192 if not requirePositive
or value >= 0:
195 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Float {test} is not positive!")
197 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be a float, not {type(test)}!")
202 if value == float(test):
203 if not requirePositive
or value >= 0:
206 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Int {test} us not positive!")
208 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be an int, not a float!")
210 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be an int, not {type(test)}")
213 if not isinstance(test, str):
214 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be a string, not a number!")
229 raise KeyError (f
"[EventSelectionConfig] Misconfiguration! {test} should be one of {list(mapping.keys())}")
232 test = test.split(
":")
234 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be provided as 'btagger:btagWP'")
240 values = test.split(
"!")
242 "B":
"GhostBHadronsFinalCount",
243 "C":
"GhostCHadronsFinalCount",
244 "T":
"GhostTQuarksFinalCount",
245 "W":
"GhostWBosonsCount",
246 "Z":
"GhostZBosonsCount",
247 "H":
"GhostHBosonsCount",
248 "TAU":
"GhostTausFinalCount"
250 return [ghost_map.get(value.upper(), value)
for value
in values]
256 self.
cutflow.append( decoration )
257 if algorithm
is not None:
258 algorithm.decorationName = f
'{decoration},as_char'
261 config.addOutputVar(
'EventInfo', decoration, decoration.split(
"_%SYS%")[0])
267 config.addSelection(
'EventInfo',
'', decoration)
273 decoration = decoration.split(
"&&")
274 decoration = [sub +
',as_char' if ',as_char' not in sub
else sub
for sub
in decoration]
275 return '&&'.join(decoration)
279 return oldSelection +
"&&" + config.getFullSelection(container, newSelection)
281 return config.getFullSelection(container, newSelection)
286 if items[0] !=
"IMPORT":
294 self.
currentDecoration = f
'{self.currentDecoration},as_char&&pass_{region}_%SYS%'
296 imported_cuts = [cut
for cut
in config.getSelectionCutFlow(
'EventInfo',
'')
if cut.startswith(region)]
302 if items[0] !=
"EL_N":
304 if len(items) != 4
and len(items) != 5:
308 thisalg = f
'{self.selectionName}_NEL_{self.step}'
309 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
310 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
electrons)
312 alg.useDressedProperties = self.useDressedProperties
318 elif len(items) == 5:
329 if items[0] !=
"MU_N":
331 if len(items) != 4
and len(items) != 5:
335 thisalg = f
'{self.selectionName}_NMU_{self.step}'
336 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
337 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
muons)
338 if "Truth" in self.
muons:
339 alg.useDressedProperties = self.useDressedProperties
345 elif len(items) == 5:
356 if items[0] !=
"SUM_EL_N_MU_N":
358 if len(items) != 4
and len(items) != 5
and len(items) != 7:
362 thisalg = f
'{self.selectionName}_SUMNELNMU_{self.step}'
363 alg = config.createAlgorithm(
'CP::SumNLeptonPtSelectorAlg', thisalg)
364 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
365 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
367 alg.useDressedProperties = self.useDressedProperties
374 elif len(items) == 5:
379 elif len(items) == 7:
393 if items[0] !=
"SUM_EL_N_MU_N_TAU_N":
395 if len(items) != 4
and len(items) != 6
and len(items) != 9:
399 thisalg = f
'{self.selectionName}_SUMNLEPTONS_{self.step}'
400 alg = config.createAlgorithm(
'CP::SumNLeptonPtSelectorAlg', thisalg)
401 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
402 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
403 alg.taus, alg.tauSelection = config.readNameAndSelection(self.
taus)
405 alg.useDressedProperties = self.useDressedProperties
413 elif len(items) == 6:
419 elif len(items) == 9:
436 if items[0] !=
"JET_N":
438 if len(items) != 4
and len(items) != 5:
442 thisalg = f
'{self.selectionName}_NJET_{self.step}'
443 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
444 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
jets)
450 elif len(items) == 5:
461 if items[0] !=
"JET_N_BTAG":
463 if len(items) != 3
and len(items) != 4
and len(items) != 5:
467 thisalg = f
'{self.selectionName}_NBJET_{self.step}'
468 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
469 particles, selection = config.readNameAndSelection(self.
jets)
470 alg.particles = particles
471 alg.objectSelection = f
'{selection}&&{self.btagDecoration},as_char' if selection
else f
'{self.btagDecoration},as_char'
476 elif len(items) == 4:
479 customBtag = f
'ftag_select_{btagger}_{btagWP}'
480 alg.objectSelection = f
'{selection}&&{customBtag},as_char' if selection
else f
'{customBtag},as_char'
486 elif len(items) == 5:
489 customBtag = f
'ftag_select_{btagger}_{btagWP}'
490 alg.objectSelection = f
'{selection}&&{customBtag},as_char' if selection
else f
'{customBtag},as_char'
499 if items[0] !=
"PH_N":
501 if len(items) != 4
and len(items) != 5:
505 thisalg = f
'{self.selectionName}_NPH_{self.step}'
506 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
507 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
photons)
513 elif len(items) == 5:
524 if items[0] !=
"TAU_N":
526 if len(items) != 4
and len(items) != 5:
530 thisalg = f
'{self.selectionName}_NTAU_{self.step}'
531 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
532 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
taus)
538 elif len(items) == 5:
549 if items[0] !=
"LJET_N":
551 if len(items) != 4
and len(items) != 5:
553 thisalg = f
'{self.selectionName}_NLJET_{self.step}'
554 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
555 alg.particles, alg.objectSelection = config.readNameAndSelection(self.largeRjets)
561 elif len(items) == 5:
572 if items[0] !=
"LJETMASS_N":
574 if len(items) != 4
and len(items) != 5:
576 thisalg = f
'{self.selectionName}_NLJETMASS_{self.step}'
577 alg = config.createAlgorithm(
'CP::NObjectMassSelectorAlg', thisalg)
578 alg.particles, alg.objectSelection = config.readNameAndSelection(self.largeRjets)
584 elif len(items) == 5:
595 if items[0] !=
"LJETMASSWINDOW_N":
597 if len(items) != 5
and len(items) != 6
and len(items) != 7:
599 thisalg = f
'{self.selectionName}_NLJETMASSWINDOW_{self.step}'
600 alg = config.createAlgorithm(
'CP::NLargeRJetMassWindowSelectorAlg', thisalg)
601 alg.ljets, alg.ljetSelection = config.readNameAndSelection(self.largeRjets)
602 vetoMode = items[-1] ==
'veto' or items[-1] ==
'VETO'
603 if len(items) == 5
or (len(items) == 6
and vetoMode):
608 alg.vetoMode = vetoMode
609 elif (len(items) == 6
and not vetoMode)
or len(items) == 7:
616 alg.vetoMode = vetoMode
623 if items[0] !=
"JET_N_GHOST":
625 if len(items) != 4
and len(items) != 5:
627 thisalg = f
'{self.selectionName}_NJETGHOST_{self.step}'
628 alg = config.createAlgorithm(
'CP::JetNGhostSelectorAlg', thisalg)
629 alg.jets, alg.jetSelection = config.readNameAndSelection(self.
jets)
631 alg.ghost = ghosts[0]
637 elif len(items) == 5:
647 if items[0] !=
"LJET_N_GHOST":
649 if len(items) != 4
and len(items) != 5:
651 thisalg = f
'{self.selectionName}_NLJETGHOST_{self.step}'
652 alg = config.createAlgorithm(
'CP::JetNGhostSelectorAlg', thisalg)
653 alg.jets, alg.jetSelection = config.readNameAndSelection(self.largeRjets)
655 alg.ghost = ghosts[0]
661 elif len(items) == 5:
671 if items[0] !=
"OBJ_N":
675 thisalg = f
'{self.selectionName}_NOBJ_{self.step}'
676 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
677 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
check_string(items[1]))
687 if items[0] !=
"MET":
693 thisalg = f
'{self.selectionName}_MET_{self.step}'
694 alg = config.createAlgorithm(
'CP::MissingETSelectorAlg', thisalg)
695 alg.met = config.readName(self.
met)
696 alg.metTerm = self.metTerm
705 if items[0] !=
"MWT":
711 thisalg = f
'{self.selectionName}_MWT_{self.step}'
712 alg = config.createAlgorithm(
'CP::TransverseMassSelectorAlg', thisalg)
713 alg.met = config.readName(self.
met)
714 alg.metTerm = self.metTerm
715 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
716 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
718 alg.useDressedProperties = self.useDressedProperties
727 if items[0] !=
"MET+MWT":
735 thisalg = f
'{self.selectionName}_METMWT_{self.step}'
736 alg = config.createAlgorithm(
'CP::MissingETPlusTransverseMassSelectorAlg', thisalg)
737 alg.met = config.readName(self.
met)
738 alg.metTerm = self.metTerm
739 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
740 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
742 alg.useDressedProperties = self.useDressedProperties
751 if items[0] !=
"MLL":
757 thisalg = f
'{self.selectionName}_MLL_{self.step}'
758 alg = config.createAlgorithm(
'CP::DileptonInvariantMassSelectorAlg', thisalg)
760 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
762 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
764 alg.useDressedProperties = self.useDressedProperties
773 if items[0] !=
"MLLWINDOW":
775 if len(items) != 3
and len(items) != 4:
779 thisalg = f
'{self.selectionName}_MLLWINDOW_{self.step}'
780 alg = config.createAlgorithm(
'CP::DileptonInvariantMassWindowSelectorAlg', thisalg)
782 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
784 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
786 alg.useDressedProperties = self.useDressedProperties
789 alg.vetoMode = (len(items) == 4
and self.
check_string(items[3]).lower() ==
"veto")
796 if not items
or len(items) > 4:
800 thisalg = f
'{self.selectionName}_OS_{self.step}'
801 alg = config.createAlgorithm(
'CP::ChargeSelectorAlg', thisalg)
802 if self.
electrons and (len(items) == 1
or "el" in items):
804 alg.truthElectrons, alg.truthElectronSelection = config.readNameAndSelection(self.
electrons)
806 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
807 if self.
muons and (len(items) == 1
or "mu" in items):
808 if "Particle" in self.
muons or "Truth" in self.
muons:
809 alg.truthMuons, alg.truthMuonSelection = config.readNameAndSelection(self.
muons)
811 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
812 if self.
taus and (len(items) == 1
or "tau" in items):
813 if "Particle" in self.
taus or "Truth" in self.
taus:
814 alg.truthTaus, alg.truthTauSelection = config.readNameAndSelection(self.
taus)
816 alg.taus, alg.tauSelection = config.readNameAndSelection(self.
taus)
824 if not items
or len(items) > 4:
828 thisalg = f
'{self.selectionName}_SS_{self.step}'
829 alg = config.createAlgorithm(
'CP::ChargeSelectorAlg', thisalg)
830 if self.
electrons and (len(items) == 1
or "el" in items):
832 alg.truthElectrons, alg.truthElectronSelection = config.readNameAndSelection(self.
electrons)
834 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
835 if self.
muons and (len(items) == 1
or "mu" in items):
836 if "Particle" in self.
muons or "Truth" in self.
muons:
837 alg.truthMuons, alg.truthMuonSelection = config.readNameAndSelection(self.
muons)
839 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
840 if self.
taus and (len(items) == 1
or "tau" in items):
841 if "Particle" in self.
taus or "Truth" in self.
taus:
842 alg.truthTaus, alg.truthTauSelection = config.readNameAndSelection(self.
taus)
844 alg.taus, alg.tauSelection = config.readNameAndSelection(self.
taus)
852 if items[0] !=
"MLL_OSSF":
854 if len(items) != 3
and len(items) != 4:
858 thisalg = f
'{self.selectionName}_MLL_OSSF_{self.step}'
859 alg = config.createAlgorithm(
'CP::DileptonOSSFInvariantMassWindowSelectorAlg', thisalg)
862 alg.truthElectrons, alg.truthElectronSelection = config.readNameAndSelection(self.
electrons)
864 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
866 if "Particle" in self.
muons or "Truth" in self.
muons:
867 alg.truthMuons, alg.truthMuonSelection = config.readNameAndSelection(self.
muons)
869 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
871 alg.useDressedProperties = self.useDressedProperties
874 alg.vetoMode = (len(items) == 4
and self.
check_string(items[3]).lower() ==
"veto")
881 if items[0] !=
"EVENTFLAG":
891 if items[0] !=
"GLOBALTRIGMATCH":
893 if len(items) != 1
and len(items) != 2 :
899 self.
setDecorationName(
None, config, f
"globalTriggerMatch{postfix}_%SYS%,as_char")
904 if items[0] !=
"RUN_NUMBER":
908 thisalg = f
'{self.selectionName}_RUN_NUMBER_{self.step}'
909 alg = config.createAlgorithm(
'CP::RunNumberSelectorAlg', thisalg)
912 alg.useRandomRunNumber = config.dataType()
is not DataType.Data
919 if items[0] !=
"SAVE":
923 thisalg = f
'{self.selectionName}_SAVE'
924 alg = config.createAlgorithm(
'CP::SaveFilterAlg', thisalg)
925 alg.FilterDescription = f
'events passing < {self.selectionName} >'
926 alg.eventDecisionOutputDecoration = f
'ignore_{self.selectionName}_%SYS%'
929 alg.selectionName = f
'pass_{self.selectionName}_%SYS%,as_char'
930 alg.decorationName = f
'ntuplepass_{self.selectionName}_%SYS%'
931 config.addOutputVar(
'EventInfo', f
'ntuplepass_{self.selectionName}_%SYS%', f
'pass_{self.selectionName}')
937 seq.append(EventCutFlowBlock())
add_NJET_selector(self, text, config)
setDecorationName(self, algorithm, config, decoration)
add_SUMNELNMU_selector(self, text, config)
raise_missinginput(self, collection)
extendObjectSelection(self, config, container, oldSelection, newSelection)
add_NEL_selector(self, text, config)
add_RUNNUMBER(self, text, config)
add_MLL_selector(self, text, config)
check_int(self, test, requirePositive=True)
add_METMWT_selector(self, text, config)
add_EVENTFLAG(self, text, config)
add_NLJETGHOST_selector(self, text, config)
add_NOBJ_selector(self, text, config)
add_NMU_selector(self, text, config)
add_MWT_selector(self, text, config)
add_SUMNLEPTONS_selector(self, text, config)
add_IMPORT(self, text, config)
add_NLJET_selector(self, text, config)
add_GLOBALTRIGMATCH(self, text, config)
raise_misconfig(self, text, keyword)
add_NBJET_selector(self, text, config)
add_SS_selector(self, text, config)
checkDecorationName(self, decoration)
add_NLJETMASS_selector(self, text, config)
check_float(self, test, requirePositive=True)
interpret(self, text, cfg)
add_OS_selector(self, text, config)
add_MET_selector(self, text, config)
add_NTAU_selector(self, text, config)
check_btagging(self, test)
add_NPH_selector(self, text, config)
add_MLLWINDOW_selector(self, text, config)
add_SAVE(self, text, config)
add_NJETGHOST_selector(self, text, config)
add_NLJETMASSWINDOW_selector(self, text, config)
add_MLL_OSSF_selector(self, text, config)
std::vector< std::string > split(const std::string &s, const std::string &t=":")