Skip to content

Commit 94a0529

Browse files
committed
fix undefined varbinning name in config parser, debug logging of selection counts and warn if total is zero, add test for non-exclusive selections and empty selections
1 parent 92409cf commit 94a0529

File tree

2 files changed

+43
-6
lines changed

2 files changed

+43
-6
lines changed

pisa/core/pipeline.py

+42-4
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,8 @@ def assert_varbinning_compat(self):
653653
)
654654
raise ValueError(
655655
"When a variable binning is used, all stages need to set "
656-
f"apply_mode='events', but {str_incompat} do(es) not!"
656+
f"apply_mode='events', but '{str_incompat}' of '{self.name}' "
657+
"do(es) not!"
657658
)
658659

659660
def assert_exclusive_varbinning(self, output_binning=None):
@@ -678,14 +679,33 @@ def assert_exclusive_varbinning(self, output_binning=None):
678679
nselections = output_binning.nselections
679680
if isinstance(selections, list):
680681
# list of selection-criteria strings
682+
# perform and report sanity checks on selected event counts
683+
# total count per selection across all containers
684+
tot_sel_counts = {sel: 0 for sel in selections}
681685
for c in self.data:
682686
keep = np.zeros(c.size)
683-
for i in range(nselections):
684-
keep += c.get_keep_mask(selections[i])
687+
# Looping over all selections for a fixed container is
688+
# sufficient to detect overlaps
689+
for sel in selections:
690+
keep_mask = c.get_keep_mask(sel)
691+
keep += keep_mask
692+
# number of events selected from this container
693+
sel_count = np.sum(keep_mask)
694+
logging.debug(f"'{c.name}' selected by '{sel}': {sel_count}")
695+
tot_sel_counts[sel] += sel_count
685696
if not np.all(keep <= 1):
686697
raise ValueError(
687-
f"Selections {selections} are not mutually exclusive!"
698+
f"Selections {selections} are not mutually exclusive for "
699+
f"'{c.name}' (at least) in pipeline '{self.name}'!"
688700
)
701+
# Warn on empty selections (don't assume that this must be an error)
702+
empty_sels = [sel for sel in selections if tot_sel_counts[sel] == 0]
703+
if empty_sels:
704+
empty_sels_str = ", ".join(empty_sels)
705+
logging.warning(
706+
f"There are empty selections in pipeline '{self.name}': "
707+
f"'{empty_sels_str}'"
708+
)
689709

690710
@property
691711
def output_binning(self):
@@ -795,6 +815,24 @@ def test_Pipeline():
795815
else:
796816
assert False
797817

818+
# also verify that pipeline correctly detects non-exclusive selections
819+
p.stages[2].apply_mode = "events"
820+
vb = p.output_binning
821+
# define a selection string which will simply be repeated
822+
assert vb.nselections > 1
823+
sel = ["pid > 0"] * vb.nselections
824+
invalid_vb = VarBinning(binnings=vb.binnings, selections=sel)
825+
try:
826+
p.output_binning = invalid_vb
827+
except ValueError:
828+
pass
829+
else:
830+
assert False
831+
832+
# pipeline should accept any empty selections
833+
sel[-1] = "pid > np.inf"
834+
invalid_vb = VarBinning(binnings=vb.binnings, selections=sel)
835+
p.output_binning = invalid_vb
798836

799837
# ----- Most of this below cang go (?) ---
800838

pisa/utils/config_parser.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -676,8 +676,7 @@ def parse_pipeline_config(config):
676676

677677
binning_dict[binning] = VarBinning(
678678
binnings=multibins,
679-
selections=bin_split,
680-
name=binning,
679+
selections=bin_split
681680
)
682681

683682
else:

0 commit comments

Comments
 (0)