# -*- coding: utf-8 -*-
# Copyright (C) Scott Coughlin (2017-)
#
# This file is part of the XPypeline python package.
#
# hveto is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# hveto is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with hveto. If not, see <http://www.gnu.org/licenses/>.
# ---- Import standard modules to the python path.
import numpy
import pandas
[docs]def prep_triggers_for_ratio(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
typeOfCutPlus,typeOfCutCross,):
# Depending on wether you are requesting a two sided or one sided cut.
# construct specific ratio and cut arrays.
# Calculate all Ratio Values
plusRatioEoverI = numpy.log10(triggers[ePlusIndex] / triggers[iPlusIndex])
crossRatioEoverI = numpy.log10(triggers[eCrossIndex] / triggers[iCrossIndex])
plusRatioIoverE = numpy.log10(triggers[iPlusIndex] / triggers[ePlusIndex])
crossRatioIoverE = numpy.log10(triggers[iCrossIndex] / triggers[eCrossIndex])
if iNullIndex == 0:
triggers['nullenergy'] = numpy.ones(plusRatioEoverI.size)
nullRatioIoverE = triggers['nullenergy']
else:
nullRatioIoverE = numpy.log10(triggers[iNullIndex] / triggers[eNullIndex])
ratioArrayNull = nullRatioIoverE
if typeOfCutPlus == 'twosided':
ratioCutsPlus = numpy.log10(vetoPlusRange)
ratioCutsCross = numpy.log10(vetoCrossRange)
ratioCutsNull = numpy.log10(vetoNullRange)
ratioCutsPlus_repeated = numpy.atleast_2d(numpy.append(ratioCutsPlus,ratioCutsPlus)).T
ratioCutsCross_repeated = numpy.atleast_2d(numpy.append(ratioCutsCross,ratioCutsCross)).T
ratioCutsNull_repeated = numpy.atleast_2d(ratioCutsNull).T
ratioArrayPlus = pandas.concat((plusRatioEoverI, plusRatioIoverE), join='outer', axis=1)
ratioArrayCross = pandas.concat((crossRatioEoverI, crossRatioIoverE), join='outer', axis=1)
else:
ratioCutsPlus = numpy.log10(abs(vetoPlusRange))
ratioCutsCross = numpy.log10(abs(vetoCrossRange))
ratioCutsNull = numpy.log10(abs(vetoNullRange))
ratioCutsPlus_repeated = numpy.atleast_2d(ratioCutsPlus).T
ratioCutsCross_repeated = numpy.atleast_2d(ratioCutsCross).T
ratioCutsNull_repeated = numpy.atleast_2d(ratioCutsNull).T
if typeOfCutPlus == 'EoverI':
ratioArrayPlus = plusRatioEoverI
else:
ratioArrayPlus = plusRatioIoverE
if typeOfCutCross == 'EoverI':
ratioArrayCross = crossRatioEoverI
else:
ratioArrayCross = crossRatioIoverE
return (ratioArrayPlus, ratioArrayCross, ratioArrayNull, ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated,
ratioCutsPlus, ratioCutsCross, ratioCutsNull)
[docs]def apply_ratio_cuts_this_trial(triggers,triggers_from_this_trial,typeOfCutPlus,
ratioArrayPlus,ratioArrayCross,ratioArrayNull,
ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated,
ratioCutsPlus, ratioCutsCross, ratioCutsNull,
detection_statistic_column_name,
applying_to_injections,loudestBackgroundRatioJob=None):
detection_statistic = numpy.atleast_2d(triggers[detection_statistic_column_name].loc[triggers_from_this_trial].to_numpy())
ratioArrayPlusJobNumber = numpy.atleast_2d(ratioArrayPlus.loc[triggers_from_this_trial].to_numpy().T)
ratioArrayCrossJobNumber = numpy.atleast_2d(ratioArrayCross.loc[triggers_from_this_trial].to_numpy().T)
ratioArrayNullJobNumber = numpy.atleast_2d(ratioArrayNull.loc[triggers_from_this_trial].to_numpy())
# Reshape Calculated Ratios and Cut Values such that they are the same size
# Specifically we will make it so that the shape is
# (# of cuts to apply by number of triggers), this means that to find
# that means that ratioArray we need to repeat the triggers by # of cuts
# and for veto* we need to repeat the threshold to be applied by how many triggers said threshold needs
# to be applied to.
ratioArrayTempPlus = numpy.repeat(ratioArrayPlusJobNumber,
len(ratioCutsPlus),
axis=0)
ratioArrayTempCross = numpy.repeat(ratioArrayCrossJobNumber,
len(ratioCutsCross),
axis=0)
ratioArrayTempNull = numpy.repeat(ratioArrayNullJobNumber,
len(ratioCutsNull),
axis=0)
vetoPlusRep = numpy.kron(ratioCutsPlus_repeated, numpy.ones((1, ratioArrayPlusJobNumber.shape[1])))
vetoCrossRep = numpy.kron(ratioCutsCross_repeated, numpy.ones((1, ratioArrayCrossJobNumber.shape[1],)))
vetoNullRep = numpy.kron(ratioCutsNull_repeated, numpy.ones((1, ratioArrayNullJobNumber.shape[1],)))
if applying_to_injections:
detection_statistic_tmp = numpy.repeat(detection_statistic,
len(ratioCutsNull),
axis=0)
loudest_background_job = numpy.kron(numpy.atleast_2d(loudestBackgroundRatioJob).T,
numpy.ones((1, detection_statistic.shape[1],)))
# Determine what clusters passed all the Ratio cuts
if applying_to_injections:
if typeOfCutPlus == 'twosided':
ratioPassCut = (((ratioArrayTempPlus >= vetoPlusRep)[0:len(ratioCutsPlus)] | (ratioArrayTempPlus >= vetoPlusRep)[len(ratioCutsPlus)::]) & ((ratioArrayTempCross >= vetoCrossRep)[0:len(ratioCutsCross)] | (ratioArrayTempCross >= vetoCrossRep)[len(ratioCutsCross)::]) & (ratioArrayTempNull >= vetoNullRep) & (detection_statistic_tmp > loudest_background_job))
else:
ratioPassCut = ((ratioArrayTempPlus >= vetoPlusRep) &
(ratioArrayTempCross >= vetoCrossRep) &
(ratioArrayTempNull >= vetoNullRep) &
(detection_statistic_tmp > loudest_background_job))
else:
if typeOfCutPlus == 'twosided':
ratioPassCut = (((ratioArrayTempPlus >= vetoPlusRep)[0:len(ratioCutsPlus)] | (ratioArrayTempPlus >= vetoPlusRep)[len(ratioCutsPlus)::]) &
((ratioArrayTempCross >= vetoCrossRep)[0:len(ratioCutsCross)] | (ratioArrayTempCross >= vetoCrossRep)[len(ratioCutsCross)::]) &
(ratioArrayTempNull >= vetoNullRep))
else:
ratioPassCut = ((ratioArrayTempPlus >= vetoPlusRep) &
(ratioArrayTempCross >= vetoCrossRep) &
(ratioArrayTempNull >= vetoNullRep))
return ratioPassCut
[docs]def xapplyratiocuts(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
FAR_Tuning,typeOfCutPlus,typeOfCutCross,
detection_statistic_column_name):
if float(FAR_Tuning).is_integer():
FAR_Tuning = (FAR_Tuning/100)
# Depending on what was asked prep triggers to apply ratio array
ratioArrayPlus, ratioArrayCross, ratioArrayNull, ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated, ratioCutsPlus, ratioCutsCross, ratioCutsNull = \
prep_triggers_for_ratio(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
typeOfCutPlus,typeOfCutCross,)
# Determine how many indepdent trials there are
background_trials = triggers.groupby(['event','internal_time_slide'])
number_of_trials = len(background_trials)
indexFARBackground = int(numpy.ceil(number_of_trials* FAR_Tuning))
loudestBackgroundRatioJob = []
trial_name = []
for key, item in background_trials:
triggers_from_this_trial = background_trials.get_group(key).index
detection_statistic = numpy.atleast_2d(triggers[detection_statistic_column_name].loc[triggers_from_this_trial].to_numpy())
ratioPassCut = apply_ratio_cuts_this_trial(triggers,triggers_from_this_trial,typeOfCutPlus,
ratioArrayPlus,ratioArrayCross,ratioArrayNull,
ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated,
ratioCutsPlus, ratioCutsCross, ratioCutsNull,
detection_statistic_column_name,
False,loudestBackgroundRatioJob=None)
# Find Surviving Offsource
backGroundArray = ratioPassCut*numpy.repeat(detection_statistic,
len(ratioCutsPlus),
axis=0)
# Find loudest surviving trigger for this trial for the grid of applied cuts
# to do this we find the max over the columns
#(remember each row represented an applied a cut)
loudestBackgroundRatioJob.append(numpy.max(backGroundArray,1))
trial_name.append(key)
loudestBackgroundRatioJob = numpy.vstack(loudestBackgroundRatioJob)
loudestBackgroundRatioJob.sort(axis=0)
return loudestBackgroundRatioJob[indexFARBackground,:]
[docs]def xapplyratiocutsinjections(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
loudestBackgroundRatioJob,typeOfCutPlus,typeOfCutCross,
detection_statistic_column_name,):
# Depending on what was asked prep triggers to apply ratio array
ratioArrayPlus, ratioArrayCross, ratioArrayNull, ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated, ratioCutsPlus, ratioCutsCross, ratioCutsNull = \
prep_triggers_for_ratio(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
typeOfCutPlus,typeOfCutCross,)
injection_trials = triggers.groupby(['injection_scale','injection_number'])
all_ratio_boolean = []
all_indices = []
for key, item in injection_trials:
triggers_from_this_trial = injection_trials.get_group(key).index
ratioPassCut = apply_ratio_cuts_this_trial(triggers,triggers_from_this_trial,typeOfCutPlus,
ratioArrayPlus,ratioArrayCross,ratioArrayNull,
ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated,
ratioCutsPlus, ratioCutsCross, ratioCutsNull,
detection_statistic_column_name,
True,loudestBackgroundRatioJob=loudestBackgroundRatioJob)
all_ratio_boolean.append(ratioPassCut)
all_indices.extend(triggers_from_this_trial)
# temporarly create a pandas dataframe indicating whether a given triggers passed
# one of the cut combinations and the loudest background trigger from that cut combination
pass_ratio_cuts = pandas.DataFrame(numpy.hstack(all_ratio_boolean).T, index=all_indices)
return triggers.join(pass_ratio_cuts)
[docs]def prep_triggers_for_alpha_cuts(triggers,
ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange2,vetoCrossRange2,vetoNullRange2,
typeOfCutPlus,typeOfCutCross,):
# Calculate all ratio values
denominator_plus = (triggers[ePlusIndex] + triggers[iPlusIndex])**0.8
denominator_cross = (triggers[eCrossIndex] + triggers[iCrossIndex])**0.8
# Calculate the so called alpha values
plusAlphaEoverI = 2*(triggers[ePlusIndex] - triggers[iPlusIndex])/denominator_plus
crossAlphaEoverI = 2*(triggers[eCrossIndex] - triggers[iCrossIndex])/denominator_cross
plusAlphaIoverE = 2*(triggers[iPlusIndex] - triggers[ePlusIndex])/denominator_plus
crossAlphaIoverE = 2*(triggers[iCrossIndex] - triggers[eCrossIndex])/denominator_cross
if iNullIndex == 0:
triggers['nullenergy'] = numpy.ones(plusAlphaEoverI.size)
nullAlphaIoverE = triggers['nullenergy']
else:
nullAlphaIoverE = 2*(triggers[iNullIndex] - triggers[eNullIndex])/(triggers[iNullIndex] + triggers[eNullIndex])**0.8
if typeOfCutPlus == 'twosided':
alphaCutsPlus = vetoPlusRange2
alphaCutsCross = vetoCrossRange2
alphaCutsNull = abs(vetoNullRange2)
alphaArrayPlus = abs(plusAlphaEoverI)+1
alphaArrayCross = abs(crossAlphaEoverI)+1
alphaArrayNull = nullAlphaIoverE+1
else:
alphaCutsPlus = abs(vetoPlusRange2)
alphaCutsCross = abs(vetoCrossRange2)
alphaCutsNull = abs(vetoNullRange2)
if typeOfCutPlus == 'EoverI':
alphaArrayPlus = plusAlphaEoverI + 1
else:
alphaArrayPlus = plusAlphaIoverE + 1
if typeOfCutCross == 'EoverI':
alphaArrayCross = crossAlphaEoverI + 1
else:
alphaArrayCross = crossAlphaIoverE + 1
alphaArrayNull = nullAlphaIoverE + 1
return alphaArrayPlus, alphaArrayCross, alphaArrayNull, alphaCutsPlus, alphaCutsCross, alphaCutsNull
[docs]def apply_alpha_cuts_to_trial(triggers,triggers_from_this_trial,
alphaArrayPlus,alphaArrayCross,alphaArrayNull,
alphaCutsPlus, alphaCutsCross, alphaCutsNull,
detection_statistic_column_name,
applying_to_injections,loudestBackgroundAlpha=None):
detection_statistic = numpy.atleast_2d(triggers[detection_statistic_column_name].loc[triggers_from_this_trial].to_numpy())
# Get all the relevant alpha ratios for triggers associated with this event
alphaArrayPlusJobNumber = alphaArrayPlus.loc[triggers_from_this_trial].to_numpy()
alphaArrayCrossJobNumber = alphaArrayCross.loc[triggers_from_this_trial].to_numpy()
alphaArrayNullJobNumber = alphaArrayNull.loc[triggers_from_this_trial].to_numpy()
# Reshape Calculated Ratios and Cut Values such that they are the same size
# Specifically we will make it so that the shape is
# (# of cuts to apply by number of triggers), this means that to find
# that means that ratioArray we need to repeat the triggers by # of cuts
# and for veto* we need to repeat the threshold to be applied by how many triggers said threshold needs
# to be applied to.
alphaArrayTempPlus = numpy.repeat(numpy.atleast_2d(alphaArrayPlusJobNumber),
len(alphaCutsPlus),
axis=0)
alphaArrayTempCross = numpy.repeat(numpy.atleast_2d(alphaArrayCrossJobNumber),
len(alphaCutsCross),
axis=0)
alphaArrayTempNull = numpy.repeat(numpy.atleast_2d(alphaArrayNullJobNumber),
len(alphaCutsNull),
axis=0)
vetoPlusRange2Rep = numpy.kron(numpy.atleast_2d(alphaCutsPlus).T,
numpy.ones((1, len(alphaArrayPlusJobNumber))))
vetoCrossRange2Rep = numpy.kron(numpy.atleast_2d(alphaCutsCross).T,
numpy.ones((1, len(alphaArrayCrossJobNumber),)))
vetoNullRange2Rep = numpy.kron(numpy.atleast_2d(alphaCutsNull).T,
numpy.ones((1, len(alphaArrayNullJobNumber),)))
if applying_to_injections:
# Now repeat the background
detection_statistic_tmp = numpy.repeat(numpy.atleast_2d(detection_statistic),
len(alphaCutsNull),
axis=0)
loudest_background_job = numpy.kron(numpy.atleast_2d(loudestBackgroundAlpha).T,
numpy.ones((1, detection_statistic.shape[1],)))
# Take absolute value of vetoRange2Rep.
vetoPlusRange2Rep = abs(vetoPlusRange2Rep)
vetoCrossRange2Rep = abs(vetoCrossRange2Rep)
vetoNullRange2Rep = abs(vetoNullRange2Rep)
vetoPlusRange2Rep[vetoPlusRange2Rep==0] = -numpy.inf
vetoCrossRange2Rep[vetoCrossRange2Rep==0] = -numpy.inf
vetoNullRange2Rep[vetoNullRange2Rep==0] = -numpy.inf
if applying_to_injections:
coherent_cuts = (
(alphaArrayTempPlus >= vetoPlusRange2Rep) &
(alphaArrayTempCross >= vetoCrossRange2Rep) &
(alphaArrayTempNull >= vetoNullRange2Rep) &
(detection_statistic_tmp > loudest_background_job)
)
else:
coherent_cuts = (
(alphaArrayTempPlus >= vetoPlusRange2Rep) &
(alphaArrayTempCross >= vetoCrossRange2Rep) &
(alphaArrayTempNull >= vetoNullRange2Rep)
)
return coherent_cuts
[docs]def xapplyalphacuts(triggers,
ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
vetoPlusRange2,vetoCrossRange2,vetoNullRange2,
FAR,typeOfCutPlus,typeOfCutCross,detection_statistic_column_name):
if float(FAR).is_integer():
FAR = (FAR/100)
alphaArrayPlus, alphaArrayCross, alphaArrayNull, alphaCutsPlus, alphaCutsCross, alphaCutsNull = \
prep_triggers_for_alpha_cuts(triggers,
ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange2,vetoCrossRange2,vetoNullRange2,
typeOfCutPlus,typeOfCutCross,)
# Depending on what was asked prep triggers to apply ratio array
ratioArrayPlus, ratioArrayCross, ratioArrayNull, ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated, ratioCutsPlus, ratioCutsCross, ratioCutsNull = \
prep_triggers_for_ratio(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
typeOfCutPlus,typeOfCutCross,)
# Depending on wether you are requesting a two sided or one sided cut.
# construct specific ratio and cut arrays.
# Determine how many indepdent trials there are
background_trials = triggers.groupby(['event','internal_time_slide'])
number_of_trials = len(background_trials)
indexFARBackground = int(numpy.ceil(number_of_trials* FAR))
loudest_background_that_survives_cut = []
trial_name = []
for key, item in background_trials:
triggers_from_this_trial = background_trials.get_group(key).index
# Extract detction statisc for triggers associated with this event
detection_statistic = numpy.atleast_2d(triggers[detection_statistic_column_name].loc[triggers_from_this_trial].to_numpy())
ratioPassCut = apply_ratio_cuts_this_trial(triggers,triggers_from_this_trial,typeOfCutPlus,
ratioArrayPlus,ratioArrayCross,ratioArrayNull,
ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated,
ratioCutsPlus, ratioCutsCross, ratioCutsNull,
detection_statistic_column_name,
False,loudestBackgroundRatioJob=None)
alpha_cuts = apply_alpha_cuts_to_trial(triggers,triggers_from_this_trial,
alphaArrayPlus,alphaArrayCross,alphaArrayNull,
alphaCutsPlus, alphaCutsCross, alphaCutsNull,
detection_statistic_column_name,
False,loudestBackgroundAlpha=None)
coherent_cuts = numpy.repeat(ratioPassCut,len(alphaCutsNull),0) & alpha_cuts
# Find loudest for each column
# Find Surviving Offsource
backGroundArray = coherent_cuts*numpy.repeat(numpy.atleast_2d(detection_statistic),
len(alphaCutsPlus),
axis=0)
# Find loudest surviving trigger for this trial for the grid of applied cuts
# to do this we find the max over the columns
#(remember each row represented an applied a cut)
loudest_background_that_survives_cut.append(numpy.max(backGroundArray,1))
trial_name.append(key)
loudest_background_that_survives_cut = numpy.vstack(loudest_background_that_survives_cut)
sorted_indices = loudest_background_that_survives_cut.argsort(axis=0)[:,0]
loudest_background_that_survives_cut.sort(axis=0)
return loudest_background_that_survives_cut[indexFARBackground,:], numpy.array(trial_name)[sorted_indices], loudest_background_that_survives_cut
[docs]def xapplyalphacutsinjection(triggers,
ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
vetoPlusRange2,vetoCrossRange2,vetoNullRange2,
loudestBackgroundAlpha,typeOfCutPlus,typeOfCutCross,detection_statistic_column_name):
alphaArrayPlus, alphaArrayCross, alphaArrayNull, alphaCutsPlus, alphaCutsCross, alphaCutsNull = \
prep_triggers_for_alpha_cuts(triggers,
ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange2,vetoCrossRange2,vetoNullRange2,
typeOfCutPlus,typeOfCutCross,)
# Depending on what was asked prep triggers to apply ratio array
ratioArrayPlus, ratioArrayCross, ratioArrayNull, ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated, ratioCutsPlus, ratioCutsCross, ratioCutsNull = \
prep_triggers_for_ratio(triggers, ePlusIndex,eCrossIndex,eNullIndex,
iPlusIndex,iCrossIndex,iNullIndex,
vetoPlusRange,vetoCrossRange,vetoNullRange,
typeOfCutPlus,typeOfCutCross,)
# Determine how many indepdent trials there are
injection_trials = triggers.groupby(['injection_scale','injection_number'])
all_alpha_boolean = []
all_indices = []
for key, item in injection_trials:
triggers_from_this_trial = injection_trials.get_group(key).index
# Extract detction statisc for triggers associated with this event
detection_statistic = triggers[detection_statistic_column_name].loc[triggers_from_this_trial].to_numpy()
ratioPassCut = apply_ratio_cuts_this_trial(triggers,triggers_from_this_trial,typeOfCutPlus,
ratioArrayPlus,ratioArrayCross,ratioArrayNull,
ratioCutsPlus_repeated, ratioCutsCross_repeated, ratioCutsNull_repeated,
ratioCutsPlus, ratioCutsCross, ratioCutsNull,
detection_statistic_column_name,
True,loudestBackgroundRatioJob=[0])
alpha_cuts = apply_alpha_cuts_to_trial(triggers,triggers_from_this_trial,
alphaArrayPlus,alphaArrayCross,alphaArrayNull,
alphaCutsPlus, alphaCutsCross, alphaCutsNull,
detection_statistic_column_name,
True,loudestBackgroundAlpha=loudestBackgroundAlpha)
coherent_cuts = numpy.repeat(ratioPassCut,len(alphaCutsNull),0) & alpha_cuts
all_alpha_boolean.append(coherent_cuts)
all_indices.extend(triggers_from_this_trial)
# temporarly create a pandas dataframe indicating whether a given triggers passed
# one of the cut combinations and the loudest background trigger from that cut combination
pass_alpha_cuts = pandas.DataFrame(numpy.hstack(all_alpha_boolean).T, index=all_indices)
return triggers.join(pass_alpha_cuts)