From 191e8f566d75ec3ad55234e372234dd1a59a010c Mon Sep 17 00:00:00 2001 From: amathad <Abhijit Mathad amathad@cern.ch> Date: Tue, 2 Mar 2021 10:22:07 +0100 Subject: [PATCH 1/6] Tuple algorithm, moving from Phys to Analysis, removing LoKiGenMC mentions --- Phys/FunTuple/CMakeLists.txt | 36 ++ Phys/FunTuple/README.md | 1 + Phys/FunTuple/options/FunTuple_opts.py | 125 +++++ Phys/FunTuple/src/FunTuple.cpp | 465 ++++++++++++++++++ Phys/FunTuple/src/MakeData.cpp | 233 +++++++++ Phys/FunTuple/src/ParticleTupleProp.cpp | 47 ++ Phys/FunTuple/src/ParticleTupleProp.h | 57 +++ .../qmtest/algorithms.qms/test-funtuple.qmt | 35 ++ .../tests/qmtest/options/FunTuple_opts.py | 125 +++++ 9 files changed, 1124 insertions(+) create mode 100644 Phys/FunTuple/CMakeLists.txt create mode 100644 Phys/FunTuple/README.md create mode 100755 Phys/FunTuple/options/FunTuple_opts.py create mode 100755 Phys/FunTuple/src/FunTuple.cpp create mode 100755 Phys/FunTuple/src/MakeData.cpp create mode 100755 Phys/FunTuple/src/ParticleTupleProp.cpp create mode 100755 Phys/FunTuple/src/ParticleTupleProp.h create mode 100644 Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt create mode 100755 Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py diff --git a/Phys/FunTuple/CMakeLists.txt b/Phys/FunTuple/CMakeLists.txt new file mode 100644 index 000000000..c87a27354 --- /dev/null +++ b/Phys/FunTuple/CMakeLists.txt @@ -0,0 +1,36 @@ +############################################################################### +# (c) Copyright 2020-2021 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. # +############################################################################### + +gaudi_subdir(FunTuple) + +gaudi_depends_on_subdirs(Phys/DaVinciKernel + Phys/DaVinciMCKernel + Kernel/LHCbMath + Phys/LoKi + Phys/LoKiMC + Phys/LoKiAlgoMC + Phys/LoKiArrayFunctors + Phys/LoKiPhys + ) + +find_package(Boost) +find_package(ROOT COMPONENTS RIO Tree) +include_directories(SYSTEM ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) + +gaudi_install_headers(CombKernel) + +gaudi_add_module(FunTuple + src/*.cpp + LINK_LIBRARIES DaVinciKernelLib DaVinciMCKernelLib LHCbMathLib LoKiAlgoMCLib LoKiArrayFunctorsLib Boost LoKiPhysLib LoKiPhysMCLib ROOT) + +gaudi_add_test(QMTest QMTEST) + +gaudi_install_python_modules() diff --git a/Phys/FunTuple/README.md b/Phys/FunTuple/README.md new file mode 100644 index 000000000..01f674cc6 --- /dev/null +++ b/Phys/FunTuple/README.md @@ -0,0 +1 @@ +New nTupling algorithm diff --git a/Phys/FunTuple/options/FunTuple_opts.py b/Phys/FunTuple/options/FunTuple_opts.py new file mode 100755 index 000000000..d7e049153 --- /dev/null +++ b/Phys/FunTuple/options/FunTuple_opts.py @@ -0,0 +1,125 @@ +#!/usr/bin/env gaudirun.py +############################################################################### +# (c) Copyright 2020-2021 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. # +############################################################################### + + +######### Define helpful classes and functions +class ParticleTupleProp: + def __init__(self, branch_name, decay_descriptor, particle_code): + """ + branch_name : Branch name of particle + decay_descriptor: Decay descriptor + particle_code : List of tuples. Each tuple contains strings defining + (Functorcode, corresponding branch name, C++ return type that could handle precision, description). + """ + self.branch_name = branch_name + self.decay_descriptor = decay_descriptor + self.particle_code = particle_code + + def to_dict(self): + return {self.branch_name: {self.decay_descriptor: self.particle_code}} + + +def convert_to_parsable_objs(particle_tuple_props): + """ + particle_tuple_props: List of ParticleTupleProp + """ + + def get_lists(ptps, i): + f_list = [] + for ptp in ptps: + f_list += [[pc[i] for pc in ptp.particle_code]] + + return f_list + + branch_list = [ptp.branch_name for ptp in particle_tuple_props] + discrp_list = [ptp.decay_descriptor for ptp in particle_tuple_props] + func_list = get_lists(particle_tuple_props, 0) + func_bnamelist = get_lists(particle_tuple_props, 1) + func_rtypelist = get_lists(particle_tuple_props, 2) + + return branch_list, discrp_list, func_list, func_bnamelist, func_rtypelist + + +######### + +from Gaudi.Configuration import * +from Configurables import LHCbApp +from Configurables import LHCb__ParticlePropertySvc +LHCb__ParticlePropertySvc( +) #To turn on verbose set LHCb__ParticlePropertySvc(OutputLevel=1) +from Configurables import CondDB +CondDB(Upgrade=True) + +app = LHCbApp() +app.DataType = "Upgrade" +app.DDDBtag = "dddb-20171126" +app.CondDBtag = "sim-20171127-vc-md100" +app.Simulation = True +ApplicationMgr().EvtMax = 5 +ApplicationMgr().EvtSel = "NONE" + +#Make MCParticles (just one Bs): Turns out TES is not clever enough to take ownership 'recursively' (set makeCustomData = True if running this algorithm) +from Configurables import MakeData +algMakeData = MakeData( + name="Alg_MakeData", + decay_descriptor= + "[B_s0 => (J/psi(1S) => mu+ mu- ) ( phi(1020) => K+ K-)]CC", + output_location="MCParticle") + +#Do we need a custom gaudi property like ParticleTupleProp? +#Configure Particles Bs +ParticleBs = ParticleTupleProp( + branch_name="Bs", + decay_descriptor= + "[B_s0 => (J/psi(1S) => mu+ mu- ) ( phi(1020) => K+ K-)]CC", + #List of tuple, each tuple (functor, branch name, precision (TODO), description). + particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), + ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) +#Configure Particles Phi +ParticlePhi = ParticleTupleProp( + branch_name="Phi", + decay_descriptor= + "[B_s0 => (J/psi(1S) => mu+ mu- ) ^( phi(1020) => K+ K-)]CC", + particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), + ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) +#Do not need to do this if a custom gaudi property is implemented +branchlist, decaydiscrpList, funcList, funcBranchNameList, funcRetunTypeList = convert_to_parsable_objs( + [ParticleBs, ParticlePhi]) + +from Configurables import FunTuple +algtupledata = FunTuple( + name="FunTuple", + tree_name="DecayTree", + branch_names=branchlist, + is_MC=True, #Since passing MCParticles + decay_descriptors=decaydiscrpList, + functors=funcList, + functor_branch_names=funcBranchNameList, + functor_return_types=funcRetunTypeList, + make_custom_data= + True, #Only set to True since running over MakeData algo (produces its own Bs->Jpsiphi MC decays). + input_location="MCParticle", + NTupleLUN='tuple') + +ApplicationMgr().TopAlg = [algMakeData, algtupledata] + +#Tuple props +outputname = "FunTuple.root" +NTupleSvc().Output = [ + "{} DATAFILE='{}' TYP='ROOT' OPT='NEW'".format(algtupledata.NTupleLUN, + outputname) +] +ApplicationMgr().ExtSvc.append(NTupleSvc()) +ApplicationMgr().HistogramPersistency = "ROOT" +# Set the compression level for the ROOT tuple file +from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv +RFileCnv('RFileCnv').GlobalCompression = "LZMA:6" diff --git a/Phys/FunTuple/src/FunTuple.cpp b/Phys/FunTuple/src/FunTuple.cpp new file mode 100755 index 000000000..c2de2c88c --- /dev/null +++ b/Phys/FunTuple/src/FunTuple.cpp @@ -0,0 +1,465 @@ +/*****************************************************************************\ +* (c) Copyright 2020-2021 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. * +\*****************************************************************************/ + +// Gaudi +#include "GaudiAlg/Consumer.h" +#include "GaudiAlg/GaudiTupleAlg.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Point3DTypes.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/Vector3DTypes.h" +#include "GaudiKernel/Vector4DTypes.h" + +// Event +#include "Event/MCParticle.h" +#include "Event/MCVertex.h" +#include "Event/Particle.h" + +// LoKi +#include "LoKi/IDecay.h" +#include "LoKi/IHybridFactory.h" +#include "LoKi/IMCDecay.h" +#include "LoKi/IMCHybridFactory.h" +#include "LoKi/Trees.h" + +// Kernel +#include "Kernel/IDecayFinder.h" +#include "Kernel/IParticlePropertySvc.h" +#include "Kernel/ParticleID.h" +#include "Kernel/ParticleProperty.h" + +// boost +#include <boost/algorithm/string/join.hpp> + +// custom class +#include "ParticleTupleProp.h" + +namespace LHCb { + namespace FTuple { + template <class T> + using Consumer = + Gaudi::Functional::Consumer<void( const T& ), Gaudi::Functional::Traits::BaseClass_t<GaudiTupleAlg>>; + typedef std::vector<std::string> TUPLE; + typedef std::vector<TUPLE> TUPLELIST; + typedef std::vector<MCParticle> MCPARTICLES; + typedef std::vector<Particle> PARTICLES; + } // namespace FTuple +} // namespace LHCb + +template <class T> +class FunTuple : public LHCb::FTuple::Consumer<T> { +public: + FunTuple( const std::string& name, ISvcLocator* pSvc ); + virtual StatusCode initialize() override; + virtual void operator()( const T& particles ) const override; + +protected: + template <typename T2> + StatusCode booktuple( const Tuples::Tuple& m_ntuple, const std::string& colname, const T2& val ) const; + StatusCode checks(); + StatusCode setParticleTupleProps(); + void FindAndBookTuple( const unsigned int& i, const T& particles, const Tuples::Tuple& ntuple ) const {} + //(Will be removed): The following overloaded function (makeMCTwoBodyDecay) are only used when m_makeCustomData is set + // to true (see m_makeCustomData property description for more info) + void makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, const int& parentid ) const; + void makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, const int& parentid, + const int& prod1id, const int& prod2id, MsgStream& log ) const; + +private: + Gaudi::Property<std::string> m_ntupleTname{this, "tree_name", "DecayTree", "Set TTree name"}; + Gaudi::Property<bool> m_isMC{this, "is_MC", true, "Set is MC TRUTH or not"}; + // After defining custom Gaudi property remove m_branchnames, m_decaydescriptors, m_functors, m_funcbranchnames, + // m_funcreturntypes (Do we need the custom Gaudi::Property like ParticleTupleProp?) + Gaudi::Property<LHCb::FTuple::TUPLE> m_branchnames{this, "branch_names", LHCb::FTuple::TUPLE(), + "List of TBranch names"}; + Gaudi::Property<LHCb::FTuple::TUPLE> m_decaydescriptors{this, "decay_descriptors", LHCb::FTuple::TUPLE(), + "List of DecayDescriptors"}; + Gaudi::Property<LHCb::FTuple::TUPLELIST> m_functors{this, "functors", LHCb::FTuple::TUPLELIST(), + "List of functor names"}; + Gaudi::Property<LHCb::FTuple::TUPLELIST> m_funcbranchnames{this, "functor_branch_names", LHCb::FTuple::TUPLELIST(), + "List of functor TBranch names"}; + // TODO: Could m_funcreturntypes propery handle the user requested precision on the variables being tupled? + Gaudi::Property<LHCb::FTuple::TUPLELIST> m_funcreturntypes{this, "functor_return_types", LHCb::FTuple::TUPLELIST(), + "List of functor return types"}; + Gaudi::Property<std::vector<std::string>> m_preamble_def{this, "Preamble", {}, "List of preamble strings"}; + Gaudi::Property<bool> m_makeCustomData{ + this, "make_custom_data", true, + "(Property for testing only, will be removed) Should only be set to true if you ran over MakeData algorithm before hand. \ + If set to true, makes Bs->Jpsi(mumu)phi(KK)\ + Feature introduced because when Bs head particle is built in MakeData algorithm and put into TES, and then is passed into this algorithm \ + the products of Bs are garbage. Turns out TES is not clever enough to take ownership 'recursively'"}; + // vector of ParticleTupleProp custom objects. These are built out of above member variables (this is the object I + // want the Gaudi::Property to be?) + std::vector<ParticleTupleProp> m_particletupleprops; + // for Particle Loki functors + std::string m_preamble; + ToolHandle<LoKi::IHybridFactory> m_factory = {"LoKi::Hybrid::Tool/HybridFactory:PUBLIC", this}; + LoKi::Types::Fun m_fun{LoKi::Constant<const LHCb::Particle*, double>( -1.0e+10 )}; + std::vector<std::vector<LoKi::Types::Fun>> m_vfun; + // for Particle decay descriptor matching + ToolHandle<Decays::IDecay> m_decaytool = {this, "Decay", "LoKi::Decay"}; + Decays::IDecay::Tree m_decayTree = Decays::Trees::Invalid_<const LHCb::Particle*>(); + // for MCParticle Loki functors + ToolHandle<LoKi::IMCHybridFactory> m_mcfactory = {"LoKi::Hybrid::MCTool/MCHybridFactory:PUBLIC", this}; + LoKi::Types::MCFun m_mcfun{LoKi::Constant<const LHCb::MCParticle*, double>( -1.0e+10 )}; + std::vector<std::vector<LoKi::Types::MCFun>> m_vmcfun; + // for MCParticle decay descriptor matching + ToolHandle<Decays::IMCDecay> m_mcdecaytool = {this, "MCDecay", "LoKi::MCDecay"}; + Decays::IMCDecay::Tree m_mcdecayTree = Decays::Trees::Invalid_<const LHCb::MCParticle*>(); + // property service + ServiceHandle<LHCb::IParticlePropertySvc> m_particlePropertySvc{this, "ParticleProperty", + "LHCb::ParticlePropertySvc"}; +}; + +template <class T> +FunTuple<T>::FunTuple( const std::string& name, ISvcLocator* pSvc ) + : LHCb::FTuple::Consumer<T>( name, pSvc, {"input_location", {"MyParticle"}} ) {} + +template <class T> +StatusCode FunTuple<T>::initialize() { + + // initialise consumer + StatusCode sc_init = LHCb::FTuple::Consumer<T>::initialize(); + if ( sc_init.isFailure() ) { return this->Error( "Error in initialisation of consumer" ); } + + // conduct checks to see if the parsed arguments are ok + StatusCode sc_check = checks(); + if ( sc_check.isFailure() ) { return this->Error( "Error in checks" ); } + + // Using the arguments make a list of ParticleTupleProp objects that hold info on (TBranch name, Decay descriptor, + // List of FunctorProp objects). The FunctorProp objects hold info on (functor name, functor TBranch name, functor + // return type (can handle precision?)) + StatusCode sc_ptp = setParticleTupleProps(); + if ( sc_ptp.isFailure() ) { return this->Error( "Error in setting ParticleTupleProps" ); } + + // Instantiate all the functors (unfortunately the FunctorProp objects created in the previous step could not hold + // this information). + m_preamble = boost::algorithm::join( m_preamble_def.value(), "\n" ); + for ( const auto& ptp : m_particletupleprops ) { + std::vector<LoKi::Types::MCFun> imfunc_mc; + std::vector<LoKi::Types::Fun> imfunc; + for ( const auto& tup : ptp.FunctorProps() ) { + if ( m_isMC ) { // MC Particles + StatusCode sc_func_mc = m_mcfactory->get( tup.Func, m_mcfun, m_preamble ); + if ( sc_func_mc.isFailure() ) { + return this->Error( "Error in MC instantiating functor in particle branch " + ptp.BranchName() + + " with functor branch name " + tup.Func_branchname ); + } + imfunc_mc.push_back( m_mcfun ); + // this->info() << "Created a function in " + ptp.BranchName() + " with " + tup.Func_branchname + " : The + // function is '" << imfunc_mc.back() << "'" << endmsg; + } else { // Particles + StatusCode sc_func = m_factory->get( tup.Func, m_fun, m_preamble ); + if ( sc_func.isFailure() ) { + return this->Error( "Error in instantiating functor in particle branch " + ptp.BranchName() + + " with functor branch name " + tup.Func_branchname ); + } + imfunc.push_back( m_fun ); + // this->info() << "Created a function in " + ptp.BranchName() + " with " + tup.Func_branchname + " : The + // function is '" << imfunc.back() << "'" << endmsg; + } + } + if ( m_isMC ) { // MC Particles related + m_vmcfun.push_back( imfunc_mc ); + } else { // Particles related + m_vfun.push_back( imfunc ); + } + } + return StatusCode::SUCCESS; +} + +template <class T> +StatusCode FunTuple<T>::checks() { + // check tuple name + if ( m_ntupleTname.empty() ) { return this->Error( "Error tree name is empty" ); } + + // check related to containers + if ( m_branchnames.empty() ) { return this->Error( "Error branch names container is empty" ); } + if ( m_decaydescriptors.empty() ) { return this->Error( "Error decay descriptor container is empty" ); } + if ( m_functors.empty() ) { return this->Error( "Error functor container is empty" ); } + if ( m_funcbranchnames.empty() ) { return this->Error( "Error functor branch names container is empty" ); } + if ( m_funcreturntypes.empty() ) { return this->Error( "Error functor return types container is empty" ); } + if ( m_branchnames.size() != m_decaydescriptors.size() ) { + return this->Error( "Error size of branch names and decay descriptors containers do not match" ); + } + if ( m_branchnames.size() != m_functors.size() ) { + return this->Error( "Error size of branch names and functor lists containers do not match" ); + } + if ( m_branchnames.size() != m_funcbranchnames.size() ) { + return this->Error( "Error size of branch names and functor branch names containers do not match" ); + } + if ( m_branchnames.size() != m_funcreturntypes.size() ) { + return this->Error( "Error size of branch names and functor return types containers do not match" ); + } + + return StatusCode::SUCCESS; +} + +template <class T> +StatusCode FunTuple<T>::setParticleTupleProps() { + // make a list of ParticleTupleProp objects to hold info related to particle being tupled + for ( unsigned int i = 0; i < m_branchnames.size(); i++ ) { + ParticleTupleProp ptp = ParticleTupleProp(); + ptp.setBranchName( m_branchnames[i] ); + ptp.setDecayDescriptor( m_decaydescriptors[i] ); + // make a list of FunctorProp objects to hold functor properties + ptp.setFunctorProps( m_functors[i], m_funcbranchnames[i], m_funcreturntypes[i] ); + // conduct checks on whether input are empty or not + if ( !ptp.checks() ) { return this->Error( "Error conducting checks with ParticleTupleProp" ); } + m_particletupleprops.push_back( ptp ); + } + + return StatusCode::SUCCESS; +} + +template <class T> +template <typename T2> +StatusCode FunTuple<T>::booktuple( const Tuples::Tuple& ntuple, const std::string& colname, const T2& val ) const { + return ntuple->column( colname, val ); +} + +template <class T> +void FunTuple<T>::operator()( const T& particles ) const { + // make ntuple + Tuples::Tuple ntuple = this->nTuple( m_ntupleTname ); + + // loop over ParticleTupleProp (i.e. individual decay descriptors to get the particles) + for ( unsigned int i = 0; i < m_particletupleprops.size(); i++ ) { FindAndBookTuple( i, particles, ntuple ); } + + // write the tuple + StatusCode sc_write = ntuple->write(); + if ( sc_write.isFailure() ) { this->err() << "Unable to write the tuple " << endmsg; } +} + +template <> +void FunTuple<LHCb::FTuple::MCPARTICLES>::FindAndBookTuple( const unsigned int& i, + const LHCb::FTuple::MCPARTICLES& particles, + const Tuples::Tuple& ntuple ) const { + // Messaging service + MsgStream log = this->info(); + MsgStream err = this->err(); + + // check that correct functors related to MCParticles are loaded + // TODO: MC Truth association with the reco particles needs to be handled + if ( !m_isMC ) { err << "Have not asked for MC but passed LHCb::MCParticles" << endmsg; } + + // Get the tuple properties + ParticleTupleProp ptp = m_particletupleprops[i]; + + // parse the decay descriptor for MC Truth + const Decays::IMCDecay::Tree decayTree = m_mcdecaytool->tree( ptp.DecayDescriptor() ); + if ( !decayTree ) { err << "Could not find MC decayTree for " + ptp.DecayDescriptor() << endmsg; } + log << "MC decay descriptor parsed is " << decayTree << endmsg; + + // create the decay finder for MC Truth + Decays::IMCDecay::Finder finder( decayTree ); + if ( !finder ) { err << "Unable to create MC decay finder'" << endmsg; } + + // make input and output constvector + LHCb::MCParticle::ConstVector output; + LHCb::MCParticle::ConstVector input; + + // Make new particles (will be removed) only used when m_makeCustomData is True (see m_makeCustomData property + // description for more info) + LHCb::MCParticle p1 = LHCb::MCParticle(); + LHCb::MCParticle p1_a = LHCb::MCParticle(); + LHCb::MCParticle p1_b = LHCb::MCParticle(); + LHCb::MCParticle p2 = LHCb::MCParticle(); + LHCb::MCParticle p2_a = LHCb::MCParticle(); + LHCb::MCParticle p2_b = LHCb::MCParticle(); + LHCb::MCParticle p = LHCb::MCParticle(); + if ( m_makeCustomData ) { + // set their properties of new particles + makeMCTwoBodyDecay( p1, p1_a, p1_b, 443, 13, -13, err ); // Jpis -> mu- mu+ + makeMCTwoBodyDecay( p2, p2_a, p2_b, 333, 321, -321, err ); // phi -> K+ K- + makeMCTwoBodyDecay( p, p1, p2, 531 ); // Bs -> Jpsi phi + input.push_back( &p ); + } else { + // fill the input vector from the input directly + for ( const auto& p : particles ) { input.push_back( &p ); } + } + + // find the MC decay + finder.findDecay( input.begin(), input.end(), output ); + + // TODO: Need to handle multiple cands. For now just throw an error + if ( output.size() > 1 ) { err << "Multiple particles match the decay descriptor " << endmsg; } + log << "Found #" << output.size() << " decays" << endmsg; + // for (const auto& p: output){log << *p << endmsg;} + + // loop over FunctorProp to get individual functor outputs + for ( unsigned int j = 0; j < ( ptp.FunctorProps() ).size(); j++ ) { + ParticleProp::FunctorProp functup = ( ptp.FunctorProps() )[j]; + std::string branchname = ptp.BranchName() + "_" + functup.Func_branchname; + double val = m_vmcfun[i][j]( output[0] ); + // log << "Had created a function '" << mcfunct << "'" << endmsg; + // log << "value function '" << val << "'" << endmsg; + + // book tuple + StatusCode sc_book = booktuple( ntuple, branchname, val ); + if ( sc_book.isFailure() ) { err << "Unable to book the columns " << endmsg; } + } +} + +template <> +void FunTuple<LHCb::FTuple::PARTICLES>::FindAndBookTuple( const unsigned int& i, + const LHCb::FTuple::PARTICLES& particles, + const Tuples::Tuple& ntuple ) const { + // Messaging service + MsgStream log = this->info(); + MsgStream err = this->err(); + + // check that correct functors related to Particles are loaded + // TODO: MC Truth association with the reco particles needs to be handled + if ( m_isMC ) { err << "Asked for MC but passed LHCb::Particles" << endmsg; } + + // Get the tuple properties + ParticleTupleProp ptp = m_particletupleprops[i]; + + // parse the decay descriptor for reco + const Decays::IDecay::Tree decayTree = m_decaytool->tree( ptp.DecayDescriptor() ); + if ( !decayTree ) { err << "Could not find decayTree for " + ptp.DecayDescriptor() << endmsg; } + log << "Decay descriptor parsed is " << decayTree << endmsg; + + // create the decay finder for reco + Decays::IDecay::Finder finder( decayTree ); + if ( !finder ) { err << "Unable to create decay finder'" << endmsg; } + + // make input and output constvector + LHCb::Particle::ConstVector output; + LHCb::Particle::ConstVector input; + for ( const auto& p : particles ) { input.push_back( &p ); } + finder.findDecay( input.begin(), input.end(), output ); + + // TODO: Need to handle multiple cands. For now just throw an error + if ( output.size() > 1 ) { this->err() << "Multiple particles match the decay descriptor " << endmsg; } + this->info() << "Found #" << output.size() << " decays" << endmsg; + // for (const auto& p: output){log << *p << endmsg;} + + for ( unsigned int j = 0; j < ( ptp.FunctorProps() ).size(); j++ ) { + ParticleProp::FunctorProp functup = ( ptp.FunctorProps() )[j]; + std::string branchname = ptp.BranchName() + "_" + functup.Func_branchname; + double val = m_vfun[i][j]( output[0] ); + // log << "value function '" << val << "'" << endmsg; + + // book tuple + StatusCode sc_book = booktuple( ntuple, branchname, val ); + if ( sc_book.isFailure() ) { err << "Unable to book the columns " << endmsg; } + } +} + +// This function is for testing purpose only and will be used only when m_makeCustomData is True, otherwise useless (see +// makeMCTwoBodyDecay property description for more info) +template <class T> +void FunTuple<T>::makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, + const int& parentid, const int& prod1id, const int& prod2id, + MsgStream& log ) const { + using std::sqrt; + + // particle id of products + const LHCb::ParticleID p1_id = LHCb::ParticleID( prod1id ); // mu+ + const LHCb::ParticleID p2_id = LHCb::ParticleID( prod2id ); // mu- + p1.setParticleID( p1_id ); + p2.setParticleID( p2_id ); + // four momenta of products + const LHCb::ParticleProperty* p1_prop = m_particlePropertySvc->find( p1_id ); + const LHCb::ParticleProperty* p2_prop = m_particlePropertySvc->find( p2_id ); + if ( !p1_prop || !p2_prop ) { log << "Could not find either p1_prop or p2_prop" << endmsg; } + const double p1_mass = p1_prop->mass(); + const double p2_mass = p2_prop->mass(); + const Gaudi::XYZVector p1_3vec{10.2, 10.9, 30.2}; + const Gaudi::XYZVector p2_3vec{20.5, 20.5, 60.6}; + double p1_E = sqrt( p1_3vec.Mag2() + p1_mass * p1_mass ); + double p2_E = sqrt( p2_3vec.Mag2() + p2_mass * p2_mass ); + const Gaudi::LorentzVector p1_4vec = Gaudi::LorentzVector( p1_3vec.X(), p1_3vec.Y(), p1_3vec.Z(), p1_E ); + const Gaudi::LorentzVector p2_4vec = Gaudi::LorentzVector( p2_3vec.X(), p2_3vec.Y(), p2_3vec.Z(), p2_E ); + p1.setMomentum( p1_4vec ); + p2.setMomentum( p2_4vec ); + + // Define origin vertex of parent (DecayVertex) + SmartRef<LHCb::MCVertex> p_orgvertx = new LHCb::MCVertex(); + const Gaudi::XYZPoint p_orgvrtx{2.8, -1.5, 1.3}; + p_orgvertx->setPosition( p_orgvrtx ); + p_orgvertx->setTime( 0.05 ); + p_orgvertx->setType( LHCb::MCVertex::DecayVertex ); + + // Define end vertices of parent + const Gaudi::XYZPoint p_endvrtx{6.8, -4.5, 3.3}; + SmartRefVector<LHCb::MCParticle> prods_endvertx; + prods_endvertx.push_back( &p1 ); + prods_endvertx.push_back( &p2 ); + SmartRef<LHCb::MCVertex> p_endvertx = new LHCb::MCVertex(); + p_endvertx->setPosition( p_endvrtx ); + p_endvertx->setTime( 0.13 ); + p_endvertx->setType( LHCb::MCVertex::DecayVertex ); + p_endvertx->setProducts( prods_endvertx ); // products in this vertex (particle 1 and 2) + SmartRefVector<LHCb::MCVertex> p_endvertxs; + p_endvertxs.push_back( p_endvertx ); + + // set properties of parent + const LHCb::ParticleID p_id = LHCb::ParticleID( parentid ); // Jpsi + p.setParticleID( p_id ); + p.setMomentum( p1_4vec + p2_4vec ); + p.setOriginVertex( p_orgvertx ); + p.setEndVertices( p_endvertxs ); + + /* + this->info() << p << endmsg; + for (const auto& mcv: p.endVertices()){ + this->info() << *mcv << endmsg; + for (const auto& mcd: (*mcv).products()){this->info() << *mcd << endmsg;} + } + */ +} + +// This function is for testing purpose only and will be used only when m_makeCustomData is True, otherwise useless (see +// makeMCTwoBodyDecay property description for more info) +template <class T> +void FunTuple<T>::makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, + const int& parentid ) const { + // get 4-momenta + const Gaudi::LorentzVector p1_4vec = p1.momentum(); + const Gaudi::LorentzVector p2_4vec = p2.momentum(); + + // Define origin vertex of parent (ppCollision vertex) + SmartRef<LHCb::MCVertex> p_orgvertx = new LHCb::MCVertex(); + p_orgvertx->setType( LHCb::MCVertex::ppCollision ); + + // Define end vertices of parent + const Gaudi::XYZPoint p_endvrtx{2.8, -1.5, 1.3}; + SmartRefVector<LHCb::MCParticle> prods_endvertx; + prods_endvertx.push_back( &p1 ); + prods_endvertx.push_back( &p2 ); + SmartRef<LHCb::MCVertex> p_endvertx = new LHCb::MCVertex(); + p_endvertx->setPosition( p_endvrtx ); + p_endvertx->setTime( 0.05 ); + p_endvertx->setType( LHCb::MCVertex::DecayVertex ); + p_endvertx->setProducts( prods_endvertx ); // products in this vertex (particle 1 and 2) + SmartRefVector<LHCb::MCVertex> p_endvertxs; + p_endvertxs.push_back( p_endvertx ); + + // set properties of p + const LHCb::ParticleID p_id = LHCb::ParticleID( parentid ); // Jpsi + p.setParticleID( p_id ); + p.setMomentum( p1_4vec + p2_4vec ); + p.setOriginVertex( p_orgvertx ); + p.setEndVertices( p_endvertxs ); + + /* + this->info() << p << endmsg; + for (const auto& mcv: p.endVertices()){ + this->info() << *mcv << endmsg; + for (const auto& mcd: (*mcv).products()){this->info() << *mcd << endmsg;} + } + */ +} + +DECLARE_COMPONENT_WITH_ID( FunTuple<LHCb::FTuple::MCPARTICLES>, "FunTuple" ) diff --git a/Phys/FunTuple/src/MakeData.cpp b/Phys/FunTuple/src/MakeData.cpp new file mode 100755 index 000000000..d05741bd3 --- /dev/null +++ b/Phys/FunTuple/src/MakeData.cpp @@ -0,0 +1,233 @@ +/*****************************************************************************\ +* (c) Copyright 2020-2021 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. * +\*****************************************************************************/ + +// Gaudi +#include "GaudiAlg/Producer.h" +#include "GaudiKernel/MsgStream.h" +#include "GaudiKernel/Point3DTypes.h" +#include "GaudiKernel/ServiceHandle.h" +#include "GaudiKernel/Vector3DTypes.h" +#include "GaudiKernel/Vector4DTypes.h" + +// Event +#include "Event/MCParticle.h" +#include "Event/MCVertex.h" + +// Kernel +#include "Kernel/IParticlePropertySvc.h" +#include "Kernel/ParticleID.h" +#include "Kernel/ParticleProperty.h" + +// LoKi +#include "LoKi/IMCDecay.h" +#include "LoKi/PrintMCDecay.h" +#include "LoKi/Trees.h" + +class MakeData : public Gaudi::Functional::Producer<std::vector<LHCb::MCParticle>()> { +public: + MakeData( const std::string& name, ISvcLocator* svcLoc ) + : Producer( name, svcLoc, {"output_location", {"MyParticle"}} ) {} + std::vector<LHCb::MCParticle> operator()() const override; + +protected: + void makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, const int& parentid, + const int& prod1id, const int& prod2id, MsgStream& log ) const; + void makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, const int& parentid ) const; + void checkDecay( Decays::IMCDecay::Finder& finder, LHCb::MCParticle::ConstVector& mcparticles, MsgStream& log ) const; + +private: + Gaudi::Property<std::string> m_headDecay{ + this, "decay_descriptor", "[B_s0 => (J/psi(1S) => mu+ mu- ) ^( phi(1020) => K+ K-)]CC", "Decay descriptor"}; + ServiceHandle<LHCb::IParticlePropertySvc> m_particlePropertySvc{this, "ParticleProperty", + "LHCb::ParticlePropertySvc"}; + ToolHandle<Decays::IMCDecay> m_mcdecaytool = {this, "MCDecay", "LoKi::MCDecay"}; +}; + +DECLARE_COMPONENT( MakeData ) + +std::vector<LHCb::MCParticle> MakeData::operator()() const { + MsgStream log = info(); + MsgStream err = error(); + log << "executing MakeData" << endmsg; + + // parse/decode the decay descriptor + const Decays::IMCDecay::Tree mcdecayTree = m_mcdecaytool->tree( m_headDecay ); + if ( !mcdecayTree ) { err << "Could not find mcdecayTree for " + m_headDecay << endmsg; } + log << "MC decay descriptor parsed is " << mcdecayTree << endmsg; + + // Define and fill container to hold the Jpsi MCParticles (only one Jpsi made) which decays to mu+ mu- + std::vector<LHCb::MCParticle> mcparticles; + LHCb::MCParticle p1 = LHCb::MCParticle(); + LHCb::MCParticle p1_a = LHCb::MCParticle(); + LHCb::MCParticle p1_b = LHCb::MCParticle(); + LHCb::MCParticle p2 = LHCb::MCParticle(); + LHCb::MCParticle p2_a = LHCb::MCParticle(); + LHCb::MCParticle p2_b = LHCb::MCParticle(); + LHCb::MCParticle p = LHCb::MCParticle(); + + makeMCTwoBodyDecay( p1, p1_a, p1_b, 443, 13, -13, err ); // Jpis -> mu- mu+ + makeMCTwoBodyDecay( p2, p2_a, p2_b, 333, 321, -321, err ); // phi -> K+ K- + makeMCTwoBodyDecay( p, p1, p2, 531 ); // Bs -> Jpsi phi + + mcparticles.push_back( p1 ); + mcparticles.push_back( p1_a ); + mcparticles.push_back( p1_b ); + mcparticles.push_back( p2 ); + mcparticles.push_back( p2_a ); + mcparticles.push_back( p2_b ); + mcparticles.push_back( p ); + + LHCb::MCParticle::ConstVector mcparticlescheck{&mcparticles[0]}; + /* + //Check all the particles are there + for (const auto& mcp: mcparticlescheck) { + log << *mcp << endmsg; + for (const auto& mcv: (*mcp).endVertices()){ + //log << *mcv << endmsg; + for (const auto& mcp1: (*mcv).products()){ + log << *mcp1 << endmsg; + for (const auto& mcv1: (*mcp1).endVertices()){ + //log << *mcv1 << endmsg; + for (const auto& mcp2: (*mcv1).products()){log << *mcp2 << endmsg;} + } + } + } + } + */ + + // create the decay finder + Decays::IMCDecay::Finder finder( mcdecayTree ); + if ( !finder ) { err << "Unable to create decay finder'" << endmsg; } + + ////check that the finder can find the decay using the descriptor + checkDecay( finder, mcparticlescheck, log ); + + return mcparticles; +} + +void MakeData::makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, const int& parentid, + const int& prod1id, const int& prod2id, MsgStream& log ) const { + using std::sqrt; + + // particle id of products + const LHCb::ParticleID p1_id = LHCb::ParticleID( prod1id ); // mu+ + const LHCb::ParticleID p2_id = LHCb::ParticleID( prod2id ); // mu- + p1.setParticleID( p1_id ); + p2.setParticleID( p2_id ); + // four momenta of products + const LHCb::ParticleProperty* p1_prop = m_particlePropertySvc->find( p1_id ); + const LHCb::ParticleProperty* p2_prop = m_particlePropertySvc->find( p2_id ); + if ( !p1_prop || !p2_prop ) { log << "Could not find either p1_prop or p2_prop" << endmsg; } + const double p1_mass = p1_prop->mass(); + const double p2_mass = p2_prop->mass(); + const Gaudi::XYZVector p1_3vec{10.2, 10.9, 30.2}; + const Gaudi::XYZVector p2_3vec{20.5, 20.5, 60.6}; + double p1_E = sqrt( p1_3vec.Mag2() + p1_mass * p1_mass ); + double p2_E = sqrt( p2_3vec.Mag2() + p2_mass * p2_mass ); + const Gaudi::LorentzVector p1_4vec = Gaudi::LorentzVector( p1_3vec.X(), p1_3vec.Y(), p1_3vec.Z(), p1_E ); + const Gaudi::LorentzVector p2_4vec = Gaudi::LorentzVector( p2_3vec.X(), p2_3vec.Y(), p2_3vec.Z(), p2_E ); + p1.setMomentum( p1_4vec ); + p2.setMomentum( p2_4vec ); + + // Define origin vertex of parent (DecayVertex) + SmartRef<LHCb::MCVertex> p_orgvertx = new LHCb::MCVertex(); + const Gaudi::XYZPoint p_orgvrtx{2.8, -1.5, 1.3}; + p_orgvertx->setPosition( p_orgvrtx ); + p_orgvertx->setTime( 0.05 ); + p_orgvertx->setType( LHCb::MCVertex::DecayVertex ); + + // Define end vertices of parent + const Gaudi::XYZPoint p_endvrtx{6.8, -4.5, 3.3}; + SmartRefVector<LHCb::MCParticle> prods_endvertx; + prods_endvertx.push_back( &p1 ); + prods_endvertx.push_back( &p2 ); + SmartRef<LHCb::MCVertex> p_endvertx = new LHCb::MCVertex(); + p_endvertx->setPosition( p_endvrtx ); + p_endvertx->setTime( 0.13 ); + p_endvertx->setType( LHCb::MCVertex::DecayVertex ); + p_endvertx->setProducts( prods_endvertx ); // products in this vertex (particle 1 and 2) + SmartRefVector<LHCb::MCVertex> p_endvertxs; + p_endvertxs.push_back( p_endvertx ); + + // set properties of parent + const LHCb::ParticleID p_id = LHCb::ParticleID( parentid ); // Jpsi + p.setParticleID( p_id ); + p.setMomentum( p1_4vec + p2_4vec ); + p.setOriginVertex( p_orgvertx ); + p.setEndVertices( p_endvertxs ); + + // log << p << endmsg; + // for (const auto& mcv: p.endVertices()){ + // log << *mcv << endmsg; + // for (const auto& mcd: (*mcv).products()){log << *mcd << endmsg;} + //} +} + +void MakeData::makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, + const int& parentid ) const { + // get 4-momenta + const Gaudi::LorentzVector p1_4vec = p1.momentum(); + const Gaudi::LorentzVector p2_4vec = p2.momentum(); + + // Define origin vertex of parent (ppCollision vertex) + SmartRef<LHCb::MCVertex> p_orgvertx = new LHCb::MCVertex(); + p_orgvertx->setType( LHCb::MCVertex::ppCollision ); + + // Define end vertices of parent + const Gaudi::XYZPoint p_endvrtx{2.8, -1.5, 1.3}; + SmartRefVector<LHCb::MCParticle> prods_endvertx; + prods_endvertx.push_back( &p1 ); + prods_endvertx.push_back( &p2 ); + SmartRef<LHCb::MCVertex> p_endvertx = new LHCb::MCVertex(); + p_endvertx->setPosition( p_endvrtx ); + p_endvertx->setTime( 0.05 ); + p_endvertx->setType( LHCb::MCVertex::DecayVertex ); + p_endvertx->setProducts( prods_endvertx ); // products in this vertex (particle 1 and 2) + SmartRefVector<LHCb::MCVertex> p_endvertxs; + p_endvertxs.push_back( p_endvertx ); + + // set properties of p + const LHCb::ParticleID p_id = LHCb::ParticleID( parentid ); // Jpsi + p.setParticleID( p_id ); + p.setMomentum( p1_4vec + p2_4vec ); + p.setOriginVertex( p_orgvertx ); + p.setEndVertices( p_endvertxs ); +} + +void MakeData::checkDecay( Decays::IMCDecay::Finder& finder, LHCb::MCParticle::ConstVector& mcparticles, + MsgStream& log ) const { + // make the output container + typedef LHCb::MCParticle::ConstVector OUTPUT; + OUTPUT output; + + // fill the container + finder.findDecay( mcparticles.begin(), mcparticles.end(), output ); + log << " found #" << output.size() << " decays" << endmsg; + + // print the marked particle in the container + for ( const auto& p : output ) { + log << *p << endmsg; + // for (const auto& mcv: (*p).endVertices()){ + // log << *mcv << endmsg; + // for (const auto& mcd: (*mcv).products()){log << *mcd << endmsg;} + //} + } + + //// print decay: Some reason the loKi services cannot import ParticlePropertyService properly + // for ( OUTPUT::const_iterator idec = output.begin() ; output.end() != idec ; ++idec ) + //{ + // const LHCb::MCParticle* dec = *idec ; + // if ( 0 == dec ) { continue ; } + // log << std::endl << " " << (idec-output.begin()+1) << " \t" ; + // LoKi::PrintMC::printDecay(dec,log,true); + //} + // log << endmsg ; +} diff --git a/Phys/FunTuple/src/ParticleTupleProp.cpp b/Phys/FunTuple/src/ParticleTupleProp.cpp new file mode 100755 index 000000000..e90a7ff68 --- /dev/null +++ b/Phys/FunTuple/src/ParticleTupleProp.cpp @@ -0,0 +1,47 @@ +/*****************************************************************************\ +* (c) Copyright 2020-2021 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. * +\*****************************************************************************/ + +#include "ParticleTupleProp.h" + +bool ParticleTupleProp::checks() { + if ( m_branchname.empty() ) { return ErrorMsg( "Error branch name is empty" ); } + + if ( m_decaydescriptor.empty() ) { return ErrorMsg( "Error decay descriptor is empty" ); } + + int count( 0 ); + for ( const auto& mtp : m_tupleprops ) { + if ( mtp.Func.empty() ) { return ErrorMsg( "Functor name is empty at " + std::to_string( count ) ); } + if ( mtp.Func_branchname.empty() ) { + return ErrorMsg( "Functor branchname is empty at " + std::to_string( count ) ); + } + if ( mtp.Func_returntype.empty() ) { + return ErrorMsg( "Functor return type is empty at " + std::to_string( count ) ); + } + count++; + } + return true; +} + +void ParticleTupleProp::setFunctorProps( std::vector<std::string>& functors, std::vector<std::string>& funcbranchnames, + std::vector<std::string>& funcreturntypes ) { + for ( unsigned int i = 0; i < functors.size(); i++ ) { + ParticleProp::FunctorProp tupleprop; + tupleprop.Func = functors[i]; + tupleprop.Func_branchname = funcbranchnames[i]; + tupleprop.Func_returntype = funcreturntypes[i]; + m_tupleprops.push_back( tupleprop ); + } +} + +bool ParticleTupleProp::ErrorMsg( std::string stg ) { // TODO: better exception handling + std::cout << stg << std::endl; + return false; +} diff --git a/Phys/FunTuple/src/ParticleTupleProp.h b/Phys/FunTuple/src/ParticleTupleProp.h new file mode 100755 index 000000000..44e72f5ad --- /dev/null +++ b/Phys/FunTuple/src/ParticleTupleProp.h @@ -0,0 +1,57 @@ +/*****************************************************************************\ +* (c) Copyright 2020-2021 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. * +\*****************************************************************************/ + +#pragma once + +// std lib +#include <iostream> +#include <vector> + +// LoKi +#include "LoKi/IDecay.h" +#include "LoKi/IHybridFactory.h" +#include "LoKi/IMCDecay.h" +#include "LoKi/IMCHybridFactory.h" +#include "LoKi/Trees.h" + +namespace ParticleProp { + typedef std::vector<std::vector<std::string>> TUPLELIST; + // define a struct to hold functor tupling properties + struct FunctorProp { + std::string Func{""}; // Functor name + std::string Func_branchname{""}; // Functor TBranch name + std::string Func_returntype{""}; // Functor return type + }; +} // namespace ParticleProp + +class ParticleTupleProp { +public: + ParticleTupleProp() {} + // set functions + void setBranchName( std::string branchname ) { m_branchname = branchname; } + void setDecayDescriptor( std::string decaydescriptor ) { m_decaydescriptor = decaydescriptor; } + void setFunctorProps( std::vector<ParticleProp::FunctorProp> tupleprops ) { m_tupleprops = tupleprops; } + void setFunctorProps( std::vector<std::string>& functors, std::vector<std::string>& funcbranchnames, + std::vector<std::string>& funcreturntypes ); + // get functions + const std::string& BranchName() const { return m_branchname; } + const std::string& DecayDescriptor() const { return m_decaydescriptor; } + const std::vector<ParticleProp::FunctorProp>& FunctorProps() const { return m_tupleprops; } + // check and validate + bool checks(); + +protected: + bool ErrorMsg( std::string stg ); // TODO: Better exception handling +private: + std::string m_branchname{""}; + std::string m_decaydescriptor{""}; + std::vector<ParticleProp::FunctorProp> m_tupleprops; +}; diff --git a/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt b/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt new file mode 100644 index 000000000..2822653fb --- /dev/null +++ b/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt @@ -0,0 +1,35 @@ +<?xml version="1.0" ?><!DOCTYPE extension PUBLIC '-//QM/2.3/Extension//EN' 'http://www.codesourcery.com/qm/dtds/2.3/-//qm/2.3/extension//en.dtd'> +<!-- + (c) Copyright 2020-2021 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. +--> +<extension class="GaudiTest.GaudiExeTest" kind="test"> + <argument name="program"><text>gaudirun.py</text></argument> + <argument name="args"><set><text>options/FunTuple_opts.py</text></set></argument> + <argument name="validator"><text> +import sys, os, glob +import ROOT as r +from ROOT import TFile + +try: + ntuple = 'FunTuple.root' + f = TFile.Open(ntuple) + if f.IsZombie(): + raise AttributeError('Output ROOT file is Zombie') + print('-- FunTuple QMTest -- : found output NTuple') + f.Close() + os.system('rm %s' %ntuple) +except IOError as err: + raise IOError('Impossible to open file: ', err) +except: + print('Unexpected error while opening file: ', sys.exc_info()[0]) + </text></argument> + +</extension> + diff --git a/Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py b/Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py new file mode 100755 index 000000000..d7e049153 --- /dev/null +++ b/Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py @@ -0,0 +1,125 @@ +#!/usr/bin/env gaudirun.py +############################################################################### +# (c) Copyright 2020-2021 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. # +############################################################################### + + +######### Define helpful classes and functions +class ParticleTupleProp: + def __init__(self, branch_name, decay_descriptor, particle_code): + """ + branch_name : Branch name of particle + decay_descriptor: Decay descriptor + particle_code : List of tuples. Each tuple contains strings defining + (Functorcode, corresponding branch name, C++ return type that could handle precision, description). + """ + self.branch_name = branch_name + self.decay_descriptor = decay_descriptor + self.particle_code = particle_code + + def to_dict(self): + return {self.branch_name: {self.decay_descriptor: self.particle_code}} + + +def convert_to_parsable_objs(particle_tuple_props): + """ + particle_tuple_props: List of ParticleTupleProp + """ + + def get_lists(ptps, i): + f_list = [] + for ptp in ptps: + f_list += [[pc[i] for pc in ptp.particle_code]] + + return f_list + + branch_list = [ptp.branch_name for ptp in particle_tuple_props] + discrp_list = [ptp.decay_descriptor for ptp in particle_tuple_props] + func_list = get_lists(particle_tuple_props, 0) + func_bnamelist = get_lists(particle_tuple_props, 1) + func_rtypelist = get_lists(particle_tuple_props, 2) + + return branch_list, discrp_list, func_list, func_bnamelist, func_rtypelist + + +######### + +from Gaudi.Configuration import * +from Configurables import LHCbApp +from Configurables import LHCb__ParticlePropertySvc +LHCb__ParticlePropertySvc( +) #To turn on verbose set LHCb__ParticlePropertySvc(OutputLevel=1) +from Configurables import CondDB +CondDB(Upgrade=True) + +app = LHCbApp() +app.DataType = "Upgrade" +app.DDDBtag = "dddb-20171126" +app.CondDBtag = "sim-20171127-vc-md100" +app.Simulation = True +ApplicationMgr().EvtMax = 5 +ApplicationMgr().EvtSel = "NONE" + +#Make MCParticles (just one Bs): Turns out TES is not clever enough to take ownership 'recursively' (set makeCustomData = True if running this algorithm) +from Configurables import MakeData +algMakeData = MakeData( + name="Alg_MakeData", + decay_descriptor= + "[B_s0 => (J/psi(1S) => mu+ mu- ) ( phi(1020) => K+ K-)]CC", + output_location="MCParticle") + +#Do we need a custom gaudi property like ParticleTupleProp? +#Configure Particles Bs +ParticleBs = ParticleTupleProp( + branch_name="Bs", + decay_descriptor= + "[B_s0 => (J/psi(1S) => mu+ mu- ) ( phi(1020) => K+ K-)]CC", + #List of tuple, each tuple (functor, branch name, precision (TODO), description). + particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), + ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) +#Configure Particles Phi +ParticlePhi = ParticleTupleProp( + branch_name="Phi", + decay_descriptor= + "[B_s0 => (J/psi(1S) => mu+ mu- ) ^( phi(1020) => K+ K-)]CC", + particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), + ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) +#Do not need to do this if a custom gaudi property is implemented +branchlist, decaydiscrpList, funcList, funcBranchNameList, funcRetunTypeList = convert_to_parsable_objs( + [ParticleBs, ParticlePhi]) + +from Configurables import FunTuple +algtupledata = FunTuple( + name="FunTuple", + tree_name="DecayTree", + branch_names=branchlist, + is_MC=True, #Since passing MCParticles + decay_descriptors=decaydiscrpList, + functors=funcList, + functor_branch_names=funcBranchNameList, + functor_return_types=funcRetunTypeList, + make_custom_data= + True, #Only set to True since running over MakeData algo (produces its own Bs->Jpsiphi MC decays). + input_location="MCParticle", + NTupleLUN='tuple') + +ApplicationMgr().TopAlg = [algMakeData, algtupledata] + +#Tuple props +outputname = "FunTuple.root" +NTupleSvc().Output = [ + "{} DATAFILE='{}' TYP='ROOT' OPT='NEW'".format(algtupledata.NTupleLUN, + outputname) +] +ApplicationMgr().ExtSvc.append(NTupleSvc()) +ApplicationMgr().HistogramPersistency = "ROOT" +# Set the compression level for the ROOT tuple file +from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv +RFileCnv('RFileCnv').GlobalCompression = "LZMA:6" -- GitLab From 7fc979e7bf8c808bfee9009565ffde0d8d84f46e Mon Sep 17 00:00:00 2001 From: amathad <Abhijit Mathad amathad@cern.ch> Date: Tue, 2 Mar 2021 18:30:48 +0100 Subject: [PATCH 2/6] TuplMinor edits to options file --- Phys/FunTuple/CMakeLists.txt | 3 +- .../{FunTuple_opts.py => example-FunTuple.py} | 46 +++++++++++-------- .../qmtest/algorithms.qms/test-funtuple.qmt | 2 +- .../{FunTuple_opts.py => example-FunTuple.py} | 46 +++++++++++-------- 4 files changed, 56 insertions(+), 41 deletions(-) rename Phys/FunTuple/options/{FunTuple_opts.py => example-FunTuple.py} (88%) rename Phys/FunTuple/tests/qmtest/options/{FunTuple_opts.py => example-FunTuple.py} (88%) diff --git a/Phys/FunTuple/CMakeLists.txt b/Phys/FunTuple/CMakeLists.txt index c87a27354..cf00de75b 100644 --- a/Phys/FunTuple/CMakeLists.txt +++ b/Phys/FunTuple/CMakeLists.txt @@ -13,8 +13,7 @@ gaudi_subdir(FunTuple) gaudi_depends_on_subdirs(Phys/DaVinciKernel Phys/DaVinciMCKernel - Kernel/LHCbMath - Phys/LoKi + Kernel/LHCbMath Phys/LoKiMC Phys/LoKiAlgoMC Phys/LoKiArrayFunctors diff --git a/Phys/FunTuple/options/FunTuple_opts.py b/Phys/FunTuple/options/example-FunTuple.py similarity index 88% rename from Phys/FunTuple/options/FunTuple_opts.py rename to Phys/FunTuple/options/example-FunTuple.py index d7e049153..6036195d1 100755 --- a/Phys/FunTuple/options/FunTuple_opts.py +++ b/Phys/FunTuple/options/example-FunTuple.py @@ -9,9 +9,28 @@ # granted to it by virtue of its status as an Intergovernmental Organization # # or submit itself to any jurisdiction. # ############################################################################### +""" +Example of tupling with the FunTuple algorithm +""" +from Configurables import LHCbApp +from Gaudi.Configuration import ApplicationMgr, NTupleSvc +from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv +from Configurables import CondDB +from Configurables import MakeData +from Configurables import FunTuple -######### Define helpful classes and functions + +""" Define helpful class and function + +class ParticleTupleProp: + A class that one can configure with branch_name, decay descriptor and functors. + +Function convert_to_parsable_objs: + Since ParticleTupleProp cannot currently be passed as Gaudi::Property, define + this function to turn member variables into parsable_objs for FunTuple + +""" class ParticleTupleProp: def __init__(self, branch_name, decay_descriptor, particle_code): """ @@ -48,17 +67,7 @@ def convert_to_parsable_objs(particle_tuple_props): return branch_list, discrp_list, func_list, func_bnamelist, func_rtypelist - -######### - -from Gaudi.Configuration import * -from Configurables import LHCbApp -from Configurables import LHCb__ParticlePropertySvc -LHCb__ParticlePropertySvc( -) #To turn on verbose set LHCb__ParticlePropertySvc(OutputLevel=1) -from Configurables import CondDB -CondDB(Upgrade=True) - +#Configure LHCb application app = LHCbApp() app.DataType = "Upgrade" app.DDDBtag = "dddb-20171126" @@ -66,17 +75,16 @@ app.CondDBtag = "sim-20171127-vc-md100" app.Simulation = True ApplicationMgr().EvtMax = 5 ApplicationMgr().EvtSel = "NONE" +CondDB(Upgrade=True) #Make MCParticles (just one Bs): Turns out TES is not clever enough to take ownership 'recursively' (set makeCustomData = True if running this algorithm) -from Configurables import MakeData algMakeData = MakeData( name="Alg_MakeData", decay_descriptor= "[B_s0 => (J/psi(1S) => mu+ mu- ) ( phi(1020) => K+ K-)]CC", output_location="MCParticle") -#Do we need a custom gaudi property like ParticleTupleProp? -#Configure Particles Bs +#Configure Particles Bs and phi ParticleBs = ParticleTupleProp( branch_name="Bs", decay_descriptor= @@ -84,18 +92,18 @@ ParticleBs = ParticleTupleProp( #List of tuple, each tuple (functor, branch name, precision (TODO), description). particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) -#Configure Particles Phi ParticlePhi = ParticleTupleProp( branch_name="Phi", decay_descriptor= "[B_s0 => (J/psi(1S) => mu+ mu- ) ^( phi(1020) => K+ K-)]CC", particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) + #Do not need to do this if a custom gaudi property is implemented branchlist, decaydiscrpList, funcList, funcBranchNameList, funcRetunTypeList = convert_to_parsable_objs( [ParticleBs, ParticlePhi]) -from Configurables import FunTuple +#Configure FunTuple algorithm algtupledata = FunTuple( name="FunTuple", tree_name="DecayTree", @@ -110,9 +118,10 @@ algtupledata = FunTuple( input_location="MCParticle", NTupleLUN='tuple') +#add the algorithms to the sequence ApplicationMgr().TopAlg = [algMakeData, algtupledata] -#Tuple props +#set Tuple properties outputname = "FunTuple.root" NTupleSvc().Output = [ "{} DATAFILE='{}' TYP='ROOT' OPT='NEW'".format(algtupledata.NTupleLUN, @@ -121,5 +130,4 @@ NTupleSvc().Output = [ ApplicationMgr().ExtSvc.append(NTupleSvc()) ApplicationMgr().HistogramPersistency = "ROOT" # Set the compression level for the ROOT tuple file -from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv RFileCnv('RFileCnv').GlobalCompression = "LZMA:6" diff --git a/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt b/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt index 2822653fb..10e103792 100644 --- a/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt +++ b/Phys/FunTuple/tests/qmtest/algorithms.qms/test-funtuple.qmt @@ -11,7 +11,7 @@ --> <extension class="GaudiTest.GaudiExeTest" kind="test"> <argument name="program"><text>gaudirun.py</text></argument> - <argument name="args"><set><text>options/FunTuple_opts.py</text></set></argument> + <argument name="args"><set><text>options/example-FunTuple.py</text></set></argument> <argument name="validator"><text> import sys, os, glob import ROOT as r diff --git a/Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py b/Phys/FunTuple/tests/qmtest/options/example-FunTuple.py similarity index 88% rename from Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py rename to Phys/FunTuple/tests/qmtest/options/example-FunTuple.py index d7e049153..6036195d1 100755 --- a/Phys/FunTuple/tests/qmtest/options/FunTuple_opts.py +++ b/Phys/FunTuple/tests/qmtest/options/example-FunTuple.py @@ -9,9 +9,28 @@ # granted to it by virtue of its status as an Intergovernmental Organization # # or submit itself to any jurisdiction. # ############################################################################### +""" +Example of tupling with the FunTuple algorithm +""" +from Configurables import LHCbApp +from Gaudi.Configuration import ApplicationMgr, NTupleSvc +from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv +from Configurables import CondDB +from Configurables import MakeData +from Configurables import FunTuple -######### Define helpful classes and functions + +""" Define helpful class and function + +class ParticleTupleProp: + A class that one can configure with branch_name, decay descriptor and functors. + +Function convert_to_parsable_objs: + Since ParticleTupleProp cannot currently be passed as Gaudi::Property, define + this function to turn member variables into parsable_objs for FunTuple + +""" class ParticleTupleProp: def __init__(self, branch_name, decay_descriptor, particle_code): """ @@ -48,17 +67,7 @@ def convert_to_parsable_objs(particle_tuple_props): return branch_list, discrp_list, func_list, func_bnamelist, func_rtypelist - -######### - -from Gaudi.Configuration import * -from Configurables import LHCbApp -from Configurables import LHCb__ParticlePropertySvc -LHCb__ParticlePropertySvc( -) #To turn on verbose set LHCb__ParticlePropertySvc(OutputLevel=1) -from Configurables import CondDB -CondDB(Upgrade=True) - +#Configure LHCb application app = LHCbApp() app.DataType = "Upgrade" app.DDDBtag = "dddb-20171126" @@ -66,17 +75,16 @@ app.CondDBtag = "sim-20171127-vc-md100" app.Simulation = True ApplicationMgr().EvtMax = 5 ApplicationMgr().EvtSel = "NONE" +CondDB(Upgrade=True) #Make MCParticles (just one Bs): Turns out TES is not clever enough to take ownership 'recursively' (set makeCustomData = True if running this algorithm) -from Configurables import MakeData algMakeData = MakeData( name="Alg_MakeData", decay_descriptor= "[B_s0 => (J/psi(1S) => mu+ mu- ) ( phi(1020) => K+ K-)]CC", output_location="MCParticle") -#Do we need a custom gaudi property like ParticleTupleProp? -#Configure Particles Bs +#Configure Particles Bs and phi ParticleBs = ParticleTupleProp( branch_name="Bs", decay_descriptor= @@ -84,18 +92,18 @@ ParticleBs = ParticleTupleProp( #List of tuple, each tuple (functor, branch name, precision (TODO), description). particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) -#Configure Particles Phi ParticlePhi = ParticleTupleProp( branch_name="Phi", decay_descriptor= "[B_s0 => (J/psi(1S) => mu+ mu- ) ^( phi(1020) => K+ K-)]CC", particle_code=[('MCP', 'TRUEP', 'double', 'True Moment'), ('MCPT', 'TRUEPT', 'double', 'True Transverse moment')]) + #Do not need to do this if a custom gaudi property is implemented branchlist, decaydiscrpList, funcList, funcBranchNameList, funcRetunTypeList = convert_to_parsable_objs( [ParticleBs, ParticlePhi]) -from Configurables import FunTuple +#Configure FunTuple algorithm algtupledata = FunTuple( name="FunTuple", tree_name="DecayTree", @@ -110,9 +118,10 @@ algtupledata = FunTuple( input_location="MCParticle", NTupleLUN='tuple') +#add the algorithms to the sequence ApplicationMgr().TopAlg = [algMakeData, algtupledata] -#Tuple props +#set Tuple properties outputname = "FunTuple.root" NTupleSvc().Output = [ "{} DATAFILE='{}' TYP='ROOT' OPT='NEW'".format(algtupledata.NTupleLUN, @@ -121,5 +130,4 @@ NTupleSvc().Output = [ ApplicationMgr().ExtSvc.append(NTupleSvc()) ApplicationMgr().HistogramPersistency = "ROOT" # Set the compression level for the ROOT tuple file -from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv RFileCnv('RFileCnv').GlobalCompression = "LZMA:6" -- GitLab From 5ba669a05b3ca54a801c5ea68e65768799f54381 Mon Sep 17 00:00:00 2001 From: Gitlab CI <noreply@cern.ch> Date: Tue, 2 Mar 2021 17:31:36 +0000 Subject: [PATCH 3/6] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/Analysis/-/jobs/12437619 --- Phys/FunTuple/options/example-FunTuple.py | 13 +++++++------ .../tests/qmtest/options/example-FunTuple.py | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/Phys/FunTuple/options/example-FunTuple.py b/Phys/FunTuple/options/example-FunTuple.py index 6036195d1..e32545238 100755 --- a/Phys/FunTuple/options/example-FunTuple.py +++ b/Phys/FunTuple/options/example-FunTuple.py @@ -19,18 +19,18 @@ from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv from Configurables import CondDB from Configurables import MakeData from Configurables import FunTuple - - """ Define helpful class and function -class ParticleTupleProp: - A class that one can configure with branch_name, decay descriptor and functors. +class ParticleTupleProp: + A class that one can configure with branch_name, decay descriptor and functors. -Function convert_to_parsable_objs: - Since ParticleTupleProp cannot currently be passed as Gaudi::Property, define +Function convert_to_parsable_objs: + Since ParticleTupleProp cannot currently be passed as Gaudi::Property, define this function to turn member variables into parsable_objs for FunTuple """ + + class ParticleTupleProp: def __init__(self, branch_name, decay_descriptor, particle_code): """ @@ -67,6 +67,7 @@ def convert_to_parsable_objs(particle_tuple_props): return branch_list, discrp_list, func_list, func_bnamelist, func_rtypelist + #Configure LHCb application app = LHCbApp() app.DataType = "Upgrade" diff --git a/Phys/FunTuple/tests/qmtest/options/example-FunTuple.py b/Phys/FunTuple/tests/qmtest/options/example-FunTuple.py index 6036195d1..e32545238 100755 --- a/Phys/FunTuple/tests/qmtest/options/example-FunTuple.py +++ b/Phys/FunTuple/tests/qmtest/options/example-FunTuple.py @@ -19,18 +19,18 @@ from GaudiKernel.Configurable import ConfigurableGeneric as RFileCnv from Configurables import CondDB from Configurables import MakeData from Configurables import FunTuple - - """ Define helpful class and function -class ParticleTupleProp: - A class that one can configure with branch_name, decay descriptor and functors. +class ParticleTupleProp: + A class that one can configure with branch_name, decay descriptor and functors. -Function convert_to_parsable_objs: - Since ParticleTupleProp cannot currently be passed as Gaudi::Property, define +Function convert_to_parsable_objs: + Since ParticleTupleProp cannot currently be passed as Gaudi::Property, define this function to turn member variables into parsable_objs for FunTuple """ + + class ParticleTupleProp: def __init__(self, branch_name, decay_descriptor, particle_code): """ @@ -67,6 +67,7 @@ def convert_to_parsable_objs(particle_tuple_props): return branch_list, discrp_list, func_list, func_bnamelist, func_rtypelist + #Configure LHCb application app = LHCbApp() app.DataType = "Upgrade" -- GitLab From f4fd0c49a37ec247fbea876d3972524c5494339f Mon Sep 17 00:00:00 2001 From: amathad <Abhijit Mathad amathad@cern.ch> Date: Wed, 3 Mar 2021 12:10:04 +0100 Subject: [PATCH 4/6] Remove Gaudi install headers for CombKernel --- Phys/FunTuple/CMakeLists.txt | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/Phys/FunTuple/CMakeLists.txt b/Phys/FunTuple/CMakeLists.txt index cf00de75b..d9effa579 100644 --- a/Phys/FunTuple/CMakeLists.txt +++ b/Phys/FunTuple/CMakeLists.txt @@ -11,20 +11,18 @@ gaudi_subdir(FunTuple) -gaudi_depends_on_subdirs(Phys/DaVinciKernel - Phys/DaVinciMCKernel - Kernel/LHCbMath - Phys/LoKiMC - Phys/LoKiAlgoMC - Phys/LoKiArrayFunctors - Phys/LoKiPhys - ) +gaudi_depends_on_subdirs(Phys/DaVinciKernel Phys/DaVinciMCKernel Kernel/LHCbMath + Phys/LoKiMC + Phys/LoKiAlgoMC + Phys/LoKiArrayFunctors + Phys/LoKiPhys + ) find_package(Boost) find_package(ROOT COMPONENTS RIO Tree) include_directories(SYSTEM ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) -gaudi_install_headers(CombKernel) +#gaudi_install_headers(CombKernel) gaudi_add_module(FunTuple src/*.cpp @@ -32,4 +30,4 @@ gaudi_add_module(FunTuple gaudi_add_test(QMTest QMTEST) -gaudi_install_python_modules() +#gaudi_install_python_modules() -- GitLab From ab9e40266789533b516c66416a274d91209393c5 Mon Sep 17 00:00:00 2001 From: amathad <Abhijit Mathad amathad@cern.ch> Date: Thu, 4 Mar 2021 11:04:04 +0100 Subject: [PATCH 5/6] RFix build warnings on platform x86_64-centos7-clang8-opt --- Phys/FunTuple/src/FunTuple.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Phys/FunTuple/src/FunTuple.cpp b/Phys/FunTuple/src/FunTuple.cpp index c2de2c88c..69fd2a091 100755 --- a/Phys/FunTuple/src/FunTuple.cpp +++ b/Phys/FunTuple/src/FunTuple.cpp @@ -66,7 +66,10 @@ protected: StatusCode booktuple( const Tuples::Tuple& m_ntuple, const std::string& colname, const T2& val ) const; StatusCode checks(); StatusCode setParticleTupleProps(); - void FindAndBookTuple( const unsigned int& i, const T& particles, const Tuples::Tuple& ntuple ) const {} + void FindAndBookTuple( const unsigned int& i, const T& particles, const Tuples::Tuple& ntuple ) const { + //variables used in explicit template specialisation, so suppress unused variable compiler warning here + (void)i; (void)particles; (void)ntuple; + } //(Will be removed): The following overloaded function (makeMCTwoBodyDecay) are only used when m_makeCustomData is set // to true (see m_makeCustomData property description for more info) void makeMCTwoBodyDecay( LHCb::MCParticle& p, LHCb::MCParticle& p1, LHCb::MCParticle& p2, const int& parentid ) const; -- GitLab From cfa69df30d180304fa52d9348eda2d2f4f924da6 Mon Sep 17 00:00:00 2001 From: Gitlab CI <noreply@cern.ch> Date: Thu, 4 Mar 2021 10:04:55 +0000 Subject: [PATCH 6/6] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/Analysis/-/jobs/12472970 --- Phys/FunTuple/src/FunTuple.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Phys/FunTuple/src/FunTuple.cpp b/Phys/FunTuple/src/FunTuple.cpp index 69fd2a091..a820dafd6 100755 --- a/Phys/FunTuple/src/FunTuple.cpp +++ b/Phys/FunTuple/src/FunTuple.cpp @@ -67,8 +67,10 @@ protected: StatusCode checks(); StatusCode setParticleTupleProps(); void FindAndBookTuple( const unsigned int& i, const T& particles, const Tuples::Tuple& ntuple ) const { - //variables used in explicit template specialisation, so suppress unused variable compiler warning here - (void)i; (void)particles; (void)ntuple; + // variables used in explicit template specialisation, so suppress unused variable compiler warning here + (void)i; + (void)particles; + (void)ntuple; } //(Will be removed): The following overloaded function (makeMCTwoBodyDecay) are only used when m_makeCustomData is set // to true (see m_makeCustomData property description for more info) -- GitLab