@@ -653,7 +653,8 @@ def assert_varbinning_compat(self):
653
653
)
654
654
raise ValueError (
655
655
"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!"
657
658
)
658
659
659
660
def assert_exclusive_varbinning (self , output_binning = None ):
@@ -678,14 +679,33 @@ def assert_exclusive_varbinning(self, output_binning=None):
678
679
nselections = output_binning .nselections
679
680
if isinstance (selections , list ):
680
681
# 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 }
681
685
for c in self .data :
682
686
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
685
696
if not np .all (keep <= 1 ):
686
697
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 } '!"
688
700
)
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
+ )
689
709
690
710
@property
691
711
def output_binning (self ):
@@ -795,6 +815,24 @@ def test_Pipeline():
795
815
else :
796
816
assert False
797
817
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
798
836
799
837
# ----- Most of this below cang go (?) ---
800
838
0 commit comments