From 79e58b404f381b4fb590b49e0c61f7945f576abc Mon Sep 17 00:00:00 2001
From: Abhijit Mathad <abhijit.mathad@cern.ch>
Date: Wed, 31 Aug 2022 10:53:19 +0200
Subject: [PATCH] Store information from RecSummary (nTracks, nPVs)

---
 .../example_data/Upgrade_LbToLcmunu.yaml      |  15 +++
 .../option_davinci_tupling_eventinfo.py       |  61 ++++++++++
 .../test_davinci_tupling_eventinfo.qmt        |  60 ++++++++++
 .../refs/test_davinci_tupling_eventinfo.ref   | 112 ++++++++++++++++++
 Phys/DaVinci/python/DaVinci/reco_objects.py   |  15 +++
 5 files changed, 263 insertions(+)
 create mode 100644 DaVinciExamples/example_data/Upgrade_LbToLcmunu.yaml
 create mode 100644 DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_eventinfo.py
 create mode 100644 DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_eventinfo.qmt
 create mode 100644 DaVinciExamples/tests/refs/test_davinci_tupling_eventinfo.ref

diff --git a/DaVinciExamples/example_data/Upgrade_LbToLcmunu.yaml b/DaVinciExamples/example_data/Upgrade_LbToLcmunu.yaml
new file mode 100644
index 000000000..07b5f4734
--- /dev/null
+++ b/DaVinciExamples/example_data/Upgrade_LbToLcmunu.yaml
@@ -0,0 +1,15 @@
+input_files:
+   - root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/Upgrade_LbToLcmunu.dst
+annsvc_config: root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/Upgrade_LbToLcmunu.tck.json
+data_type: Upgrade
+input_type: ROOT
+simulation: True
+conddb_tag: sim-20210617-vc-mu100
+dddb_tag: dddb-20210617
+input_raw_format: 0.5
+lumi: false
+ntuple_file: 'mytuple.root'
+print_freq: 1
+process: 'Hlt2'
+stream: 'default'
+evt_max: -1
\ No newline at end of file
diff --git a/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_eventinfo.py b/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_eventinfo.py
new file mode 100644
index 000000000..19cf451a5
--- /dev/null
+++ b/DaVinciExamples/python/DaVinciExamples/tupling/option_davinci_tupling_eventinfo.py
@@ -0,0 +1,61 @@
+###############################################################################
+# (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 information from RecSumarry
+(e.g. nPVs, nTracks, nFTClusters)
+"""
+import Functors as F
+from FunTuple import FunctorCollection as FC
+from FunTuple import FunTuple_Particles as Funtuple
+from PyConf.components import force_location
+from DaVinci.algorithms import add_filter
+from DaVinci import make_config, Options
+from DaVinci.algorithms import get_odin
+from FunTuple.functorcollections import EventInfo
+from DaVinci.reco_objects import get_rec_summary
+
+
+def main(options: Options):
+    #define fields
+    fields = {'Lb': '[Lambda_b0 -> (Lambda_c+ -> p+ K- pi+) mu-]CC'}
+
+    #define variables and add them to all fields
+    #lb_variables = Kinematics()
+    lb_variables = FC({'PT': F.PT})
+    variables = {"ALL": lb_variables}
+
+    #get RecSummary object that holds information about nPVs, nTracks, nFTClusters
+    # Note more information can be added to the RecSummary object
+    # (see MRs: https://gitlab.cern.ch/lhcb/Moore/-/merge_requests/1649)
+    rec_summary = get_rec_summary(options)
+    evt_vars = FC({
+        'nTracks': F.VALUE_OR(-1) @ F.NTRACKS(rec_summary),
+        'nPVs': F.VALUE_OR(-1) @ F.NPVS(rec_summary),
+        'nFTClusters': F.VALUE_OR(-1) @ F.NFTCLUSTERS(rec_summary)
+    })
+    #Get RunNUmber and EventNumber
+    odin = get_odin(options)
+    evt_vars += EventInfo(odin)
+
+    #get particles to run over
+    line_name = 'Hlt2SLB_LbToLcMuNu_LcToPKPi_Line'
+    particles = force_location(f"/Event/HLT2/{line_name}/Particles")
+    my_filter = add_filter(options, "Myfilter", f"HLT_PASS('{line_name}')")
+    #define tupling algorithm
+    my_tuple = Funtuple(
+        name="Tuple",
+        tuple_name="DecayTree",
+        fields=fields,
+        variables=variables,
+        event_variables=evt_vars,
+        inputs=particles)
+
+    return make_config(options, [my_filter, my_tuple])
diff --git a/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_eventinfo.qmt b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_eventinfo.qmt
new file mode 100644
index 000000000..520a42bd7
--- /dev/null
+++ b/DaVinciExamples/tests/qmtest/tupling.qms/test_davinci_tupling_eventinfo.qmt
@@ -0,0 +1,60 @@
+<?xml version="1.0" ?>
+<!--
+###############################################################################
+# (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.                                       #
+###############################################################################
+-->
+<!DOCTYPE extension  PUBLIC '-//QM/2.3/Extension//EN'  'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'>
+<extension class="GaudiTest.GaudiExeTest" kind="test">
+  <argument name="program"><text>lbexec</text></argument>
+  <argument name="args"><set>
+    <text>DaVinciExamples.tupling.option_davinci_tupling_eventinfo:main</text>
+  </set></argument>
+  <argument name="options_yaml_fn"><text>$DAVINCIEXAMPLESROOT/example_data/Upgrade_LbToLcmunu.yaml</text></argument>
+  <argument name="extra_options_yaml"><text>
+    ntuple_file: tuple_LbToLcmunu.root
+    print_freq: 1
+  </text></argument>
+  <argument name="reference"><text>../refs/test_davinci_tupling_eventinfo.ref</text></argument>
+  <argument name="error_reference"><text>../refs/empty.ref</text></argument>
+  <argument name="validator"><text>
+from DaVinciTests.QMTest.DaVinciExclusions import preprocessor,remove_known_warnings
+validateWithReference(preproc = preprocessor)
+
+import sys, os, glob
+from ROOT import TFile
+
+B_vars_stored = ['nTracks', 'nPVs', 'nFTClusters', 'EVENTNUMBER', 'RUNNUMBER', 'Lb_PT']
+
+#sort the expected vars
+B_vars_stored = sorted(B_vars_stored)
+
+#open the TFile and TTree
+ntuple = './tuple_LbToLcmunu.root'
+if not os.path.isfile(ntuple): raise Exception(f"File: {ntuple} does not exist!")
+f      = TFile.Open(ntuple)
+t_B    = f.Get('Tuple/DecayTree')
+
+#sort the stores vars
+b_names = sorted([b.GetName() for b in t_B.GetListOfLeaves()])
+
+B_excluded_1 = set(B_vars_stored) - set(b_names)
+B_excluded_2 = set(b_names) - set(B_vars_stored)
+if len(B_excluded_1) != 0: raise Exception('Number of stored variables is less than what is expected. The extra variables expected are: ' , B_excluded_1)
+if len(B_excluded_2) != 0: raise Exception('Number of stored variables is greater than what is expected. The extra variables stored are: ', B_excluded_2)
+
+f.Close()
+print('Test successfully completed!')
+os.system(f"rm {ntuple}")
+countErrorLines({"FATAL": 0, "WARNING": 0, "ERROR": 0},
+                stdout=remove_known_warnings(stdout))
+
+  </text></argument>
+</extension>
diff --git a/DaVinciExamples/tests/refs/test_davinci_tupling_eventinfo.ref b/DaVinciExamples/tests/refs/test_davinci_tupling_eventinfo.ref
new file mode 100644
index 000000000..d76c5d44f
--- /dev/null
+++ b/DaVinciExamples/tests/refs/test_davinci_tupling_eventinfo.ref
@@ -0,0 +1,112 @@
+ApplicationMgr    SUCCESS
+====================================================================================================================================
+====================================================================================================================================
+ApplicationMgr       INFO Application Manager Configured successfully
+DetectorPersistencySvc                 INFO Added successfully Conversion service:XmlCnvSvc
+DetectorDataSvc                     SUCCESS Detector description database: git:/lhcb.xml
+MagneticFieldGridReader INFO  Opened magnetic field file:  DBASE/FieldMap/vXrYpZ/cdf//field.v5r0.c1.up.cdf
+MagneticFieldGridReader INFO  Opened magnetic field file:  DBASE/FieldMap/vXrYpZ/cdf//field.v5r0.c2.up.cdf
+MagneticFieldGridReader INFO  Opened magnetic field file:  DBASE/FieldMap/vXrYpZ/cdf//field.v5r0.c3.up.cdf
+MagneticFieldGridReader INFO  Opened magnetic field file:  DBASE/FieldMap/vXrYpZ/cdf//field.v5r0.c4.up.cdf
+NTupleSvc                              INFO Added stream file:tuple_LbToLcmunu.root as FILE1
+RootHistSvc                            INFO Writing ROOT histograms to: tuple_LbToLcmunu.root
+HistogramPersistencySvc                INFO Added successfully Conversion service:RootHistSvc
+FSROutputStreamDstWriter               INFO Data source: EventDataSvc output: SVC='Gaudi::RootCnvSvc'
+ApplicationMgr                         INFO Application Manager Initialized successfully
+DeFTDetector                           INFO Current FT geometry version =   64
+ApplicationMgr                         INFO Application Manager Started successfully
+EventPersistencySvc                    INFO Added successfully Conversion service:RootCnvSvc
+EventSelector                       SUCCESS Reading Event record 1. Record number within stream 1: 1
+RFileCnv                               INFO opening Root file "tuple_LbToLcmunu.root" for writing
+RCWNTupleCnv                           INFO Booked TTree with ID: DecayTree "DecayTree" in directory tuple_LbToLcmunu.root:/Tuple
+EventSelector                       SUCCESS Reading Event record 2. Record number within stream 1: 2
+EventSelector                       SUCCESS Reading Event record 3. Record number within stream 1: 3
+EventSelector                       SUCCESS Reading Event record 4. Record number within stream 1: 4
+EventSelector                       SUCCESS Reading Event record 5. Record number within stream 1: 5
+EventSelector                       SUCCESS Reading Event record 6. Record number within stream 1: 6
+EventSelector                       SUCCESS Reading Event record 7. Record number within stream 1: 7
+ApplicationMgr                         INFO Application Manager Stopped successfully
+FSROutputStreamDstWriter               INFO Set up File Summary Record
+FSROutputStreamDstWriter               INFO Events output: 1
+Tuple                               SUCCESS Booked 1 N-Tuples and 0 Event Tag Collections
+Tuple                               SUCCESS List of booked N-Tuples in directory "FILE1/Tuple"
+Tuple                               SUCCESS  ID=DecayTree     Title="DecayTree"                               #items=6  {EVENTNUMBER,RUNNUMBER,nFTClusters,nPVs,nTracks,Lb_PT}
+LAZY_AND: DaVinci                                   #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+ NONLAZY_OR: FileSummaryRecords                     #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+  LAZY_AND: GenFSR                                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecordStream/FSROutputStreamDstWriter            #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+ NONLAZY_OR: UserAnalysis                           #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+  LAZY_AND: default                                 #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   LHCb__UnpackRawEvent/LHCb__UnpackRawEvent        #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   HltPackedBufferDecoder/HltPackedBufferDecoder    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   UnpackMCParticle/UnpackMCParticle                #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   UnpackMCVertex/UnpackMCVertex                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecVertexUnpacker/RecVertexUnpacker              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecVertexUnpacker/RecVertexUnpacker#1            #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecVertexUnpacker/RecVertexUnpacker#2            #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecVertexUnpacker/RecVertexUnpacker#3            #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecVertexUnpacker/RecVertexUnpacker#4            #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#1                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#2                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#3                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#4                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#5                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#6                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   VertexUnpacker/VertexUnpacker#7                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker                      #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#1                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#2                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#3                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#4                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#5                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#6                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#7                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#8                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   TrackUnpacker/TrackUnpacker#9                    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RichPIDUnpacker/RichPIDUnpacker                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RichPIDUnpacker/RichPIDUnpacker#1                #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   MuonPIDUnpacker/MuonPIDUnpacker                  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   MuonPIDUnpacker/MuonPIDUnpacker#1                #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   CaloHypoUnpacker/CaloHypoUnpacker                #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   CaloHypoUnpacker/CaloHypoUnpacker#1              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   CaloHypoUnpacker/CaloHypoUnpacker#2              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   CaloHypoUnpacker/CaloHypoUnpacker#3              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ProtoParticleUnpacker/ProtoParticleUnpacker      #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ProtoParticleUnpacker/ProtoParticleUnpacker#1    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker                #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#1              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#2              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#3              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#4              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#5              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#6              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#7              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   ParticleUnpacker/ParticleUnpacker#8              #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   RecSummaryUnpacker/RecSummaryUnpacker            #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   P2VRelationUnpacker/P2VRelationUnpacker          #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   P2VRelationUnpacker/P2VRelationUnpacker#1        #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   P2VRelationUnpacker/P2VRelationUnpacker#2        #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   P2VRelationUnpacker/P2VRelationUnpacker#3        #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   P2VRelationUnpacker/P2VRelationUnpacker#4        #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   PP2MCPRelationUnpacker/PP2MCPRelationUnpacker    #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   PP2MCPRelationUnpacker/PP2MCPRelationUnpacker#1  #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   LoKi__HDRFilter/Myfilter                         #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+   FunTupleBase_Particles/Tuple                     #=7       Sum=7           Eff=|( 100.0000 +- 0.00000 )%|
+ToolSvc                                INFO Removing all tools created by ToolSvc
+RFileCnv                               INFO dumping contents of /NTUPLES/FILE1
+TFile: name=tuple_LbToLcmunu.root, title=Gaudi Trees, option=CREATE
+NTupleSvc                              INFO NTuples saved successfully
+ApplicationMgr                         INFO Application Manager Finalized successfully
+ApplicationMgr                         INFO Application Manager Terminated successfully
+Myfilter                               INFO Number of counters : 1
+ |    Counter                                      |     #     |    sum     | mean/eff^* | rms/err^*  |     min     |     max     |
+ |*"#passed"                                       |         7 |          7 |( 100.0000 +-  0.000000)% |
+ToolSvc.HltFactory                     INFO Number of counters : 1
+ |    Counter                                      |     #     |    sum     | mean/eff^* | rms/err^*  |     min     |     max     |
+ | "# loaded from PYTHON"                          |         1 |
+Tuple                                  INFO Number of counters : 3
+ |    Counter                                      |     #     |    sum     | mean/eff^* | rms/err^*  |     min     |     max     |
+ | "# events with multiple candidates for field Lb"|         1 |
+ | "# non-empty events for field Lb"               |         7 |
+ | "# processed events"                            |         7 |
diff --git a/Phys/DaVinci/python/DaVinci/reco_objects.py b/Phys/DaVinci/python/DaVinci/reco_objects.py
index d85113e16..dff5dbabf 100644
--- a/Phys/DaVinci/python/DaVinci/reco_objects.py
+++ b/Phys/DaVinci/python/DaVinci/reco_objects.py
@@ -26,6 +26,7 @@ from PyConf.tonic import configurable
 from PyConf.Algorithms import RecV1ToPVConverter
 
 from DaVinci.locations import LocationsUnpackedReco, enums_as_dict
+from DaVinci.algorithms import unpack_locations
 
 
 @configurable
@@ -104,6 +105,20 @@ def make_pvs_v2(process='Spruce'):
     return RecV1ToPVConverter(InputVertices=pvs).OutputVertices
 
 
+def get_rec_summary(options):
+    #Would ideally want to do reconstruction(process=process)['RecSummary']
+    # However throws an error: "multiple algorithms declare /Event/HLT2/Rec/Summary"
+    # For now use a "hack" (FIX ME)
+    unpackers = unpack_locations(options, False)
+    rec_summary = None
+    for alg in unpackers:
+        if "OutputName" in alg.outputs.keys():
+            if (alg.OutputName.location == '/Event/HLT2/Rec/Summary'):
+                rec_summary = alg.OutputName
+
+    return rec_summary
+
+
 def get_particles(process="Spruce", location=""):
 
     if process == 'Spruce':
-- 
GitLab