diff --git a/Phys/FunctorCore/include/Functors/Combination.h b/Phys/FunctorCore/include/Functors/Combination.h index ee5efe8adcdeaff4baa732f84a54525eb6399b67..b232a1a8d8181e8ac367dbb4ca7645ef4e37aad8 100644 --- a/Phys/FunctorCore/include/Functors/Combination.h +++ b/Phys/FunctorCore/include/Functors/Combination.h @@ -20,6 +20,7 @@ #include "GaudiKernel/System.h" #include "Kernel/IDistanceCalculator.h" #include "Kernel/STLExtensions.h" +#include "SelTools/DistanceCalculator.h" /** @file Combination.h * @brief Definitions of functors for tuple-likes of track-like objects. @@ -81,10 +82,10 @@ namespace Functors::detail { } }; - std::optional m_dist; - std::optional m_parent; - std::optional> m_tool; - std::string m_tool_name; + std::optional m_dist; + std::optional m_parent; + std::optional> m_tool; + std::string m_tool_name; public: IDistanceCalculatorHolder( std::string instance ) : m_tool_name{ std::move( instance ) } {} @@ -174,6 +175,22 @@ namespace Functors::detail { template struct DistanceOfClosestApproach; + template + struct DistanceOfClosestApproach<-1, -1, method, IDistanceCalculator> : public Function { + DistanceOfClosestApproach( std::string instance = "LoKi::DistanceCalculator" ) : m_dist{ std::move( instance ) } {} + + void bind( TopLevelInfo& top_level ) { m_dist.emplace( top_level ); } + + auto prepare( EventContext const& evtCtx, TopLevelInfo const& ) const { + return [calc = m_dist.template prepare( evtCtx )]( const auto& p1, const auto& p2 ) { + return calc( Sel::Utils::deref_if_ptr( p1 ), Sel::Utils::deref_if_ptr( p2 ) ); + }; + } + + private: + IDistanceCalculatorHolder m_dist; + }; + template struct DistanceOfClosestApproach : public Function { static_assert( N >= 1 && M >= 1, "Indices start from 1 for LoKi compatibility." ); @@ -196,8 +213,26 @@ namespace Functors::detail { IDistanceCalculatorHolder m_dist; }; + template + struct DistanceOfClosestApproach<-1, -1, method, Sel::DistanceCalculator> : public Function { + + void bind( TopLevelInfo& top_level ) { m_dist.emplace( top_level.algorithm() ); } + + template + auto operator()( P1 const& p1, P2 const& p2 ) const { + if constexpr ( method == DOCAMethod::Distance ) { + return m_dist->particleDOCA( Sel::Utils::deref_if_ptr( p1 ), Sel::Utils::deref_if_ptr( p2 ) ); + } else { + return m_dist->particleDOCAChi2( Sel::Utils::deref_if_ptr( p1 ), Sel::Utils::deref_if_ptr( p2 ) ); + } + } + + private: + std::optional m_dist; + }; + template - struct DistanceOfClosestApproach : public Function { + struct DistanceOfClosestApproach : public Function { static_assert( N >= 1 && M >= 1, "Indices start from 1 for LoKi compatibility." ); void bind( TopLevelInfo& top_level ) { m_dist.emplace( top_level.algorithm() ); } @@ -217,16 +252,15 @@ namespace Functors::detail { } private: - std::optional m_dist; + std::optional m_dist; }; - ////// struct MaxDistanceOfClosestApproach; template struct MaxDistanceOfClosestApproach; template - struct MaxDistanceOfClosestApproach : public Function { + struct MaxDistanceOfClosestApproach : public Function { void bind( TopLevelInfo& top_level ) { m_dist.emplace( top_level.algorithm() ); } template auto operator()( CombinationType const& combination_ptr ) const { @@ -247,7 +281,7 @@ namespace Functors::detail { } private: - std::optional m_dist; + std::optional m_dist; }; template @@ -277,7 +311,7 @@ namespace Functors::detail { class MaxDistanceOfClosestApproachCut; template - class MaxDistanceOfClosestApproachCut : public Predicate { + class MaxDistanceOfClosestApproachCut : public Predicate { public: MaxDistanceOfClosestApproachCut( float thresh ) : m_thresh( thresh ) {} @@ -300,8 +334,8 @@ namespace Functors::detail { } private: - std::optional m_dist; - float m_thresh; + std::optional m_dist; + float m_thresh; }; template @@ -343,13 +377,13 @@ namespace Functors::Combination { template const auto SDistanceOfClosestApproach = - detail::DistanceOfClosestApproach{}; + detail::DistanceOfClosestApproach{}; template const auto DistanceOfClosestApproach = detail::DistanceOfClosestApproach{}; template const auto SDistanceOfClosestApproachChi2 = - detail::DistanceOfClosestApproach{}; + detail::DistanceOfClosestApproach{}; template const auto DistanceOfClosestApproachChi2 = detail::DistanceOfClosestApproach{}; @@ -358,11 +392,11 @@ namespace Functors::Combination { // over all pairs in the combination, and then use composition const auto MaxSDistanceOfClosestApproach = - detail::MaxDistanceOfClosestApproach{}; + detail::MaxDistanceOfClosestApproach{}; const auto MaxDistanceOfClosestApproach = detail::MaxDistanceOfClosestApproach{}; const auto MaxSDistanceOfClosestApproachChi2 = - detail::MaxDistanceOfClosestApproach{}; + detail::MaxDistanceOfClosestApproach{}; const auto MaxDistanceOfClosestApproachChi2 = detail::MaxDistanceOfClosestApproach{}; @@ -370,11 +404,11 @@ namespace Functors::Combination { // when applied over all pairs in the combination, and then use composition // using MaxSDistanceOfClosestApproachCut = - detail::MaxDistanceOfClosestApproachCut; + detail::MaxDistanceOfClosestApproachCut; using MaxDistanceOfClosestApproachCut = detail::MaxDistanceOfClosestApproachCut; using MaxSDistanceOfClosestApproachChi2Cut = - detail::MaxDistanceOfClosestApproachCut; + detail::MaxDistanceOfClosestApproachCut; using MaxDistanceOfClosestApproachChi2Cut = detail::MaxDistanceOfClosestApproachCut; diff --git a/Phys/FunctorCore/include/Functors/Composite.h b/Phys/FunctorCore/include/Functors/Composite.h index 92feb936b00882d05a8830a84b310d8d81e9e3c3..1f2b2db350862fd31589fb80929dd1d9dfc25745 100644 --- a/Phys/FunctorCore/include/Functors/Composite.h +++ b/Phys/FunctorCore/include/Functors/Composite.h @@ -10,20 +10,19 @@ \*****************************************************************************/ #pragma once #include "Event/FlavourTag.h" +#include "Event/Particle.h" +#include "Event/Particle_v2.h" #include "Event/State.h" #include "Functors/Core.h" #include "Functors/Function.h" +#include "Functors/TrackLike.h" #include "Functors/Utilities.h" #include "Kernel/IParticlePropertySvc.h" #include "Kernel/ParticleProperty.h" #include "LHCbMath/MatVec.h" #include "SelKernel/Utilities.h" #include "SelKernel/VertexRelation.h" - -#include "Event/Particle.h" -#include "Event/Particle_v2.h" -#include "Functors/TrackLike.h" - +#include "SelTools/DistanceCalculator.h" #include #include @@ -83,7 +82,7 @@ namespace Functors::Composite { } private: - std::optional m_dist_calc; + std::optional m_dist_calc; }; template diff --git a/Phys/FunctorCore/include/Functors/Utilities.h b/Phys/FunctorCore/include/Functors/Utilities.h index ff422f7a28ccdfaf992a28bd8e5191a57e3dfeef..c30256fb4b89240eaafc471fc4815086d68c3c0a 100644 --- a/Phys/FunctorCore/include/Functors/Utilities.h +++ b/Phys/FunctorCore/include/Functors/Utilities.h @@ -40,9 +40,6 @@ namespace Functors::detail { /** Default type of the TES container of PVs. */ using DefaultPVContainer_t = LHCb::Event::PV::PrimaryVertexContainer; - /** Default DistanceCalculator type. */ - using DefaultDistanceCalculator_t = Sel::DistanceCalculator; - /** Default LifetimeFitter type. */ using DefaultLifetimeFitter_t = Sel::LifetimeFitter; diff --git a/Phys/FunctorCore/python/Functors/__init__.py b/Phys/FunctorCore/python/Functors/__init__.py index 83eae7fd3a8ab43775e9dadb91756798fa5fc8b8..9ded1725a3bb2e89999507851cc91d3bc205c6d4 100644 --- a/Phys/FunctorCore/python/Functors/__init__.py +++ b/Phys/FunctorCore/python/Functors/__init__.py @@ -1955,7 +1955,49 @@ MTDOCACHI2._F = Functor( ], ) -SDOCA = Functor( + +def __create_doca_functor(*args, **kwargs): + """ + Build a Functor and return a callable wrapper expecting exactly two arguments: + - (int, int) -> functor(a, b) + - (BoundFunctor, BoundFunctor) -> functor(-1, -1).bind(a, b) + """ + + def call(*args_, **kwargs_): + if args_ and kwargs_: + raise TypeError("Do not mix positional and keyword arguments.") + + # get the two arguments a and b + if kwargs_: + # TODO: add deprecation message so the kwargs branch can be dropped again... + if set(kwargs_.keys()) != {"Child1", "Child2"}: + raise TypeError( + f"Must be invoked with 'Child1' and 'Child2', got {kwargs_.keys} instead" + ) + a, b = kwargs_["Child1"], kwargs_["Child2"] + else: + if len(args_) != 2: + raise TypeError("must be invoked with exactly two positional arguments") + a, b = args_ + + # dispatch based on the types of a and b + if isinstance(a, int) and isinstance(b, int): + return call._F(a, b) + if isinstance(a, BoundFunctor) and isinstance(b, BoundFunctor): + return call._F(-1, -1).bind(a, b) + raise TypeError( + f"{call._F.name} expects (int, int) or (BoundFunctor, BoundFunctor); " + f"got ({type(a).__name__}, {type(b).__name__})" + ) + + # expose underlying functor and mirror its metadata + call._F = Functor(*args, **kwargs) + call.__name__ = getattr(call._F, "name", "wrapped_functor") + call.__doc__ = getattr(call._F, "docstring", call.__doc__) + return call + + +SDOCA = __create_doca_functor( "SDOCA", "Combination::SDistanceOfClosestApproach", """Compute the distance of closest approach between two 'states'.""", @@ -1973,7 +2015,9 @@ SDOCA = Functor( ], AllowMultiplePositionalArguments=True, ) -DOCA = Functor( + + +DOCA = __create_doca_functor( "DOCA", "Combination::DistanceOfClosestApproach", """Compute the distance of closest approach between two track-like objects which may need transport over longer distances.""", @@ -1991,7 +2035,9 @@ DOCA = Functor( ], AllowMultiplePositionalArguments=True, ) -SDOCACHI2 = Functor( + + +SDOCACHI2 = __create_doca_functor( "SDOCACHI2", "Combination::SDistanceOfClosestApproachChi2", """Compute the significance of the distance of closest @@ -2010,7 +2056,9 @@ SDOCACHI2 = Functor( ], AllowMultiplePositionalArguments=True, ) -DOCACHI2 = Functor( + + +DOCACHI2 = __create_doca_functor( "DOCACHI2", "Combination::DistanceOfClosestApproachChi2", """Compute the significance of the distance of closest @@ -2029,6 +2077,7 @@ DOCACHI2 = Functor( ], AllowMultiplePositionalArguments=True, ) + MAXSDOCA = Functor( "MAXSDOCA", "Combination::MaxSDistanceOfClosestApproach",