5from functools
import partial
7from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
8from AnalysisAlgorithmsConfig.ConfigSequence
import groupBlocks
9from AsgAnalysisAlgorithms.AsgAnalysisConfig
import EventCutFlowBlock
10from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType, ConfigDeprecationWarning
14 """Raised when an EXPR cut uses a syntactically valid but unimplemented
15 feature (an unknown variable or collection). Subclasses ValueError so the
16 framework's existing tolerance and `except ValueError` still apply."""
20 """Raised when an EXPR cut is internally inconsistent or ill-typed (wrong
21 operand count, an operation undefined for the given object, etc.)."""
25 """ConfigBlock for merging the output of various selection streams"""
28 super(EventSelectionMergerConfig, self).
__init__()
30 self.setBlockName(
'EventSelectionMerger')
31 self.addDependency(
'EventSelection', required=
True)
32 self.addOption(
'noFilter',
False, type=bool,
33 info=
"do not apply an event filter, i.e. setting it to `False` "
34 "removes events not passing the full list of selection cuts.")
37 """Return the instance name for this block"""
45 selections = config.getContainerMeta(
'EventInfo',
'eventSelectionNames',
47 selections = [sel
for sel
in selections
if not sel.startswith(
"pass_SUB")]
49 alg = config.createAlgorithm(
'CP::SaveFilterAlg',
50 'EventSelectionMerger' + selections[0].
split(
"_%SYS%")[0])
51 alg.FilterDescription =
'events passing at least one EventSelection'
52 alg.eventDecisionOutputDecoration =
'ignore_anySelection_%SYS%'
53 alg.selection =
'||'.join([sel +
',as_char' for sel
in selections])
54 alg.noFilter = self.noFilter
55 alg.selectionName =
'pass_anySelection_%SYS%'
56 alg.decorationName =
'ntuplepass_anySelection_%SYS%'
60 """ConfigBlock for interpreting text-based event selections"""
65 "EL_N": (
"electrons",
"NEL"),
66 "MU_N": (
"muons",
"NMU"),
67 "JET_N": (
"jets",
"NJET"),
68 "PH_N": (
"photons",
"NPH"),
69 "TAU_N": (
"taus",
"NTAU"),
70 "LJET_N": (
"largeRjets",
"NLJET"),
74 super(EventSelectionConfig, self).
__init__()
75 self.setBlockName(
'EventSelection')
76 self.addOption(
'selectionName',
'', type=str,
78 info=
"the name of the event selection, used to uniquely identify "
79 "the `EventSelectionConfig` block.")
80 self.addOption(
'electrons',
"", type=str,
81 info=
"the input electron container, with a possible selection, in "
82 "the format `container` or `container.selection`.")
83 self.addOption(
'muons',
"", type=str,
84 info=
"the input muon container, with a possible selection, in the "
85 "format `container` or `container.selection`.")
86 self.addOption(
'jets',
"", type=str,
87 info=
"the input jet container, with a possible selection, in the "
88 "format `container` or `container.selection`.")
89 self.addOption(
'largeRjets',
"", type=str,
90 info=
"the large-R jet container, with a possible selection, in "
91 "the format `container` or `container.selection`.")
92 self.addOption(
'photons',
"", type=str,
93 info=
"the input photon container, with a possible selection, in "
94 "the format `container` or `container.selection`.")
95 self.addOption(
'taus',
"", type=str,
96 info=
"the input tau-jet container, with a possible selection, in "
97 "the format `container` or `container.selection`.")
98 self.addOption(
'met',
"", type=str,
99 info=
"the input MET container.")
100 self.addOption(
'metTerm',
"Final", type=str,
101 info=
"the MET term to use when computing MET-based quantities.")
102 self.addOption(
'btagDecoration',
"", type=str,
103 info=
"the b-tagging decoration to use when defining b-jets.")
104 self.addOption(
'preselection',
"", type=str,
105 info=
"the event-wise selection flag to start this event selection "
107 self.addOption(
'selectionCuts',
"", type=str,
109 info=
"a single string listing one selection cut per line. "
110 "See [available keywords](https://topcptoolkit.docs.cern.ch/latest/settings/eventselection/#available-keywords).")
111 self.addOption(
'debugMode',
False, type=bool,
112 info=
"whether to create an output branch for every single line "
113 "of the selection cuts. Setting it to `False` only saves the"
115 self.addOption(
'useDressedProperties',
True, type=bool,
116 info=
"whether to use dressed truth electron and truth muon "
117 "kinematics rather than simple 4-vector kinematics.")
124 """Return the instance name for this block"""
128 """Map each keyword to its handler. Dispatch is an exact lookup on the
129 first token, which removes the ordering fragility of token-membership."""
145 "OS": partial(self.
_add_charge, osMode=
True, tag=
"OS"),
146 "SS": partial(self.
_add_charge, osMode=
False, tag=
"SS"),
155 for kw, (attr, tag)
in self.
_NOBJECT.items():
160 existing = config.getContainerMeta(
'EventInfo',
'eventSelectionNames', defaultValue=[])
161 config.setContainerMeta(
'EventInfo',
'eventSelectionNames',
162 existing + [f
'pass_{self.selectionName}_%SYS%'], allowOverwrite=
True)
171 if self.selectionCuts
is None:
172 raise ValueError (
"[EventSelectionConfig] You must provide the 'selectionCuts' option to 'EventSelectionConfig': "
173 "a single string where each line represents a different selection cut to apply in order.")
174 for line
in self.selectionCuts.
split(
"\n"):
183 if not text
or text.startswith(
"#"):
186 keyword = text.split()[0]
189 raise ValueError (f
"[EventSelectionConfig] The following selection cut is not recognised! --> {text}")
197 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Check {keyword} in: {text}")
200 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Missing input collection for {collection}")
203 """Validate the leading keyword and the number of arguments."""
204 if items[0] != keyword:
206 if len(items)
not in validCounts:
212 if not requirePositive
or value >= 0:
215 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Float {test} is not positive!")
217 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be a float, not {type(test)}!")
222 if value == float(test):
223 if not requirePositive
or value >= 0:
226 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! Int {test} us not positive!")
228 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be an int, not a float!")
230 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be an int, not {type(test)}")
233 if not isinstance(test, str):
234 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be a string, not a number!")
249 raise KeyError (f
"[EventSelectionConfig] Misconfiguration! {test} should be one of {list(mapping.keys())}")
252 test = test.split(
":")
254 raise ValueError (f
"[EventSelectionConfig] Misconfiguration! {test} should be provided as 'btagger:btagWP'")
260 values = test.split(
"!")
262 "B":
"GhostBHadronsFinalCount",
263 "C":
"GhostCHadronsFinalCount",
264 "T":
"GhostTQuarksFinalCount",
265 "W":
"GhostWBosonsCount",
266 "Z":
"GhostZBosonsCount",
267 "H":
"GhostHBosonsCount",
268 "TAU":
"GhostTausFinalCount"
270 return [ghost_map.get(value.upper(), value)
for value
in values]
280 self.
cutflow.append( decoration )
281 if algorithm
is not None:
282 algorithm.decorationName = f
'{decoration},as_char'
285 config.addOutputVar(
'EventInfo', decoration, decoration.split(
"_%SYS%")[0])
291 config.addSelection(
'EventInfo',
'', decoration)
297 decoration = decoration.split(
"&&")
298 decoration = [sub +
',as_char' if ',as_char' not in sub
else sub
for sub
in decoration]
299 return '&&'.join(decoration)
303 return oldSelection +
"&&" + config.getFullSelection(container, newSelection)
305 return config.getFullSelection(container, newSelection)
312 """Enable dressed kinematics when any of the given electron/muon
313 containers is a truth container. Dressed kinematics only exist for
314 truth electrons and muons, so only those specs should be passed here."""
315 if any(spec
and (
"Particle" in spec
or "Truth" in spec)
for spec
in specs):
316 alg.useDressedProperties = self.useDressedProperties
319 """Parse the trailing `[extraSel] value sign count` grammar (4 or 5
320 tokens), applying the optional extra object selection in place.
321 Returns (value, sign, count)."""
325 config, container, alg.objectSelection, extraSel)
334 """Assign (name, selection) to the reco or truth handles of `alg`
335 depending on whether `spec` points to a truth container.
336 `reco`/`truth` are (nameAttr, selectionAttr) pairs."""
337 name, sel = config.readNameAndSelection(spec)
338 nameAttr, selAttr = truth
if (
"Particle" in spec
or "Truth" in spec)
else reco
339 setattr(alg, nameAttr, name)
340 setattr(alg, selAttr, sel)
347 """Generic builder for the N-object pT selectors (EL_N, MU_N, JET_N,
348 PH_N, TAU_N, LJET_N): identical except for the source container, which
349 is always required since the cut acts on it."""
351 spec = getattr(self, attr)
354 if len(items)
not in (4, 5):
356 thisalg = f
'{self.selectionName}_{tag}_{self.step}'
357 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
358 alg.particles, alg.objectSelection = config.readNameAndSelection(spec)
359 if attr
in (
"electrons",
"muons"):
363 items, config, alg, spec.split(
".")[0])
374 self.
currentDecoration = f
'{self.currentDecoration},as_char&&pass_{region}_%SYS%'
376 imported_cuts = [cut
for cut
in config.getSelectionCutFlow(
'EventInfo',
'')
if cut.startswith(region)]
385 thisalg = f
'{self.selectionName}_NBJET_{self.step}'
386 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
387 particles, selection = config.readNameAndSelection(self.
jets)
388 alg.particles = particles
389 alg.objectSelection = f
'{selection}&&{self.btagDecoration},as_char' if selection
else f
'{self.btagDecoration},as_char'
394 elif len(items) == 4:
397 customBtag = f
'ftag_select_{btagger}_{btagWP}'
398 alg.objectSelection = f
'{selection}&&{customBtag},as_char' if selection
else f
'{customBtag},as_char'
404 elif len(items) == 5:
407 customBtag = f
'ftag_select_{btagger}_{btagWP}'
408 alg.objectSelection = f
'{selection}&&{customBtag},as_char' if selection
else f
'{customBtag},as_char'
417 self.
_check_args(items,
"SUM_EL_N_MU_N", (4, 5, 7))
420 thisalg = f
'{self.selectionName}_SUMNELNMU_{self.step}'
421 alg = config.createAlgorithm(
'CP::SumNLeptonPtSelectorAlg', thisalg)
422 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
423 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
431 elif len(items) == 5:
436 elif len(items) == 7:
450 self.
_check_args(items,
"SUM_EL_N_MU_N_TAU_N", (4, 6, 9))
453 thisalg = f
'{self.selectionName}_SUMNLEPTONS_{self.step}'
454 alg = config.createAlgorithm(
'CP::SumNLeptonPtSelectorAlg', thisalg)
455 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
456 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
457 alg.taus, alg.tauSelection = config.readNameAndSelection(self.
taus)
466 elif len(items) == 6:
472 elif len(items) == 9:
490 thisalg = f
'{self.selectionName}_NLJETMASS_{self.step}'
491 alg = config.createAlgorithm(
'CP::NObjectMassSelectorAlg', thisalg)
492 alg.particles, alg.objectSelection = config.readNameAndSelection(self.largeRjets)
495 items, config, alg, self.largeRjets.
split(
".")[0])
501 self.
_check_args(items,
"LJETMASSWINDOW_N", (5, 6, 7))
502 thisalg = f
'{self.selectionName}_NLJETMASSWINDOW_{self.step}'
503 alg = config.createAlgorithm(
'CP::NLargeRJetMassWindowSelectorAlg', thisalg)
504 alg.ljets, alg.ljetSelection = config.readNameAndSelection(self.largeRjets)
505 vetoMode = items[-1] ==
'veto' or items[-1] ==
'VETO'
506 if len(items) == 5
or (len(items) == 6
and vetoMode):
511 alg.vetoMode = vetoMode
512 elif (len(items) == 6
and not vetoMode)
or len(items) == 7:
519 alg.vetoMode = vetoMode
527 thisalg = f
'{self.selectionName}_NJETGHOST_{self.step}'
528 alg = config.createAlgorithm(
'CP::JetNGhostSelectorAlg', thisalg)
529 alg.jets, alg.jetSelection = config.readNameAndSelection(self.
jets)
531 alg.ghost = ghosts[0]
537 elif len(items) == 5:
548 thisalg = f
'{self.selectionName}_NLJETGHOST_{self.step}'
549 alg = config.createAlgorithm(
'CP::JetNGhostSelectorAlg', thisalg)
550 alg.jets, alg.jetSelection = config.readNameAndSelection(self.largeRjets)
552 alg.ghost = ghosts[0]
558 elif len(items) == 5:
569 thisalg = f
'{self.selectionName}_NOBJ_{self.step}'
570 alg = config.createAlgorithm(
'CP::NObjectPtSelectorAlg', thisalg)
571 alg.particles, alg.objectSelection = config.readNameAndSelection(self.
check_string(items[1]))
584 thisalg = f
'{self.selectionName}_MET_{self.step}'
585 alg = config.createAlgorithm(
'CP::MissingETSelectorAlg', thisalg)
586 alg.met = config.readName(self.
met)
587 alg.metTerm = self.metTerm
599 thisalg = f
'{self.selectionName}_MWT_{self.step}'
600 alg = config.createAlgorithm(
'CP::TransverseMassSelectorAlg', thisalg)
601 alg.met = config.readName(self.
met)
602 alg.metTerm = self.metTerm
603 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
604 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
619 thisalg = f
'{self.selectionName}_METMWT_{self.step}'
620 alg = config.createAlgorithm(
'CP::MissingETPlusTransverseMassSelectorAlg', thisalg)
621 alg.met = config.readName(self.
met)
622 alg.metTerm = self.metTerm
623 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
624 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
637 thisalg = f
'{self.selectionName}_MLL_{self.step}'
638 alg = config.createAlgorithm(
'CP::DileptonInvariantMassSelectorAlg', thisalg)
640 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
642 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
655 thisalg = f
'{self.selectionName}_MLLWINDOW_{self.step}'
656 alg = config.createAlgorithm(
'CP::DileptonInvariantMassWindowSelectorAlg', thisalg)
658 alg.electrons, alg.electronSelection = config.readNameAndSelection(self.
electrons)
660 alg.muons, alg.muonSelection = config.readNameAndSelection(self.
muons)
664 alg.vetoMode = (len(items) == 4
and self.
check_string(items[3]).lower() ==
"veto")
670 """Builder shared by OS and SS: same algorithm, opposite charge mode."""
672 if not items
or len(items) > 4:
676 thisalg = f
'{self.selectionName}_{tag}_{self.step}'
677 alg = config.createAlgorithm(
'CP::ChargeSelectorAlg', thisalg)
678 allLeptons = (len(items) == 1)
679 if self.
electrons and (allLeptons
or "el" in items):
681 (
'electrons',
'electronSelection'),
682 (
'truthElectrons',
'truthElectronSelection'))
683 if self.
muons and (allLeptons
or "mu" in items):
685 (
'muons',
'muonSelection'),
686 (
'truthMuons',
'truthMuonSelection'))
687 if self.
taus and (allLeptons
or "tau" in items):
689 (
'taus',
'tauSelection'),
690 (
'truthTaus',
'truthTauSelection'))
701 thisalg = f
'{self.selectionName}_MLL_OSSF_{self.step}'
702 alg = config.createAlgorithm(
'CP::DileptonOSSFInvariantMassWindowSelectorAlg', thisalg)
705 (
'electrons',
'electronSelection'),
706 (
'truthElectrons',
'truthElectronSelection'))
709 (
'muons',
'muonSelection'),
710 (
'truthMuons',
'truthMuonSelection'))
714 alg.vetoMode = (len(items) == 4
and self.
check_string(items[3]).lower() ==
"veto")
733 self.
setDecorationName(
None, config, f
"globalTriggerMatch{postfix}_%SYS%,as_char")
739 thisalg = f
'{self.selectionName}_RUN_NUMBER_{self.step}'
740 alg = config.createAlgorithm(
'CP::RunNumberSelectorAlg', thisalg)
743 alg.useRandomRunNumber = config.dataType()
is not DataType.Data
754 "jet": (
"jets",
False,
False),
755 "bjet": (
"jets",
True,
False),
756 "el": (
"electrons",
False,
False),
757 "mu": (
"muons",
False,
False),
758 "tau": (
"taus",
False,
False),
759 "ph": (
"photons",
False,
False),
760 "ljet": (
"largeRjets",
False,
False),
761 "met": (
"met",
False,
True),
767 "dR": (2, 2,
",",
True,
False),
768 "dEta": (2, 2,
",",
True,
False),
769 "dPhi": (2, 2,
",",
False,
True),
770 "m": (1,
None,
"+",
False,
False),
771 "e": (1,
None,
"+",
False,
False),
772 "pt": (1,
None,
"+",
False,
True),
773 "eta": (1, 1,
None,
True,
False),
774 "phi": (1, 1,
None,
False,
True),
777 _EXPR_TOKEN_RE = re.compile(
r"""
778 (?P<NUM>\d+\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+|\d+)
779 | (?P<GE>>=) | (?P<LE><=) | (?P<EQ>==) | (?P<LT><) | (?P<GT>>)
780 | (?P<ID>[A-Za-z_][A-Za-z0-9_]*)
781 | (?P<LP>\() | (?P<RP>\)) | (?P<LB>\[) | (?P<RB>\])
782 | (?P<COMMA>,) | (?P<PLUS>\+) | (?P<MINUS>-)
788 while pos < len(text):
792 f
"[EventSelectionConfig] EXPR: cannot parse near '{text[pos:]}'")
794 if m.lastgroup !=
"WS":
795 tokens.append((m.lastgroup, m.group()))
796 tokens.append((
"END",
""))
812 f
"[EventSelectionConfig] EXPR: expected {kind}, got '{tok[1]}'")
822 return variable, separator, operands, sign, refValue
829 while self.
_expr_peek()[0]
in (
"COMMA",
"PLUS"):
831 if separator
is None:
833 elif sep != separator:
835 "[EventSelectionConfig] EXPR: cannot mix ',' and '+' separators")
838 return variable, separator, operands
851 if tok[0]
not in (
"LT",
"GT",
"EQ",
"GE",
"LE"):
853 f
"[EventSelectionConfig] EXPR: expected a comparison operator, got '{tok[1]}'")
862 return -value
if negative
else value
867 f
"[EventSelectionConfig] EXPR: variable '{variable}' is not available. "
868 "Please request it from the EventSelectionAlgorithms developers.")
869 minN, maxN, sep, _needsEta, metOk = self.
_EXPR_VARS[variable]
871 if n < minN
or (maxN
is not None and n > maxN):
872 expected = f
"{minN}" if maxN == minN
else (f
"{minN}+" if maxN
is None else f
"{minN}-{maxN}")
874 f
"[EventSelectionConfig] EXPR: '{variable}' takes {expected} operand(s), got {n}")
875 if n > 1
and separator != sep:
876 want = {
",":
"','",
"+":
"'+'"}.
get(sep, str(sep))
878 f
"[EventSelectionConfig] EXPR: '{variable}' operands must be separated by {want}")
879 for coll, index
in operands:
882 f
"[EventSelectionConfig] EXPR: collection '{coll}' is not available. "
883 "Please request it from the EventSelectionAlgorithms developers.")
888 f
"[EventSelectionConfig] EXPR: 'met' is not valid for '{variable}'")
889 if index
is not None:
891 "[EventSelectionConfig] EXPR: 'met' cannot be indexed")
894 "[EventSelectionConfig] EXPR: 'met' cannot be combined in a sum")
897 f
"[EventSelectionConfig] EXPR: '{coll}' must be indexed, e.g. {coll}[0]")
900 body = text[len(
"EXPR"):].
strip()
906 thisalg = f
'{self.selectionName}_EXPR_{self.step}'
907 alg = config.createAlgorithm(
'CP::ObjectKinematicSelectorAlg', thisalg)
908 alg.variable = variable
910 alg.refValue = refValue
912 operandKinds, collections, selections, indices = [], [], [], []
914 for coll, index
in operands:
916 container = getattr(self, opt)
920 operandKinds.append(
"MET")
923 operandKinds.append(
"PARTICLE")
924 name, selection = config.readNameAndSelection(container)
928 selection = (f
'{selection}&&{self.btagDecoration},as_char'
929 if selection
else f
'{self.btagDecoration},as_char')
930 collections.append(name)
931 selections.append(selection)
932 indices.append(index)
934 alg.operandKinds = operandKinds
935 alg.collections = collections
936 alg.selections = selections
937 alg.indices = indices
941 alg.met = config.readName(self.
met)
942 alg.metTerm = self.metTerm
950 _EVENTVAR_TYPES = {
"float":
"floatVariable",
"int":
"intVariable",
"double":
"doubleVariable"}
958 self.
raise_misconfig(text, f
"value type (one of {sorted(self._EVENTVAR_TYPES)})")
960 thisalg = f
'{self.selectionName}_EVENTVAR_{self.step}'
961 alg = config.createAlgorithm(
'CP::EventScalarSelectorAlg', thisalg)
965 alg.refValue = self.
check_float(items[4], requirePositive=
False)
977 "[EventSelectionConfig] The 'SAVE' keyword is deprecated: the event "
978 "filter is now created automatically at the end of each EventSelection "
979 f
"block. Please remove the 'SAVE' line from selection '{self.selectionName}'.",
980 category=ConfigDeprecationWarning, stacklevel=2)
984 """Create the SaveFilterAlg that turns the accumulated event selection
985 into a named, persisted selection (and ntuple branch). Called once per
986 block, automatically at the end of makeAlgs."""
987 thisalg = f
'{self.selectionName}_SAVE'
988 alg = config.createAlgorithm(
'CP::SaveFilterAlg', thisalg)
989 alg.FilterDescription = f
'events passing < {self.selectionName} >'
990 alg.eventDecisionOutputDecoration = f
'ignore_{self.selectionName}_%SYS%'
993 alg.selectionName = f
'pass_{self.selectionName}_%SYS%,as_char'
994 alg.decorationName = f
'ntuplepass_{self.selectionName}_%SYS%'
995 config.addOutputVar(
'EventInfo', f
'ntuplepass_{self.selectionName}_%SYS%', f
'pass_{self.selectionName}')
1002 seq.append(EventCutFlowBlock())
setDecorationName(self, algorithm, config, decoration)
add_SUMNELNMU_selector(self, text, config)
raise_missinginput(self, collection)
extendObjectSelection(self, config, container, oldSelection, newSelection)
_expr_parse_operand(self)
add_RUNNUMBER(self, text, config)
add_MLL_selector(self, text, config)
check_int(self, test, requirePositive=True)
add_METMWT_selector(self, text, config)
add_EVENTVAR_selector(self, text, config)
add_EVENTFLAG(self, text, config)
_add_charge(self, text, config, *, osMode, tag)
add_NLJETGHOST_selector(self, text, config)
add_NOBJ_selector(self, text, config)
add_MWT_selector(self, text, config)
_route_lepton(self, alg, config, spec, reco, truth)
add_SUMNLEPTONS_selector(self, text, config)
add_IMPORT(self, text, config)
_add_nobject(self, text, config, *, attr, tag)
_expr_parse_funcall(self)
add_GLOBALTRIGMATCH(self, text, config)
raise_misconfig(self, text, keyword)
_expr_parse(self, tokens)
add_NBJET_selector(self, text, config)
_expr_validate(self, variable, separator, operands)
checkDecorationName(self, decoration)
add_NLJETMASS_selector(self, text, config)
_val_sign_count(self, items, config, alg, container)
check_float(self, test, requirePositive=True)
interpret(self, text, cfg)
_check_args(self, items, keyword, validCounts)
_maybe_dressed(self, alg, *specs)
_expr_tokenize(self, text)
add_MET_selector(self, text, config)
check_btagging(self, test)
add_EXPR_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)
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
std::vector< std::string > split(const std::string &s, const std::string &t=":")
bool match(std::string s1, std::string s2)
match the individual directories of two strings
void handler(int sig)
signal handler