def determine_number_of_triggers(hist: Hist, jet_pt: analysis_objects.JetPtBin) -> int: """ Determine the number of triggers for the specific analysis parameters. When retrieving the number of triggers, carefully note the information below: .. code-block:: python >>> hist = ROOT.TH1D("test", "test", 10, 0, 10) >>> x = 2, y = 5 >>> hist.FindBin(x) 2 >>> hist.FindBin(x+epsilon) 2 >>> hist.FindBin(y) 6 >>> hist.FindBin(y-epsilon) 5 Note: The bin + epsilon on the lower bin is not strictly necessary, but it is used for consistency. Note: This bin + epsilon technique is frequently used when determining projector bin ends. Args: hist: Histogram containing the number of triggers. jet_pt: Jet pt for which we want to know the number of triggers. Returns: Number of triggers for the selected analysis parameters. """ #logger.debug( # f"Find bin({jet_pt.range.min} + epsilon): " # f"{hist.FindBin(jet_pt.range.min + epsilon)} to " # f"Find bin({jet_pt.range.max} - epsilon): " # f"{hist.FindBin(jet_pt.range.max - epsilon)}" #) number_of_triggers: int = hist.Integral( hist.FindBin(jet_pt.range.min + epsilon), hist.FindBin(jet_pt.range.max - epsilon)) logger.info( f"n_trig for [{jet_pt.range.min}, {jet_pt.range.max}): {number_of_triggers}" ) return number_of_triggers
def calculate_systematic_2D( nominal: Hist, variation: Hist, signal_dominated: analysis_objects.AnalysisBin, background_dominated: analysis_objects.AnalysisBin) -> float: """ Calculate a systematic in 2D. Args: nominal: Nominal hist. variation: Systematically varied hist. signal_dominated: Signal dominated region. Background_dominated: Background dominated region. Returns: The systematic calculated over the specified ranges. """ # Calculate the nominal integral in the signal region nominal_signal = nominal.Integral( 1, nominal.GetXaxis().GetNbins(), nominal.GetYaxis().FindBin(-1.0 * signal_dominated.max + epsilon), nominal.GetYaxis().FindBin(signal_dominated.max - epsilon), ) # And in the background dominated region nominal_background = nominal.Integral( 1, nominal.GetXaxis().GetNbins(), nominal.GetYaxis().FindBin(-1.0 * background_dominated.max + epsilon), nominal.GetYaxis().FindBin(-1.0 * background_dominated.min - epsilon), ) + nominal.Integral( 1, nominal.GetXaxis().GetNbins(), nominal.GetYaxis().FindBin(background_dominated.min + epsilon), nominal.GetYaxis().FindBin(background_dominated.max - epsilon), ) # Calculate the variation integral in the signal region variation_signal = variation.Integral( 1, variation.GetXaxis().GetNbins(), variation.GetYaxis().FindBin(-1.0 * signal_dominated.max + epsilon), variation.GetYaxis().FindBin(signal_dominated.max - epsilon), ) # And in the background dominated region variation_background = variation.Integral( 1, variation.GetXaxis().GetNbins(), variation.GetYaxis().FindBin(-1.0 * background_dominated.max + epsilon), variation.GetYaxis().FindBin(-1.0 * background_dominated.min - epsilon), ) + variation.Integral( 1, variation.GetXaxis().GetNbins(), variation.GetYaxis().FindBin(background_dominated.min + epsilon), variation.GetYaxis().FindBin(background_dominated.max - epsilon), ) # Basically, signal / variation # NOTE: There is no need to apply the correlation scale factor because it will cancel # in the factor. factor = (nominal_signal / nominal_background) / (variation_signal / variation_background) # Help out mypy because it doesn't understand ROOT return cast(float, factor)