From d498d162c2aa5992fff7279389c605aa2c4a0873 Mon Sep 17 00:00:00 2001 From: Davide Fazzini <davide.fazzini@cern.ch> Date: Fri, 21 Oct 2022 21:57:41 +0200 Subject: [PATCH] Update tagging array qmtest including mctruth infos --- .../option_davinci_tupling_array_taggers.py | 144 +++++++++++++++--- .../test_davinci_tupling_array_taggers.qmt | 3 +- .../test_davinci_tupling_array_taggers.ref | 87 +++++++---- 3 files changed, 187 insertions(+), 47 deletions(-) diff --git a/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_array_taggers.py b/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_array_taggers.py index 272b7726c..c493dbcfa 100644 --- a/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_array_taggers.py +++ b/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_array_taggers.py @@ -10,68 +10,175 @@ ############################################################################### """ Option file for testing the ParticleTaggerAlg algorithm and the related ThOr -functors MAP_INPUT_ARRAY. The job runs over a spruced sample and retrieves a +functors MAP_INPUT_ARRAY. + +The aim of this example, is to retrieve and store in the final ntuple some +variables related to the additional tracks generated in the event that are not +included in the decay chain. This kind of task has been developed for flavour +tagging pourposes but can be extended also to other area. + +In particular, the job runs over a spruced sample and retrieves a set of B0 -> Ds K+ candidates. For each candidate the ParticleTaggerAlg looks at the TES location defined via the 'make_long_pions' -function and creates a 'one-to-many' relation map relating all the available +function and creates a 'one-to-many' relation map linking all the available tracks to the B candidate of the events. Then the MAP_INPUT_ARRAY functor takes in input this relation map and for each entry stores the output of an external functor (i.e F.P, F.PT) in a vector. + +In addition, MC truth information for each track in the 'make_long-pions' +location is retrieved and stored in the final tuples via the 'configured_MCTruthAndBkgCatAlg' function. + +N.B. the job runs over a spruced sample, but the same flow can be used also for +turbo .dst. """ -import Functors as F -from PyConf.Algorithms import ParticleTaggerAlg, ParticleContainerMerger -from FunTuple import FunctorCollection, FunTuple_Particles as Funtuple from PyConf.reading import get_particles +from PyConf.Algorithms import ParticleTaggerAlg, ParticleContainerMerger + +import Functors as F +from FunTuple import FunctorCollection as FC, FunTuple_Particles as Funtuple from DaVinci import Options, make_config from DaVinci.algorithms import add_filter from DaVinci.common_particles import make_long_pions +from DaVinci.truth_matching import configured_MCTruthAndBkgCatAlg def main(options: Options): - bd2dsk_line = "SpruceB2OC_BdToDsmK_DsmToHHH_FEST_Line" + # Define the fields of the decay chain of interest + fields = { + 'B0': "[B0 -> D_s- K+]CC", + 'Ds': "[B0 -> ^D_s- K+]CC", + 'Kp': "[B0 -> D_s- ^K+]CC", + } + + # Retrieve particles surviving a specific spruced line + bd2dsk_line = "Spruce_Test_line" bd2dsk_data = get_particles(f"/Event/Spruce/{bd2dsk_line}/Particles") + # Create a new pion container via the 'make_long_pions()' function + # implemented in DaVinci.common_particles modulo. pions = make_long_pions() + # Since the provenance of the tracks is not important in this kind of task, + # the 'ParticleTaggerAlg' runs over a unique 'ParticleContainerMerger' + # object, merging together all the track containers defined by the user. tagging_container = ParticleContainerMerger( InputContainers=[pions]).OutputContainer + # Define ParticleTagger algorithm and create a relation table between the + # decay mother particle, i.e. B0 meson and all the tracks defined in the + # 'tagging_contaienr'. tagAlg = ParticleTaggerAlg( Input=bd2dsk_data, TaggingContainer=tagging_container, OutputLevel=3) + # Retrieve the relation map linking all the underlying tracks availanle in the 'tagging_container' + # to the B meson. This map will be used in the next steps for the functor evaluation. tagAlg_rels = tagAlg.OutputRelations + # If the user needs to store the MC truth information related to the tracks + # available in the event, the same fucntions used for the decay chain + # particles can be followed. + # For a comparison define both a relation map to the corresponding MC particles + # for the decay chain ('mctruth') and for the other tracks in the event ('mctruth_pions'). + mctruth = configured_MCTruthAndBkgCatAlg(inputs=bd2dsk_data) + mctruth_pions = configured_MCTruthAndBkgCatAlg(inputs=tagging_container) + + # Helper 'lambda functions' can be used to evaluate a specific functor (func) over all the particles + # linked in a relation table, defined by the 'Relations' keyword. + # In this case we create a lambda function that apply a functor, given as input by the user, + # to all the MC particles found by the 'configured_MCTruthAndBkgCatAlg' instances + # defined before: both for the signal decay chain and for the underlying tracks. + # In particular the 'MCAssocTable' method can be used to obtain the correct relation map from the + # 'mctruth' and 'mctruth_pions' objects defined before. + MCTRUTH = lambda func: F.MAP_INPUT(Functor=func, Relations=mctruth.MCAssocTable) + MCTRUTH_pions = lambda func: F.MAP_INPUT(Functor=func, Relations=mctruth_pions.MCAssocTable) + #make collection of functors - variables_B = FunctorCollection({ + # Define all the variables to be associated to the B field + # + #N.B: a default value has to be defined for functors returning an int/bool value (or an array of int/bool values) + #in case the output is empty: e.g. "TRUEID" or "TagTr_TRUEKEY[nTags]". + variables_B = FC({ 'THOR_MASS': F.MASS, + 'PT': + F.PT, + # Retrieve the true ID for the B meson usign the 'MCTRUTH' lambda fucntion definded above + "TRUEID": + F.VALUE_OR(0) @ MCTRUTH(F.PARTICLE_ID), + # Define variables for the tagging particles associated to the B meson. + # The 'MAP_INPUT_ARRAY' functor can be used to evaluate the functor of interest to all the tracks + # linked the 'tagAlg_rels' relation table generated via the 'ParticleTaggeerAlg' algorithm. "TagTr_P": F.MAP_INPUT_ARRAY(Functor=F.P, Relations=tagAlg_rels), # Currently this stores a branch called "indx" which corresponds to nPVs. # You can give a custom name for this via following "TagTr_PT[nTags]": F.MAP_INPUT_ARRAY(Functor=F.PT, Relations=tagAlg_rels), + "TagTr_PHI[nTags]": + F.MAP_INPUT_ARRAY(Functor=F.PHI, Relations=tagAlg_rels), + # Define variables containing the MC truth information for the underlying tracks. + # The 'MAP_INPUT_ARRAY' functor can be used as in the previous example, but in this case + # the 'MCTRUTH_pions' lambda funtion has to be exploited for applying the functor of interest + # to MC particles associated to the underlying tracks. + # + # N.B.: an additional default value has to be added in the definition of MAP_INPUT_ARRAY + # in case of internal functors built via lambda functions in order to ensure that a valid + # output is always defined, e.g. MCTRUTH_pions. + "TagTr_TRUEID[nTags]": + F.VALUE_OR([0]) @ F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(0) @ MCTRUTH_pions(F.PARTICLE_ID), + Relations=tagAlg_rels), + "TagTr_TRUEKEY[nTags]": + F.VALUE_OR([-1]) @ F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(-1) @ MCTRUTH_pions(F.OBJECT_KEY), + Relations=tagAlg_rels), + "TagTr_TRUEP[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.P), + Relations=tagAlg_rels), + "TagTr_TRUEPT[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.PT), + Relations=tagAlg_rels), + "TagTr_TRUEPX[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.PX), + Relations=tagAlg_rels), + "TagTr_TRUEPY[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.PY), + Relations=tagAlg_rels), + "TagTr_TRUEPZ[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.PZ), + Relations=tagAlg_rels), + "TagTr_TRUEENERGY[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.ENERGY), + Relations=tagAlg_rels), + "TagTr_TRUEPHI[nTags]": + F.MAP_INPUT_ARRAY( + Functor=F.VALUE_OR(F.NaN) @ MCTRUTH_pions(F.PHI), + Relations=tagAlg_rels), }) - #make collection of functors for Muplus - variables_all = FunctorCollection({ + # Make collection of functors for all the signal decay chain particles + variables_all = FC({ 'THOR_P': F.P, 'THOR_PT': F.PT, }) - fields = { - 'B0': "[B0 -> D_s- K+]CC", - 'Ds': "[B0 -> ^D_s- K+]CC", - 'Kp': "[B0 -> D_s- ^K+]CC", - } - + # Define a dict with all the variables to be stored associated to the corresponding field. variables = { 'ALL': variables_all, #adds variables to all fields 'B0': variables_B, } + # Define the FunTuple object that will produce the final .root files, passing the directory and name + # of the output tree, the list of fields and the dict of variables to be stored, and the input data + # location containing the signal decay chain particles. tuple_B0DsK = Funtuple( name="B0DsK_Tuple", tuple_name="DecayTree", @@ -79,8 +186,11 @@ def main(options: Options): variables=variables, inputs=bd2dsk_data) + # Define a filter in order to process only the event with at least on candidates of interest. + # This is a very important step aimed to reduce both the computation time required by the job and + # to prevent any failure due to empty TES location. filter_B0DsK = add_filter(options, "HDRFilter_B0DsK", f"HLT_PASS('{bd2dsk_line}')") - algs = [filter_B0DsK, tuple_B0DsK] - return make_config(options, algs) + # Configure DaVinci passing the options and a list of the user-defined algortithms to be run. + return make_config(options, [filter_B0DsK, tuple_B0DsK]) diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_array_taggers.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_array_taggers.qmt index 35238856a..9d4afa92e 100644 --- a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_array_taggers.qmt +++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_array_taggers.qmt @@ -17,9 +17,8 @@ <argument name="args"><set> <text>DaVinciExamples.tupling.option_davinci_tupling_array_taggers:main</text> </set></argument> - <argument name="options_yaml_fn"><text>$DAVINCIEXAMPLESROOT/example_data/Spruce_all_lines_dst.yaml</text></argument> + <argument name="options_yaml_fn"><text>$DAVINCIEXAMPLESROOT/example_data/test_spruce_MCtools.yaml</text></argument> <argument name="extra_options_yaml"><text> - process: Spruce histo_file: DV-example-tagger-his.root ntuple_file: DV-example-tagger-ntp.root </text></argument> diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref b/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref index f2e08b620..73402b708 100644 --- a/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref +++ b/DaVinciExamples/tests/refs/test_davinci_tupling_array_taggers.ref @@ -6,7 +6,13 @@ NTupleSvc INFO Added stream file:DV-example-tagger- RootHistSvc INFO Writing ROOT histograms to: DV-example-tagger-his.root HistogramPersistencySvc INFO Added successfully Conversion service:RootHistSvc FSROutputStreamDstWriter INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc' +MCTruthAndBkgCatAlg#1.DaVinciSma... INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP] +MCTruthAndBkgCatAlg#1.DaVinciSma... INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP] +MCTruthAndBkgCatAlg#1.Background... INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP] FunctionalParticleMaker.LoKi::Hy... INFO CUT: ' ( (TrTYPE==3) &TrALL) ' +MCTruthAndBkgCatAlg#2.DaVinciSma... INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP] +MCTruthAndBkgCatAlg#2.DaVinciSma... INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP] +MCTruthAndBkgCatAlg#2.Background... INFO Will look into [/Event/Spruce/HLT2/Relations/ChargedPP2MCP, /Event/Spruce/HLT2/Relations/NeutralPP2MCP] ApplicationMgr INFO Application Manager Initialized successfully ApplicationMgr INFO Application Manager Started successfully EventPersistencySvc INFO Added successfully Conversion service:RootCnvSvc @@ -20,15 +26,16 @@ FSROutputStreamDstWriter INFO Set up File Summary Record FSROutputStreamDstWriter INFO Events output: 1 B0DsK_Tuple SUCCESS Booked 1 N-Tuples and 0 Event Tag Collections B0DsK_Tuple SUCCESS List of booked N-Tuples in directory "FILE1/B0DsK_Tuple" -B0DsK_Tuple SUCCESS ID=DecayTree Title="DecayTree" #items=11 {B0_THOR_MASS,indx,B0_TagTr_P[1]/V,nTags,B0_TagTr_PT[1]/V,B0_THOR_P,B0_THOR_PT,Ds_} -LAZY_AND: DaVinci #=118 Sum=75 Eff=|( 63.55932 +- 4.43039 )%| - NONLAZY_OR: FileSummaryRecords #=118 Sum=118 Eff=|( 100.0000 +- 0.00000 )%| - LAZY_AND: GenFSR #=118 Sum=118 Eff=|( 100.0000 +- 0.00000 )%| - RecordStream/FSROutputStreamDstWriter #=118 Sum=118 Eff=|( 100.0000 +- 0.00000 )%| - NONLAZY_OR: UserAnalysis #=118 Sum=75 Eff=|( 63.55932 +- 4.43039 )%| - LAZY_AND: default #=118 Sum=75 Eff=|( 63.55932 +- 4.43039 )%| - LoKi__HDRFilter/HDRFilter_B0DsK #=118 Sum=75 Eff=|( 63.55932 +- 4.43039 )%| - FunTupleBase_Particles/B0DsK_Tuple #=75 Sum=75 Eff=|( 100.0000 +- 0.00000 )%| +B0DsK_Tuple SUCCESS ID=DecayTree Title="DecayTree" #items=23 {B0_THOR_MASS,B0_PT,B0_TRUEID,indx,B0_TagTr_P[1]/V,nTags,B0_TagTr_PT[1]/V,B0_TagTr} +LAZY_AND: DaVinci #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + NONLAZY_OR: FileSummaryRecords #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + LAZY_AND: GenFSR #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + RecordStream/FSROutputStreamDstWriter #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + NONLAZY_OR: UserAnalysis #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + LAZY_AND: default #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + LHCb__UnpackRawEvent/LHCb__UnpackRawEvent#1 #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + LoKi__HDRFilter/HDRFilter_B0DsK #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| + FunTupleBase_Particles/B0DsK_Tuple #=14 Sum=14 Eff=|( 100.0000 +- 0.00000 )%| RFileCnv INFO dumping contents of /NTUPLES/FILE1 TFile: name=DV-example-tagger-ntp.root, title=Gaudi Trees, option=CREATE NTupleSvc INFO NTuples saved successfully @@ -36,35 +43,59 @@ ApplicationMgr INFO Application Manager Finalized succes ApplicationMgr INFO Application Manager Terminated successfully B0DsK_Tuple INFO Number of counters : 7 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | - | "# events with multiple candidates for field B0"| 65 | - | "# events with multiple candidates for field Ds"| 65 | - | "# events with multiple candidates for field Kp"| 65 | - | "# non-empty events for field B0" | 75 | - | "# non-empty events for field Ds" | 75 | - | "# non-empty events for field Kp" | 75 | - | "# processed events" | 75 | + | "# events with multiple candidates for field B0"| 2 | + | "# events with multiple candidates for field Ds"| 2 | + | "# events with multiple candidates for field Kp"| 2 | + | "# non-empty events for field B0" | 14 | + | "# non-empty events for field Ds" | 14 | + | "# non-empty events for field Kp" | 14 | + | "# processed events" | 14 | FunctionalParticleMaker INFO Number of counters : 4 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | - |*"# passed ProtoParticle filter" | 2117 | 2117 |( 100.0000 +- 0.000000)% | - |*"# passed Track filter" | 2117 | 2117 |( 100.0000 +- 0.000000)% | - | "Nb created anti-particles" | 75 | 1074 | 14.320 | 28.046 | 2.0000 | 148.00 | - | "Nb created particles" | 75 | 1043 | 13.907 | 27.832 | 2.0000 | 144.00 | + |*"# passed ProtoParticle filter" | 57 | 57 |( 100.0000 +- 0.000000)% | + |*"# passed Track filter" | 57 | 57 |( 100.0000 +- 0.000000)% | + | "Nb created anti-particles" | 14 | 28 | 2.0000 | 0.0000 | 2.0000 | 2.0000 | + | "Nb created particles" | 14 | 29 | 2.0714 | 0.25754 | 2.0000 | 3.0000 | HDRFilter_B0DsK INFO Number of counters : 1 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | - |*"#passed" | 118 | 75 |( 63.55932 +- 4.430389)% | + |*"#passed" | 14 | 14 |( 100.0000 +- 0.000000)% | +HltPackedBufferDecoder INFO Number of counters : 1 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | " DstData raw bank has a zero encoding key, and it is not explicitly specified for decoding -- make sure that this really what you want"| 14 | +MCTruthAndBkgCatAlg#1 INFO Number of counters : 3 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | "Events" | 14 | + | "Ghosts" | 1 | 0 | 0.0000 | 0.0000 | 4.2950e+09 | 0.0000 | + | "Particles" | 96 | 0 | 0.0000 | 0.0000 | 4.2950e+09 | 0.0000 | +MCTruthAndBkgCatAlg#2 INFO Number of counters : 2 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | "Events" | 14 | + | "Particles" | 57 | 0 | 0.0000 | 0.0000 | 4.2950e+09 | 0.0000 | +PP2MCPRelationUnpacker INFO Number of counters : 1 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | "# PackedData" | 14 | 84 | 6.0000 | +PP2MCPRelationUnpacker#1 INFO Number of counters : 1 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | "# AbsentBuffer" | 14 | 0 | 0.0000 | ParticleContainerMerger INFO Number of counters : 2 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | - | "# input particles" | 75 | 2117 | 28.227 | - | "# output particles" | 2117 | 0 | 0.0000 | + | "# input particles" | 14 | 57 | 4.0714 | + | "# output particles" | 57 | 0 | 0.0000 | ParticleTaggerAlg INFO Number of counters : 3 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | - | "Events" | 75 | - | "Input Particles" | 75 | 459 | 6.1200 | 7.6680 | 1.0000 | 50.000 | - | "Output Particles" | 75 | 2117 | 28.227 | 55.806 | 4.0000 | 292.00 | + | "Events" | 14 | + | "Input Particles" | 14 | 16 | 1.1429 | 0.34993 | 1.0000 | 2.0000 | + | "Output Particles" | 14 | 57 | 4.0714 | 0.25754 | 4.0000 | 5.0000 | ParticleUnpacker INFO Number of counters : 2 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | - | "# Linked BufferData" | 826 | 4290998 | 5194.9 | - | "# UnpackedData" | 150 | 91119 | 607.46 | + | "# Linked BufferData" | 161 | 117195 | 727.92 | + | "# UnpackedData" | 28 | 3700 | 132.14 | +ProtoParticleUnpacker#1 INFO Number of counters : 1 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | "# AbsentBuffer" | 14 | 0 | 0.0000 | +Spruce INFO Number of counters : 1 + | Counter | # | sum | mean/eff^* | rms/err^* | min | max | + | " HltDecReports has a zero TCK, and it is not explicitly specified for decoding -- make sure that this really what you want"| 14 | ToolSvc.HltFactory INFO Number of counters : 1 | Counter | # | sum | mean/eff^* | rms/err^* | min | max | ToolSvc.PPFactoryHybridFactory INFO Number of counters : 1 -- GitLab