@@ -134,18 +134,55 @@ def get_selector(self, year=None):
134134 else :
135135 return self .selector
136136
137+ def get_type (self ):
138+ if self .isData :
139+ return data_key
140+ elif self .isSignal :
141+ return "signal"
142+ else :
143+ return "bg"
144+
137145
138146@dataclass
139- class Channel :
140- """Channel."""
147+ class HLT :
148+ """HLT."""
149+
150+ name : str # "HLT_" prefix will automatically be removed
151+ dataset : str # which dataset e.g. JetMET, Muon etc.
152+ years : list [str ] = None # which years? defaults to union of `mc_years` and `data_years`
153+ mc_years : list [str ] = None # which years for MC? defaults to input `years`
154+ data_years : list [str ] = None # which years for data? defaults to input `years`
155+
156+ def __post_init__ (self ):
157+ if self .years is None and (self .mc_years is None or self .data_years is None ):
158+ raise ValueError (
159+ f"Invalid HLT { self .name } : either `years` or (`mc_years` and `data_years`) must be provided"
160+ )
161+
162+ if self .years is None :
163+ self .years = list (set (self .mc_years + self .data_years ))
164+
165+ if self .mc_years is None :
166+ self .mc_years = self .years
141167
142- key : str # key in dictionaries etc.
143- label : str # label for plotting
144- data_samples : list [str ] # datasets for this channel
145- triggers : list [str ] | dict [str , list [str ]] # list of triggers or dict of triggers per year
146- isLepton : bool # lepton channel or fully hadronic
147- lepton_dataset : str = None # lepton dataset (if applicable)
148- lepton_triggers : str = None # lepton triggers (if applicable)
168+ if self .data_years is None :
169+ self .data_years = self .years
170+
171+ if self .name .startswith ("HLT_" ):
172+ self .name = self .name [4 :]
173+
174+ def check_year (self , year : str , data_only : bool = False , mc_only : bool = False ) -> bool :
175+ """Check if the HLT is valid for a given year, optionally for data or MC only"""
176+ if data_only and mc_only :
177+ raise ValueError ("data_only and mc_only cannot both be True" )
178+
179+ if data_only and year not in self .data_years :
180+ return False
181+
182+ if mc_only and year not in self .mc_years :
183+ return False
184+
185+ return year in self .years
149186
150187
151188@contextlib .contextmanager
@@ -406,7 +443,8 @@ def load_sample(
406443 events = pd .read_parquet (parquet_path , filters = filters , columns = load_columns )
407444 except Exception :
408445 warnings .warn (
409- f"Can't read file with requested columns/filters for { load_sample } !" , stacklevel = 1
446+ f"Can't read file with requested columns/filters for { load_sample } !" ,
447+ stacklevel = 1 ,
410448 )
411449 continue
412450
@@ -497,7 +535,10 @@ def load_samples(
497535 continue
498536
499537 sample_path = data_dir / sample
500- parquet_path , pickles_path = sample_path / "parquet" , sample_path / "pickles"
538+ parquet_path , pickles_path = (
539+ sample_path / "parquet" ,
540+ sample_path / "pickles" ,
541+ )
501542
502543 # no parquet directory?
503544 if not parquet_path .exists ():
@@ -510,7 +551,8 @@ def load_samples(
510551 except Exception :
511552 events = pd .read_parquet (parquet_path , filters = filters , columns = load_columns )
512553 warnings .warn (
513- f"Can't read file with requested columns/filters for { sample } !" , stacklevel = 1
554+ f"Can't read file with requested columns/filters for { sample } !" ,
555+ stacklevel = 1 ,
514556 )
515557 continue
516558
@@ -623,7 +665,6 @@ def tau32FittedSF_4(events: pd.DataFrame):
623665
624666
625667def makeHH (events : pd .DataFrame , key : str , mass : str ):
626-
627668 h1 = vector .array (
628669 {
629670 "pt" : events [key ]["bbFatJetPt" ].to_numpy ()[:, 0 ],
0 commit comments