diff --git a/Phys/ParticleCombiners/CombKernel/ParticleCombination.h b/Phys/ParticleCombiners/CombKernel/ParticleCombination.h index 3a331a674392d700180807f4467f62989fb5ba86..1ae462cfe1fc2b3d08ab7877b8e234073a5da187 100644 --- a/Phys/ParticleCombiners/CombKernel/ParticleCombination.h +++ b/Phys/ParticleCombiners/CombKernel/ParticleCombination.h @@ -9,27 +9,58 @@ * or submit itself to any jurisdiction. * \*****************************************************************************/ #pragma once -#include "ParticleCombiner.h" #include +#include #include #include +#include "Kernel/HeaderMapping.h" +#include "Kernel/IDistanceCalculator.h" + namespace Combination::details { using fp = float; } -template +struct IDistanceCalculator; + +/** @brief A list of particle objects. + * + * A 'combination' is simply an ordered list of particle objects. This + * combination object holds such a list and has several member functions for + * computing kinematic and geometric 'properties' of the list. + * + * The 'four momentum' of a combination is defined as the sum of the four + * momentum of the particles held by it. Most other intrinsic properties can be + * derived from this, such as the 'invariant mass' of a combination. + * + * Some other methods exist to make this object compatible with the API expected + * by the ThOr functor framework, allowing an instance of ParticleCombination to + * be passed in as an argument to a functor. + */ +template struct ParticleCombination { + static constexpr auto N = sizeof...( InputTypes ); + static_assert( N >= 1 ); + // Assert that all members of the parameter pack have the same type + using Particle_t = std::tuple_element_t<0, std::tuple>; + static_assert( std::conjunction_v...> ); + + ParticleCombination( IDistanceCalculator const* distance_calculator, IGeometryInfo const& geometry ) + : m_distance_calculator( distance_calculator ), m_geometry{geometry} {} - using child_array = std::array; - child_array m_children{}; + /// Pointers to each of the N child objects in this combination + std::array m_children{}; - NBodyParticleCombinerBase const* m_legacy_accessor; - ParticleCombination( NBodyParticleCombinerBase const* legacy_accessor ) : m_legacy_accessor( legacy_accessor ) {} + /// Distance calculator used to compute distance-related quantities + IDistanceCalculator const* m_distance_calculator; + /// Geometry information passed to the distance calculator + IGeometryInfo const& m_geometry; + + /** @brief Squared-magnitude of the four momentum sum of the children. + */ Combination::details::fp mom2() const { using Combination::details::fp; - using std::sqrt; double px = std::numeric_limits::min(); double py = std::numeric_limits::min(); double pz = std::numeric_limits::min(); @@ -41,6 +72,29 @@ struct ParticleCombination { return px * px + py * py + pz * pz; } + /** @brief Magnitude of the four momentum sum of the children. + */ + Combination::details::fp p() const { + using std::sqrt; + return sqrt( mom2() ); + } + + /** @brief Transverse momentum component of the four momentum sum of the children. + */ + Combination::details::fp pt() const { + using Combination::details::fp; + using std::sqrt; + double px = std::numeric_limits::min(); + double py = std::numeric_limits::min(); + for ( auto* i : m_children ) { + px += i->momentum().px(); + py += i->momentum().py(); + } + return sqrt( px * px + py * py ); + } + + /** @brief Invariant mass of the four momentum sum of the children. + */ Combination::details::fp mass() const { using Combination::details::fp; using std::sqrt; @@ -49,37 +103,47 @@ struct ParticleCombination { return sqrt( energy * energy - mom2() ); } + /** @brief Distance of closest approach between two children. + */ template auto doca( DistanceCalculator const& ) const { static_assert( I1 < N && I2 < N ); double current_distance{}; - m_legacy_accessor->m_dist_calc->distance( m_children[I1], m_children[I2], current_distance ).ignore(); + m_distance_calculator->distance( m_children[I1], m_children[I2], current_distance, m_geometry ).ignore(); return current_distance; } + /** @brief Return true if the maximum distance of closest approach across all + * possible pairs of children is less than the threshold. + */ template bool maxdocacut( DistanceCalculator const&, Combination::details::fp thresh ) const { using Combination::details::fp; for ( auto i1 = m_children.begin(); i1 != m_children.end(); ++i1 ) { for ( auto i2 = std::next( i1 ); i2 != m_children.end(); ++i2 ) { double current_distance = std::numeric_limits::min(); - m_legacy_accessor->m_dist_calc->distance( *i1, *i2, current_distance, m_legacy_accessor->geometry() ); + m_distance_calculator->distance( *i1, *i2, current_distance, m_geometry ).ignore(); + // Short circuit if we find a DOCA above the threshold if ( current_distance > thresh ) { return false; }; } } return true; } + /** @brief Distance of closest approach chi^2 between two children. + */ template auto docachi2( DistanceCalculator const& ) const { static_assert( I1 < N && I2 < N ); double current_chi2{}, current_distance{}; - m_legacy_accessor->m_dist_calc - ->distance( m_children[I1], m_children[I2], current_distance, current_chi2, m_legacy_accessor->geometry() ) + m_distance_calculator->distance( m_children[I1], m_children[I2], current_distance, current_chi2, m_geometry ) .ignore(); return current_chi2; } + /** @brief Maximum distance of closest approach chi^2 across all possible pairs + * of children is less. + */ template Combination::details::fp maxdocachi2( DistanceCalculator const& ) const { using Combination::details::fp; @@ -88,13 +152,16 @@ struct ParticleCombination { for ( auto i2 = std::next( i1 ); i2 != m_children.end(); ++i2 ) { double current_chi2 = std::numeric_limits::min(); double current_distance = std::numeric_limits::min(); - m_legacy_accessor->m_dist_calc->distance( *i1, *i2, current_distance, current_chi2 ); + m_distance_calculator->distance( *i1, *i2, current_distance, current_chi2, m_geometry ).ignore(); chi2 = std::max( chi2, current_chi2 ); } } return chi2; } + /** @brief Return true if the maximum distance of closest approach chi^2 across + * all possible pairs of children is less than the threshold. + */ template bool maxdocachi2cut( DistanceCalculator const&, Combination::details::fp thresh ) const { using Combination::details::fp; @@ -102,9 +169,8 @@ struct ParticleCombination { for ( auto i2 = std::next( i1 ); i2 != m_children.end(); ++i2 ) { double current_chi2 = std::numeric_limits::min(); double current_distance = std::numeric_limits::min(); - m_legacy_accessor->m_dist_calc - ->distance( *i1, *i2, current_distance, current_chi2, m_legacy_accessor->geometry() ) - .ignore( /* AUTOMATICALLY ADDED FOR gaudi/Gaudi!763 */ ); + m_distance_calculator->distance( *i1, *i2, current_distance, current_chi2, m_geometry ).ignore(); + // Short circuit if we find a DOCA chi^2 above the threshold if ( current_chi2 > thresh ) { return false; }; } } @@ -112,12 +178,18 @@ struct ParticleCombination { } }; -template -auto begin( ParticleCombination const& combination ) { +template +auto begin( ParticleCombination const& combination ) { return combination.m_children.begin(); } -template -auto end( ParticleCombination const& combination ) { +template +auto end( ParticleCombination const& combination ) { return combination.m_children.end(); } + +// Register headers +template +struct LHCb::header_map> { + static constexpr auto value = ( LHCb::header_map_v + ... ) + "CombKernel/ParticleCombination.h"; +}; diff --git a/Phys/ParticleCombiners/CombKernel/ParticleCombiner.h b/Phys/ParticleCombiners/CombKernel/ParticleCombiner.h index 18b2fce0ffb2efbb0c2fa64c1723dc8c9e4b9912..043b95a2686cb0f2cb618794fee5f780560867fc 100644 --- a/Phys/ParticleCombiners/CombKernel/ParticleCombiner.h +++ b/Phys/ParticleCombiners/CombKernel/ParticleCombiner.h @@ -1,5 +1,5 @@ /*****************************************************************************\ -* (c) Copyright 2000-2019 CERN for the benefit of the LHCb Collaboration * +* (c) Copyright 2000-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". * @@ -8,262 +8,633 @@ * granted to it by virtue of its status as an Intergovernmental Organization * * or submit itself to any jurisdiction. * \*****************************************************************************/ - #pragma once +#include -// legacy stuff -#include "Kernel/IDistanceCalculator.h" +#include -#include "DetDesc/DetectorElement.h" -#include "DetDesc/GenericConditionAccessorHolder.h" +#include "CombKernel/ParticleCombination.h" #include "Event/Particle.h" -#include "Event/RecVertex.h" -#include "Event/Track_v1.h" -#include "Functors/Core.h" -#include "Functors/Function.h" -#include "Functors/IFactory.h" -#include "Functors/with_functor_maps.h" -#include "Functors/with_functors.h" #include "Kernel/GetDecay.h" #include "Kernel/ICheckOverlap.h" #include "Kernel/IDecodeSimpleDecayString.h" +#include "Kernel/IDistanceCalculator.h" #include "Kernel/IParticleCombiner.h" #include "Kernel/IParticlePropertySvc.h" -#include "Kernel/ParticleProperty.h" -#include "PrKernel/PrSelection.h" -#include "GaudiAlg/MergingTransformer.h" -#include "GaudiAlg/Transformer.h" +#include "DetDesc/DetectorElement.h" +#include "DetDesc/GenericConditionAccessorHolder.h" -#include +#include "GaudiAlg/Transformer.h" -template -struct ParticleCombination; +#include "Functors/with_functors.h" namespace Combiner { namespace constants { - static constexpr auto max_particlecontainer_size = 500; // TODO optimize - static constexpr auto max_outcontainer_size = 200; // TODO optimize - static constexpr auto max_combinationcontainer_size = 10000; // TODO optimize - - constexpr auto make_combiner_map = []( auto i ) { - if constexpr ( i == 12 ) - return "Comb12Cut"; - else if constexpr ( i == 13 ) - return "Comb13Cut"; - else if constexpr ( i == 14 ) - return "Comb14Cut"; - else if constexpr ( i == 123 ) - return "Comb123Cut"; - else - return "Comb1234Cut"; - }; - - template - constexpr static auto combiner_name = make_combiner_map( std::integral_constant{} ); - + // TODO optimise based on real-world usage + static constexpr auto max_outcontainer_size = 200; } // namespace constants - template + // Get the name of the Mth combination cut of an N-particle combiner + // Very ugly, but not worth the effort to do something beautiful and constexpr + template + std::string combinationCutName() { + static_assert( N >= 2 ); + static_assert( M + 1 < N ); + std::string name{"Combination"}; + if ( M + 2 < N ) { + // M = 0 => "12" + // M = 1 => "123" + // etc. + name += "12"; + for ( auto i = 0ul; i < M; ++i ) { name += std::to_string( i + 3 ); } + } + name += "Cut"; + return name; + } + + // Tag types for combination functors + template struct CombTypes { - using Combination = ParticleCombination; - constexpr static auto Headers = std::array{"CombKernel/ParticleCombination.h"}; - struct Cut { - using Signature = bool( Combination const& ); // TODO mask_v instead of bool - constexpr static auto PropertyName = constants::combiner_name; - constexpr static auto ExtraHeaders = Headers; - }; - }; + static constexpr auto N = sizeof...( Ts ); + static_assert( N >= 2 ); - template - struct MotherTypes { - constexpr static auto Headers = std::array{"Event/Particle.h"}; + // Adapted from https://stackoverflow.com/a/45172773/596068 + template