diff --git a/Bc2KKpiMC/dv_data.py b/Bc2KKpiMC/dv_data.py new file mode 100644 index 0000000000000000000000000000000000000000..378be189164dc7e7285e4b7d2c9dd98b7bbed706 --- /dev/null +++ b/Bc2KKpiMC/dv_data.py @@ -0,0 +1,22 @@ +from .tupling_maker import template +from DaVinci import Options, make_config +from . import private_combiner + +from RecoConf.event_filters import require_pvs + +from RecoConf.reconstruction_objects import make_pvs +def Bc2KKpi(options: Options): + decay_descriptor = { + "Bc": "[B_c+ -> K+ K- pi+ ]CC", + "Kp": "[B_c+ -> ^K+ K- pi+ ]CC", + "Km": "[B_c+ -> K+ ^K- pi+ ]CC", + "pip": "[B_c+ -> K+ K- ^pi+ ]CC", + } + descriptor='[B_c+ -> K+ K- pi+ ]cc' + kaon = private_combiner.make_kaon_forBc3h() + pion = private_combiner.make_pion_forBc3h() + particles = [kaon, kaon, pion] + line_name = 'SpruceBandQ_BcToKpKmPip' + my_tuple = template(decay_descriptor, line_name, True,[],private_combiner.make_bc(particles,descriptor)) +# my_filter = line_prefilter(line_name) + return make_config(options, [require_pvs(make_pvs()), my_tuple]) diff --git a/Bc2KKpiMC/info.yaml b/Bc2KKpiMC/info.yaml new file mode 100644 index 0000000000000000000000000000000000000000..79029dda12767b3a14270f4041e9a7bf038a9586 --- /dev/null +++ b/Bc2KKpiMC/info.yaml @@ -0,0 +1,37 @@ +defaults: + application: DaVinci/v64r12 + wg: BandQ + inform: + - tianyu.shi@cren.ch + - xuhao.yuan@cern.ch +# data configuration +{%- set data_info = [ + ('14103034','W31_34', 'W31.34', 'HLT1_2024.W31.34_noUT/HLT2-2024.W31.34', 'MagUp', 'Nu6.3', 'dddb-20240427', 'sim10-2024.Q1.2-v1.1-mu100'), + ('14103034','W35_37', 'W35.37', 'HLT2-2024.W35.39', 'MagUp', 'Nu6.3', 'dddb-20240427', 'sim10-2024.Q1.2-v1.1-mu100'), + ('14103034','W37_39', 'W37.39', 'HLT2-2024.W35.39', 'MagDown', 'Nu6.3', 'dddb-20240427', 'sim10-2024.Q1.2-v1.1-md100'), + ('14103034','W40_42', 'W40.42', 'HLT2-2024.W40.42', 'MagUp', 'Nu7.6', 'dddb-20240427', 'sim10-2024.Q1.2-v1.1-mu100'), + ('14103034','W40_42', 'W40.42', 'HLT2-2024.W40.42', 'MagDown', 'Nu7.6', 'dddb-20240427', 'sim10-2024.Q1.2-v1.1-md100'), +]%} +{%- for event_type,block_name, block, hlt2, polarity, nu, dddb, conddb in data_info %} +mc_Bc2KKpi_{{event_type}}_{{block_name}}_{{polarity}}_2024: + application: "DaVinci/v64r12" + input: + bk_query: "/MC/2024/Beam6800GeV-2024.{{block}}-{{polarity}}-{{nu}}-25ns-BcVegPyPythia8/Sim10e/{{hlt2}}/{{event_type}}/HLT2.DST" + dq_flags: + - OK + keep_running: true + n_test_lfns: 1 + output: "mc_{{block_name}}.ROOT" + options: + entrypoint: Bc2KKpiMC.dv_data:Bc2KKpi + extra_options: + conddb_tag: {{ conddb }} + dddb_tag: {{ dddb }} + input_type: ROOT + input_raw_format: 0.5 + simulation: True + data_type: 'Upgrade' + input_process: Hlt2 + geometry_version: run3/2024.Q1.2-v00.00 + conditions_version: master +{%- endfor %} diff --git a/Bc2KKpiMC/private_combiner.py b/Bc2KKpiMC/private_combiner.py new file mode 100644 index 0000000000000000000000000000000000000000..6ebcf5a1fef5aa9f777fd8d3ebe9b3ab2d980385 --- /dev/null +++ b/Bc2KKpiMC/private_combiner.py @@ -0,0 +1,277 @@ +import Functors as F +from Functors.math import in_range + +from GaudiKernel.SystemOfUnits import GeV, MeV, picosecond, mm + +from PyConf import configurable + +from Hlt2Conf.algorithms_thor import ParticleCombiner, ParticleFilter +from RecoConf.reconstruction_objects import make_pvs +from Functors import require_all +from PyConf import configurable +from Hlt2Conf.standard_particles import make_has_rich_long_pions as make_pions, \ + make_has_rich_long_kaons as make_kaons, \ + make_has_rich_long_protons as make_protons +from Hlt2Conf.lines.config_pid import nopid_hadrons + +_MASS_MIN = 120 * MeV # minimal mass in case of pi0->gg + +def _make_generic(particles, + descriptor, + name='bandq_generic_{hash}', + am_min=5100 * MeV, + am_max=5550 * MeV, + m_min=5140 * MeV, + m_max=5510 * MeV, + achi2_doca_max=25, + vtx_chi2pdof_max=20, + comb_cut_add=None, + vtx_cut_add=None): + + combination_code = (in_range(am_min, F.MASS, am_max)) + + vertex_code = require_all( + in_range(m_min, F.MASS, m_max), F.CHI2DOF < vtx_chi2pdof_max) + + if comb_cut_add is not None: + combination_code &= comb_cut_add + + if vtx_cut_add is not None: + vertex_code &= vtx_cut_add + + if len(particles) == 2: + return ParticleCombiner( + name=name, + Inputs=particles, + DecayDescriptor=descriptor, + CombinationCut=combination_code, + CompositeCut=vertex_code) + + if len(particles) == 3: + + combination12_code = require_all(F.MASS < am_max - _MASS_MIN, + F.SDOCACHI2(1, 2) < achi2_doca_max) + + combination_code &= require_all( + F.SDOCACHI2(1, 3) < achi2_doca_max, + F.SDOCACHI2(2, 3) < achi2_doca_max) + + return ParticleCombiner( + name=name, + Inputs=particles, + DecayDescriptor=descriptor, + Combination12Cut=combination12_code, + CombinationCut=combination_code, + CompositeCut=vertex_code) + + if len(particles) == 4: + combination12_code = require_all(F.MASS < am_max - 2 * _MASS_MIN, + F.SDOCACHI2(1, 2) < achi2_doca_max) + + combination123_code = require_all(F.MASS < am_max - _MASS_MIN, + F.SDOCACHI2(1, 3) < achi2_doca_max, + F.SDOCACHI2(2, 3) < achi2_doca_max) + + combination_code &= require_all( + F.SDOCACHI2(1, 4) < achi2_doca_max, + F.SDOCACHI2(2, 4) < achi2_doca_max, + F.SDOCACHI2(3, 4) < achi2_doca_max) + + return ParticleCombiner( + name=name, + Inputs=particles, + DecayDescriptor=descriptor, + Combination12Cut=combination12_code, + Combination123Cut=combination123_code, + CombinationCut=combination_code, + CompositeCut=vertex_code) + + if len(particles) >= 5: + combination12_code = require_all(F.MASS < am_max - 3 * _MASS_MIN, + F.SDOCACHI2(1, 2) < achi2_doca_max) + + combination123_code = require_all(F.MASS < am_max - 2 * _MASS_MIN, + F.SDOCACHI2(1, 3) < achi2_doca_max, + F.SDOCACHI2(2, 3) < achi2_doca_max) + + combination1234_code = require_all(F.MASS < am_max - _MASS_MIN, + F.SDOCACHI2(1, 4) < achi2_doca_max, + F.SDOCACHI2(2, 4) < achi2_doca_max, + F.SDOCACHI2(3, 4) < achi2_doca_max) + + combination_code &= require_all( + F.SDOCACHI2(1, 5) < achi2_doca_max, + F.SDOCACHI2(2, 5) < achi2_doca_max, + F.SDOCACHI2(3, 5) < achi2_doca_max, + F.SDOCACHI2(4, 5) < achi2_doca_max) + + return ParticleCombiner( + name=name, + Inputs=particles, + DecayDescriptor=descriptor, + Combination12Cut=combination12_code, + Combination123Cut=combination123_code, + Combination1234Cut=combination1234_code, + CombinationCut=combination_code, + CompositeCut=vertex_code) + + +def make_b_hadron( + particles, + descriptor, + name='bandq_b_hadron_{hash}', + am_min=5100 * MeV, + am_max=5550 * MeV, + m_min=5140 * MeV, + m_max=5510 * MeV, + achi2_doca_max=25, + vtx_chi2pdof_max=20, + bpvltime_min=0.2 * picosecond, + bpvdira_min=0.995, # [AVOID BIAS IN DIRECTION WRT TO PV], 0.995 (tan<0.1) is safe enough even for B from Tbb + bpvfdchi2_min=0, + minVDz=0. * mm, + minRho=0. * mm, + comb_cut_add=None): + + vtx_cut_add = require_all(F.BPVLTIME() > bpvltime_min, + F.BPVVDRHO() > minRho, + F.BPVVDZ() > minVDz, + F.BPVFDCHI2() > bpvfdchi2_min, + F.BPVDIRA() > bpvdira_min) + + return _make_generic( + particles=particles, + descriptor=descriptor, + name=name, + am_min=am_min, + am_max=am_max, + m_min=m_min, + m_max=m_max, + achi2_doca_max=achi2_doca_max, + vtx_chi2pdof_max=vtx_chi2pdof_max, + vtx_cut_add=vtx_cut_add, + comb_cut_add=comb_cut_add) + + +def make_bc(particles, + descriptor, + name='bandq_Bc_{hash}', + am_min=6050 * MeV, + am_max=6555 * MeV, + m_min=6090 * MeV, + m_max=6510 * MeV, + bpvltime_min=0.1 * picosecond, + **decay_arguments): + """ + Return B&Q Bc+. + """ + return make_b_hadron( + particles, + descriptor, + name=name, + am_min=am_min, + am_max=am_max, + m_min=m_min, + m_max=m_max, + bpvltime_min=bpvltime_min, + **decay_arguments) + +def make_charged_hadrons(make_particles=make_pions, + name="bandq_charged_hadrons_{hash}", + pt_min=200. * MeV, + p_min=2.5 * GeV, + p_max=150. * GeV, + eta_min=2., + eta_max=5., + mipchi2dvprimary_min=0, + ghostProb_max=None, + pid=None): + + pvs = make_pvs() + + code = require_all(F.PT > pt_min, in_range(p_min, F.P, p_max), + in_range(eta_min, F.ETA, eta_max), + F.MINIPCHI2(pvs) > mipchi2dvprimary_min) + + if (pid is not None) and (not nopid_hadrons()): + code &= pid + if (ghostProb_max is not None): + code &= (F.GHOSTPROB < ghostProb_max) + + return ParticleFilter(make_particles(), name=name, Cut=F.FILTER(code)) + +def make_detached_pions(name='bandq_detached_pions_{hash}', + mipchi2dvprimary_min=4., + pt_min=200. * MeV, + p_min=2.5 * GeV, + pid=(F.PID_K < 0.), + ghostProb_max=None, + **decay_arguments): + """ + Return B&Q detached pions. + """ + return make_charged_hadrons( + name=name, + make_particles=make_pions, + mipchi2dvprimary_min=mipchi2dvprimary_min, + pt_min=pt_min, + p_min=p_min, + pid=pid, + ghostProb_max=ghostProb_max, + **decay_arguments) +def make_detached_kaons(name='bandq_detached_kaons_{hash}', + mipchi2dvprimary_min=4., + pt_min=200. * MeV, + p_min=2.5 * GeV, + pid=(F.PID_K > 0.), + ghostProb_max=None, + **decay_arguments): + """ + Return B&Q detached kaons. + """ + return make_charged_hadrons( + make_particles=make_kaons, + name=name, + mipchi2dvprimary_min=mipchi2dvprimary_min, + pt_min=pt_min, + p_min=p_min, + pid=pid, + ghostProb_max=ghostProb_max, + **decay_arguments) + +def make_pion_forBc3h(name='bandq_pion_forBc3h_{hash}', + pt_min=1000. * MeV, + p_min=3.2 * GeV, + pid=(F.PID_K < -5.), + mipchi2dvprimary_min=12.): + return make_detached_pions( + name=name, + pt_min=pt_min, + p_min=p_min, + pid=pid, + mipchi2dvprimary_min=mipchi2dvprimary_min) + +def make_kaon_forBc3h(name='bandq_kaon_forBc3h_{hash}', + pt_min=1000. * MeV, + p_min=3.2 * GeV, + pid=(F.PID_K > 5.), + mipchi2dvprimary_min=12.): + return make_detached_kaons( + name=name, + pt_min=pt_min, + p_min=p_min, + pid=pid, + mipchi2dvprimary_min=mipchi2dvprimary_min) + + +def make_BcToKpKmPip(name='bandq_BcToKpKmPip_{hash}'): + pion = make_pion_forBc3h() + kaon = make_kaon_forBc3h() + line_alg = make_bc( + name=name, + particles=[kaon, kaon, pion], + descriptor="[B_c+ -> K+ K- pi+ ]cc") + return line_alg + + + diff --git a/Bc2KKpiMC/tupling_maker.py b/Bc2KKpiMC/tupling_maker.py new file mode 100644 index 0000000000000000000000000000000000000000..0c6cb6f7ad998ca392afa0428c5a1fad5c7f8bae --- /dev/null +++ b/Bc2KKpiMC/tupling_maker.py @@ -0,0 +1,349 @@ +############################################################################### +# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration # +# # +# This software is distributed under the terms of the GNU General Public # +# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". # +# # +# In applying this licence, CERN does not waive the privileges and immunities # +# granted to it by virtue of its status as an Intergovernmental Organization # +# or submit itself to any jurisdiction. # +############################################################################### +""" +Read an HLT2 file and create an ntuple with the new DaVinci configuration. +""" +import Functors as F +import FunTuple.functorcollections as FC +from FunTuple import FunctorCollection +from FunTuple import FunTuple_Particles as Funtuple +from PyConf.reading import get_particles, get_pvs, get_rec_summary +from DaVinci.algorithms import create_lines_filter +from DaVinciMCTools import MCTruthAndBkgCat +from FunTuple.functorcollections import MCHierarchy, MCPrimaries, MCPromptDecay, Kinematics, SelectionInfo, HltTisTos, MCVertexInfo, MCKinematics, ParticleID, EventInfo +from PyConf.reading import get_odin # get_decreports, +from DecayTreeFitter import DecayTreeFitter +from . import private_combiner + +_basic = "basic" +_composite = "composite" +_toplevel = "toplevel" + +def all_variables(pvs, mctruth, ptype, candidates=None, ftAlg=None): + """ + function that returns dictionary of functors that work. + + functors are listed in order of https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors_reference.html#module-Functo + """ + if ptype not in [_basic, _composite]: + Exception(f"I want {_basic} or {_composite}. Got {ptype}") + all_vars = FunctorCollection({}) + + comp = _composite == ptype or _toplevel == ptype # is composite + basic = _basic == ptype # is not composite + top = _toplevel == ptype # the B + + all_vars += FC.Kinematics()# Add some usual variables: M, P, PTXYZ, E + + if basic: + all_vars += FC.ParticleID(extra_info=True) # Add ProbNN and PID for basic partiels + + if comp: + all_vars.update({"ALV": F.ALV(Child1=1, Child2=2)}) + if comp: # all these require a vertex + all_vars.update({"BPVCORRM": F.BPVCORRM(pvs)}) + all_vars.update({"BPVCORRMERR": F.BPVCORRMERR(pvs)}) + all_vars.update({"BPVDIRA": F.BPVDIRA(pvs)}) + all_vars.update({"BPVDLS": F.BPVDLS(pvs)}) + all_vars.update({"BPVETA": F.BPVETA(pvs)}) + all_vars.update({"BPVFD": F.BPVFD(pvs)}) + all_vars.update({"BPVFDCHI2": F.BPVFDCHI2(pvs)}) + all_vars.update({"BPVFDIR": F.BPVFDIR(pvs)}) + all_vars.update({"BPVFDVEC": F.BPVFDVEC(pvs)}) + all_vars.update({"ALLPV_FD": F.ALLPV_FD(pvs)}) +# all_vars.update({"ALLPV_IP": F.ALLPV_IP(pvs)}) + all_vars.update({"BPVLTIME": F.BPVLTIME(pvs)}) + all_vars.update({"BPVVDRHO": F.BPVVDRHO(pvs)}) +# all_vars.update({"BPVVDX": F.BPVVDX(pvs)}) +# all_vars.update({"BPVVDY": F.BPVVDY(pvs)}) +# all_vars.update({"BPVVDZ": F.BPVVDZ(pvs)}) +# all_vars.update({"DOCA": F.SDOCA(Child1=1, Child2=2)}) +# all_vars.update({"DOCACHI2": F.SDOCACHI2(Child1=1, Child2=2)}) +# all_vars.update({"END_VRHO": F.END_VRHO}) + all_vars.update({"END_VX": F.END_VX}) + all_vars.update({"END_VY": F.END_VY}) + all_vars.update({"END_VZ": F.END_VZ}) + all_vars.update({"MAXPT": F.MAX(F.PT)}) + all_vars.update({"MAXDOCA": F.MAXSDOCA}) + all_vars.update({"MAXDOCACHI2": F.MAXSDOCACHI2}) +# all_vars.update({"SDOCA": F.SDOCA(1, 2)}) +# all_vars.update({"SDOCACHI2": F.SDOCACHI2(1, 2)}) +# all_vars.update({"SUBCOMB23_MM": F.SUBCOMB(Functor=F.MASS, Indices=(2, 3))}) + all_vars.update({"SUMPT": F.SUM(F.PT)}) + all_vars.update({"MINPT": F.MIN(F.PT)}) + all_vars.update({"SUMPT": F.SUM(F.PT)}) + all_vars.update({"MAXP": F.MAX(F.P)}) + all_vars.update({"MINP": F.MIN(F.P)}) + all_vars.update({"SUMP": F.SUM(F.P)}) + + + + + if basic: + all_vars.update({"GHOSTPROB": F.GHOSTPROB}) + all_vars.update({"ISMUON": F.ISMUON}) + all_vars.update({"INMUON": F.INMUON}) + all_vars.update({"INECAL": F.INECAL}) + all_vars.update({"INHCAL": F.INHCAL}) + all_vars.update({"HASBREM": F.HASBREM}) + all_vars.update({"BREMENERGY": F.BREMENERGY}) + all_vars.update({"BREMBENDCORR": F.BREMBENDCORR}) + all_vars.update({"BREMPIDE": F.BREMPIDE}) + all_vars.update({"ECALPIDE": F.ECALPIDE}) + all_vars.update({"ECALPIDMU": F.ECALPIDMU}) + all_vars.update({"HCALPIDE": F.HCALPIDE}) + all_vars.update({"HCALPIDMU": F.HCALPIDMU}) + all_vars.update({"ELECTRONSHOWEREOP": F.ELECTRONSHOWEREOP}) + all_vars.update({"CLUSTERMATCH": F.CLUSTERMATCH_CHI2}) + all_vars.update({"ELECTRONMATCH": F.ELECTRONMATCH_CHI2}) + all_vars.update({"BREMHYPOMATCH": F.BREMHYPOMATCH_CHI2}) + all_vars.update({"ELECTRONENERGY": F.ELECTRONENERGY}) + all_vars.update({"BREMHYPOENERGY": F.BREMHYPOENERGY}) + all_vars.update({"BREMHYPODELTAX": F.BREMHYPODELTAX}) + all_vars.update({"ELECTRONID": F.ELECTRONID}) + all_vars.update({"HCALEOP": F.HCALEOP}) + # Note: the observables for the two functors below are (TRACK_MOM_X, TRACK_MOM_Y, TRACK_MOM_Z}) + # and (TRACK_POS_CLOSEST_TO_BEAM_X, TRACK_POS_CLOSEST_TO_BEAM_Y, TRACK_POS_CLOSEST_TO_BEAM_Z), + # which is why the trailing underscore in the name is added i.e. "TRACK_MOM_" and "TRACK_POS_CLOSEST_TO_BEAM_" +# all_vars.update({"TRACK_MOM_": F.TRACK_MOMVEC}) +# all_vars.update({"TRACK_POS_CLOSESTTOBEAM_": F.TRACK_POSVEC_CLOSESTTOBEAM}) +# all_vars.update({"IS_ABS_ID_pi": F.IS_ABS_ID("pi+")}) + all_vars.update({"IS_ID_pi": F.IS_ID("pi-")}) + all_vars.update({"PDG_MASS_pi": F.PDG_MASS("pi+")}) + all_vars.update({"SIGNED_DELTA_MASS_pi": F.SIGNED_DELTA_MASS("pi+")}) + all_vars.update({"ABS_DELTA_MASS_pi": F.ABS_DELTA_MASS("pi+")}) + all_vars.update({"IS_NOT_H": F.IS_NOT_H}) + all_vars.update({"IS_PHOTON": F.IS_PHOTON}) + all_vars.update({"TRACKPT": F.TRACK_PT}) +# all_vars.update({"TRACKHISTORY": F.VALUE_OR(-1) @ F.TRACKHISTORY @ F.TRACK}) + all_vars.update({"QOVERP": F.QOVERP @ F.TRACK}) + all_vars.update({"NDOF": F.VALUE_OR(-1) @ F.NDOF @ F.TRACK}) + all_vars.update({"NFTHITS": F.VALUE_OR(-1) @ F.NFTHITS @ F.TRACK}) + all_vars.update({"NHITS": F.VALUE_OR(-1) @ F.NHITS @ F.TRACK}) + all_vars.update({"NUTHITS": F.VALUE_OR(-1) @ F.NUTHITS @ F.TRACK}) + all_vars.update({"NVPHITS": F.VALUE_OR(-1) @ F.NVPHITS @ F.TRACK}) + all_vars.update({"TRACKHASVELO": F.VALUE_OR(-1) @ F.TRACKHASVELO @ F.TRACK}) +# all_vars.update({"TRACKHASUT": F.VALUE_OR(-1) @ F.TRACKHASUT @ F.TRACK}) + # all_vars.update({"SHOWER_SHAPE": F.CALO_NEUTRAL_SHOWER_SHAPE}) + all_vars.update({"TX": F.TX}) + all_vars.update({"TY": F.TY}) + + + all_vars.update({"BPVIP": F.BPVIP(pvs)}) + all_vars.update({"BPVIPCHI2": F.BPVIPCHI2(pvs)}) + all_vars.update({"BPVX": F.BPVX(pvs)}) + all_vars.update({"BPVY": F.BPVY(pvs)}) + all_vars.update({"BPVZ": F.BPVZ(pvs)}) + all_vars.update({"MINIP": F.MINIP(pvs)}) + all_vars.update({"MINIPCHI2": F.MINIPCHI2(pvs)}) + + all_vars.update({"CHARGE": F.CHARGE}) + all_vars.update({"CHI2": F.CHI2}) + all_vars.update({"CHI2DOF": F.CHI2DOF}) + +# if top: # apply this only to B +# all_vars.update({"CHILD1_PT": F.CHILD(1, F.PT)}) # example of CHILD +# all_vars.update({"Ds_END_VZ": F.CHILD(1, F.END_VZ)}) +# all_vars.update({"Delta_END_VZ_DsB0": F.CHILD(1, F.END_VZ) - F.END_VZ}) + + + all_vars.update({"ETA": F.ETA}) + all_vars.update({"FOURMOMENTUM": F.FOURMOMENTUM}) +# all_vars.update({"ISBASIC": F.ISBASICPARTICLE}) + + all_vars.update({"MASS": F.MASS}) + +# all_vars.update({"OBJECT_KEY": F.OBJECT_KEY}) + + all_vars.update({"PHI": F.PHI}) + +# all_vars.update({"ABS_PX": F.ABS @ F.PX}) + +# all_vars.update({"REFERENCEPOINT_X": F.REFERENCEPOINT_X}) +# all_vars.update({"REFERENCEPOINT_Y": F.REFERENCEPOINT_Y}) +# all_vars.update({"REFERENCEPOINT_Z": F.REFERENCEPOINT_Z}) + + + + + print(f"### For {ptype} returning variables {all_vars.functor_dict.keys()}") + return all_vars + + +def event_variables(PVs, ODIN, decreports, lines): + """ + event variables + """ + + evt_vars = FunctorCollection({}) + evt_vars += EventInfo() + + + evt_vars += FC.SelectionInfo(selection_type="Hlt2", trigger_lines=lines) + if decreports: + evt_vars.update( + { + "DECISIONS": F.DECISIONS( + Lines=[bd2dsk_line + "Decision"], DecReports=decreports + ) + } + ) + evt_vars.update( + { + "DECREPORTS_FILTER": F.DECREPORTS_FILTER( + Lines=[bd2dsk_line + "Decision"], DecReports=decreports + ) + } + ) + + if ODIN: + evt_vars.update({"EVENTTYPE": F.EVENTTYPE(ODIN)}) + + evt_vars.update({"PV_SIZE": F.SIZE(PVs)}) + + if decreports: + evt_vars.update({"TCK": F.TCK(decreports)}) + + print(f"### For event returning variables {evt_vars.functor_dict.keys()}") + return evt_vars + + +def template(decay_descriptor, line_name, isturbo, Hlt2_decisions, input_data): + + evtpath_prefix = "/Event/Spruce/" + if isturbo: + evtpath_prefix = "/Event/HLT2/" + +# input_data = get_particles(evtpath_prefix + f"{line_name}/Particles") + + pvs = get_pvs() + + Hlt1_decisions = [ + 'Hlt1TrackMVADecision', 'Hlt1TwoTrackMVADecision', 'Hlt1D2KKDecision', + 'Hlt1D2KPiDecision', 'Hlt1D2PiPiDecision', + 'Hlt1DiMuonHighMassDecision', 'Hlt1DiMuonLowMassDecision', + 'Hlt1DiMuonSoftDecision', + 'Hlt1KsToPiPiDecision', 'Hlt1LowPtMuonDecision', + 'Hlt1LowPtDiMuonDecision', 'Hlt1SingleHighPtMuonDecision', + 'Hlt1TrackMuonMVADecision', "Hlt1DiMuonNoIP_SSDecision", + "Hlt1DiMuonDrellYan_VLowMassDecision", + "Hlt1DiMuonDrellYan_VLowMass_SSDecision", + "Hlt1DiMuonDrellYanDecision", + "Hlt1DiMuonDrellYan_SSDecision", + "Hlt1DetJpsiToMuMuPosTagLineDecision", + "Hlt1DetJpsiToMuMuNegTagLineDecision", + "Hlt1TrackElectronMVADecision", + "Hlt1SingleHighPtElectronDecision", + "Hlt1DiElectronDisplacedDecision", + "Hlt1SingleHighEtDecision", + "Hlt1DiPhotonHighMassDecision", + "Hlt1Pi02GammaGammaDecision", + "Hlt1DiElectronHighMass_SSDecision", + "Hlt1DiElectronHighMassDecision", + "Hlt1DiMuonNoIPDecision", + ] + + composite_variables = FunctorCollection({ + "END_VX_ERR":F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.ENDVERTEX, + "END_VY_ERR":F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.ENDVERTEX, + "END_VZ_ERR":F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.ENDVERTEX, + "BPVX_ERR": F.SQRT @ F.CALL(0,0) @ F.POS_COV_MATRIX @ F.BPV(pvs), + "BPVY_ERR": F.SQRT @ F.CALL(1,1) @ F.POS_COV_MATRIX @ F.BPV(pvs), + "BPVZ_ERR": F.SQRT @ F.CALL(2,2) @ F.POS_COV_MATRIX @ F.BPV(pvs), + "PERR": F.SQRT @ F.PERR2, + "PXERR": F.SQRT @ F.CALL(0,0) @ F.THREE_MOM_COV_MATRIX, + "PYERR": F.SQRT @ F.CALL(1,1) @ F.THREE_MOM_COV_MATRIX, + "PZERR": F.SQRT @ F.CALL(2,2) @ F.THREE_MOM_COV_MATRIX, + }) + + composite_variables += HltTisTos( selection_type="Hlt1", trigger_lines=Hlt1_decisions, data=input_data) + if not isturbo: + composite_variables += HltTisTos( selection_type="Hlt2", trigger_lines=Hlt2_decisions, data=input_data) + + daughter_variables = FunctorCollection({ + "PERR": F.SQRT @ F.PERR2, + "PZERR": F.SQRT @ F.CALL(2,2) @ F.THREE_MOM_COV_MATRIX, + }) + + #define event level variables + odin = get_odin() + decreports = None + rec_sum=get_rec_summary() + event_info = event_variables(pvs, odin, decreports, [line_name]) + FunctorCollection({ + "nPVs": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nPVs"), + "nTTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nTTracks"), + "nLongTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nLongTracks"), + "nDownstreamTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nDownstreamTracks"), + "nUpstreamTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nUpstreamTracks"), + "nVeloTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVeloTracks"), + "nBackTracks": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nBackTracks"), + "nRich1Hits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nRich1Hits"), + "nRich2Hits": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nRich2Hits"), + "nVPClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nVPClusters"), + "nFTClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nFTClusters"), + "eCalTot": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"eCalTot"), + "hCalTot": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"hCalTot"), + "nEcalClusters": F.VALUE_OR(-1) @F.RECSUMMARY_INFO(rec_sum,"nEcalClusters"), + "ALLPVX": F.ALLPVX(pvs), + "ALLPVY": F.ALLPVY(pvs), + "ALLPVZ": F.ALLPVZ(pvs), + }) + + event_info += FC.SelectionInfo( + selection_type="Hlt1", trigger_lines=Hlt1_decisions + ) + + + def extra_info(mctruth): + return FunctorCollection({ + "TRUEKEY": F.VALUE_OR(-1) @ mctruth(F.OBJECT_KEY), + "TRUEEID": F.VALUE_OR(0) @ mctruth(F.PARTICLE_ID), + "TRUEORIGIN_VZ" : F.VALUE_OR(-1000) @ mctruth(F.ORIGIN_VZ), + "TRUEORIGIN_VX" : F.VALUE_OR(-1000) @ mctruth(F.ORIGIN_VX), + "TRUEORIGIN_VY" : F.VALUE_OR(-1000) @ mctruth(F.ORIGIN_VY), + "TRUEEND_VZ" : F.VALUE_OR(-1000) @ mctruth(F.END_VZ), + "TRUEEND_VX" : F.VALUE_OR(-1000) @ mctruth(F.END_VX), + "TRUEEND_VY" : F.VALUE_OR(-1000) @ mctruth(F.END_VY), + "TRUEENERGY": F.VALUE_OR(-1e6) @ mctruth(F.ENERGY), + "TRUEP": F.VALUE_OR(-1e6) @ mctruth(F.P), + "TRUEFOURMOMENTUM": mctruth(F.FOURMOMENTUM), + "TRUE_PX" : F.VALUE_OR(-1e6) @ mctruth(F.PX), + "TRUE_PY" : F.VALUE_OR(-1e6) @ mctruth(F.PY), + "TRUE_PZ" : F.VALUE_OR(-1e6) @ mctruth(F.PZ), + "TRUE_MASS" : F.VALUE_OR(-1) @ mctruth(F.MASS), + "MC_LIFETIME" : F.VALUE_OR(-1) @ mctruth(F.MC_LIFETIME), + "BKGCAT": mctruth.BkgCat + }) + + mc_truth = MCTruthAndBkgCat(input_data, name = f"MCTruthAndBkgCat_{line_name}_" ) + + variables = { + "ALL" : extra_info(mc_truth), + "Bc": composite_variables + all_variables(pvs, None, _composite), + "Kp": daughter_variables + all_variables(pvs, None, _basic), + "Km": daughter_variables + all_variables(pvs, None, _basic), + "pip": daughter_variables + all_variables(pvs, None, _basic), + } + + #define FunTuple instance + my_tuple = Funtuple( + name=line_name, + tuple_name="DecayTree", + fields=decay_descriptor, + variables=variables, + event_variables=event_info, + store_multiple_cand_info = True, + inputs=input_data) + + return my_tuple + +#def line_prefilter(line_name): +# return create_lines_filter(name=f"HLT_PASS{line_name}", lines=[line_name])