diff --git a/Phys/FunTuple/python/FunTuple/functorcollections.py b/Phys/FunTuple/python/FunTuple/functorcollections.py index 810d804e69864672c44daec83b0c72a0c9a8f5e7..1cb23aff83b0656cea26864c4a896d498b5c7761 100644 --- a/Phys/FunTuple/python/FunTuple/functorcollections.py +++ b/Phys/FunTuple/python/FunTuple/functorcollections.py @@ -24,7 +24,7 @@ from PyConf.reading import get_odin, get_decreports, get_hlt1_selreports # type from PyConf.application import make_data_with_FetchDataFromFile # type: ignore[import] from PyConf.dataflow import DataHandle # type: ignore[import] from PyConf.components import Algorithm # type: ignore[import] -from PyConf.Algorithms import HltTisTosAlg, Hlt1TrueSimEffAlg, Hlt2TrueSimEffAlg # type: ignore[import] +from PyConf.Algorithms import HltTisTosAlg, Hlt1TrueSimEffAlg, Hlt2TrueSimEffAlg, WeightedRelTableAlg # type: ignore[import] import DaVinciMCTools # type: ignore[import] from DecayTreeFitter import DecayTreeFitter # type: ignore[import] from .FunctorCollection import FunctorCollection @@ -40,7 +40,8 @@ __all__ = ( "MCPromptDecay", "MCReconstructible", "MCReconstructed", - "TrackIsolation", + "ParticleIsolation", + "ConeIsolation", "NeutralCaloInfo", "DecayTreeFitterResults", "ParticleID", @@ -838,41 +839,42 @@ def MCReconstructed( return FunctorCollection(func_dict) -def TrackIsolation(*, iso_rel_table: Algorithm) -> FunctorCollection: +def ParticleIsolation(*, iso_rel_table: Algorithm, name: str = "") -> FunctorCollection: """ - Candidate-level collection of functors on track isolation, using information related to the particles - inside the cone around a given reference particle. + Candidate-level collection of functors on track or neutral isolation, using information from 'iso_rel_table' argument relating containers of reference and extra particle, namely head particles of the cone and particles inside the cone. Args: - iso_rel_table (WeightedRelTableAlg): algorithm instance returning the required relations table + iso_rel_table (Algorithm): algorithm instance returning the required relations table that maps a reference particle (forming the head of the cone) - to associated particles inside the cone itself. + to associated particles (inside the cone itself). + name (string, optional): string that helps in distinguishing variables + according to some criteria (for example if the isolation criteria are applied to charged or neutral particles). + Defaults to "". Example: + import Functors as F from FunTuple import FunTuple_Particles as Funtuple - from FunTuple.functorcollections import TrackIsolation + from FunTuple.functorcollections import ParticleIsolation from PyConf.Algorithms import WeightedRelTableAlg + from PyConf.reading import get_particles + branches = {"B": "[B0 -> ([J/psi(1S) -> tau+ mu-]CC)(K*(892)0 -> K+ pi-)]CC"} + + b2ksttaumu_data = get_particles(f"/Event/HLT2/{line}/Particles") + b_cciso_data = get_particles(f"/Event/HLT2/{line}/B_{tes_long_track_iso}/Particles") iso_rel_table = WeightedRelTableAlg( - ReferenceParticles=..., - InputCandidates=..., - Cut=..., + ReferenceParticles=b2ksttaumu_data, + InputCandidates=b_cciso_data, + Cut=F.require_all(F.DR2()<1., ~F.FIND_IN_TREE()), #requires cone geometry with max_coneangle = 1. and extra particles not belonging to the signal OutputLevel=INFO) - variables = TrackIsolation(iso_rel_table) + variables = FC.ParticleIsolation(name="CC", iso_rel_table=iso_rel_table) tuple = Funtuple(name="MyTuple", - fields=..., + fields=branches, variables=variables, ...) - - - Todo: - Exclude particles that are in the decay descriptor and therefore belong to the decay that is being looked for. - At the moment WeightedRelTableAlg is making relations between the reference particle (head of the cone) - and related particles (particles within the cone) without checking whenever the particles in the cone - belong to the same decay of the head. """ SUMCONE = lambda func: F.SUMCONE( Functor=func, Relations=iso_rel_table.OutputRelations @@ -892,23 +894,109 @@ def TrackIsolation(*, iso_rel_table: Algorithm) -> FunctorCollection: # evaluate DELTA PHI between reference and related particles DELTA_PHI = F.ADJUST_ANGLE @ (REL_PHI - REF_PHI) - TrackIsolationVariables = { - "HEAD_CMULT": F.VALUE_OR(0) + prefix = "HEAD" + if name: + prefix += f"_{name}" + + ParticleIsolationVariables = { + f"{prefix}_CMULT": F.VALUE_OR(0) @ F.MAP_INPUT_SIZE(Relations=iso_rel_table.OutputRelations), - "HEAD_CP": SUMCONE(F.P), - "HEAD_CPT": SUMCONE(F.PT), - "HEAD_CPX": SUMCONE(F.PX), - "HEAD_CPY": SUMCONE(F.PY), - "HEAD_CPZ": SUMCONE(F.PZ), - "HEAD_PASY": ASYM(F.P), - "HEAD_PTASY": ASYM(F.PT), - "HEAD_PXASY": ASYM(F.PX), - "HEAD_PYASY": ASYM(F.PY), - "HEAD_PZASY": ASYM(F.PZ), - "HEAD_DETA": F.MAP(DELTA_ETA()).bind(RELS(), F.FORWARDARGS), - "HEAD_DPHI": F.MAP(DELTA_PHI()).bind(RELS(), F.FORWARDARGS), + f"{prefix}_CP": SUMCONE(F.P), + f"{prefix}_CPT": SUMCONE(F.PT), + f"{prefix}_CPX": SUMCONE(F.PX), + f"{prefix}_CPY": SUMCONE(F.PY), + f"{prefix}_CPZ": SUMCONE(F.PZ), + f"{prefix}_PASY": ASYM(F.P), + f"{prefix}_PTASY": ASYM(F.PT), + f"{prefix}_PXASY": ASYM(F.PX), + f"{prefix}_PYASY": ASYM(F.PY), + f"{prefix}_PZASY": ASYM(F.PZ), + f"{prefix}_DETA": F.MAP(DELTA_ETA()).bind(RELS(), F.FORWARDARGS), + f"{prefix}_DPHI": F.MAP(DELTA_PHI()).bind(RELS(), F.FORWARDARGS), } - return FunctorCollection(TrackIsolationVariables) + return FunctorCollection(ParticleIsolationVariables) + + +def ConeIsolation( + *, + head_cone: DataHandle, + charged_cone: DataHandle, + neutral_cone: DataHandle, + cut: DataHandle, + name: str = "", +) -> FunctorCollection: + """ + Candidate-level collection of functors on charged and neutral isolation, using information from relations between sets of particles determined by a given criteria. Calculates the relations that 'head_cone' particle selection has with 'charged_cone' particle selection and 'neutral_cone' particle selection, respectively. The cone isolation criteria are determined by the expression in the 'cut'. + + Args: + head_cone (DataHandle): container that represents the reference particles (head of the cone). + charged_cone (DataHandle): container that represents the extra charged particles persisted from the event. + neutral_cone (DataHandle): container that represents the extra neutral particles persisted from the event. + cut (DataHandle): selection to relate head particles with extra particles + name (string, optional): string that helps in distinguishing variables + according to some criteria (for example the cone size criteria). + Defaults to "". + + Example: + import Functors as F + from FunTuple import FunTuple_Particles as Funtuple + from FunTuple.functorcollections import ParticleIsolation + from PyConf.Algorithms import WeightedRelTableAlg + from PyConf.reading import get_particles + from GaudiKernel.SystemOfUnits import GeV + + branches = {"B": "[B0 -> ([J/psi(1S) -> tau+ mu-]CC)(K*(892)0 -> K+ pi-)]CC"} + + b2ksttaumu_data = get_particles(f"/Event/HLT2/{line}/Particles") + b_cciso_data = get_particles(f"/Event/HLT2/{line}/B_{tes_long_track_iso}/Particles") + b_nciso_data = get_particles(f"/Event/HLT2/{line}/B_{tes_neutrals_iso}/Particles") + + variables = FC.ConeIsolation(name="MassConst", head_cone=b2ksttaumu_data, charged_cone=b_cciso_data, neutral_cone=b_nciso_data, cut=((F.COMB_MASS-F.MASS@F.FORWARDARG0)<0.5*GeV) + + tuple = Funtuple(name="MyTuple", + fields=branches, + variables=variables, + ...) + """ + # Prepare relation tables + cc_isoAlg = WeightedRelTableAlg( + ReferenceParticles=head_cone, InputCandidates=charged_cone, Cut=cut + ) + nc_isoAlg = WeightedRelTableAlg( + ReferenceParticles=head_cone, InputCandidates=neutral_cone, Cut=cut + ) + + cc_str = "CC" + nc_str = "NC" + if name: + cc_str += f"_{name}" + nc_str += f"_{name}" + + cc_prefix = "HEAD_" + cc_str + nc_prefix = "HEAD_" + nc_str + # Invoke twice the ParticleIsolation functorcollection, once for neutral and once for charged particles, then add to the functor dictionary + func_dict = { + f"{cc_prefix}_Max_PT": F.MAXCONE( + Functor=F.PT, Relations=cc_isoAlg.OutputRelations + ), + f"{cc_prefix}_Min_PT": F.MINCONE( + Functor=F.PT, Relations=cc_isoAlg.OutputRelations + ), + f"{nc_prefix}_Max_PT": F.MAXCONE( + Functor=F.PT, Relations=nc_isoAlg.OutputRelations + ), + f"{nc_prefix}_Min_PT": F.MINCONE( + Functor=F.PT, Relations=nc_isoAlg.OutputRelations + ), + } + func_dict.update( + ParticleIsolation(name=f"{cc_str}", iso_rel_table=cc_isoAlg).functor_dict + ) + func_dict.update( + ParticleIsolation(name=f"{nc_str}", iso_rel_table=nc_isoAlg).functor_dict + ) + + return FunctorCollection(func_dict) def NeutralCaloInfo() -> FunctorCollection: