from typing import List
import pandas as pd
import basf2
import basf2 as b2
import modularAnalysis as ma
import variables.collections as vc
import variables.utils as vu
from variables import variables as va
from vibe.core.utils.misc import fancy_validation_mode_header
from vibe.core.validation_mode import ValidationModeBaseClass
from vibe.core.helper.histogram_tools import HistVariable, Histogram, HistComponent
from vibe.core.helper.root_helper import makeROOTCompatible
__all__ = [
"Tautopi3pi",
]
[docs]
@fancy_validation_mode_header
class Tautopi3pi(ValidationModeBaseClass):
name = "Tautopi3pi"
latex_str = r"$\tau^+, \tau^- \rightarrow \pi^+ \pi^- \pi^+ \nu, pi^-$"
[docs]
def create_basf2_path(self):
myPath = basf2.Path()
# Define 'good' tracks and photons
trackCuts = "dr <= 1.0 and -3.0 <= dz <= 3.0"
gammaCuts = "E > 0.50 and -0.8660 < cosTheta < 0.9563"
ma.fillParticleList("pi+:track", trackCuts, path=myPath)
ma.fillParticleList("gamma:good", gammaCuts, path=myPath)
ma.fillParticleList("e+:tag", trackCuts, path=myPath)
ma.fillParticleList("mu+:tag", trackCuts, path=myPath)
# Reconstruction using 3-1 prong topology.
ma.applyEventCuts("countInList(pi+:track) == 4", path=myPath)
# PID cuts
ma.copyLists("pi+:id", "pi+:track", path=myPath)
# Signal: tau -> 3 pi nu
ma.reconstructDecay("tau+:signal -> pi+:id pi-:id pi+:id ?nu", "M < 1.8", path=myPath)
# Tag decay
# Hadronic tag: tau -> pi + nu_tau
ma.reconstructDecay("tau-:piTag -> pi-:id ?nu", "", path=myPath, dmID=3)
ma.copyLists("tau+:tag", "tau-:piTag", path=myPath)
# To store information of the tagging mode
va.addAlias("dmIDTag", "daughter(1, extraInfo(decayModeID))")
# Tau pair candidates from a virtual photon (vpho)
ma.reconstructDecay("vpho:all -> tau+:signal tau-:tag", "", path=myPath)
# Event shape and event kinematics
ma.buildEventShape(
["pi+:track", "gamma:good"],
thrust=True,
foxWolfram=False,
cleoCones=False,
jets=False,
harmonicMoments=False,
allMoments=False,
collisionAxis=False,
sphericity=False,
path=myPath,
)
ma.buildEventKinematics(["pi+:track", "gamma:good"], path=myPath)
# Select vpho candidates with signal and tag in opposite sides of the event.
va.addAlias(
"prod1", "formula(daughter(0, daughter(0, cosToThrustOfEvent))*daughter(1, daughter(0,cosToThrustOfEvent)))"
)
va.addAlias(
"prod2", "formula(daughter(0, daughter(1, cosToThrustOfEvent))*daughter(1, daughter(0,cosToThrustOfEvent)))"
)
va.addAlias(
"prod3", "formula(daughter(0, daughter(2, cosToThrustOfEvent))*daughter(1, daughter(0,cosToThrustOfEvent)))"
)
ma.applyCuts("vpho:all", "prod1 < 0 and prod2 < 0 and prod3 < 0", path=myPath)
# Photons on signal and tag side
ma.copyList("gamma:sig", "gamma:good", path=myPath)
ma.copyList("gamma:tag", "gamma:good", path=myPath)
# 1-prong on positive or negative side of thrust axis
va.addAlias("tagInPosThrust", "countInList(vpho:all, daughter(1, daughter(0,cosToThrustOfEvent)) > 0)")
va.addAlias("tagInNegThrust", "countInList(vpho:all, daughter(1, daughter(0,cosToThrustOfEvent)) < 0)")
positiveThrust = b2.create_path()
negativeThrust = b2.create_path()
ma.applyCuts("gamma:tag", "cosToThrustOfEvent > 0", path=positiveThrust)
ma.applyCuts("gamma:sig", "cosToThrustOfEvent < 0", path=positiveThrust)
ma.applyCuts("gamma:tag", "cosToThrustOfEvent < 0", path=negativeThrust)
ma.applyCuts("gamma:sig", "cosToThrustOfEvent > 0", path=negativeThrust)
# take different paths if tag in cosToThrustOfEvent > or < 0
sigThrustModule = myPath.add_module("VariableToReturnValue", variable="tagInPosThrust")
sigThrustModule.if_value("> 0", positiveThrust, b2.AfterConditionPath.CONTINUE)
sigThrustModule = myPath.add_module("VariableToReturnValue", variable="tagInNegThrust")
sigThrustModule.if_value("> 0", negativeThrust, b2.AfterConditionPath.CONTINUE)
# the number of photons and pi0s in 3prong and 1prong hemispheres
va.addAlias("nPhotons_signal", "nParticlesInList(gamma:sig)")
va.addAlias("nPhotons_tag", "nParticlesInList(gamma:tag)")
# Energy in each side
va.addAlias("photonE_sig", "totalEnergyOfParticlesInList(gamma:sig)")
va.addAlias("photonE_tag", "totalEnergyOfParticlesInList(gamma:tag)")
va.addAlias("photonECMS_sig", "useCMSFrame(totalEnergyOfParticlesInList(gamma:sig))")
va.addAlias("photonECMS_tag", "useCMSFrame(totalEnergyOfParticlesInList(gamma:tag))")
# MC matching of the tau candidates
ma.matchMCTruth("tau+:signal", path=myPath)
ma.matchMCTruth("tau+:tag", path=myPath)
# Information of the generated decay mode
ma.labelTauPairMC(path=myPath)
va.addAlias("M_12", "daughterInvM(0, 1)")
va.addAlias("M_23", "daughterInvM(1, 2)")
va.addAlias("M_31", "daughterInvM(0, 2)")
va.addAlias("M_123", "daughterInvM(0, 1, 2)")
# PID for tag side
pid_tag_daughter = vu.create_aliases(vc.pid, "daughter(0, {variable})", "tagSide")
# Event variables to store
eventVariables = [
"thrust",
"visibleEnergyOfEventCMS",
"missingMomentumOfEvent",
"missingMomentumOfEvent_theta",
"missingMomentumOfEventCMS",
"missingMomentumOfEventCMS_theta",
"totalPhotonsEnergyOfEvent",
"missingMass2OfEvent",
"nPhotons_signal",
"nPhotons_tag",
"photonE_sig",
"photonE_tag",
"photonECMS_sig",
"photonECMS_tag",
"dmIDTag",
"tauPlusMCMode",
"tauMinusMCMode",
]
mcVariables = ["mcErrors", "genMotherPDG", "mcPDG"]
invmass_sig = ["M_12", "M_23", "M_31", "M_123"]
kVariables = vc.inv_mass + vc.kinematics
variableList = (
vu.create_aliases_for_selected(list_of_variables=eventVariables, decay_string="^vpho")
+ vu.create_aliases_for_selected(
list_of_variables=mcVariables + ["charge"], decay_string="vpho -> ^tau+ ^tau-"
)
+ vu.create_aliases_for_selected(list_of_variables=invmass_sig, decay_string="vpho -> ^tau+ tau-")
+ vu.create_aliases_for_selected(
list_of_variables=kVariables + ["isSignal"], decay_string="vpho -> [^tau+ -> ^pi+ ^pi- ^pi-] ^tau-"
)
+ vu.create_aliases_for_selected(
list_of_variables=vc.pid, decay_string="vpho -> [tau+ -> ^pi+ ^pi- ^pi+] tau- "
)
+ vu.create_aliases_for_selected(list_of_variables=pid_tag_daughter, decay_string="vpho -> tau+ ^tau- ")
)
self.variables_to_validation_ntuple(
decay_str="vpho:all",
variables=variableList,
path=myPath,
)
return myPath
@property
def analysis_validation_histograms(self) -> List[Histogram]:
return [
Histogram(
name="Thrust",
title="Thrust of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="thrust"),
label="Thrust",
unit="",
bins=60,
scope=(0.7, 1.0),
),
hist_components=[
HistComponent(
label="Signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
Histogram(
name="Visible_Energy",
title=r"$E_{vis}$ of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="visibleEnergyOfEventCMS"),
label=r"$E_{visible}$ in CMS",
unit="GeV",
bins=50,
scope=(1.0, 11.0),
),
hist_components=[
HistComponent(
label="signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
Histogram(
name="M_a1",
title=r"$M_{a1}$ of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="tau_0_M"),
label=r"$M_{a1}$",
unit=r"GeV/$c^2$",
bins=80,
scope=(0.2, 1.8),
),
hist_components=[
HistComponent(
label="signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
Histogram(
name="M_12",
title=r"$M_{12} & M_{23}$ of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="tau_M_12"),
label=r"$M_{\pi^{\pm} \pi^{\mp}}$",
unit=r"GeV/$c^2$",
bins=80,
scope=(0.2, 1.8),
merged_variable=makeROOTCompatible(variable="tau_M_23"),
),
hist_components=[
HistComponent(
label="Signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
Histogram(
name="M_31",
title=r"$M_{31}$ of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="tau_M_31"),
label=r"$M_{\pi^{\pm}\pi^{\pm}}$",
unit=r"GeV/$c^2$",
bins=80,
scope=(0.2, 1.8),
),
hist_components=[
HistComponent(
label="Signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
Histogram(
name="M_123",
title=r"$M_{123}$ of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="tau_M_123"),
label=r"$M_{2\pi^{\mp}\pi^{\pm}}$",
unit=r"GeV/$c^2$",
bins=80,
scope=(0.2, 1.8),
),
hist_components=[
HistComponent(
label="Signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
Histogram(
name="Momentum_tag-track",
title=r"$P_{tag-track}$ of pi3pi",
hist_variable=HistVariable(
df_label=makeROOTCompatible(variable="tau_1_p"),
label=r"$Momentum_{tag-track}$",
unit="GeV",
bins=80,
scope=(0.0, 8.0),
),
hist_components=[
HistComponent(
label="Signal",
additional_cut_str="dmIDTag == 3 and nPhotons_signal==0 and nPhotons_tag==0 and tau_0_isSignal==1",
),
],
),
]
[docs]
def get_number_of_signal_for_efficiency(self, df: pd.DataFrame) -> float:
return df["tau_0_isSignal"].sum()