diff --git a/Phys/DaVinciMCTools/python/DaVinciMCTools/MCReconstructed.py b/Phys/DaVinciMCTools/python/DaVinciMCTools/MCReconstructed.py index f63195c660d2ff9e07fcd074456433f775e04296..f48bfd639c8e44874b62228dfee073a776e6b91f 100644 --- a/Phys/DaVinciMCTools/python/DaVinciMCTools/MCReconstructed.py +++ b/Phys/DaVinciMCTools/python/DaVinciMCTools/MCReconstructed.py @@ -134,7 +134,9 @@ class MCReconstructed: self.QOVERP = self.__call__(F.VALUE_OR(F.NaN) @ F.QOVERP @ F.TRACK) # Predefined no track related functors - self.Reconstructed = wrap(self.__call__(F.CAST_TO_INT @ F.MC_RECONSTRUCTED), -1) + self.Reconstructed = wrap( + self.__call__(F.VALUE_OR(-1) @ F.CAST_TO_INT @ F.MC_RECONSTRUCTED), -1 + ) self.PIDmu = self.__call__(F.PID_MU) self.PIDpi = self.__call__(F.PID_PI) self.PIDk = self.__call__(F.PID_K) diff --git a/Phys/FunctorCore/include/Functors/Adapters.h b/Phys/FunctorCore/include/Functors/Adapters.h index 66a35d7b5150ff81925a3308076d3e84b5896588..2b5b140737f6b5bf36f861caf2057ec83d65b918 100644 --- a/Phys/FunctorCore/include/Functors/Adapters.h +++ b/Phys/FunctorCore/include/Functors/Adapters.h @@ -118,7 +118,7 @@ namespace Functors::Adapters { }; template - struct SubCombination : Function { + struct SubCombination_t : Function { static_assert( ( ( idxs > 0 ) && ... ) ); static_assert( sizeof...( idxs ) > 1 ); auto name() const { return "SubCombination< " + ( ( std::to_string( idxs ) + ", " ) + ... ) + " >"; } @@ -131,6 +131,9 @@ namespace Functors::Adapters { } }; + template + constexpr auto SubCombination = SubCombination_t{}; + /** @class BasicsFromComposite * @brief Adapter that retrieves the basic particles from a composite one * If the functor is applied to a basic particle, it will throw an exception @@ -254,11 +257,7 @@ namespace Functors::Adapters { * TTree). Clearly this only makes sense if it has been arranged elsewhere * that the functor return value is conceptually a scalar arithmetic value. */ - struct ConvertToPOD : Function { - template - auto operator()( T data ) const { - return LHCb::Utils::as_arithmetic( data ); - } - }; + constexpr auto ConvertToPOD = + TrivialFunctor{ "ConvertToPOD", []( auto d ) { return LHCb::Utils::as_arithmetic( d ); } }; } // namespace Functors::Adapters diff --git a/Phys/FunctorCore/include/Functors/Combination.h b/Phys/FunctorCore/include/Functors/Combination.h index f972a82a20460e4dd4c7e55846832a87f268c73f..422aaa6eb62966df6e77a7f32cffa263bc55a2d0 100644 --- a/Phys/FunctorCore/include/Functors/Combination.h +++ b/Phys/FunctorCore/include/Functors/Combination.h @@ -32,7 +32,7 @@ namespace Functors::detail { template void throw_exception_if_basic( T const& p, std::string const& msg = "DistanceOfClosestApproach::operator()" ) { - if constexpr ( is_legacy_particle ) { + if constexpr ( requires { p.isBasicParticle(); } ) { if ( p.isBasicParticle() ) throw GaudiException{ msg, "Specified combination has no daughters. Note that the functor should only be applied to " @@ -103,6 +103,18 @@ namespace Functors::detail { m_geom_name = std::move( rhs.m_geom_name ); return *this; } + IDistanceCalculatorHolder( IDistanceCalculatorHolder const& rhs ) + : m_tool_name{ rhs.m_tool_name }, m_geom_name{ rhs.m_geom_name } { + if ( m_parent.has_value() || m_dist.has_value() || m_tool.has_value() ) + throw GaudiException{ "DistanceOfClosestApproach(&&)", "attempt to copy after bind", StatusCode::FAILURE }; + } + IDistanceCalculatorHolder& operator=( IDistanceCalculatorHolder const& rhs ) { + if ( m_parent.has_value() || m_dist.has_value() || m_tool.has_value() ) + throw GaudiException{ "DistanceOfClosestApproach(&&)", "attempt to copy after bind", StatusCode::FAILURE }; + m_tool_name = rhs.m_tool_name; + m_geom_name = rhs.m_geom_name; + return *this; + } void emplace( TopLevelInfo& top_level ) { m_dist.emplace( top_level.algorithm() ); @@ -228,16 +240,16 @@ namespace Functors::detail { // check if basic particle and throw an useful exception for this doca functor Functors::detail::throw_exception_if_basic( combination, "MaxDistanceOfClosestApproach::operator()" ); using LHCb::Event::decayProducts; - const auto& dp = decayProducts( combination ); - return dp.pairwise_transform_reduce( - [&]( const auto& i1, const auto& i2 ) { - if constexpr ( method == DOCAMethod::Distance ) { - return m_dist->particleDOCA( i1, i2 ); - } else { - return m_dist->particleDOCAChi2( i1, i2 ); - } - }, - maximum ); + return decayProducts( combination ) + .pairwise_transform_reduce( + [&]( const auto& i1, const auto& i2 ) { + if constexpr ( method == DOCAMethod::Distance ) { + return m_dist->particleDOCA( i1, i2 ); + } else { + return m_dist->particleDOCAChi2( i1, i2 ); + } + }, + maximum ); } private: @@ -257,8 +269,7 @@ namespace Functors::detail { // check if basic particle and throw an useful exception for this doca functor Functors::detail::throw_exception_if_basic( combination, "MaxDistanceOfClosestApproach::operator()" ); using LHCb::Event::decayProducts; - const auto& dp = decayProducts( combination ); - return dp.pairwise_transform_reduce( transform, maximum ); + return decayProducts( combination ).pairwise_transform_reduce( transform, maximum ); }; } @@ -313,8 +324,9 @@ namespace Functors::detail { // check if basic particle and throw an useful exception for this doca functor Functors::detail::throw_exception_if_basic( combination, "MaxDistanceOfClosestApproachCut::operator()" ); using LHCb::Event::decayProducts; - const auto& dp = decayProducts( combination ); - return dp.pairwise_none_of( [&]( const auto& i1, const auto& i2 ) { return calc( i1, i2 ) > threshold; } ); + return decayProducts( combination ).pairwise_none_of( [&]( const auto& i1, const auto& i2 ) { + return calc( i1, i2 ) > threshold; + } ); }; } @@ -336,29 +348,29 @@ namespace Functors::Combination { // computes the relevant observable template - using SDistanceOfClosestApproach = - detail::DistanceOfClosestApproach; + const auto SDistanceOfClosestApproach = + detail::DistanceOfClosestApproach{}; template - using DistanceOfClosestApproach = - detail::DistanceOfClosestApproach; + const auto DistanceOfClosestApproach = + detail::DistanceOfClosestApproach{}; template - using SDistanceOfClosestApproachChi2 = - detail::DistanceOfClosestApproach; + const auto SDistanceOfClosestApproachChi2 = + detail::DistanceOfClosestApproach{}; template - using DistanceOfClosestApproachChi2 = - detail::DistanceOfClosestApproach; + const auto DistanceOfClosestApproachChi2 = + detail::DistanceOfClosestApproach{}; // TODO: replace functors below with one generic functor which computes the maximum of some other functor // over all pairs in the combination, and then use composition - using MaxSDistanceOfClosestApproach = - detail::MaxDistanceOfClosestApproach; - using MaxDistanceOfClosestApproach = - detail::MaxDistanceOfClosestApproach; - using MaxSDistanceOfClosestApproachChi2 = - detail::MaxDistanceOfClosestApproach; - using MaxDistanceOfClosestApproachChi2 = - detail::MaxDistanceOfClosestApproach; + const auto MaxSDistanceOfClosestApproach = + detail::MaxDistanceOfClosestApproach{}; + const auto MaxDistanceOfClosestApproach = + detail::MaxDistanceOfClosestApproach{}; + const auto MaxSDistanceOfClosestApproachChi2 = + detail::MaxDistanceOfClosestApproach{}; + const auto MaxDistanceOfClosestApproachChi2 = + detail::MaxDistanceOfClosestApproach{}; // TODO: replace functors below with one generic functor which cuts on the the maximum of some other functor // when applied over all pairs in the combination, and then use composition @@ -373,11 +385,11 @@ namespace Functors::Combination { detail::MaxDistanceOfClosestApproachCut; /** @brief cos(angle) between two children. + * note: Indices start from 1 for LoKi compatibility. */ template - struct CosAngleBetweenDecayProducts : Function { - static_assert( N >= 1 && M >= 1, "Indices start from 1 for LoKi compatibility." ); - + requires( N > 0 && M > 0 ) + struct CosAngleBetweenDecayProducts_t : Function { template auto operator()( CombinationType const& combination_ptr ) const { auto const& combination = Sel::Utils::deref_if_ptr( combination_ptr ); @@ -393,14 +405,11 @@ namespace Functors::Combination { } }; - struct Charge : public Function { - static constexpr auto name() { return "Charge"; } - - template - auto operator()( T const& item ) const { - using LHCb::Event::charge; - return charge( item ); - } - }; + template + constexpr auto CosAngleBetweenDecayProducts = CosAngleBetweenDecayProducts_t{}; + constexpr auto Charge = TrivialFunctor{ "Charge", []( auto const& item ) { + using LHCb::Event::charge; + return charge( item ); + } }; } // namespace Functors::Combination diff --git a/Phys/FunctorCore/include/Functors/Common.h b/Phys/FunctorCore/include/Functors/Common.h index ac3d1d88c468eae076bf8b530e2c15fd316b9281..66ad904ac4460abc3271a1b449fdd43bf8b299cf 100644 --- a/Phys/FunctorCore/include/Functors/Common.h +++ b/Phys/FunctorCore/include/Functors/Common.h @@ -31,11 +31,15 @@ namespace Functors::Common { * This functor is meant to e.g. access individual matrix values. Thus, we * only support integer values for now to not make this functor too complex. */ - template - struct Call final : public Function { + class Call final : public Function { + std::array m_indices; + + public: + constexpr Call( int i, int j ) : m_indices{ i, j } {} + constexpr Call( std::tuple ij ) : m_indices{ std::get<0>( ij ), std::get<1>( ij ) } {} template auto operator()( Data const& d ) const { - return std::invoke( Sel::Utils::deref_if_ptr( d ), indices... ); + return Sel::Utils::deref_if_ptr( d )( m_indices[0], m_indices[1] ); } }; @@ -43,7 +47,7 @@ namespace Functors::Common { template decltype( auto ) wrap_if_ref( T&& in ) { if constexpr ( std::is_lvalue_reference_v ) { - return std::ref( std::forward( in ) ); + return std::ref( in ); } else { return std::forward( in ); } @@ -68,43 +72,29 @@ namespace Functors::Common { * many type checks that aren't written to handle e.g. * reference_wrapper */ - template - struct ForwardArgs; - - template <> - struct ForwardArgs<> final : public Function { - template - auto operator()( Ts&&... d ) const { - return std::make_tuple( details::wrap_if_ref( std::forward( d ) )... ); - } - }; + + constexpr auto ForwardArgs = + TrivialFunctor{ "ForwardArgs", []( auto&&... d ) { + return std::make_tuple( details::wrap_if_ref( std::forward( d ) )... ); + } }; // even in the single argument case we use make tuple to decay the reference // wrapper a different option would be to have 2 overloads, (T0&&, ...) // returing by value and (T0&, ...) returning T& - template <> - struct ForwardArgs<0> final : public Function { - template - auto operator()( T0&& d, Ts... ) const { - return std::make_tuple( details::wrap_if_ref( std::forward( d ) ) ); - } + constexpr auto ForwardArg0 = TrivialFunctor{ + "ForwardArgs<0>", + []( T&& d, auto... ) { + return std::make_tuple( details::wrap_if_ref( std::forward( d ) ) ); + } // namespace Functors::Common }; - template <> - struct ForwardArgs<1> final : Function { - template - auto operator()( T0, T1&& d, Ts... ) const { - return std::make_tuple( details::wrap_if_ref( std::forward( d ) ) ); - } - }; + constexpr auto ForwardArg1 = TrivialFunctor{ "ForwardArgs<1>", []( auto, T&& d, auto... ) { + return std::make_tuple( details::wrap_if_ref( std::forward( d ) ) ); + } }; - template <> - struct ForwardArgs<2> final : Function { - template - auto operator()( T0, T1, T2&& d, Ts... ) const { - return std::make_tuple( details::wrap_if_ref( std::forward( d ) ) ); - } - }; + constexpr auto ForwardArg2 = TrivialFunctor{ "ForwardArgs<2>", []( auto, auto, T&& d, auto... ) { + return std::make_tuple( details::wrap_if_ref( std::forward( d ) ) ); + } }; /** * @brief std::get value by Index @@ -112,119 +102,104 @@ namespace Functors::Common { * @tparam Index */ template - struct Get final : Function { + struct Get_t final : Function { - template - constexpr auto operator()( std::tuple&& tup ) const { - return std::get( std::forward>( tup ) ); + template + constexpr auto operator()( T&& tup ) const -> decltype( std::get( std::forward( tup ) ) ) { + return std::get( std::forward( tup ) ); } template constexpr auto operator()( Args&&... args ) const { - return ( *this )( ForwardArgs{}( args... ) ); + return ( *this )( ForwardArgs( std::forward( args )... ) ); } }; - /** - * @brief Functor to return address of object - */ - struct AddressOf final : Function { - template - auto operator()( Data const& d ) const { - if constexpr ( std::is_pointer_v ) { - return d; - } else { - return std::addressof( d ); - } - } - }; + template + constexpr auto Get = Get_t{}; /** - * @brief Functor to trafo vecs into linalg vectors - * FIXME make it such that we don't need this hack + * @brief Functor to return address of object */ - struct ToLinAlg final : Function { + // clang format gets confused by the following lambdas... + // clang-format off + constexpr auto AddressOf = + TrivialFunctor{"AddressOf", + []( T& d ) -> void const* { + static_assert( !std::is_pointer_v ); // make sure we don't take the address of a pointer! + return std::addressof( d ); }, + []( T* d )-> void const* { + static_assert( !std::is_pointer_v ); // disallow pointers to pointers + return d; + }, + []( const SmartRef& d ) -> void const* { return d.target(); } + }; +// clang-format on + +/** + * @brief Functor to trafo vecs into linalg vectors + * FIXME make it such that we don't need this hack + */ +#if 0 + struct ToLinAlg_t final : Function { template - // warning we can't perfectly forward lvalues here. - // using decltype(auto) would lead to dangling references - Data operator()( Data&& d ) const { - return std::forward( d ); - } + Data operator()( Data&& d ) const { return std::forward( d ); } template auto operator()( ROOT::Math::PositionVector3D d ) const { return LHCb::LinAlg::Vec{ d.x(), d.y(), d.z() }; } }; + constexpr auto ToLinAlg = ToLinAlg_t{}; +#else + + constexpr auto ToLinAlg = + TrivialFunctor{ "ToLinAlg", + // warning we can't perfectly forward lvalues here. + // using decltype(auto) would lead to dangling references + []( auto&& d ) { return std::forward( d ); }, + []( ROOT::Math::PositionVector3D d ) { + return LHCb::LinAlg::Vec{ d.x(), d.y(), d.z() }; + } }; +#endif /** * @brief Functor to return X(input). */ - struct X_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return X( Sel::Utils::deref_if_ptr( d ) ); - } - }; + constexpr auto X_Coordinate = TrivialFunctor{ "X", []( auto const& d ) { return X( d ); } }; + /** * @brief Functor to return Y(input). */ - struct Y_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return Y( Sel::Utils::deref_if_ptr( d ) ); - } - }; + constexpr auto Y_Coordinate = TrivialFunctor{ "Y", []( auto const& d ) { return Y( d ); } }; /** * @brief Functor to return Z(input). */ - struct Z_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return Z( Sel::Utils::deref_if_ptr( d ) ); - } - }; + constexpr auto Z_Coordinate = TrivialFunctor{ "Z", []( auto const& d ) { return Z( d ); } }; /** * @brief Functor to return E(input). */ - struct E_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return E( Sel::Utils::deref_if_ptr( d ) ); - } - }; + constexpr auto E_Coordinate = TrivialFunctor{ "E", []( auto const& d ) { return E( d ); } }; /** * @brief Functor to return input.phi(). */ - struct Phi_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).phi(); - } - }; + constexpr auto Phi_Coordinate = + TrivialFunctor{ "Phi", []( auto const& d ) -> decltype( d.phi() ) { return d.phi(); } }; /** * @brief Functor to return input.eta(). */ - struct Eta_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).eta(); - } - }; + constexpr auto Eta_Coordinate = + TrivialFunctor{ "Eta", []( auto const& d ) -> decltype( d.eta() ) { return d.eta(); } }; /** * @brief Functor to return input.rho(). */ - struct Rho_Coordinate final : Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).rho(); - } - }; + constexpr auto Rho_Coordinate = + TrivialFunctor{ "Rho", []( auto const& d ) -> decltype( d.rho() ) { return d.rho(); } }; /** * @brief Functor to flatten outer_range> into vec @@ -233,480 +208,392 @@ namespace Functors::Common { template concept RangeOfRanges = std::ranges::range && std::ranges::range>; } - struct Flatten final : Function { - template - auto operator()( RangeOfRanges const& rr ) const { - using value_t = std::ranges::range_value_t>; - std::vector flattened; - // loop over the range of ranges - for ( auto& r : rr ) { flattened.insert( flattened.end(), std::ranges::begin( r ), std::ranges::end( r ) ); } - return flattened; - } - }; + constexpr auto Flatten = + TrivialFunctor{ "Flatten", []( RangeOfRanges const& rr ) { + using value_t = std::ranges::range_value_t>; + std::vector flattened; + // loop over the range of ranges + for ( auto& r : rr ) { + flattened.insert( flattened.end(), std::ranges::begin( r ), std::ranges::end( r ) ); + } + return flattened; + } }; /** * @brief Functor to return input.mag(). */ - struct Magnitude final : Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).mag(); - } - }; + constexpr auto Magnitude = + TrivialFunctor{ "Magnitude", []( auto const& d ) -> decltype( d.mag() ) { return d.mag(); } }; /** * @brief Functor to return input/input.mag(). */ - struct UnitVector final : Function { - template - auto operator()( Data const& d ) const { - auto const& vec = Sel::Utils::deref_if_ptr( d ); - return vec / vec.mag(); - } - }; + constexpr auto UnitVector = + TrivialFunctor{ "UnitVector", []( auto const& d ) -> decltype( d / d.mag() ) { return d / d.mag(); } }; /** * @brief Functor to return dot product of 2 inputs * * assumes dot(input1, input2) is defined */ - struct Dot final : Function { - template - auto operator()( Data const& d1, Data const& d2 ) const { - return dot( Sel::Utils::deref_if_ptr( d1 ), Sel::Utils::deref_if_ptr( d2 ) ); - } - }; + constexpr auto Dot = TrivialFunctor{ + "Dot", []( auto const& d1, auto const& d2 ) -> decltype( dot( d1, d2 ) ) { return dot( d1, d2 ); } }; /** * @brief Functor to return normalized dot product of 2 inputs */ - struct NormedDot final : Function { - template - auto operator()( Data const& d1, Data const& d2 ) const { - using std::sqrt; - return dot( Sel::Utils::deref_if_ptr( d1 ), Sel::Utils::deref_if_ptr( d2 ) ) / sqrt( d1.mag2() * d2.mag2() ); - } - - // FIXME another hack because TrackCompactVertex 3-mom returns vec3... - template - auto operator()( LHCb::LinAlg::Vec const& d1, - ROOT::Math::DisplacementVector3D const& r2 ) const { - using std::sqrt; - decltype( d1 ) d2{ r2.x(), r2.y(), r2.z() }; - return dot( Sel::Utils::deref_if_ptr( d1 ), Sel::Utils::deref_if_ptr( d2 ) ) / sqrt( d1.mag2() * d2.mag2() ); - } - }; - - /** - * @brief Functor for adjusting the angle if greater than PI - */ - struct AdjustAngle final : Function { - template - auto operator()( Data const& d ) const { - using std::abs, std::fmod, std::copysign; - auto angle = LHCb::Utils::as_arithmetic( d ); - while ( angle > 2 * M_PI ) angle -= 2 * M_PI; - while ( angle < -2 * M_PI ) angle += 2 * M_PI; - return abs( angle ) > M_PI ? fmod( angle, M_PI ) - copysign( M_PI, angle ) : angle; - } - }; - - /** - * @brief Functor to return best pv. - */ - struct BestPV final : Function { - // decltype(auto) because PV could be heavy and we only want to forward the - // ref, right? - template - decltype( auto ) operator()( VContainer const& vertices, TrackLike const& tr ) const { - const auto& particle = Sel::Utils::deref_if_ptr( tr ); - return Sel::getBestPV( particle, vertices ); - } - - template - decltype( auto ) operator()( Particle const& p ) const { - return Sel::Utils::deref_if_ptr( p ).pv().target(); - } - }; - - /** - * @brief Functor to return pv associated to object. - */ - struct OwnPV final : Function { - static constexpr auto name() { return "OwnPV"; } - // decltype(auto) because PV could be heavy and we only want to forward the - // ref, right? - template - decltype( auto ) operator()( Particle const& p ) const { - return Sel::Utils::deref_if_ptr( p ).pv().target(); - } - }; - - /** - * @brief Functor to return of object has associated pv - */ - struct HasOwnPV : public Predicate { - static constexpr auto name() { return "HasOwnPV"; } - // template - template - constexpr auto operator()( T const& p ) const -> decltype( ( *this )( *p ) ) { - return ( *this )( *p ); - } - template - constexpr auto operator()( Particle const& p ) const -> decltype( static_cast( p.pv() ) ) { - return static_cast( p.pv() ); - } - }; - /** - * @brief Functor to return endvertex. - */ - struct EndVertex final : Function { - // template - template - auto operator()( T const& p ) const -> decltype( ( *this )( *p ) ) { - return ( *this )( *p ); - } - - template - auto operator()( HasEndVertex const& p ) const -> decltype( p.endVertex() ) { - return p.endVertex(); - } - - LHCb::MCVertex const* operator()( LHCb::MCParticle const& p ) const { return p.goodEndVertex(); } - }; - - /** - * @brief Functor to return endvertex. - */ - struct Position final : Function { - - template - auto operator()( HasAPosition const& p ) const { - return Sel::Utils::deref_if_ptr( p ).position(); - } - // // hack around inconsistent interfaces, e.g endVertex returning a 3d point or - // // vertex object and calling position on a 3d point doesn't work... - template - auto operator()( LHCb::LinAlg::Vec const& p ) const { - return p; - } - template - auto operator()( ROOT::Math::PositionVector3D const& p ) const { - return p; - } - - auto operator()( LHCb::MCVertex const* p ) const { - if ( p ) { return p->position(); } - constexpr auto nan = std::numeric_limits::quiet_NaN(); - return Gaudi::XYZPoint( nan, nan, nan ); - } - - template - auto operator()( std::array const& items ) const { - using float_v = typename SIMDWrapper::type_map>::type::float_v; - return std::apply( - [this]( const auto&... i ) { - constexpr auto nan = std::numeric_limits::quiet_NaN(); - const auto invalid = LHCb::LinAlg::Vec{ nan, nan, nan }; - auto const into_vec3 = []( auto const& pos ) { - return LHCb::LinAlg::Vec{ pos.x(), pos.y(), pos.z() }; - }; - using LHCb::LinAlg::gather; - return gather( std::array{ ( i ? into_vec3( ( *this )( *i ) ) : invalid )... } ); - }, - items ); - } - }; - - struct ImpactParameter : Function { - static constexpr auto name() { return "ImpactParameter"; } - - template - auto operator()( Position_t const& vertex_pos, TrackChunk const& track_chunk ) const { - using Sel::Utils::impactParameterSquared; - return sqrt( impactParameterSquared( vertex_pos, track_chunk ) ); - } - }; - - struct ImpactParameterChi2 : Function { - static constexpr auto name() { return "ImpactParameterChi2"; } - - template - auto operator()( VertexType const& vertex, TrackChunk const& track_chunk ) const { - using Sel::Utils::impactParameterChi2; - return impactParameterChi2( track_chunk, vertex ); - } - }; - - struct ImpactParameterChi2ToVertex : Function { - static constexpr auto name() { return "ImpactParameterChi2ToVertex"; } - - template - auto operator()( VContainer const& vertices, Particle const& particlep ) const { - // Get the associated PV -- this uses a link if it's available and - // computes the association if it's not. - using Sel::Utils::impactParameterChi2; - const auto& particle = Sel::Utils::deref_if_ptr( particlep ); - return impactParameterChi2( particle, Sel::getBestPV( particle, vertices ) ); - } - - template - auto operator()( Particle const& particlep ) const { - // Get the associated PV -- this uses a link if it's available and - // computes the association if it's not. - using Sel::Utils::impactParameterChi2; - const auto& particle = Sel::Utils::deref_if_ptr( particlep ); - return particle.pv() ? impactParameterChi2( particle, particle.pv().target() ) : -1; - } - }; - - struct ImpactParameterChi2ToOwnPV : Function { - static constexpr auto name() { return "ImpactParameterChi2ToOwnPV"; } - template - auto operator()( Particle const& particlep ) const { - // Get the associated PV -- this uses a link if it's available and - // computes the association if it's not. - using Sel::Utils::impactParameterChi2; - const auto& particle = Sel::Utils::deref_if_ptr( particlep ); - return particle.pv() ? impactParameterChi2( particle, *particle.pv() ) : -1; - } - }; - - template - struct TES final : public Function { - - // grammar.py turns list into vector so we just accept this for now - // constructor efficiency isn't that important to us anyhow - TES( std::vector tes_locs ) { - if ( tes_locs.size() != m_tes_locs.size() ) { - throw GaudiException{ "TES Functor constructor expects " + std::to_string( m_tes_locs.size() ) + - " locations, but only got " + std::to_string( tes_locs.size() ), - name(), StatusCode::FAILURE }; - } - for ( std::size_t i{ 0 }; i < m_tes_locs.size(); ++i ) { m_tes_locs[i] = std::move( tes_locs[i] ); } - } - - // need this as per default this copy would be deleted because a copy of a - // DataObjectReadHandle is deleted because AnyDataWrapper has a deleted copy. - TES( TES const& other ) : m_tes_locs( other.m_tes_locs ) {} - - /** Set up the DataHandles, attributing the data dependencies to the given - * algorithm: set up each member of m_handles by calling .emplace() with the TES - * location and algorithm pointer. - */ - void bind( TopLevelInfo& top_level ) { - auto* alg = top_level.algorithm(); - if ( !alg ) throw GaudiException( "invoking bind without algorithm", __PRETTY_FUNCTION__, StatusCode::FAILURE ); - if ( alg->msgLevel( MSG::DEBUG ) ) { alg->debug() << "Init of DataHandles of Functor: " << name() << endmsg; } - static_assert( std::is_base_of_v>, - "You must include the full declaration of the owning algorithm type!" ); - std::apply( - [&]( auto&... h ) { - auto loc = m_tes_locs.begin(); - ( init_data_handle( h.emplace( *loc++, alg ), alg ), ... ); - }, - m_handles ); - } - - /** - * Retrieve the data dependencies from the TES and bake them into the - * "prepared" functor that we return - */ - auto prepare() const { - // Get a tuple of references to the data objects on the TES - auto deps = std::apply( [&]( auto&... h ) { return std::tie( deref( h )... ); }, m_handles ); - - // Bake this into a new lambda that we return - return [deps]( auto const&... ) { return deps; }; - } + // clang format gets confused by `requires` statements... + // clang-format off + constexpr auto NormedDot = TrivialFunctor{ + "NormedDot", []( auto const& d1, auto const& d2 ) + requires requires { + dot( d1, d2 ); + d1.mag2(); + d2.mag2(); } + { + using std::sqrt; + return dot( d1, d2 ) / sqrt( d1.mag2() * d2.mag2() ); + } , + // FIXME another hack because TrackCompactVertex 3-mom returns vec3... + []( + LHCb::LinAlg::Vec const& d1, + ROOT::Math::DisplacementVector3D const& r2 ) + { + using std::sqrt; + decltype( d1 ) d2{r2.x(), r2.y(), r2.z()}; + return dot( d1, d2 ) / sqrt( d1.mag2() * d2.mag2() ); + } + }; +// clang-format on + +/** + * @brief Functor for adjusting the angle if greater than PI + */ +constexpr auto AdjustAngle = + TrivialFunctor{ "AdjustAngle", []( auto const& d ) { + using std::abs, std::fmod, std::copysign; + auto angle = LHCb::Utils::as_arithmetic( d ); + while ( angle > 2 * M_PI ) angle -= 2 * M_PI; + while ( angle < -2 * M_PI ) angle += 2 * M_PI; + return abs( angle ) > M_PI ? fmod( angle, M_PI ) - copysign( M_PI, angle ) : angle; + } }; + +/** + * @brief Functor to return best pv. + */ +// decltype(auto) because PV could be heavy and we only want to forward the +// ref, right? +constexpr auto BestPV = + GenericFunctor{ "BestPV", + []( auto const& vertices, auto const& tr ) -> decltype( Sel::getBestPV( tr, vertices ) ) { + return Sel::getBestPV( tr, vertices ); + }, + []( auto const& p ) -> decltype( p.pv().target() ) { return p.pv().target(); } }; + +/** + * @brief Functor to return pv associated to object. + */ +constexpr auto OwnPV = + GenericFunctor{ "OwnPV", []( auto const& p ) -> decltype( p.pv().target() ) { return p.pv().target(); } }; + +/** + * @brief Functor to return of object has associated pv + */ +constexpr auto HasOwnPV = + TrivialPredicate{ "HasOwnPV", []( auto const& p ) -> decltype( p.pv(), bool{} ) { return p.pv() != nullptr; }, + []( auto const* p ) -> decltype( p->pv(), bool{} ) { return p && p->pv(); } }; + +/** + * @brief Functor to return endvertex. + */ +constexpr auto EndVertex = + GenericFunctor{ "EndVertex", []( const auto& v ) -> decltype( v.endVertex() ) { return v.endVertex(); }, + []( const auto& v ) -> decltype( v.goodEndVertex() ) { return v.goodEndVertex(); } }; + +/** + * @brief Functor to return endvertex. + */ +struct Position_t final : Function { + + template + auto operator()( HasAPosition const& p ) const -> decltype( Sel::Utils::deref_if_ptr( p ).position() ) { + return Sel::Utils::deref_if_ptr( p ).position(); + } + // // hack around inconsistent interfaces, e.g endVertex returning a 3d point or + // // vertex object and calling position on a 3d point doesn't work... + template + auto operator()( LHCb::LinAlg::Vec const& p ) const { + return p; + } + template + auto operator()( ROOT::Math::PositionVector3D const& p ) const { + return p; + } - [[nodiscard]] std::string name() const { - std::stringstream s; - using GaudiUtils::operator<<; - s << m_tes_locs; - return "TES" + s.str(); - } + auto operator()( LHCb::MCVertex const* p ) const { + if ( p ) { return p->position(); } + constexpr auto nan = std::numeric_limits::quiet_NaN(); + return Gaudi::XYZPoint( nan, nan, nan ); + } - private: - std::array m_tes_locs; - std::tuple>...> m_handles; - - /** - * @brief Initialize a TES DataHandle and check that the owning algorithm - * was configured correctly and already holds our input in ExtraInputs - * - * For more info on the logic please see the detailed explanation of how - * functors obtain their data dependencies in the doc of the FunctorFactory. - * - * @param handle This handle will be initialized - * @param alg Algorithm/Tool which owns this functor - */ - template - void init_data_handle( DataObjectReadHandle& handle, Algorithm* alg ) { - if ( alg->msgLevel( MSG::DEBUG ) ) { - alg->debug() << " + " << handle.objKey() - << " (will call init(): " << ( alg->FSMState() == Gaudi::StateMachine::INITIALIZED ) << ")" - << endmsg; - } - if ( alg->extraInputDeps().count( handle.objKey() ) == 0 ) { - throw GaudiException{ "Usage of DataHandle[\"" + handle.objKey() + - "\"] in TES Functor requires that owning algorithm " + alg->name() + - " contains this TES location inside the ExtraInputs property. This is likely a " - "Configuration/PyConf bug!", - name(), StatusCode::FAILURE }; - } + template + auto operator()( std::array const& items ) const { + using float_v = typename SIMDWrapper::type_map>::type::float_v; + return std::apply( + [this]( const auto&... i ) { + constexpr auto nan = std::numeric_limits::quiet_NaN(); + const auto invalid = LHCb::LinAlg::Vec{ nan, nan, nan }; + auto const into_vec3 = []( auto const& pos ) { + return LHCb::LinAlg::Vec{ pos.x(), pos.y(), pos.z() }; + }; + using LHCb::LinAlg::gather; + return gather( std::array{ ( i ? into_vec3( ( *this )( *i ) ) : invalid )... } ); + }, + items ); + } +}; +constexpr auto Position = Position_t{}; + +constexpr auto ImpactParameter = + TrivialFunctor{ "ImpactParameter", []( auto const& vertex_pos, auto const& track_chunk ) { + using Sel::Utils::impactParameterSquared; + return sqrt( impactParameterSquared( vertex_pos, track_chunk ) ); + } }; + +constexpr auto ImpactParameterChi2 = + TrivialFunctor{ "ImpactParameterChi2", []( auto const& vertex, auto const& track_chunk ) { + using Sel::Utils::impactParameterChi2; + return impactParameterChi2( track_chunk, vertex ); + } }; + +constexpr auto ImpactParameterChi2ToVertex = + TrivialFunctor{ "ImpactParameterChi2ToVertex", + []( auto const& vertices, auto const& particle ) { + // Get the associated PV -- this uses a link if it's available and + // computes the association if it's not. + using Sel::Utils::impactParameterChi2; + return impactParameterChi2( particle, Sel::getBestPV( particle, vertices ) ); + }, + []( auto const& particle ) { + // Get the associated PV -- this uses a link if it's available and + // computes the association if it's not. + using Sel::Utils::impactParameterChi2; + return particle.pv() ? impactParameterChi2( particle, particle.pv().target() ) : -1; + } }; + +constexpr auto ImpactParameterChi2ToOwnPV = + TrivialFunctor{ "ImpactParameterChi2ToOwnPV", []( auto const& particle ) { + using Sel::Utils::impactParameterChi2; + return particle.pv() ? impactParameterChi2( particle, *particle.pv() ) : -1; + } }; + +template +struct TES final : public Function { + + // grammar.py turns list into vector so we just accept this for now + // constructor efficiency isn't that important to us anyhow + TES( std::vector tes_locs ) { + if ( tes_locs.size() != m_tes_locs.size() ) { + throw GaudiException{ "TES Functor constructor expects " + std::to_string( m_tes_locs.size() ) + + " locations, but only got " + std::to_string( tes_locs.size() ), + name(), StatusCode::FAILURE }; + } + for ( std::size_t i{ 0 }; i < m_tes_locs.size(); ++i ) { m_tes_locs[i] = std::move( tes_locs[i] ); } + } - // DataObjectReadHandle has a protected `init()` so we need to call it - // through it's base class. This is the same thing Gaudi::Algorithm does in - // sysInitialize(). We do it here because this DataHandle is created inside - // start(), at which point the step of initializing the handles of an - // algorithm has already happened. - // !! Exception !! if we are getting this functor from the cache then we - // are already creating it in intialize(), and we need to skip the init() - // call as it's also done in the sysInitialize() of the algorithm and it is - // apparently forbidden to call init() twice on a DataHandle which is - // checked via an assert in DataObjectHandleBase->init(). So we only run - // init() here if the algorithm is already in an INITIALIZEDD state which - // means this construction is happening inside start() - if ( alg->FSMState() == Gaudi::StateMachine::INITIALIZED ) { static_cast( &handle )->init(); } - } + // need this as per default this copy would be deleted because a copy of a + // DataObjectReadHandle is deleted because AnyDataWrapper has a deleted copy. + TES( TES const& other ) : m_tes_locs( other.m_tes_locs ) {} - /** Check an optional data handle is initialised and doesn't return - * nullptr, then return a reference to the actual data. - */ - template - auto const& deref( std::optional const& optional_handle ) const { - if ( !optional_handle ) { - throw GaudiException{ "TES Functor called without being bound to an algorithm", name(), StatusCode::FAILURE }; - } - auto data_ptr = optional_handle->get(); - if ( !data_ptr ) { - throw GaudiException{ "Functor got nullptr from its DataHandle", name(), StatusCode::FAILURE }; - } - return *data_ptr; - } - }; - /** - * @brief Evaluates the abs of a quantity + /** Set up the DataHandles, attributing the data dependencies to the given + * algorithm: set up each member of m_handles by calling .emplace() with the TES + * location and algorithm pointer. */ - struct Abs final : public Function { - template - auto operator()( Data const& d ) const { - using std::abs; - return abs( d ); - } - }; + void bind( TopLevelInfo& top_level ) { + auto* alg = top_level.algorithm(); + if ( !alg ) throw GaudiException( "invoking bind without algorithm", __PRETTY_FUNCTION__, StatusCode::FAILURE ); + if ( alg->msgLevel( MSG::DEBUG ) ) { alg->debug() << "Init of DataHandles of Functor: " << name() << endmsg; } + static_assert( std::is_base_of_v>, + "You must include the full declaration of the owning algorithm type!" ); + std::apply( + [&]( auto&... h ) { + auto loc = m_tes_locs.begin(); + ( init_data_handle( h.emplace( *loc++, alg ), alg ), ... ); + }, + m_handles ); + } /** - * @brief Evaluates the sqrt of a quantity + * Retrieve the data dependencies from the TES and bake them into the + * "prepared" functor that we return */ - struct Sqrt final : public Function { - template - auto operator()( Data const& d ) const { - using std::sqrt; - return sqrt( d ); - } - }; - - /** - * @brief return the set of relations associated to a relation table - * */ - struct Relations final : public Function { - template - auto operator()( Table const& table, From const& from ) const { - const auto& range = table.relations( &Sel::Utils::deref_if_ptr( from ) ); - return !range.empty() ? Functors::Optional{ std::move( range ) } : std::nullopt; - } - }; - - /** - * @brief return the element on the FROM side of a relation - * */ - struct From final : Function { - template - auto operator()( Data const& relation ) const -> decltype( relation.from() ) { - return relation.from(); - } - }; + auto prepare( EventContext const&, TopLevelInfo const& ) const { + // Get a tuple of references to the data objects on the TES, and capture them + // in a lambda which always returns them, and return that lambda + return [deps = std::apply( [&]( auto&... h ) { return std::tie( deref( h )... ); }, m_handles )]( auto const&... ) { + return deps; + }; + } - /** - * @brief return the element on the TO side of a relation - * */ - struct To final : public Function { - template - auto operator()( Data const& relation ) const -> decltype( relation.to() ) { - return relation.to(); - } - }; + [[nodiscard]] std::string name() const { + std::stringstream s; + using GaudiUtils::operator<<; + s << m_tes_locs; + return "TES" + s.str(); + } - /** - * @brief return the element on the WEIGHT side of a relation - * */ - struct Weight final : public Function { - template - auto operator()( Data const& relation ) const -> decltype( relation.weight() ) { - return relation.weight(); - } - }; +private: + std::array m_tes_locs; + std::tuple>...> m_handles; /** - * @brief return true of the floating pointing numbers are close to each other - * within some tolerance + * @brief Initialize a TES DataHandle and check that the owning algorithm + * was configured correctly and already holds our input in ExtraInputs + * + * For more info on the logic please see the detailed explanation of how + * functors obtain their data dependencies in the doc of the FunctorFactory. + * + * @param handle This handle will be initialized + * @param alg Algorithm/Tool which owns this functor */ - struct RequireClose final : Predicate { - RequireClose( float abs_th = 1e-34, float rel_th = 1e-7 ) : m_abs( abs_th ), m_rel( rel_th / 2 ) {} - - template - bool operator()( Data v1_d, Data v2_d ) const { - auto const v1 = LHCb::Utils::as_arithmetic( v1_d ); - auto const v2 = LHCb::Utils::as_arithmetic( v2_d ); - using std::abs; - using std::max; - return abs( v1 - v2 ) < max( m_abs, m_rel * ( abs( v1 ) + abs( v2 ) ) ); - } - - private: - float m_abs, m_rel; - }; + template + void init_data_handle( DataObjectReadHandle& handle, Algorithm* alg ) { + if ( alg->msgLevel( MSG::DEBUG ) ) { + alg->debug() << " + " << handle.objKey() + << " (will call init(): " << ( alg->FSMState() == Gaudi::StateMachine::INITIALIZED ) << ")" + << endmsg; + } + if ( alg->extraInputDeps().count( handle.objKey() ) == 0 ) { + throw GaudiException{ "Usage of DataHandle[\"" + handle.objKey() + + "\"] in TES Functor requires that owning algorithm " + alg->name() + + " contains this TES location inside the ExtraInputs property. This is likely a " + "Configuration/PyConf bug!", + name(), StatusCode::FAILURE }; + } + + // DataObjectReadHandle has a protected `init()` so we need to call it + // through it's base class. This is the same thing Gaudi::Algorithm does in + // sysInitialize(). We do it here because this DataHandle is created inside + // start(), at which point the step of initializing the handles of an + // algorithm has already happened. + // !! Exception !! if we are getting this functor from the cache then we + // are already creating it in intialize(), and we need to skip the init() + // call as it's also done in the sysInitialize() of the algorithm and it is + // apparently forbidden to call init() twice on a DataHandle which is + // checked via an assert in DataObjectHandleBase->init(). So we only run + // init() here if the algorithm is already in an INITIALIZEDD state which + // means this construction is happening inside start() + if ( alg->FSMState() == Gaudi::StateMachine::INITIALIZED ) { static_cast( &handle )->init(); } + } - /** - * @brief Evaluates the median of a vector + /** Check an optional data handle is initialised and doesn't return + * nullptr, then return a reference to the actual data. */ - struct Median final : public Function { - template - auto operator()( Range range ) const { - double median = 0; - if ( !range.empty() ) { - size_t middle = range.size() / 2; - std::nth_element( range.begin(), range.begin() + middle, range.end() ); - median = static_cast( range[middle] ); - if ( range.size() % 2 == 0 ) { // even - take the average of the two 'middle' elements - median -= 0.5 * static_cast( - range[middle] - - *std::max_element( range.begin(), range.begin() + middle ) ); // note: the rhs is always - // positive (or zero) - } - } - return ( !range.empty() ) ? Functors::Optional{ median } : std::nullopt; - } - }; + template + auto const& deref( std::optional const& handle ) const { + if ( !handle ) { + throw GaudiException{ "TES Functor called without being bound to an algorithm", name(), StatusCode::FAILURE }; + } + auto data_ptr = handle->get(); + if ( !data_ptr ) { throw GaudiException{ "Functor got nullptr from its DataHandle", name(), StatusCode::FAILURE }; } + return *data_ptr; + } +}; +/** + * @brief Evaluates the abs of a quantity + */ +constexpr auto Abs = TrivialFunctor{ "Abs", []( auto const& d ) { + using std::abs; + return abs( d ); + } }; + +/** + * @brief Evaluates the sqrt of a quantity + */ +constexpr auto Sqrt = TrivialFunctor{ "Sqrt", []( auto const& d ) { + using std::sqrt; + return sqrt( d ); + } }; + +/** + * @brief return the set of relations associated to a relation table + * */ +constexpr auto Relations = + GenericFunctor{ "Relations", []( auto const& table, auto const& from ) requires requires { table.relations( &from ); +} +{ + const auto& range = table.relations( &from ); + return !range.empty() ? Functors::Optional{ std::move( range ) } : std::nullopt; +} +} +; + +/** + * @brief return the element on the FROM side of a relation + * */ +constexpr auto From = + TrivialFunctor{ "From", []( auto const& relation ) -> decltype( relation.from() ) { return relation.from(); } }; + +/** + * @brief return the element on the TO side of a relation + * */ +constexpr auto To = + TrivialFunctor{ "To", []( auto const& relation ) -> decltype( relation.to() ) { return relation.to(); } }; + +/** + * @brief return the element on the WEIGHT side of a relation + * */ +constexpr auto Weight = TrivialFunctor{ + "Weight", []( auto const& relation ) -> decltype( relation.weight() ) { return relation.weight(); } }; + +/** + * @brief return true of the floating pointing numbers are close to each other + * within some tolerance + */ +struct RequireClose final : Predicate { + RequireClose( float abs_th = 1e-34, float rel_th = 1e-7 ) : m_abs( abs_th ), m_rel( rel_th / 2 ) {} + + template + bool operator()( Data v1_d, Data v2_d ) const { + auto const v1 = LHCb::Utils::as_arithmetic( v1_d ); + auto const v2 = LHCb::Utils::as_arithmetic( v2_d ); + using std::abs; + using std::max; + return abs( v1 - v2 ) < max( m_abs, m_rel * ( abs( v1 ) + abs( v2 ) ) ); + } - /** - * @brief Evaluates the mean of a vector - */ - struct Mean final : public Function { - template - auto operator()( const Range& range ) const { - double mean = 0; - - // Calculate the sum of elements in the range - if ( !range.empty() ) { - double sum = std::accumulate( range.begin(), range.end(), 0.0 ); // cast to double to avoid overflow - mean = sum / range.size(); +private: + float m_abs, m_rel; +}; + +/** + * @brief Evaluates the median of the elements in a container + * Note: the container is accepted _by value_ (i.e. a copy is made) + * as we need to (partially) sort (i.e. mutate it!) to find the median + */ +constexpr auto Median = TrivialFunctor{ + "Median", []( std::ranges::range auto range ) -> Functors::Optional { + if ( range.empty() ) return std::nullopt; + size_t middle = range.size() / 2; + std::nth_element( range.begin(), range.begin() + middle, range.end() ); + double median = static_cast( range[middle] ); + if ( range.size() % 2 == 0 ) { // even - take the average of the two 'middle' elements + median -= 0.5 * static_cast( + range[middle] - + *std::max_element( range.begin(), range.begin() + middle ) ); // note: the rhs is always + // positive (or zero) } - return ( !range.empty() ) ? Functors::Optional{ mean } : std::nullopt; - } - }; + return median; + } }; + +/** + * @brief Evaluates the mean of a vector + */ +constexpr auto Mean = TrivialFunctor{ "Mean", []( std::ranges::range auto const& range ) -> Functors::Optional { + if ( range.empty() ) return std::nullopt; + return std::accumulate( range.begin(), range.end(), 0.0 ) / + range.size(); // accumulate as double to avoid overflow + } }; } // namespace Functors::Common diff --git a/Phys/FunctorCore/include/Functors/Composite.h b/Phys/FunctorCore/include/Functors/Composite.h index 15131a8761052e288b83987aacecf348b6ebd46c..c214de0d66cec3614ae4ba59e29bf84adf8b5411 100644 --- a/Phys/FunctorCore/include/Functors/Composite.h +++ b/Phys/FunctorCore/include/Functors/Composite.h @@ -57,7 +57,7 @@ namespace Functors::Composite { /**MTDOCACHI2**/ template - struct MotherTrajectoryDistanceOfClosestApproachChi2 : public Function { + struct MotherTrajectoryDistanceOfClosestApproachChi2_t : public Function { static_assert( N >= 1, "Indices start from 1 for LoKi compatibility." ); void bind( TopLevelInfo& top_level ) { m_dist_calc.emplace( top_level.algorithm() ); } @@ -67,10 +67,7 @@ namespace Functors::Composite { auto const bestPV = Sel::getBestPV( composite, vertices ); using LHCb::Event::decayProducts; - auto const& children = decayProducts( composite ); - auto const& pN = children[N - 1]; - - auto const& pN_state = Sel::stateVectorFromComposite( pN ); + auto const child_state = Sel::stateVectorFromComposite( decayProducts( composite )[N - 1] ); using LHCb::Event::posCovMatrix; using LHCb::Event::referencePoint; @@ -82,30 +79,28 @@ namespace Functors::Composite { endVertexPos( *bestPV ), threeMomentum( composite ), threeMomCovMatrix( composite ), posCovMatrix( *bestPV ), threeMomPosCovMatrix( composite ) ); - const auto& dist_calc = *m_dist_calc; - return dist_calc.stateDOCAChi2( composite_state, pN_state ); + return m_dist_calc->stateDOCAChi2( composite_state, child_state ); } private: std::optional m_dist_calc; }; + template + const auto MotherTrajectoryDistanceOfClosestApproachChi2 = MotherTrajectoryDistanceOfClosestApproachChi2_t{}; + /** @brief Flight distance chi2 to the given vertex. * * Note that if the given data object contains a vertex link then that will * be checked for compatibility with the given vertex container and, if it * matches, be used. */ - struct FlightDistanceChi2ToVertex : public Function { - /** This allows some error messages to be customised. It is not critical. */ - static constexpr auto name() { return "FlightDistanceChi2ToVertex"; } - - template - auto operator()( Vertex_t const& vertex, Particle const& composite ) const { - auto const& comp = Sel::Utils::deref_if_ptr( composite ); - return Sel::Utils::flightDistanceChi2( comp, vertex ); - } - }; + // FIXME: making this a generic functor leads to an unexpected optional wrapper in the MVA functors??? + constexpr auto FlightDistanceChi2ToVertex = + TrivialFunctor{ "FlightDistanceChi2ToVertex", []( auto const& vertex, auto const& composite ) { + auto const& comp = Sel::Utils::deref_if_ptr( composite ); + return Sel::Utils::flightDistanceChi2( comp, vertex ); + } }; // First a helper for the momentum perpendicular to the flight vector template @@ -115,15 +110,16 @@ namespace Functors::Composite { auto const d = endVertexPos( comp ) - endVertexPos( vtx ); auto const mom = threeMomentum( comp ); auto const perp = mom - d * ( dot( mom, d ) / d.mag2() ); - auto const pt = perp.mag(); - return pt; + return perp.mag(); } /** @brief Calculate the corrected mass for the given PV. */ - struct CorrectedMass : public Function { - static constexpr auto name() { return "CorrectedMass"; } - CorrectedMass( float invisible_mass = 0.0 ) : m_invisible_mass2( invisible_mass * invisible_mass ){}; + class CorrectedMass : public Function { + float m_invisible_mass2 = 0; + + public: + constexpr CorrectedMass( float invisible_mass = 0.0 ) : m_invisible_mass2( invisible_mass * invisible_mass ){}; template auto operator()( Vertex_t const& vtx, Composite const& composite ) const { @@ -135,18 +131,16 @@ namespace Functors::Composite { auto const pt = perpendicularMomentum( vtx, composite ); // Calculate the corrected mass - return sqrt( mass2( composite ) + pt * pt ) + sqrt( pt * pt + m_invisible_mass2 ); + return sqrt( mass2( composite ) + pt * pt ) + + ( m_invisible_mass2 == 0 ? pt : sqrt( pt * pt + m_invisible_mass2 ) ); } - - private: - float m_invisible_mass2; }; /** @brief Calculate the corrected mass error for a given PV. */ struct CorrectedMassError : public Function { static constexpr auto name() { return "CorrectedMassError"; } - CorrectedMassError( float invisible_mass = 0.0 ) : m_invisible_mass2( invisible_mass * invisible_mass ){}; + constexpr CorrectedMassError( float invisible_mass = 0.0 ) : m_invisible_mass2( invisible_mass * invisible_mass ){}; template auto operator()( Vertex_t const& vertices, Composite const& composite ) const { @@ -204,15 +198,23 @@ namespace Functors::Composite { }; /** @brief Calculate the composite mass using the given child mass hypotheses. */ - template struct MassWithHypotheses : public Function { /** Create a mass functor with a list of mass hypotheses that can be a mix * of floating point values (in MeV) and names of particles. Particle * names are translated into mass values using the ParticlePropertySvc. */ - MassWithHypotheses( std::tuple mass_inputs ) : m_mass_inputs{ std::move( mass_inputs ) } {} - void bind( TopLevelInfo& top_level ) { bind( top_level, std::index_sequence_for{} ); } + template + MassWithHypotheses( Tuple const& mass_inputs ) { + m_inputs.reserve( std::tuple_size_v ); + std::apply( + [&]( auto const&... i ) { + // TODO: static_assert that std::decay_t is amongs the variant types... + // TODO: somehow map double->float, and drop double... (use Gaudi::overload?) + ( m_inputs.emplace_back( std::in_place_type>, i ), ... ); + }, + mass_inputs ); + } template auto operator()( CombinationType const& comb ) const { @@ -221,11 +223,14 @@ namespace Functors::Composite { using LHCb::Event::decayProducts; auto children = decayProducts( comb ); auto NumChildren = children.size(); - if ( sizeof...( MassInputs ) != NumChildren || m_mass_values.size() != NumChildren ) { - throw GaudiException{ - "Mismatch between number of mass values given (" + std::to_string( sizeof...( MassInputs ) ) + - ") and the number of children in the given object (" + std::to_string( NumChildren ) + ")", - "Functors::Composite::Mass", StatusCode::FAILURE }; + if ( m_masses.size() != m_inputs.size() ) { + throw GaudiException{ "Functor has not been bound", __PRETTY_FUNCTION__, StatusCode::FAILURE }; + } + if ( m_masses.size() != NumChildren ) { + throw GaudiException{ "Mismatch between number of mass values given (" + std::to_string( m_masses.size() ) + + ") and the number of children in the given object (" + std::to_string( NumChildren ) + + ")", + __PRETTY_FUNCTION__, StatusCode::FAILURE }; } using LHCb::Event::threeMomentum; using std::sqrt; @@ -234,55 +239,48 @@ namespace Functors::Composite { using three_t = decltype( threeMomentum( children[0] ) ); three_t mom{ 0, 0, 0 }; for ( const auto& [i, child] : LHCb::range::enumerate( children ) ) { - E += sqrt( threeMomentum( child ).mag2() + m_mass_values[i] * m_mass_values[i] ); + E += sqrt( threeMomentum( child ).mag2() + m_masses[i] * m_masses[i] ); mom = mom + threeMomentum( child ); } return sqrt( E * E - mom.mag2() ); } - private: - template - void bind( TopLevelInfo& top_level, std::index_sequence ) { + void bind( TopLevelInfo& top_level ) { // Avoid setting up the service if we don't need it (e.g. all hypotheses) // were specified numerically) std::optional> pp_svc{ std::nullopt }; - // Helper to convert a member of m_mass_inputs to a numeric value. - auto const converter = [&]( auto const& mass_or_name ) { - if constexpr ( std::is_same_v> ) { - return mass_or_name; - } else { - if ( !pp_svc ) { - pp_svc.emplace( top_level.algorithm(), top_level.generate_property_name(), "LHCb::ParticlePropertySvc" ); - } - auto const* pp = pp_svc.value()->find( mass_or_name ); - if ( !pp ) { - throw GaudiException{ "Couldn't get ParticleProperty for particle '" + mass_or_name + "'", - "Functors::Composite::Mass::bind()", StatusCode::FAILURE }; - } - return pp->mass(); - } - }; - ( ( m_mass_values[Ns] = converter( std::get( m_mass_inputs ) ) ), ... ); + for ( auto const& i : m_inputs ) { + std::visit( Gaudi::overload( [&]( float v ) { m_masses.push_back( v ); }, + [&]( double v ) { m_masses.push_back( static_cast( v ) ); }, + [&]( std::string const& s ) { + if ( !pp_svc ) + pp_svc.emplace( top_level.algorithm(), top_level.generate_property_name(), + "LHCb::ParticlePropertySvc" ); + auto const* pp = pp_svc.value()->find( s ); + if ( !pp ) { + throw GaudiException{ "Couldn't get ParticleProperty for particle '" + s + "'", + "Functors::Composite::Mass::bind()", + StatusCode::FAILURE }; + } + m_masses.push_back( pp->mass() ); + } ), + i ); + } } - std::tuple m_mass_inputs; - std::array m_mass_values{}; + std::vector m_masses{}; + std::vector> m_inputs{}; }; /** @brief Return the input object's mass as defined by an accessor. */ - struct Mass : public Function { - static constexpr auto name() { return "Mass"; } - - template - auto operator()( Particle const& particle ) const { - using LHCb::Event::mass2; - using std::sqrt; - return sqrt( mass2( particle ) ); - } - }; + constexpr auto Mass = TrivialFunctor{ "Mass", []( auto const& particle ) { + using LHCb::Event::mass2; + using std::sqrt; + return sqrt( mass2( particle ) ); + } }; /** @brief Calculate the lifetime of the particle with respect to the vertex. */ - struct Lifetime : public Function { + struct Lifetime_t : public Function { static constexpr auto name() { return "Lifetime"; } void bind( TopLevelInfo& top_level ) { m_lifetime_calc.bind( top_level.algorithm() ); } @@ -296,9 +294,10 @@ namespace Functors::Composite { private: Functors::detail::DefaultLifetimeFitter_t m_lifetime_calc; }; + inline const auto Lifetime = Lifetime_t{}; /** @brief Calculate the lifetime of the particle with respect to the vertex. */ - struct ComputeDecayLengthSignificance : public Function { + struct ComputeDecayLengthSignificance_t : public Function { /** This allows some error messages to be customised. It is not critical. */ static constexpr auto name() { return "ComputeDecayLengthSignificance"; } @@ -314,6 +313,7 @@ namespace Functors::Composite { private: Functors::detail::DefaultLifetimeFitter_t m_lifetime_calc; }; + inline const auto ComputeDecayLengthSignificance = ComputeDecayLengthSignificance_t{}; /** @brief Get the tagging decision from specific FlavourTag tagger. */ class TaggingDecision : public Function { @@ -377,49 +377,48 @@ namespace Functors::Composite { namespace BTracking { - template - auto getTrack( Composite2TrackRelations const& relations, Composite const& composite ) { - auto const& comp = Sel::Utils::deref_if_ptr( composite ); - auto track_range = relations.relations( &comp ); - return track_range.empty() ? std::nullopt : Functors::Optional{ track_range.front().to() }; - } - - /** @brief Get heavy flavour track associated to composite. */ - struct Track : public Function { - static constexpr auto name() { return "BTracking::Track"; } - + namespace detail { template - auto operator()( Composite2TrackRelations const& relations, Composite const& composite ) const { - return getTrack( relations, composite ); + auto getTrack( Composite2TrackRelations const& relations, Composite const& composite ) { + auto const& comp = Sel::Utils::deref_if_ptr( composite ); + auto track_range = relations.relations( &comp ); + return track_range.empty() ? std::nullopt : Functors::Optional{ track_range.front().to() }; } - }; + } // namespace detail - /** @brief Calculate the corrected mass using heavy flavour tracking info. */ - struct CorrectedMass : public Function { - static constexpr auto name() { return "BTracking::CorrectedMass"; } + /** @brief Get heavy flavour track associated to composite. */ + constexpr auto Track = TrivialFunctor{ + "BTracking::Track", + []( auto const& relations, auto const& composite ) -> decltype( detail::getTrack( relations, composite ) ) { + return detail::getTrack( relations, composite ); + } }; - template - auto operator()( Composite2TrackRelations const& relations, Composite const& composite ) const { - using FType = SIMDWrapper::scalar::float_v; - using Sel::Utils::mass2; - using Sel::Utils::threeMomentum; + /** @brief Calculate the corrected mass using heavy flavour tracking info. */ + constexpr auto CorrectedMass = TrivialFunctor{ + "BTracking::CorrectedMass", + []( auto const& relations, auto const& composite ) requires requires { detail::getTrack( relations, composite ); + } // namespace BTracking + { + using FType = SIMDWrapper::scalar::float_v; + using Sel::Utils::mass2; + using Sel::Utils::threeMomentum; - auto track = getTrack( relations, composite ); - if ( !track.has_value() ) return FType{ 0 }; + auto track = detail::getTrack( relations, composite ); + if ( !track ) return FType{ 0 }; - // direction using first hit (or end vertex if not available, as saved in heavy flavour track) - auto const state = track.value()->firstState(); - auto const d = LHCb::LinAlg::Vec{ state.tx(), state.ty(), 1. }; + // direction using first hit (or end vertex if not available, as saved in heavy flavour track) + auto const state = track.value()->firstState(); + auto const d = LHCb::LinAlg::Vec{ state.tx(), state.ty(), 1. }; - // Get the pT variable that we need - auto const mom = threeMomentum( composite ); - auto const perp = mom - d * ( dot( mom, d ) / d.mag2() ); - auto const pt = perp.mag(); + // Get the pT variable that we need + auto const mom = threeMomentum( composite ); + auto const perp = mom - d * ( dot( mom, d ) / d.mag2() ); + auto const pt = perp.mag(); - // Calculate the corrected mass - return pt + sqrt( mass2( composite ) + pt * pt ); - } - }; - } // namespace BTracking + // Calculate the corrected mass + return pt + sqrt( mass2( composite ) + pt * pt ); + } +}; // namespace Functors::Composite +} // namespace BTracking } // namespace Functors::Composite diff --git a/Phys/FunctorCore/include/Functors/Core.h b/Phys/FunctorCore/include/Functors/Core.h index 2eef567b090938091a262e211e9270ffc0cb71d2..b84eca2ca911b399199997f2bc37654c59bad4eb 100644 --- a/Phys/FunctorCore/include/Functors/Core.h +++ b/Phys/FunctorCore/include/Functors/Core.h @@ -253,12 +253,15 @@ namespace Functors { template LHCB_FUNCTORS_INLINE auto prepared( Functor const& f, EventContext const& evtCtx, TopLevelInfo const& top_level ) { auto prepare = [&]( Functor const& f, EventContext const& evtCtx, TopLevelInfo const& top_level ) { + // veto old-style code which may have different 'prepare' functions... + static_assert( + !requires { f.prepare(); }, "please implement prepare(evtCtx,top_level) instead of prepare()" ); + static_assert( + !requires { f.prepare( top_level ); }, + "please implement prepare(evtCtx,top_level) instead of prepare(top_level)" ); + if constexpr ( requires { f.prepare( evtCtx, top_level ); } ) { return f.prepare( evtCtx, top_level ); - } else if constexpr ( requires { f.prepare( top_level ); } ) { - return f.prepare( top_level ); - } else if constexpr ( requires { f.prepare(); } ) { - return f.prepare(); } else { return std::cref( f ); } @@ -269,7 +272,7 @@ namespace Functors { }; }; template - auto prepared( Functor&& f, EventContext const& evtCtx, TopLevelInfo const& top_level ) = delete; + auto prepared( Functor&&, EventContext const&, TopLevelInfo const& ) = delete; } // namespace detail diff --git a/Phys/FunctorCore/include/Functors/Decay.h b/Phys/FunctorCore/include/Functors/Decay.h index ecfadbe26441f59d30df377fb2c6936072f5b93f..c2fd59369758ed16e2508a01b1e9a4e29fb843c9 100644 --- a/Phys/FunctorCore/include/Functors/Decay.h +++ b/Phys/FunctorCore/include/Functors/Decay.h @@ -11,23 +11,20 @@ #pragma once #include "Functors/Function.h" #include "Functors/Utilities.h" -#include "GaudiAlg/GaudiTupleAlg.h" #include "GaudiKernel/GaudiException.h" -#include "GaudiKernel/System.h" #include "Kernel/IDecayFinder.h" #include "LoKi/IMCDecay.h" -#include "LoKi/IMCHybridFactory.h" /** @file Decay.h * @brief Definitions of functors related to the decay chain. */ namespace Functors::detail { // function that checks if the number of caret symbol ("^") in the decay descriptor is 0 or 1 - inline void checkCaret( const std::string& decay ) { + inline void checkCaret( std::string_view decay ) { auto nCaret = std::count( decay.begin(), decay.end(), '^' ); if ( nCaret > 1 ) { - throw GaudiException( "The decay descriptor '" + decay + "' contains more than one caret symbol ('^')", "Decay", - StatusCode::FAILURE ); + throw GaudiException( fmt::format( "The decay descriptor '{}' contains more than one caret symbol ('^')", decay ), + "Decay", StatusCode::FAILURE ); } } } // namespace Functors::detail @@ -52,7 +49,8 @@ namespace Functors::Decay { LHCb::Particle::ConstVector in_v = { &part }; LHCb::Particle::ConstVector out_v; bool found_particle = tool->findDecay( m_decay_desc, in_v, out_v ).isSuccess() && ( out_v.size() == 1 ); - return found_particle ? Functors::Optional{ out_v.front() } : std::nullopt; + return found_particle ? Functors::Optional{ out_v.front() } + : std::nullopt; // FIXME: an optional pointer is a semantic stutter } auto operator()( const LHCb::Particle* part ) const { return Functors::and_then( part, *this ); } @@ -76,13 +74,13 @@ namespace Functors::Decay { assert( m_find_decay.has_value() ); if ( !m_find_decay->get() ) m_find_decay->retrieve().ignore(); auto tool = m_find_decay->get(); + Decays::IMCDecay::Finder finder( tool->tree( m_decay_desc ) ); LHCb::MCParticle::ConstVector in_v = { &part }; LHCb::MCParticle::ConstVector out_v; - Decays::IMCDecay::Tree decayTree = tool->tree( m_decay_desc ); - Decays::IMCDecay::Finder finder( decayTree ); finder.findDecay( in_v.begin(), in_v.end(), out_v ); bool found_particle = ( out_v.size() == 1 ); - return found_particle ? Functors::Optional{ out_v.front() } : std::nullopt; + return found_particle ? Functors::Optional{ out_v.front() } + : std::nullopt; // FIXME: an optional pointer is a semantic stutter } auto operator()( const LHCb::MCParticle* part ) const { return Functors::and_then( part, *this ); } diff --git a/Phys/FunctorCore/include/Functors/Detector.h b/Phys/FunctorCore/include/Functors/Detector.h index 92ef6e744f6adf45aa1ae155528759f073ed6f9b..dc41b28e0d13ad5ea2103b4687d50aa274a8ca86 100644 --- a/Phys/FunctorCore/include/Functors/Detector.h +++ b/Phys/FunctorCore/include/Functors/Detector.h @@ -10,24 +10,37 @@ \*****************************************************************************/ #pragma once -// This code is DD4hep specific +#include +#include +#include +#include +#include +// this is where standard_geometry_top is defined +#include #if USE_DD4HEP - +// This code is DD4hep specific # include -# include -# include -# include -# include -# include # include -# include -# include - -// this is where standard_geometry_top is defined -# include +#else +# include +# include +# include +#endif +#include +#include namespace Functors::Detector { - struct DeLHCb final : public Function { + +#if USE_DD4HEP + struct DeLHCb_t final : public Function { + DeLHCb_t() = default; + DeLHCb_t( const DeLHCb_t& ) { + if ( m_condCtx ) + throw GaudiException{ "DeLHCb Functor can not be copied after it is bound to an algorithm", + "Functors::Detector::DeLHCb", StatusCode::FAILURE }; + } + DeLHCb_t& operator=( const DeLHCb_t& rhs ) = delete; + /** Set up the DataHandles, attributing the data dependencies to the given * algorithm, using .emplace() with the Condition location and algorithm pointer. */ @@ -41,12 +54,13 @@ namespace Functors::Detector { * Retrieve the data dependencies from the Condition and bake them into the * "prepared" functor that we return */ - auto prepare( EventContext const& /* evtCtx */, TopLevelInfo const& ) const { + auto prepare( EventContext const&, TopLevelInfo const& ) const { // Note: getting the a condition key from a string is really this complicated static const dd4hep::Condition::key_type delhcb_key = [] { auto const& path = LHCb::standard_geometry_top; const auto colonPos = path.find_first_of( ':' ); - assert( colonPos != path.npos ); + if ( colonPos == path.npos ) + throw GaudiException{ "invalid path", "Functors::Detector::DeLHCb", StatusCode::FAILURE }; const auto det_name = path.substr( 0, colonPos ); const auto cond_name = path.substr( colonPos + 1 ); return dd4hep::ConditionKey::KeyMaker{ dd4hep::detail::hash32( det_name ), cond_name }.hash; @@ -61,13 +75,35 @@ namespace Functors::Detector { auto& slice = *m_condCtx->get(); // Get the DeLHCb instance from the current conditions slice // and bake this into a new lambda that we return - return [de = LHCb::Detector::DeLHCb( slice->pool->get( delhcb_key ) )]( auto const&... ) { return de; }; + return [de = LHCb::Detector::DeLHCb{ slice->pool->get( delhcb_key ) }]( auto const&... ) -> decltype( auto ) { + return de; + }; } private: std::optional> m_condCtx; }; +#else + + struct DeLHCb_t final : public Function { + auto operator()( auto&&... ) const { + throw GaudiException{ "DeLHCb Functor is specific to DD4HEP -- you are using DetDesc -- please switch platforms " + "or remove call to this functor", + "Functors::Detector::DeLHCb", StatusCode::FAILURE }; + struct FakeDetDescDeLHCb { + std::optional interactionRegion() const { return {}; } + std::optional lhcInfo() const { return {}; } + std::optional SMOG() const { return {}; } + }; + return FakeDetDescDeLHCb{}; + } + }; + +#endif + + inline const auto DeLHCb = DeLHCb_t{}; + namespace details { template class DeLHCInfoFunctor final : public Function { @@ -75,7 +111,17 @@ namespace Functors::Detector { public: constexpr DeLHCInfoFunctor( F f ) : fun{ std::move( f ) } {} +#if USE_DD4HEP auto operator()( LHCb::Detector::DeLHCb const& de ) const { return Functors::and_then( de.lhcInfo(), fun ); } +#else + auto operator()( auto const& ) const { + throw GaudiException{ + "DeSMOGInfoFunctor is specific to DD4HEP -- you are using DetDesc -- please switch platforms " + "or remove call to this functor", + "Functors::Detector::DeSMOGInfoFunctor", StatusCode::FAILURE }; + return Functors::and_then( std::optional{}, fun ); + } +#endif }; template @@ -84,30 +130,39 @@ namespace Functors::Detector { public: constexpr DeSMOGInfoFunctor( F f ) : fun{ std::move( f ) } {} +#if USE_DD4HEP auto operator()( LHCb::Detector::DeLHCb const& de ) const { return Functors::and_then( de.SMOG(), [&]( const auto& info ) { return static_cast( std::invoke( fun, info ) ); } ); } +#else + auto operator()( auto const& ) const { + throw GaudiException{ + "DeSMOGInfoFunctor is specific to DD4HEP -- you are using DetDesc -- please switch platforms " + "or remove call to this functor", + "Functors::Detector::DeSMOGInfoFunctor", StatusCode::FAILURE }; + return std::optional{}; + } +#endif }; } // namespace details // Get the fill number from LHC condition - inline constexpr auto FillNumber = details::DeLHCInfoFunctor{ &LHCb::Detector::LHCInfo::fillnumber }; + constexpr auto FillNumber = details::DeLHCInfoFunctor{ &LHCb::Detector::LHCInfo::fillnumber }; // Get the LHC energy condition - inline constexpr auto LHCEnergy = details::DeLHCInfoFunctor{ &LHCb::Detector::LHCInfo::lhcenergy }; + constexpr auto LHCEnergy = details::DeLHCInfoFunctor{ &LHCb::Detector::LHCInfo::lhcenergy }; // Get the LHCb clock phase from LHC condition - inline constexpr auto LHCbClockPhase = details::DeLHCInfoFunctor{ &LHCb::Detector::LHCInfo::lhcbclockphase }; + constexpr auto LHCbClockPhase = details::DeLHCInfoFunctor{ &LHCb::Detector::LHCInfo::lhcbclockphase }; // Get the SMOG injection mode from SMOG condition - inline constexpr auto SMOGInjectionMode = details::DeSMOGInfoFunctor{ &LHCb::Detector::SMOGInfo::injection_mode }; + constexpr auto SMOGInjectionMode = details::DeSMOGInfoFunctor{ &LHCb::Detector::SMOGInfo::injection_mode }; // Get the SMOG injected gas - inline constexpr auto SMOGInjectedGas = details::DeSMOGInfoFunctor{ &LHCb::Detector::SMOGInfo::injected_gas }; + constexpr auto SMOGInjectedGas = details::DeSMOGInfoFunctor{ &LHCb::Detector::SMOGInfo::injected_gas }; // Get the SMOG stable injection flag - inline constexpr auto SMOGStableInjection = details::DeSMOGInfoFunctor{ &LHCb::Detector::SMOGInfo::stable_injection }; + constexpr auto SMOGStableInjection = details::DeSMOGInfoFunctor{ &LHCb::Detector::SMOGInfo::stable_injection }; } // namespace Functors::Detector -#endif diff --git a/Phys/FunctorCore/include/Functors/Example.h b/Phys/FunctorCore/include/Functors/Example.h index 6851a815ece1ea571de1822010276cd6d97f9bad..622d39188346bc42e6f66f7409347820423eacfe 100644 --- a/Phys/FunctorCore/include/Functors/Example.h +++ b/Phys/FunctorCore/include/Functors/Example.h @@ -14,12 +14,7 @@ #include namespace Functors::Examples { - struct TimesTwo : public Function { - template - auto operator()( Data const& value ) const { - return value * 2; - } - }; + constexpr auto TimesTwo = TrivialFunctor{ "TimesTwo", []( auto const& value ) { return value * 2; } }; struct PlusN : public Function { PlusN( int n ) : N( n ) {} @@ -39,13 +34,8 @@ namespace Functors::Examples { } }; - struct ThorBeatsLoki : public Predicate { - // for reference see https://www.youtube.com/watch?v=-JPkvO1e1Gw - template - bool operator()( Data const&... ) const { - return true; - } - }; + // for reference see https://www.youtube.com/watch?v=-JPkvO1e1Gw + constexpr auto ThorBeatsLoki = TrivialPredicate{ "ThorBeatsLoKi", []( auto const&... ) { return true; } }; template struct OptReturn : public Function { @@ -55,11 +45,6 @@ namespace Functors::Examples { }; // mainly to test the bind logic - struct AddInputs : public Function { - template - auto operator()( Data const&... input ) const { - return ( input + ... ); - } - }; + constexpr auto AddInputs = TrivialFunctor{ "AddInputs", []( auto const&... input ) { return ( input + ... ); } }; } // namespace Functors::Examples diff --git a/Phys/FunctorCore/include/Functors/Filter.h b/Phys/FunctorCore/include/Functors/Filter.h index 181343714318202f5be8bba29a30f475dff84a8d..6d3c8d9bb01e1c349082d26271e14c31a77b7c2a 100644 --- a/Phys/FunctorCore/include/Functors/Filter.h +++ b/Phys/FunctorCore/include/Functors/Filter.h @@ -47,8 +47,7 @@ namespace Functors { } /** @brief Conditionally copy an std::vector. */ - template - requires std::is_invocable_v + template F, typename A> std::vector filter( F&& f, TopLevelInfo const&, std::vector const& input ) { using LHCb::Utils::as_arithmetic; std::vector out; @@ -70,8 +69,7 @@ namespace Functors { * LHCb::Particle. The filter then accepts some container of T in to a * non-owning view. */ - template - requires std::is_invocable_v + template F> SharedObjectsContainer filter( F&& f, TopLevelInfo const&, Gaudi::NamedRange_> const& input ) { using LHCb::Utils::as_arithmetic; @@ -81,8 +79,7 @@ namespace Functors { /** @brief Filter a particle combination */ - template - requires std::is_invocable_v && std::conjunction_v...> + template F, std::same_as... Ts> SharedObjectsContainer filter( F&& f, TopLevelInfo const&, LHCb::ParticleCombination const& input ) { using LHCb::Utils::as_arithmetic; return { input.begin(), input.end(), @@ -168,6 +165,6 @@ namespace Functors { * type. */ template - using filtered_t = std::decay_t(), std::declval() )( std::declval() ) )>; } // namespace Functors diff --git a/Phys/FunctorCore/include/Functors/Function.h b/Phys/FunctorCore/include/Functors/Function.h index e3e1e1e4fc12b37a68a651a013895bacc968d51f..0da4569cbd6a7cd30c6b339231276b185546d5bf 100644 --- a/Phys/FunctorCore/include/Functors/Function.h +++ b/Phys/FunctorCore/include/Functors/Function.h @@ -39,9 +39,6 @@ namespace Functors::detail { fwd_as_flattened_tuple( ts )... ); } - template - constexpr bool always_false_v = false; - template inline constexpr bool is_constructible_from_tuple_v = false; @@ -98,6 +95,137 @@ namespace Functors::detail { namespace Functors { + template + class TrivialFunctor : public Function, private Fn... { + std::string_view m_name; + + public: + // note that the `const char (&name)[N]` is chosen as argument to make sure that + // it is a literal -- as then `m_name` will be valid for the duration of its lifetime + template + constexpr TrivialFunctor( const char ( &name )[N], Fn... fn ) : Fn{ std::move( fn ) }..., m_name{ name } {} + constexpr auto name() const { return m_name; } + using Fn::operator()...; + }; + + template + TrivialFunctor( const char ( &name )[N], Fn&&... ) -> TrivialFunctor...>; + + template + class TrivialFunctor : public Function { + R ( T::*m_fn )() const = nullptr; + std::string_view m_name = {}; + + public: + template + constexpr TrivialFunctor( const char ( &name )[N], R ( T::*fn )() const ) : m_fn{ fn }, m_name{ name } {} + constexpr auto name() const { return m_name; } + R operator()( T const& obj ) const { return ( obj.*m_fn )(); } + }; + + template + class TrivialFunctor : public Function { + R ( *m_fn )( Args... ) = nullptr; + std::string_view m_name = {}; + + public: + template + constexpr TrivialFunctor( const char ( &name )[N], R ( *fn )( Args... ) ) : m_fn{ fn }, m_name{ name } {} + constexpr auto name() const { return m_name; } + R operator()( Args... obj ) const { return ( *m_fn )( obj... ); } + }; + + // GenericFunctor is a generalization of TrivialFunctor: it adds methods which allow the functor + // to be called with pointers and SmartRefs. The return value is wrapped in an optional in order + // to handle the case the pointer/SmartRef does not point at a valid object -- unless the return type + // is a pointer, in which case a nullptr is returned. + template + struct GenericFunctor : TrivialFunctor { + using TrivialFunctor::TrivialFunctor; + using TrivialFunctor::operator(); + TrivialFunctor const& as_base() const { return *this; } + + template + requires requires( TrivialFunctor const& fun, const T* t, const Args&... args ) { fun( *t, args... ); } + auto operator()( const T* t, const Args&... args ) const { + if constexpr ( std::is_pointer_v ) { + return t ? as_base()( *t, args... ) : nullptr; + } else { + return t ? Functors::Optional{ as_base()( *t, args... ) } : std::nullopt; + } + } + template + requires requires( TrivialFunctor const& fun, const T& t, const U* u, const Args&... args ) { + fun( t, *u, args... ); + } + auto operator()( const T& t, const U* u, const Args&... args ) const { + if constexpr ( std::is_pointer_v ) { + return u ? as_base()( t, *u, args... ) : nullptr; + } else { + return u ? Functors::Optional{ as_base()( t, *u, args... ) } : std::nullopt; + } + } + + // explicitly deal with SmartRef-s + template + requires requires( TrivialFunctor const& fun, const SmartRef& t, const Args&... args ) { + fun( *t, args... ); + } + auto operator()( const SmartRef& t, const Args&... args ) const { + return ( *this )( t.target(), args... ); + } + + template + requires requires( TrivialFunctor const& fun, const T& t, const SmartRef& u, const Args&... args ) { + fun( t, *u, args... ); + } + auto operator()( const T& t, const SmartRef& u, const Args&... args ) const { + return ( *this )( t, u.target(), args... ); + } + }; + template + GenericFunctor( const char ( &name )[N], Fn&&... ) -> GenericFunctor...>; + + template + class TrivialPredicate : public Predicate, private Fn... { + std::string_view m_name; + + public: + // note that the `const char (&name)[N]` is chosen as argument to make sure that + // it is a literal -- as then `m_name` will be valid for the duration of its lifetime + template + constexpr TrivialPredicate( const char ( &name )[N], Fn... fn ) : Fn{ std::move( fn ) }..., m_name{ name } {} + constexpr auto name() const { return m_name; } + using Fn::operator()...; + }; + + template + TrivialPredicate( const char ( &name )[N], Fn&&... ) -> TrivialPredicate...>; + + template + class TrivialPredicate : public Predicate { + R ( T::*m_fn )() const = nullptr; + std::string_view m_name = {}; + + public: + template + constexpr TrivialPredicate( const char ( &name )[N], R ( T::*fn )() const ) : m_fn{ fn }, m_name{ name } {} + constexpr auto name() const { return m_name; } + bool operator()( T const& obj ) const { return static_cast( ( obj.*m_fn )() ); } + }; + + template + class TrivialPredicate : public Predicate { + R ( *m_fn )( Args... ) = nullptr; + std::string_view m_name = {}; + + public: + template + constexpr TrivialPredicate( const char ( &name )[N], R ( *fn )( Args... ) ) : m_fn{ fn }, m_name{ name } {} + constexpr auto name() const { return m_name; } + bool operator()( Args const&... obj ) const { return static_cast( ( *m_fn )( obj... ) ); } + }; + /** @class NumericValue * @brief Trivial function that holds a numeric constant. * @@ -117,7 +245,7 @@ namespace Functors { }; template - NumericValue( T ) -> NumericValue; + NumericValue( T ) -> NumericValue>; template NumericValue( std::integral_constant ) -> NumericValue; @@ -126,7 +254,7 @@ namespace Functors { * promoted to NumericValue. */ template - concept FunctorConstant = std::is_arithmetic_v>; + concept FunctorConstant = std::is_arithmetic_v> || std::is_enum_v>; } // namespace detail @@ -134,51 +262,43 @@ namespace Functors { * @brief Trivial functor that always returns true. * @todo Better handling in case sizeof...(Data) > 1 */ - struct AcceptAll : public Predicate { - template - constexpr auto operator()( Data&&... ) const { - if constexpr ( sizeof...( Data ) > 0 ) { - using FirstType = std::decay_t>>; - if constexpr ( Sel::Utils::has_static_mask_true_v ) { - return FirstType::mask_true(); - } else { - return true; - } - } else { - return true; - } - } - }; + constexpr auto AcceptAll = TrivialPredicate{ "All", []( Data&&... ) { + if constexpr ( sizeof...( Data ) > 0 ) { + using FirstType = + std::decay_t>>; + if constexpr ( requires { FirstType::mask_true(); } ) { + return FirstType::mask_true(); + } else { + return true; + } + } else { + return true; + } + } }; /** @class AcceptNone * @brief Trivial functor that always returns false. * @todo Better handling in case sizeof...(Data) > 1 */ - struct AcceptNone : public Predicate { - template - constexpr auto operator()( Data&&... ) const { - if constexpr ( sizeof...( Data ) > 0 ) { - using FirstType = std::decay_t>>; - if constexpr ( Sel::Utils::has_static_mask_true_v ) { - return !FirstType::mask_true(); - } else { - return false; - } - } else { - return false; - } - } - }; + constexpr auto AcceptNone = TrivialPredicate{ "None", []( Data&&... ) { + if constexpr ( sizeof...( Data ) > 0 ) { + using FirstType = + std::decay_t>>; + if constexpr ( requires { FirstType::mask_true(); } ) { + return !FirstType::mask_true(); + } else { + return false; + } + } else { + return false; + } + } }; /** @class Identity * @brief Trivial functor that returns the same value. */ - struct Identity_t : public Function { - template - constexpr auto operator()( T&& t ) const -> decltype( auto ) { - return std::forward( t ); - } - }; + constexpr auto Identity = + TrivialFunctor{ "Identity", []( T&& t ) -> decltype( auto ) { return std::forward( t ); } }; /** @class Column Instantiated with a "label" , when acting on object T returns T("label") @@ -187,38 +307,15 @@ namespace Functors { Column_t( std::string label ) : m_label{ std::move( label ) } {} template - constexpr auto operator()( const T& t ) const { + constexpr decltype( auto ) operator()( const T& t ) const + requires requires( const T& t, std::string const& s ) { t( s ); } + { return t( m_label ); } private: std::string m_label{ "" }; }; - - /** @class MemberFn - Adapt a member function into a functor - */ - template - class MemberFn : public Function { - R ( T::*m_fn )() const = nullptr; - std::string_view m_name = {}; - - public: - // note that the `const char (&name)[N]` is chosen as argument to make sure that - // it is a literal -- as then `m_name` will be valid for the duration of its lifetime - template - constexpr MemberFn( R ( T::*fn )() const, const char ( &name )[N] ) : m_fn{ fn }, m_name{ name } {} - constexpr auto name() const { return m_name; } - R operator()( T const& obj ) const { return ( obj.*m_fn )(); } - auto operator()( T const* obj ) const { - if constexpr ( std::is_pointer_v ) { - return obj ? ( obj->*m_fn )() : nullptr; - } else { - return obj ? Functors::Optional{ ( obj->*m_fn )() } : std::nullopt; - } - } - }; - namespace detail { namespace composition { @@ -301,7 +398,7 @@ namespace Functors { return [op = std::move( op ), ... pf = prepared( f, evtCtx, top_level )]( auto mask, auto&&... input ) -> decltype( auto ) { // Evaluate all the functors and let the given Operator combine the results. - return [&]( I&&... i ) { + return [&op]( I&&... i ) { // If one (or more) of the functors has an optional return, we have to propagate it if constexpr ( ( is_our_optional_v> || ... ) ) { // Predicate should not return optional values. @@ -657,9 +754,9 @@ namespace Functors { return NumericValue{ log( f ) }; } else { return detail::compose( - []( auto&& arg ) { + []( auto x ) { using std::log; - return log( std::forward( arg ) ); + return log( x ); }, std::forward( f ) ); } @@ -670,9 +767,9 @@ namespace Functors { template LHCB_FUNCTORS_INLINE constexpr auto exp( F&& f ) { return detail::compose( - []( auto&& arg ) { + []( auto x ) { using std::exp; - return exp( std::forward( arg ) ); + return exp( x ); }, std::forward( f ) ); } @@ -682,9 +779,9 @@ namespace Functors { template LHCB_FUNCTORS_INLINE constexpr auto sqrt( F&& f ) { return detail::compose( - []( auto&& arg ) { + []( auto x ) { using std::sqrt; - return sqrt( std::forward( arg ) ); + return sqrt( x ); }, std::forward( f ) ); } @@ -694,21 +791,21 @@ namespace Functors { template LHCB_FUNCTORS_INLINE constexpr auto arccos( F&& f ) { return detail::compose( - []( auto&& arg ) { + []( auto x ) { using std::acos; using LHCb::Utils::as_arithmetic; - return acos( as_arithmetic( std::forward( arg ) ) ); + return acos( as_arithmetic( x ) ); }, std::forward( f ) ); } - /** Wrapper for (cond) ? true_val : false_val. + /** Wrapper for (cond) ? true_fun : false_fun. */ template - LHCB_FUNCTORS_INLINE constexpr auto where( Pred&& cond, F2&& true_val, F3&& false_val ) { + LHCB_FUNCTORS_INLINE constexpr auto where( Pred&& cond, F2&& true_fun, F3&& false_fun ) { return detail::promote_and_compose( []( auto&& arg1, auto arg2, auto arg3 ) { return arg1 ? arg2 : arg3; }, std::forward( cond ), - std::forward( true_val ), std::forward( false_val ) ); + std::forward( true_fun ), std::forward( false_fun ) ); } /** Wrapper for std::abs( contained_functor_value ). @@ -716,9 +813,9 @@ namespace Functors { template LHCB_FUNCTORS_INLINE constexpr auto abs( F&& f ) { return detail::compose( - []( auto&& arg ) { + []( auto x ) { using std::abs; - return abs( std::forward( arg ) ); + return abs( x ); }, std::forward( f ) ); } @@ -758,7 +855,7 @@ namespace Functors { } /* Sign function*/ - // Returns 1 if x > 0, -1 if x < 0, FIXME: and 0 if x is zero. + // Returns 1 if x > 0, -1 if x < 0, FIXME?? and 0 if x is zero. template LHCB_FUNCTORS_INLINE constexpr auto sign( F&& f ) { return detail::compose( diff --git a/Phys/FunctorCore/include/Functors/Functional.h b/Phys/FunctorCore/include/Functors/Functional.h index d56abcac79e1d34d4c5a9351062c950b10f6716b..29b1619407b6c3be16fe8fd2fc0a37f48bc72301 100644 --- a/Phys/FunctorCore/include/Functors/Functional.h +++ b/Phys/FunctorCore/include/Functors/Functional.h @@ -1,5 +1,5 @@ /*****************************************************************************\ -* (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration * +* (c) Copyright 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". * @@ -13,6 +13,8 @@ #include "Functors/Function.h" #include "Functors/Utilities.h" #include +#include +// #include namespace Functors::Functional { @@ -33,8 +35,8 @@ namespace Functors::Functional { auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { if constexpr ( requires_explicit_mask ) { - return [pf = detail::prepared( m_f, evtCtx, top_level )]( - auto mask, Range const& range, auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( auto mask, std::ranges::range auto const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; static_assert( std::is_invocable_v( Range const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( std::ranges::range auto const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; static_assert( std::is_invocable_v ); @@ -151,119 +153,111 @@ namespace Functors::Functional { /** * @brief return front element of range * */ - struct Front final : public Function { - template - auto operator()( Data&& range ) const -> decltype( std::forward( range ).front() ) { - return std::forward( range ).front(); - } + constexpr auto Front = TrivialFunctor{ + "Front", + []( T&& r ) -> decltype( std::forward( r ).front() ) { + return std::forward( r ).front(); + } // namespace Functors::Functional }; + /** * @brief return back element of range * */ - struct Back final : public Function { - template - auto operator()( Data&& range ) const -> decltype( std::forward( range ).back() ) { - return std::forward( range ).back(); - } - }; + constexpr auto Back = TrivialFunctor{ "Back", []( T&& r ) -> decltype( std::forward( r ).back() ) { + return std::forward( r ).back(); + } }; /* * * @brief reverse the order of an range * */ - struct Reverse final : public Function { - template - auto operator()( Range&& range ) const { - using std::ranges::rbegin; - using std::ranges::rend; - return std::vector>{ rbegin( range ), rend( range ) }; - } - }; + // constexpr auto Reverse = TrivialFunctor{"Reverse",[](auto&& r) { return reverse( std::forward(r) ); } + // }; + constexpr auto Reverse = + TrivialFunctor{ "Reverse", []( Range&& range ) { + using std::ranges::rbegin; + using std::ranges::rend; + return std::vector>{ rbegin( range ), rend( range ) }; + } }; /* * * @brief return min element of range * */ - struct Min final : public Function { - template - auto operator()( Range const& range ) const { - using std::min; - using std::ranges::begin; - using std::ranges::end; - - // FIXME doc. - return std::accumulate( begin( range ), end( range ), - std::ranges::range_value_t{ std::numeric_limits::max() }, - []( auto curr_min_value, auto value ) { return min( curr_min_value, value ); } ); - } - }; + constexpr auto Min = + TrivialFunctor{ "Min", []( Range const& range ) { + using std::ranges::begin; + using std::ranges::end; + // FIXME doc. + return std::accumulate( begin( range ), end( range ), + std::ranges::range_value_t{ std::numeric_limits::max() }, + []( auto curr_min_value, auto value ) { + using std::min; + return min( curr_min_value, value ); + } ); + } }; /* * * @brief reduces range to minimum value that is not zero * */ - struct MinElementNotZero final : public Function { - template - auto operator()( Range&& range ) const { - using Sel::Utils::select; - using std::abs; - using std::min; - using std::ranges::begin; - using std::ranges::end; - using data_t = std::ranges::range_value_t; - // reduce to smallest value that is not zero - return std::accumulate( - begin( range ), end( range ), std::numeric_limits::max(), []( auto curr_min_value, auto value ) { - return select( !LHCb::essentiallyZero( value ), min( curr_min_value, value ), curr_min_value ); - } ); - } - }; + constexpr auto MinElementNotZero = + TrivialFunctor{ "MinElementNotZero", []( Range const& range ) { + using Sel::Utils::select; + using std::abs; + using std::min; + using std::ranges::begin; + using std::ranges::end; + return std::accumulate( begin( range ), end( range ), + std::numeric_limits>::max(), + []( auto curr_min_value, auto value ) { + return select( !LHCb::essentiallyZero( value ), + min( curr_min_value, value ), curr_min_value ); + } ); + } }; /* * * @brief return max element of range * */ - struct Max final : public Function { - template - auto operator()( Range const& range ) const { - using std::max; - using std::ranges::begin; - using std::ranges::end; - - // FIXME doc. - return std::accumulate( begin( range ), end( range ), - std::ranges::range_value_t{ std::numeric_limits::lowest() }, - []( auto curr_max_value, auto value ) { return max( curr_max_value, value ); } ); - } - }; + constexpr auto Max = TrivialFunctor{ "Max", []( Range const& range ) { + using std::ranges::begin; + using std::ranges::end; + // FIXME doc. + return std::accumulate( + begin( range ), end( range ), + std::ranges::range_value_t{ std::numeric_limits::lowest() }, + []( auto curr_max_value, auto value ) { + using std::max; + return max( curr_max_value, value ); + } ); + } }; /* * * @brief return sum element of range * */ - struct Sum final : public Function { - template > - auto operator()( Range const& range, Init init = 0 ) const { - using std::ranges::begin; - using std::ranges::end; - return std::accumulate( begin( range ), end( range ), std::ranges::range_value_t{ init } ); - } - }; - - /** @brief Return the entry among a set of relations for which the application of the functor gives minimum value. + constexpr auto Sum = TrivialFunctor( + "Sum", []( Range const& range, std::ranges::range_value_t init = 0 ) { + using std::ranges::begin; + using std::ranges::end; + return std::accumulate( begin( range ), end( range ), std::ranges::range_value_t{ init } ); + } ); + + /** @brief Return the entry from a range for which the provided functor returns the smallest value. * * */ template - struct EntryWithMinRelatedValueOf final : public Function { + struct MinElement final : public Function { - EntryWithMinRelatedValueOf( F f ) : m_f{ std::move( f ) } {} + MinElement( F f ) : m_f{ std::move( f ) } {} constexpr static bool requires_explicit_mask = detail::requires_explicit_mask_v; /* Improve error messages. */ - constexpr auto name() const { return "EntryWithMinRelatedValueOf( " + detail::get_name( m_f ) + " )"; } + constexpr auto name() const { return "MinElement( " + detail::get_name( m_f ) + " )"; } void bind( TopLevelInfo& top_level ) { detail::bind( m_f, top_level ); } auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { if constexpr ( requires_explicit_mask ) { - return [pf = detail::prepared( m_f, evtCtx, top_level )]( - auto mask, Range const& range, auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( auto mask, std::ranges::range auto const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; using std::next; @@ -271,18 +265,19 @@ namespace Functors::Functional { if ( begin( range ) == end( range ) ) throw std::runtime_error( "Attempt to iterate over an empty range" ); - auto min_entry = std::accumulate( - next( begin( range ) ), end( range ), - make_pair( *begin( range ), pf( mask_arg, mask, *begin( range ), input... ) ), - [&]( auto accumulator, auto current_entry ) { - auto current_value = pf( mask_arg, mask, current_entry, input... ); - return current_value < accumulator.second ? make_pair( current_entry, current_value ) : accumulator; - } ); - return min_entry.first; + return std::accumulate( next( begin( range ) ), end( range ), + make_pair( *begin( range ), pf( mask_arg, mask, *begin( range ), input... ) ), + [&]( auto accumulator, auto current_entry ) { + auto current_value = pf( mask_arg, mask, current_entry, input... ); + return current_value < accumulator.second + ? make_pair( current_entry, current_value ) + : accumulator; + } ) + .first; }; } else { - return [pf = detail::prepared( m_f, evtCtx, top_level )]( Range const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( std::ranges::range auto const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; using std::next; @@ -290,13 +285,15 @@ namespace Functors::Functional { if ( begin( range ) == end( range ) ) throw std::runtime_error( "Attempt to iterate over an empty range" ); - auto min_entry = std::accumulate( - next( begin( range ) ), end( range ), make_pair( *begin( range ), pf( *begin( range ), input... ) ), - [&]( auto accumulator, auto current_entry ) { - auto current_value = pf( current_entry, input... ); - return current_value < accumulator.second ? make_pair( current_entry, current_value ) : accumulator; - } ); - return min_entry.first; + return std::accumulate( next( begin( range ) ), end( range ), + make_pair( *begin( range ), pf( *begin( range ), input... ) ), + [&]( auto accumulator, auto current_entry ) { + auto current_value = pf( current_entry, input... ); + return current_value < accumulator.second + ? make_pair( current_entry, current_value ) + : accumulator; + } ) + .first; }; } } @@ -309,21 +306,21 @@ namespace Functors::Functional { * * */ template - struct EntryWithMaxRelatedValueOf final : public Function { + struct MaxElement final : public Function { - EntryWithMaxRelatedValueOf( F f ) : m_f{ std::move( f ) } {} + MaxElement( F f ) : m_f{ std::move( f ) } {} constexpr static bool requires_explicit_mask = detail::requires_explicit_mask_v; /* Improve error messages. */ - constexpr auto name() const { return "EntryWithMaxRelatedValueOf( " + detail::get_name( m_f ) + " )"; } + constexpr auto name() const { return "MaxElement( " + detail::get_name( m_f ) + " )"; } void bind( TopLevelInfo& top_level ) { detail::bind( m_f, top_level ); } auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { if constexpr ( requires_explicit_mask ) { - return [pf = detail::prepared( m_f, evtCtx, top_level )]( - auto mask, Range const& range, auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( auto mask, std::ranges::range auto const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; using std::next; @@ -341,8 +338,8 @@ namespace Functors::Functional { return max_entry.first; }; } else { - return [pf = detail::prepared( m_f, evtCtx, top_level )]( Range const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( std::ranges::range auto const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; using std::next; @@ -370,12 +367,10 @@ namespace Functors::Functional { * optional is empty * */ template - struct CastTo final : Function { - template - auto operator()( U&& value ) const -> decltype( static_cast( std::forward( value ) ) ) { - return static_cast( std::forward( value ) ); - } - }; + constexpr auto CastTo = + TrivialFunctor{ "CastTo", []( U&& value ) -> decltype( static_cast( std::forward( value ) ) ) { + return static_cast( std::forward( value ) ); + } }; /** * @brief Return the value inside a Functors::Optional, or a default value if @@ -428,29 +423,25 @@ namespace Functors::Functional { * @brief Return the value from a map given a key * */ template - struct ValueFromDict final : public Function { + class ValueFromDict final : public Function { + Key m_key; + public: ValueFromDict( Key k ) : m_key{ std::move( k ) } {} template - requires requires( Dict d, Key k ) { - d.find( k ); - d.end(); - } - auto operator()( Dict&& dict ) const { + requires requires( Dict d, Key k ) { d.find( k ) != d.end(); } + auto operator()( Dict const& dict ) const { auto i = dict.find( m_key ); return i != dict.end() ? Functors::Optional{ i->second } : std::nullopt; } - - private: - Key m_key; }; /** * @brief Return the value inside a Functors::Optional. * If nullopt it throws an error. * */ - struct Value final : public Function { + struct Value_t final : public Function { // inform composedfunctor that this functor will turn an optional into a concrete value even if optional is not // engaged @@ -471,25 +462,41 @@ namespace Functors::Functional { } }; + constexpr auto Value = Value_t{}; + /** * @brief Return true if the input has a valid value. * */ - struct HasValue final : Predicate { + struct HasValue_t final : Predicate { // inform composedfunctor that this functor will turn an optional into a concrete value even if optional is not // engaged static constexpr bool is_optional_unwrapper = true; template - bool operator()( U&& opt_value ) const { - if constexpr ( detail::is_our_optional_v> ) { - return opt_value.has_value(); - } else { - return true; - } + bool operator()( Optional const& o ) const { + return o.has_value(); + } + template + bool operator()( std::optional const& o ) const { + return o.has_value(); + } + template + bool operator()( SmartRef const& o ) const { + return o != nullptr; + } + bool operator()( void const* const& o ) const { return o != nullptr; } + bool operator()( std::nullptr_t ) const { return false; } + bool operator()( std::nullopt_t ) const { return false; } + template + requires( !std::is_pointer_v ) + bool operator()( Arg const& ) const { + return true; } }; + constexpr auto HasValue = HasValue_t{}; + /** * @brief Count the number of elements in a range satisfying the specified predicate * */ @@ -511,8 +518,8 @@ namespace Functors::Functional { return std::ranges::count_if( range, LHCb::cxx::bind_front( predicate, mask_arg, mask ) ); }; } else { - return [predicate = detail::prepared( m_predicate, evtCtx, top_level )]( - Range const& range ) { return std::ranges::count_if( range, predicate ); }; + return [predicate = detail::prepared( m_predicate, evtCtx, top_level )]( + std::ranges::range auto const& range ) { return std::ranges::count_if( range, predicate ); }; } } }; diff --git a/Phys/FunctorCore/include/Functors/FunctorDesc.h b/Phys/FunctorCore/include/Functors/FunctorDesc.h index cf518a2fe33f7fa6adee7bc40b0f3180d83f66fc..bca209c0090fe6b1552c8cd382aab7acbe947b82 100644 --- a/Phys/FunctorCore/include/Functors/FunctorDesc.h +++ b/Phys/FunctorCore/include/Functors/FunctorDesc.h @@ -39,7 +39,7 @@ namespace ThOr { }; namespace Defaults { - inline FunctorDesc const ALL{ "::Functors::AcceptAll{}", {}, "ALL" }; + inline FunctorDesc const ALL{ "::Functors::AcceptAll", {}, "ALL" }; } // namespace Defaults } // namespace ThOr diff --git a/Phys/FunctorCore/include/Functors/LHCbMath.h b/Phys/FunctorCore/include/Functors/LHCbMath.h index 943957ef256efc68a59ebfbe2c1dca83a66c1423..a61b1457fd98eb34b3482d1e8fb73ea5318391ee 100644 --- a/Phys/FunctorCore/include/Functors/LHCbMath.h +++ b/Phys/FunctorCore/include/Functors/LHCbMath.h @@ -32,175 +32,95 @@ namespace Functors::LHCbMath { /** * @brief scalarMomentum, access the scalar momentum by input.scalarMomentum() */ - struct scalarMomentum : public Function { - - constexpr auto name() const { return "scalarMomentum"; } - - template - auto operator()( const T& input ) const -> decltype( input.scalarMomentum() ) { - return input.scalarMomentum(); - } - - template - auto operator()( const T* p ) const -> decltype( Functors::and_then( p, *this ) ) { - return Functors::and_then( p, *this ); - } - - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, - "The functor Functors::LHCbMath::scalarMomentum can only apply to object that has member function " - "scalarMomentum()" ); - } - }; + constexpr auto scalarMomentum = GenericFunctor{ + "scalarMomentum", []( auto const& i ) -> decltype( i.scalarMomentum() ) { return i.scalarMomentum(); } }; /** * @brief normed_dot_3dim, calculates the cosine of angle between two 3-vectors. If passed vectors are 4-vectors, the * functor will use only coordinate part. */ - struct normed_dot_3dim : public Function { - - constexpr auto name() const { return "normed_dot_3dim"; } - - template - auto operator()( const T1& v1, const T2& v2 ) const { - const auto dot = []( const auto x1, const auto y1, const auto z1, const auto x2, const auto y2, const auto z2 ) { - return x1 * x2 + y1 * y2 + z1 * z2; - }; - return dot( v1.x(), v1.y(), v1.z(), v2.x(), v2.y(), v2.z() ) / - sqrt( dot( v1.x(), v1.y(), v1.z(), v1.x(), v1.y(), v1.z() ) * - dot( v2.x(), v2.y(), v2.z(), v2.x(), v2.y(), v2.z() ) ); - } - - template - auto operator()( const T& v1, const T& v2 ) const -> decltype( Functors::Optional{ ( *this )( *v1, *v2 ) } ) { - return ( v1 && v2 ) ? Functors::Optional{ ( *this )( *v1, *v2 ) } : std::nullopt; - } - - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, - "The functor Functors::LHCbMath::normed_dot_3dim can only apply to objects with implemented .x(), " - ".y() and .z() member functions or their pointers" ); - } - }; + constexpr auto normed_dot_3dim = TrivialFunctor{ "normed_dot_3dim", []( const auto& v1, const auto& v2 ) { + const auto dot = []( const auto& i, const auto& j ) { + return i.x() * j.x() + i.y() * j.y() + i.z() * j.z(); + }; + return dot( v1, v2 ) / sqrt( dot( v1, v1 ) * dot( v2, v2 ) ); + } }; /** * @brief boost_to, boost the first input LHCb::LinAlg::Vec<4> to the frame, where the second input * LHCb::LinAlg::Vec<4> rests */ - struct boost_to : public Function { - - constexpr auto name() const { return "boost_to"; } - - template - auto operator()( const T1& input, const T2& ref ) const { - const auto result = - ( ROOT::Math::VectorUtil::boost( LHCb::LinAlg::convert( input ), LHCb::LinAlg::convert( ref ).BoostToCM() ) ); - return LHCb::LinAlg::Vec( result.X(), result.Y(), result.Z(), result.E() ); - } - - template - auto operator()( const T& p, const T& ref ) const -> decltype( Functors::Optional{ ( *this )( *p, *ref ) } ) { - return ( p && ref ) ? Functors::Optional{ ( *this )( *p, *ref ) } : std::nullopt; - } - - template - auto operator()( Data... ) const { - static_assert( - detail::always_false_v, - "The functor Functors::LHCbMath::boost_to can only apply to LHCb::LinAlg::Vec<4> objects or their pointers" ); - } - }; + constexpr auto boost_to = TrivialFunctor{ + "boost_to", []( const auto& input, const auto& ref ) requires requires { LHCb::LinAlg::convert( input ); + LHCb::LinAlg::convert( ref ); +} // namespace Functors::LHCbMath +{ + const auto result = + ( ROOT::Math::VectorUtil::boost( LHCb::LinAlg::convert( input ), LHCb::LinAlg::convert( ref ).BoostToCM() ) ); + return LHCb::LinAlg::Vec( result.X(), result.Y(), result.Z(), result.E() ); +} +} +; + +/** + * @brief boost_from, boost the first input LHCb::LinAlg::Vec<4> from the frame, where the second input + * LHCb::LinAlg::Vec<4> rests, to the lab frame + */ +constexpr auto boost_from = TrivialFunctor{ + "boost_from", []( const auto& input, const auto& ref ) requires requires { LHCb::LinAlg::convert( input ); +LHCb::LinAlg::convert( ref ); +} +{ + const auto result = + ( ROOT::Math::VectorUtil::boost( LHCb::LinAlg::convert( input ), -LHCb::LinAlg::convert( ref ).BoostToCM() ) ); + return LHCb::LinAlg::Vec( result.X(), result.Y(), result.Z(), result.E() ); +} +} +; + +/** + * @brief mass, access the scalar momentum by input.invariantMass() + */ +constexpr auto invariantMass = GenericFunctor{ + "invariantMass", []( auto const& input ) -> decltype( input.invariantMass() ) { return input.invariantMass(); } }; +namespace ValueWithError { /** - * @brief boost_from, boost the first input LHCb::LinAlg::Vec<4> from the frame, where the second input - * LHCb::LinAlg::Vec<4> rests, to the lab frame + * @brief Value, access the value of Gaudi::Math::ValueWithError */ - struct boost_from : public Function { + constexpr auto Value = TrivialFunctor{ "ValueWithError::Value", &Gaudi::Math::ValueWithError::value }; - constexpr auto name() const { return "boost_from"; } + /** + * @brief Error, access the value of Gaudi::Math::ValueWithError + */ + constexpr auto Error = TrivialFunctor{ "ValueWithError::Error", &Gaudi::Math::ValueWithError::error }; - template - auto operator()( const T1& input, const T2& ref ) const { - const auto result = ( ROOT::Math::VectorUtil::boost( LHCb::LinAlg::convert( input ), - -LHCb::LinAlg::convert( ref ).BoostToCM() ) ); - return LHCb::LinAlg::Vec( result.X(), result.Y(), result.Z(), result.E() ); - } +} // namespace ValueWithError - template - auto operator()( const T& p, const T& ref ) const -> decltype( Functors::Optional{ ( *this )( *p, *ref ) } ) { - return ( p && ref ) ? Functors::Optional{ ( *this )( *p, *ref ) } : std::nullopt; - } +namespace ParticleParams { + /** + * @brief flightDistance, access the decay length of Gaudi::Math::ParticleParams + */ + constexpr auto flightDistance = + TrivialFunctor{ "ParticleParams::flightDistance", &Gaudi::Math::ParticleParams::flightDistance }; + + /** + * @brief ctau, access the c*tau of Gaudi::Math::ParticleParams + */ + constexpr auto ctau = TrivialFunctor{ "ParticleParams::ctau", &Gaudi::Math::ParticleParams::ctau }; - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, "The functor Functors::LHCbMath::boost_from can only apply " - "to LHCb::LinAlg::Vec<4> objects or their pointers" ); - } - }; + /** + * @brief lenPosCov, access the "Matrix" with correlation errors between position and decay length from + * Gaudi::Math::ParticleParams + */ + constexpr auto lenPosCov = TrivialFunctor{ "ParticleParams::lenPosCov", &Gaudi::Math::ParticleParams::lenPosCov }; /** - * @brief mass, access the scalar momentum by input.invariantMass() + * @brief lenMomCov, access the "Matrix" with correlation errors between momentum and decay length from + * Gaudi::Math::ParticleParams */ - struct invariantMass : public Function { - - constexpr auto name() const { return "invariantMass"; } - - template - auto operator()( const T& input ) const -> decltype( input.invariantMass() ) { - return input.invariantMass(); - } - - template - auto operator()( const T* p ) const -> decltype( Functors::and_then( p, *this ) ) { - return Functors::and_then( p, *this ); - } - - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, "The functor Functors::LHCbMath::invariantMass can only " - "apply to object that has member function invariantMass()" ); - } - }; - - namespace ValueWithError { - /** - * @brief Value, access the value of Gaudi::Math::ValueWithError - */ - inline constexpr auto Value = MemberFn{ &Gaudi::Math::ValueWithError::value, "ValueWithError::Value" }; - - /** - * @brief Error, access the value of Gaudi::Math::ValueWithError - */ - inline constexpr auto Error = MemberFn{ &Gaudi::Math::ValueWithError::error, "ValueWithError::Error" }; - - } // namespace ValueWithError - - namespace ParticleParams { - /** - * @brief flightDistance, access the decay length of Gaudi::Math::ParticleParams - */ - inline constexpr auto flightDistance = - MemberFn{ &Gaudi::Math::ParticleParams::flightDistance, "ParticleParams::flightDistance" }; - - /** - * @brief ctau, access the c*tau of Gaudi::Math::ParticleParams - */ - inline constexpr auto ctau = MemberFn{ &Gaudi::Math::ParticleParams::ctau, "ParticleParams::ctau" }; - - /** - * @brief lenPosCov, access the "Matrix" with correlation errors between position and decay length from - * Gaudi::Math::ParticleParams - */ - inline constexpr auto lenPosCov = MemberFn{ &Gaudi::Math::ParticleParams::lenPosCov, "ParticleParams::lenPosCov" }; - - /** - * @brief lenMomCov, access the "Matrix" with correlation errors between momentum and decay length from - * Gaudi::Math::ParticleParams - */ - inline constexpr auto lenMomCov = MemberFn{ &Gaudi::Math::ParticleParams::lenMomCov, "ParticleParams::lenMomCov" }; - - } // namespace ParticleParams + constexpr auto lenMomCov = TrivialFunctor{ "ParticleParams::lenMomCov", &Gaudi::Math::ParticleParams::lenMomCov }; + +} // namespace ParticleParams } // namespace Functors::LHCbMath diff --git a/Phys/FunctorCore/include/Functors/MVA.h b/Phys/FunctorCore/include/Functors/MVA.h index 27058c7f98c6313144cc1e86e32daf0576d095f8..9811fc7b3441d730d2b931c90c34817d03e03d6a 100644 --- a/Phys/FunctorCore/include/Functors/MVA.h +++ b/Phys/FunctorCore/include/Functors/MVA.h @@ -72,7 +72,60 @@ namespace Functors { /** Prepare the functor for use. */ auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { - return prepare( evtCtx, top_level, std::index_sequence_for{} ); + // Prepare all of the functors and capture the resulting tuple + return std::apply( + [&]( auto const&... fns ) { + return [this, ... pf = detail::prepared( fns, evtCtx, top_level )]( auto const& mask, + auto const&... input ) { + // Let the implementation specify if inputs should be float, double + // etc. For now, until we have SIMD-friendly MVA implementations, + // this will just be a scalar numeric type. + using MVA_input_t = typename MVAImpl::input_type; + static_assert( std::is_arithmetic_v ); + // Figure out what the functors are going to yield... + // using functor_ret_ts = std::tuple( fs )( input... ) )...>; + // Don't strictly demand the types are the same, we could stomach a mix of float/double/... + using functor_ret_t = std::common_type_t; + // If this is a plain arithmetic type, this should be easy... + if constexpr ( std::is_arithmetic_v ) { + // MVA expects float/double/.., functors yield that, just calculate + // the inputs and evaluate it + std::array values{}; + // Want to put the result of evaluating std::get( m_inputs ) into values[m_indices[I]] + auto i_indx = m_indices.begin(); + ( ( values[*i_indx++] = std::invoke( pf, mask_arg, mask, input... ) ), ... ); + // Evaluate the classifier + return m_impl( values ); + } else { + // Presumably this is because functor_ret_t is a SIMDWrapper type + // (though maybe we should check that explicitly) + std::array::scalar_t, functor_ret_t::size()>, + sizeof...( pf )> + values{}; + // Evaluate the functors SIMD-wise + auto i_indx = m_indices.begin(); + ( static_cast( std::invoke( pf, mask_arg, mask, input... ) ) + .store( values[*i_indx++] ), + ... ); + // Evaluate the classifier element-wise + // TODO get MVA implementations that accept vector types + std::array mva_vals{}; + for ( auto i = 0ul; i < functor_ret_t::size(); ++i ) { + // Avoid evaluating the MVA for entries that are already masked out + using detail::testbit; + if ( !testbit( mask, i ) ) { + mva_vals[i] = std::numeric_limits::lowest(); + continue; + } + std::array values2{}; + for ( auto j = 0ul; j < values2.size(); ++j ) { values2[j] = values[j][i]; } + mva_vals[i] = m_impl( values2 ); + } + return functor_ret_t{ mva_vals.data() }; + } + }; + }, + m_inputs ); } /** Flag that this functor would like to be invoked with an extra zeroth @@ -82,57 +135,6 @@ namespace Functors { static constexpr bool requires_explicit_mask = true; private: - template - auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level, std::index_sequence ) const { - // Prepare all of the functors and capture the resulting tuple - return [this, ... pf = detail::prepared( std::get( m_inputs ), evtCtx, top_level )]( auto const& mask, - auto const&... input ) { - // Let the implementation specify if inputs should be float, double - // etc. For now, until we have SIMD-friendly MVA implementations, - // this will just be a scalar numeric type. - using MVA_input_t = typename MVAImpl::input_type; - static_assert( std::is_arithmetic_v ); - // Figure out what the functors are going to yield... - // using functor_ret_ts = std::tuple( fs )( input... ) )...>; - // Don't strictly demand the types are the same, we could stomach a mix of float/double/... - using functor_ret_t = std::common_type_t; - // If this is a plain arithmetic type, this should be easy... - if constexpr ( std::is_arithmetic_v ) { - // MVA expects float/double/.., functors yield that, just calculate - // the inputs and evaluate it - std::array values{}; - // Want to put the result of evaluating std::get( m_inputs ) into values[m_indices[I]] - ( ( values[m_indices[I]] = std::invoke( pf, mask_arg, mask, input... ) ), ... ); - // Evaluate the classifier - return m_impl( values ); - } else { - // Presumably this is because functor_ret_t is a SIMDWrapper type - // (though maybe we should check that explicitly) - std::array::scalar_t, functor_ret_t::size()>, - sizeof...( Inputs )> - values{}; - // Evaluate the functors SIMD-wise - ( static_cast( std::invoke( pf, mask_arg, mask, input... ) ).store( values[m_indices[I]] ), - ... ); - // Evaluate the classifier element-wise - // TODO get MVA implementations that accept vector types - std::array mva_vals{}; - for ( auto i = 0ul; i < functor_ret_t::size(); ++i ) { - // Avoid evaluating the MVA for entries that are already masked out - using detail::testbit; - if ( !testbit( mask, i ) ) { - mva_vals[i] = std::numeric_limits::lowest(); - continue; - } - std::array values2{}; - for ( auto j = 0ul; j < values2.size(); ++j ) { values2[j] = values[j][i]; } - mva_vals[i] = m_impl( values2 ); - } - return functor_ret_t{ mva_vals.data() }; - } - }; - } - MVAImpl m_impl; std::tuple m_inputs; std::array m_indices; @@ -153,6 +155,6 @@ namespace Functors { */ template auto MVA( Sel::MVA_config_dict const& config, std::pair&&... inputs ) { - return detail::MVA{ config, std::forward>( inputs )... }; + return detail::MVA{ config, std::move( inputs )... }; } } // namespace Functors diff --git a/Phys/FunctorCore/include/Functors/NeutralLike.h b/Phys/FunctorCore/include/Functors/NeutralLike.h index a8b7f5780c22afb90b5c84847c62c4eecbfe6306..cfbd964022178efb420e31de1a80f61db8e18b7d 100644 --- a/Phys/FunctorCore/include/Functors/NeutralLike.h +++ b/Phys/FunctorCore/include/Functors/NeutralLike.h @@ -19,29 +19,29 @@ namespace Functors::Neutral { */ template - struct NeutralPID_Accessor_t : MemberFn { + struct NeutralPID_Accessor_t : TrivialFunctor { template - constexpr NeutralPID_Accessor_t( R ( LHCb::NeutralPID::*fn )() const, const char ( &name )[N] ) - : MemberFn{ fn, name } {} - using MemberFn::operator(); - auto operator()( LHCb::ProtoParticle const& pp ) const { return Functors::and_then( pp.neutralPID(), *this ); } - auto operator()( LHCb::Particle const& p ) const { return Functors::and_then( p.proto(), *this ); } + constexpr NeutralPID_Accessor_t( const char ( &name )[N], R ( LHCb::NeutralPID::*fn )() const ) + : TrivialFunctor{ name, fn } {} + using TrivialFunctor::operator(); + auto operator()( LHCb::Particle const& p ) const { + return Functors::and_then( p.proto(), &LHCb::ProtoParticle::neutralPID, *this ); + } auto operator()( LHCb::Particle const* p ) const { return Functors::and_then( p, *this ); } }; - inline constexpr auto IsPhoton = NeutralPID_Accessor_t{ &LHCb::NeutralPID::IsPhoton, "Neutral::IsPhoton" }; - inline constexpr auto IsNotH = NeutralPID_Accessor_t{ &LHCb::NeutralPID::IsNotH, "Neutral::IsNotH" }; - inline constexpr auto ShowerShape = NeutralPID_Accessor_t{ &LHCb::NeutralPID::ShowerShape, "Neutral::ShowerShape" }; - inline constexpr auto NeutralE19 = NeutralPID_Accessor_t{ &LHCb::NeutralPID::CaloNeutralE19, "Neutral::NeutralE19" }; - inline constexpr auto NeutralE49 = NeutralPID_Accessor_t{ &LHCb::NeutralPID::CaloNeutralE49, "Neutral::NeutralE49" }; - inline constexpr auto Saturation = NeutralPID_Accessor_t{ &LHCb::NeutralPID::Saturation, "Neutral::Saturation" }; - inline constexpr auto NeutralHcal2Ecal = - NeutralPID_Accessor_t{ &LHCb::NeutralPID::CaloNeutralHcal2Ecal, "Neutral::NeutralHcal2Ecal" }; - inline constexpr auto NeutralEcal = - NeutralPID_Accessor_t{ &LHCb::NeutralPID::CaloNeutralEcal, "Neutral::NeutralEcal" }; - inline constexpr auto ClusterMass = NeutralPID_Accessor_t{ &LHCb::NeutralPID::ClusterMass, "Neutral::ClusterMass" }; + constexpr auto IsPhoton = NeutralPID_Accessor_t{ "Neutral::IsPhoton", &LHCb::NeutralPID::IsPhoton }; + constexpr auto IsNotH = NeutralPID_Accessor_t{ "Neutral::IsNotH", &LHCb::NeutralPID::IsNotH }; + constexpr auto ShowerShape = NeutralPID_Accessor_t{ "Neutral::ShowerShape", &LHCb::NeutralPID::ShowerShape }; + constexpr auto NeutralE19 = NeutralPID_Accessor_t{ "Neutral::NeutralE19", &LHCb::NeutralPID::CaloNeutralE19 }; + constexpr auto NeutralE49 = NeutralPID_Accessor_t{ "Neutral::NeutralE49", &LHCb::NeutralPID::CaloNeutralE49 }; + constexpr auto Saturation = NeutralPID_Accessor_t{ "Neutral::Saturation", &LHCb::NeutralPID::Saturation }; + constexpr auto NeutralHcal2Ecal = + NeutralPID_Accessor_t{ "Neutral::NeutralHcal2Ecal", &LHCb::NeutralPID::CaloNeutralHcal2Ecal }; + constexpr auto NeutralEcal = NeutralPID_Accessor_t{ "Neutral::NeutralEcal", &LHCb::NeutralPID::CaloNeutralEcal }; + constexpr auto ClusterMass = NeutralPID_Accessor_t{ "Neutral::ClusterMass", &LHCb::NeutralPID::ClusterMass }; - inline constexpr auto NeutralID = + constexpr auto NeutralID = Functors::PID::details::CellIDFunc{ &LHCb::ProtoParticle::neutralPID, &LHCb::NeutralPID::CaloNeutralID }; } // namespace Functors::Neutral diff --git a/Phys/FunctorCore/include/Functors/Optional.h b/Phys/FunctorCore/include/Functors/Optional.h index d3d9eefc4e107c89571918d40159167c4c4b92e5..8487456ae811e0087b0d6ceb043d86a1ce694de1 100644 --- a/Phys/FunctorCore/include/Functors/Optional.h +++ b/Phys/FunctorCore/include/Functors/Optional.h @@ -43,6 +43,7 @@ namespace Functors { * @return bool: true if Optional contains value, else false */ [[nodiscard]] constexpr bool has_value() const { return m_value.has_value(); } + [[nodiscard]] constexpr explicit operator bool() const { return has_value(); } /** * @brief const access to contained object * diff --git a/Phys/FunctorCore/include/Functors/PID.h b/Phys/FunctorCore/include/Functors/PID.h index 8344853c8f3ee61521ef1115c0cbdb2491ed5d32..2501fd68b9516d224faeabdde3660d13b9642170 100644 --- a/Phys/FunctorCore/include/Functors/PID.h +++ b/Phys/FunctorCore/include/Functors/PID.h @@ -54,152 +54,124 @@ namespace Functors::PID { }; } // namespace details - inline constexpr auto RichDLLe = details::RichDLL{ Rich::ParticleIDType::Electron }; - inline constexpr auto RichDLLmu = details::RichDLL{ Rich::ParticleIDType::Muon }; - inline constexpr auto RichDLLp = details::RichDLL{ Rich::ParticleIDType::Proton }; - inline constexpr auto RichDLLk = details::RichDLL{ Rich::ParticleIDType::Kaon }; - inline constexpr auto RichDLLpi = details::RichDLL{ Rich::ParticleIDType::Pion }; - inline constexpr auto RichDLLd = details::RichDLL{ Rich::ParticleIDType::Deuteron }; - inline constexpr auto RichDLLbt = details::RichDLL{ Rich::ParticleIDType::BelowThreshold }; + constexpr auto RichDLLe = details::RichDLL{ Rich::ParticleIDType::Electron }; + constexpr auto RichDLLmu = details::RichDLL{ Rich::ParticleIDType::Muon }; + constexpr auto RichDLLp = details::RichDLL{ Rich::ParticleIDType::Proton }; + constexpr auto RichDLLk = details::RichDLL{ Rich::ParticleIDType::Kaon }; + constexpr auto RichDLLpi = details::RichDLL{ Rich::ParticleIDType::Pion }; + constexpr auto RichDLLd = details::RichDLL{ Rich::ParticleIDType::Deuteron }; + constexpr auto RichDLLbt = details::RichDLL{ Rich::ParticleIDType::BelowThreshold }; - inline constexpr auto RichScaledDLLe = details::RichDLL{ Rich::ParticleIDType::Electron, true }; - inline constexpr auto RichScaledDLLmu = details::RichDLL{ Rich::ParticleIDType::Muon, true }; + constexpr auto RichScaledDLLe = details::RichDLL{ Rich::ParticleIDType::Electron, true }; + constexpr auto RichScaledDLLmu = details::RichDLL{ Rich::ParticleIDType::Muon, true }; - inline constexpr auto Rich1GasUsed = details::RichPIDPredicate{ &LHCb::RichPID::usedRich1Gas }; - inline constexpr auto Rich2GasUsed = details::RichPIDPredicate{ &LHCb::RichPID::usedRich2Gas }; + constexpr auto Rich1GasUsed = details::RichPIDPredicate{ &LHCb::RichPID::usedRich1Gas }; + constexpr auto Rich2GasUsed = details::RichPIDPredicate{ &LHCb::RichPID::usedRich2Gas }; - inline constexpr auto RichThresholdEl = + constexpr auto RichThresholdEl = details::RichPIDPredicate{ &LHCb::RichPID::isAboveThreshold, Rich::ParticleIDType::Electron }; - inline constexpr auto RichThresholdKa = + constexpr auto RichThresholdKa = details::RichPIDPredicate{ &LHCb::RichPID::isAboveThreshold, Rich::ParticleIDType::Kaon }; - inline constexpr auto RichThresholdMu = + constexpr auto RichThresholdMu = details::RichPIDPredicate{ &LHCb::RichPID::isAboveThreshold, Rich::ParticleIDType::Muon }; - inline constexpr auto RichThresholdPi = + constexpr auto RichThresholdPi = details::RichPIDPredicate{ &LHCb::RichPID::isAboveThreshold, Rich::ParticleIDType::Pion }; - inline constexpr auto RichThresholdPr = + constexpr auto RichThresholdPr = details::RichPIDPredicate{ &LHCb::RichPID::isAboveThreshold, Rich::ParticleIDType::Proton }; - inline constexpr auto RichThresholdDe = + constexpr auto RichThresholdDe = details::RichPIDPredicate{ &LHCb::RichPID::isAboveThreshold, Rich::ParticleIDType::Deuteron }; // MUON // - /** @brief IsMuon, as defined by the accessor of the same name. - */ - struct IsMuon : Predicate { - bool operator()( LHCb::ProtoParticle const& pp ) const { - return Functors::and_then( pp.muonPID(), *this ).value_or( false ); - } + namespace details { + template + class MuonPIDPredicate : public Predicate { + Pred m_pred; - bool operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), *this ).value_or( false ); - } + public: + constexpr MuonPIDPredicate( Pred pred ) : m_pred{ pred } {} - auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } + bool operator()( LHCb::ProtoParticle const& p ) const { + return Functors::and_then( p.LHCb::ProtoParticle::muonPID(), *this ).value_or( false ); + } + bool operator()( LHCb::Particle const& p ) const { + return Functors::and_then( p.proto(), *this ).value_or( false ); + } - template - auto operator()( Data const& d ) const -> decltype( Sel::Utils::deref_if_ptr( d ).IsMuon() ) { - return Sel::Utils::deref_if_ptr( d ).IsMuon(); - } - }; + template + auto operator()( T const& p ) const -> decltype( m_pred( p ) ) { + return m_pred( p ); + } - /** @brief InMuon to access the Muon Inacceptance information. - */ - struct InAcceptance : Predicate { - auto operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), &LHCb::ProtoParticle::muonPID, &LHCb::MuonPID::InAcceptance ) - .value_or( false ); - } + template + auto operator()( T const* p ) const -> decltype( ( *this )( *p ) ) { + return ( *this )( *p ); + } + }; + } // namespace details - auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } + /** @brief IsMuon, as defined by the accessor of the same name. + */ + constexpr auto IsMuon = + details::MuonPIDPredicate{ []( const auto& d ) -> decltype( d.IsMuon() ) { return d.IsMuon(); } }; - // template - template - auto operator()( Data const& d ) const -> decltype( d.InAcceptance() ) { - return d.InAcceptance(); - } - }; + /** @brief InMuon to access the Muon Inacceptance information. + */ + constexpr auto InAcceptance = + details::MuonPIDPredicate{ []( auto const& d ) -> decltype( d.InAcceptance() ) { return d.InAcceptance(); } }; /** @brief IsMuonTight, as defined by the accessor of the same name. */ - struct IsMuonTight : Predicate { - bool operator()( LHCb::ProtoParticle const& pp ) const { - return Functors::and_then( pp.muonPID(), &LHCb::MuonPID::IsMuonTight ).value_or( false ); - } + constexpr auto IsMuonTight = + details::MuonPIDPredicate{ []( auto const& d ) -> decltype( d.IsMuonTight() ) { return d.IsMuonTight(); } }; - bool operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), *this ).value_or( false ); - } + namespace details { + template + class MuonPIDFunction : public Function { + R ( LHCb::MuonPID::*m_mfn )() const; + Fun m_fn; - auto operator()( LHCb::Particle const* p ) const { return Functors::and_then( p, *this ).value_or( false ); } + public: + constexpr MuonPIDFunction( R ( LHCb::MuonPID::*mfn )() const, Fun fn ) : m_mfn{ mfn }, m_fn{ std::move( fn ) } {} - template - auto operator()( Data const& d ) const -> decltype( Sel::Utils::deref_if_ptr( d ).IsMuonTight() ) { - return Sel::Utils::deref_if_ptr( d ).IsMuonTight(); - } - }; + auto operator()( LHCb::Particle const& p ) const { + return Functors::and_then( p.proto(), &LHCb::ProtoParticle::muonPID, m_mfn ); + } + + template + auto operator()( T const& p ) const -> decltype( m_fn( p ) ) { + return m_fn( p ); + } + + template + auto operator()( T const* p ) const -> decltype( ( *this )( *p ) ) { + return ( *this )( *p ); + } + }; + } // namespace details /** @brief Chi2Corr, as defined by the accessor of the same name. Chi2 taking into account correlations using only * hits from the Muon detector. */ - struct MuonChi2Corr : Function { - auto operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), &LHCb::ProtoParticle::muonPID, &LHCb::MuonPID::chi2Corr ); - } - - auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } - - template - auto operator()( Data const& d ) const -> decltype( Sel::Utils::deref_if_ptr( d ).Chi2Corr() ) { - return Sel::Utils::deref_if_ptr( d ).Chi2Corr(); - } - }; + constexpr auto MuonChi2Corr = details::MuonPIDFunction{ + &LHCb::MuonPID::chi2Corr, []( const auto& d ) -> decltype( d.Chi2Corr() ) { return d.Chi2Corr(); } }; /** @brief MuonLLMu, as defined by the accessor LLMu. Muon likelihood using only Muon detector information */ - struct MuonLLMu : Function { - auto operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), &LHCb::ProtoParticle::muonPID, &LHCb::MuonPID::MuonLLMu ); - } - - auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } - - template - auto operator()( Data const& d ) const -> decltype( Sel::Utils::deref_if_ptr( d ).LLMu() ) { - return Sel::Utils::deref_if_ptr( d ).LLMu(); - } - }; + constexpr auto MuonLLMu = details::MuonPIDFunction{ + &LHCb::MuonPID::MuonLLMu, []( const auto& d ) -> decltype( d.LLMu() ) { return d.LLMu(); } }; /** @brief MuonLLBg, as defined by the accessor LLBg. Background likelihood using only Muon detector information */ - struct MuonLLBg : Function { - auto operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), &LHCb::ProtoParticle::muonPID, &LHCb::MuonPID::MuonLLBg ); - } - - auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } - - template - auto operator()( Data const& d ) const -> decltype( Sel::Utils::deref_if_ptr( d ).LLBg() ) { - return Sel::Utils::deref_if_ptr( d ).LLBg(); - } - }; + constexpr auto MuonLLBg = details::MuonPIDFunction{ + &LHCb::MuonPID::MuonLLBg, []( const auto& d ) -> decltype( d.LLBg() ) { return d.LLBg(); } }; /** @brief MuonCatBoost, as defined by the accessor CatBoost. MVA output using only Muon detector and track * information */ - struct MuonCatBoost : public Function { - auto operator()( LHCb::Particle const& p ) const { - return Functors::and_then( p.proto(), &LHCb::ProtoParticle::muonPID, &LHCb::MuonPID::muonMVA2 ); - } - - auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } - - template - auto operator()( Data const& d ) const -> decltype( Sel::Utils::deref_if_ptr( d ).CatBoost() ) { - return Sel::Utils::deref_if_ptr( d ).CatBoost(); - } - }; + constexpr auto MuonCatBoost = details::MuonPIDFunction{ + &LHCb::MuonPID::muonMVA2, []( const auto& d ) -> decltype( d.CatBoost() ) { return d.CatBoost(); } }; // CALO // @@ -217,11 +189,11 @@ namespace Functors::PID { : m_obj{ obj }, m_fn{ fn } {} bool operator()( LHCb::ProtoParticle const& p ) const { - auto const* pid = ( p.*m_obj )(); - return pid ? ( pid->*m_fn )() : false; + return Functors::and_then( ( p.*m_obj )(), m_fn ).value_or( false ); + } + bool operator()( LHCb::Particle const& p ) const { + return Functors::and_then( p.proto(), *this ).value_or( false ); } - auto operator()( LHCb::ProtoParticle const* p ) const { return p ? ( *this )( *p ) : false; } - auto operator()( LHCb::Particle const& p ) const { return ( *this )( p.proto() ); } auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } }; @@ -235,105 +207,98 @@ namespace Functors::PID { constexpr CaloFunction( T const* ( LHCb::ProtoParticle::*obj )() const, bool ( T::*acc )() const, R ( T::*fn )() const ) : m_obj{ obj }, m_acc{ acc }, m_fn{ fn } {} - auto operator()( LHCb::ProtoParticle const& p ) const { - const T* pid = ( p.*m_obj )(); - return pid && ( pid->*m_acc )() ? Functors::Optional{ ( pid->*m_fn )() } : std::nullopt; + auto operator()( T const& pid ) const { + return ( pid.*m_acc )() ? Functors::Optional{ ( pid.*m_fn )() } : std::nullopt; } - auto operator()( LHCb::ProtoParticle const* p ) const { return Functors::and_then( p, *this ); } - auto operator()( LHCb::Particle const& p ) const { return ( *this )( p.proto() ); } + auto operator()( LHCb::ProtoParticle const& p ) const { return Functors::and_then( ( p.*m_obj )(), *this ); } + auto operator()( LHCb::Particle const& p ) const { return Functors::and_then( p.proto(), *this ); } auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } }; - template + template class CellIDFunc : Function { T const* ( LHCb::ProtoParticle::*m_obj )() const; - R ( T::*m_fn )() const; + LHCb::Detector::Calo::CellID ( T::*m_fn )() const; public: - constexpr CellIDFunc( T const* ( LHCb::ProtoParticle::*obj )() const, R ( T::*fn )() const ) + constexpr CellIDFunc( T const* ( LHCb::ProtoParticle::*obj )() const, + LHCb::Detector::Calo::CellID ( T::*fn )() const ) : m_obj{ obj }, m_fn{ fn } {} - LHCb::Detector::Calo::CellID operator()( LHCb::ProtoParticle const& p ) const { - auto const* pid = ( p.*m_obj )(); - return pid ? ( pid->*m_fn )() : LHCb::Detector::Calo::CellID{}; + auto operator()( LHCb::ProtoParticle const& p ) const { + return Functors::and_then( ( p.*m_obj )(), m_fn ).value_or( LHCb::Detector::Calo::CellID{} ); } - auto operator()( LHCb::ProtoParticle const* p ) const { - return p ? ( *this )( *p ) : LHCb::Detector::Calo::CellID{}; + auto operator()( LHCb::Particle const& p ) const { + return Functors::and_then( p.proto(), *this ).value_or( LHCb::Detector::Calo::CellID{} ); } - auto operator()( LHCb::Particle const& p ) const { return ( *this )( p.proto() ); } auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } }; } // namespace details - inline constexpr auto InEcal = - details::CaloPredicate{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal }; - inline constexpr auto InHcal = - details::CaloPredicate{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InHcal }; + constexpr auto InEcal = details::CaloPredicate{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal }; + constexpr auto InHcal = details::CaloPredicate{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InHcal }; - inline constexpr auto InBrem = details::CaloPredicate{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem }; - inline constexpr auto HasBrem = details::CaloPredicate{ &LHCb::ProtoParticle::bremInfo, &BremInfo::HasBrem }; + constexpr auto InBrem = details::CaloPredicate{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem }; + constexpr auto HasBrem = details::CaloPredicate{ &LHCb::ProtoParticle::bremInfo, &BremInfo::HasBrem }; - inline constexpr auto EcalPIDe = + constexpr auto EcalPIDe = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, &CaloChargedPID::EcalPIDe }; - inline constexpr auto EcalPIDmu = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, - &CaloChargedPID::InEcal, &CaloChargedPID::EcalPIDmu }; - inline constexpr auto ElectronShowerEoP = details::CaloFunction{ + constexpr auto EcalPIDmu = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, + &CaloChargedPID::EcalPIDmu }; + constexpr auto ElectronShowerEoP = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, &CaloChargedPID::ElectronShowerEoP }; - inline constexpr auto ElectronShowerDLL = details::CaloFunction{ + constexpr auto ElectronShowerDLL = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, &CaloChargedPID::ElectronShowerDLL }; - inline constexpr auto ElectronMatch = details::CaloFunction{ - &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, &CaloChargedPID::ElectronMatch }; - inline constexpr auto ElectronEnergy = details::CaloFunction{ - &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, &CaloChargedPID::ElectronEnergy }; - inline constexpr auto ElectronID = - details::CellIDFunc{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::ElectronID }; - inline constexpr auto ClusterID = - details::CellIDFunc{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::ClusterID }; - - inline constexpr auto HcalPIDe = + constexpr auto ElectronMatch = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, + &CaloChargedPID::ElectronMatch }; + constexpr auto ElectronEnergy = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InEcal, + &CaloChargedPID::ElectronEnergy }; + constexpr auto ElectronID = details::CellIDFunc{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::ElectronID }; + constexpr auto ClusterID = details::CellIDFunc{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::ClusterID }; + + constexpr auto HcalPIDe = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InHcal, &CaloChargedPID::HcalPIDe }; - inline constexpr auto HcalPIDmu = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, - &CaloChargedPID::InHcal, &CaloChargedPID::HcalPIDmu }; - inline constexpr auto HcalEoP = + constexpr auto HcalPIDmu = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InHcal, + &CaloChargedPID::HcalPIDmu }; + constexpr auto HcalEoP = details::CaloFunction{ &LHCb::ProtoParticle::caloChargedPID, &CaloChargedPID::InHcal, &CaloChargedPID::HcalEoP }; - inline constexpr auto BremEnergy = + constexpr auto BremEnergy = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremEnergy }; - inline constexpr auto BremPIDe = + constexpr auto BremPIDe = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremPIDe }; - inline constexpr auto BremBendCorr = + constexpr auto BremBendCorr = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremBendingCorrection }; - inline constexpr auto BremHypoMatch = + constexpr auto BremHypoMatch = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremHypoMatch }; - inline constexpr auto BremHypoEnergy = + constexpr auto BremHypoEnergy = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremHypoEnergy }; - inline constexpr auto BremHypoDeltaX = + constexpr auto BremHypoDeltaX = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremHypoDeltaX }; - inline constexpr auto BremTrackBasedEnergy = + constexpr auto BremTrackBasedEnergy = details::CaloFunction{ &LHCb::ProtoParticle::bremInfo, &BremInfo::InBrem, &BremInfo::BremTrackBasedEnergy }; - inline constexpr auto BremHypoID = details::CellIDFunc{ &LHCb::ProtoParticle::bremInfo, &BremInfo::BremHypoID }; + constexpr auto BremHypoID = details::CellIDFunc{ &LHCb::ProtoParticle::bremInfo, &BremInfo::BremHypoID }; - struct ClusterMatch : public Function { + struct ClusterMatch_t : Function { Functors::Optional operator()( LHCb::ProtoParticle const& p ) const { if ( p.track() ) { - auto pid = p.caloChargedPID(); - return pid ? Functors::Optional{ pid->ClusterMatch() } - : invalid_value; // FIXME: replace `invalid_value` with `std::nullopt` + return Functors::and_then( p.caloChargedPID(), &LHCb::Event::Calo::CaloChargedPID::ClusterMatch ) + .value_or( invalid_value ); // FIXME: drop `.value_or(invalid_value)` } else { return Functors::and_then( p.neutralPID(), &LHCb::NeutralPID::CaloTrMatch ); } } - auto operator()( LHCb::ProtoParticle const* p ) const { return Functors::and_then( p, *this ); } - auto operator()( LHCb::Particle const& p ) const { return ( *this )( p.proto() ); } + auto operator()( LHCb::Particle const& p ) const { return Functors::and_then( p.proto(), *this ); } auto operator()( LHCb::Particle const* p ) const { return ( *this )( *p ); } }; + constexpr auto ClusterMatch = ClusterMatch_t{}; namespace CaloCellID { - inline constexpr auto All = Functors::MemberFn{ &LHCb::Detector::Calo::CellID::all, "CaloCellID::All" }; - inline constexpr auto Area = Functors::MemberFn{ &LHCb::Detector::Calo::CellID::area, "CaloCellID::Area" }; - inline constexpr auto Row = Functors::MemberFn{ &LHCb::Detector::Calo::CellID::row, "CaloCellID::Row" }; - inline constexpr auto Column = Functors::MemberFn{ &LHCb::Detector::Calo::CellID::col, "CaloCellID::Col" }; + constexpr auto All = Functors::TrivialFunctor{ "CaloCellID::All", &LHCb::Detector::Calo::CellID::all }; + constexpr auto Area = Functors::TrivialFunctor{ "CaloCellID::Area", &LHCb::Detector::Calo::CellID::area }; + constexpr auto Row = Functors::TrivialFunctor{ "CaloCellID::Row", &LHCb::Detector::Calo::CellID::row }; + constexpr auto Column = Functors::TrivialFunctor{ "CaloCellID::Col", &LHCb::Detector::Calo::CellID::col }; } // namespace CaloCellID diff --git a/Phys/FunctorCore/include/Functors/Particle.h b/Phys/FunctorCore/include/Functors/Particle.h index 14c717f4fc5d147b4d97d32fcb31c1a61461b88b..7d66a4a4bfee4ea6fbdc7499cde9c6f328a1ee09 100644 --- a/Phys/FunctorCore/include/Functors/Particle.h +++ b/Phys/FunctorCore/include/Functors/Particle.h @@ -8,9 +8,7 @@ * granted to it by virtue of its status as an Intergovernmental Organization * * or submit itself to any jurisdiction. * \*****************************************************************************/ - #pragma once - #include "Core/FloatComparison.h" #include "Event/Particle_v2.h" #include "Functors/Function.h" @@ -28,6 +26,10 @@ namespace Functors::detail { + template + constexpr bool is_legacy_particle = + std::is_same_v>>>; + template using has_track_t = decltype( std::declval().track() ); template @@ -38,22 +40,6 @@ namespace Functors::detail { constexpr bool is_charged_basic = std::is_same_v>>>; - // define the various trigger categories - enum class TriggerCategories : unsigned int { TOS = 0, TIS, TUS }; - // define a helper class for checking the trigger category - template - struct IsTrigCategory : public Predicate { - bool operator()( const LHCb::detail::TisTosResult_t& r ) const { - if constexpr ( TrigCat == TriggerCategories::TOS ) - return r.TOS(); - else if constexpr ( TrigCat == TriggerCategories::TIS ) - return r.TIS(); - else if constexpr ( TrigCat == TriggerCategories::TUS ) - return r.TUS(); - else - throw GaudiException( "Unknown trigger type", "IsTos", StatusCode::FAILURE ); - } - }; }; // namespace Functors::detail /** @namespace Functors::Particle @@ -98,138 +84,117 @@ namespace Functors::Particle { private: std::variant m_id; - std::optional> m_pp_svc{ std::nullopt }; + std::optional> m_pp_svc{}; }; /** @brief get the track object from the charged basic particle * E.g. When requisting track momentum one can use this * functor in the composition via F.TRACK_PT = F.PT @ F.TRACK */ - struct GetTrack : public Function { + struct GetTrack_t : public Function { // Perfect forward template - requires( !is_legacy_particle && !detail::has_track && !detail::is_charged_basic ) + requires( !detail::is_legacy_particle && !detail::has_track && !detail::is_charged_basic ) decltype( auto ) operator()( Data&& value ) const { return std::forward( value ); } // Legacy particles: LHCb::Particle and LHCb::ProtoParticle template - requires( (is_legacy_particle || detail::has_track) && !detail::is_charged_basic ) + requires( (detail::is_legacy_particle || detail::has_track) && !detail::is_charged_basic ) auto operator()( Data&& d ) const { - if constexpr ( is_legacy_particle ) { - auto trk = Sel::Utils::get_track_from_particle( d ); - return ( trk ) ? Functors::Optional{ trk } : std::nullopt; + if constexpr ( detail::is_legacy_particle ) { + auto const* pp = Sel::Utils::deref_if_ptr( d ).proto(); + auto trk = pp ? pp->track() : nullptr; + return trk ? Functors::Optional{ trk } + : std::nullopt; // FIXME: wrapping a pointer in an optional is a semantic stutter } else { auto trk = Sel::Utils::deref_if_ptr( d ).track(); - return ( trk ) ? Functors::Optional{ trk } : std::nullopt; + return trk ? Functors::Optional{ trk } + : std::nullopt; // FIXME: wrapping a pointer in an optional is a semantic stutter }; } // V2 LHCb::Event::ChargedBasics template - requires( !is_legacy_particle && !detail::has_track && detail::is_charged_basic ) - auto const& operator()( Data const& d ) const { + auto operator()( Data const& d ) const -> decltype( d.tracks() ) { return d.tracks(); } }; + constexpr auto GetTrack = GetTrack_t{}; /** @brief get the protoparticle from the particle - * E.g. need while Relation tables are made from ProtoParticles + * Needed because e.g. some Relation tables are made from ProtoParticles and not Particles... */ - struct GetProtoParticle : public Function { - // for v1 const ref - auto operator()( LHCb::Particle const& d ) const { return d.proto(); } - - // for v1 pointer - auto operator()( LHCb::Particle const* p ) const { - assert( p != nullptr && "The input particle cannot be NULL." ); - return ( *this )( *p ); - } - }; + constexpr auto GetProtoParticle = GenericFunctor{ "GetProtoParticle", &LHCb::Particle::proto }; /** @brief covariance matrix for (px, py, pz) */ - struct threeMomCovMatrix : public Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::threeMomCovMatrix; - return threeMomCovMatrix( d ); - } - }; + constexpr auto threeMomCovMatrix = TrivialFunctor{ "threeMomCovMatrix", []( auto const& d ) { + using LHCb::Event::threeMomCovMatrix; + return threeMomCovMatrix( d ); + } }; /** @brief covariance matrix for (px, py, pz) x (x, y, z) * [(x,px), (x,py), (x,pz)] * [(y,px), (y,py), (y,pz)] * [(z,px), (z,py), (z,pz)] */ - struct threeMomPosCovMatrix : public Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::threeMomPosCovMatrix; - return threeMomPosCovMatrix( d ); - } - }; + constexpr auto threeMomPosCovMatrix = TrivialFunctor{ "threeMomPosCovMatrix", []( auto const& d ) { + using LHCb::Event::threeMomPosCovMatrix; + return threeMomPosCovMatrix( d ); + } }; /** @brief covariance matrix for (px, py, pz, pe) x (x, y, z) * [(x,px), (x,py), (x,pz), (x,pe)] * [(y,px), (y,py), (y,pz), (y,pe)] * [(z,px), (z,py), (z,pz), (z,pe)] */ - struct momPosCovMatrix : public Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::momPosCovMatrix; - return momPosCovMatrix( d ); - } - }; + constexpr auto momPosCovMatrix = TrivialFunctor{ "momPosCovMatrix", []( auto const& d ) { + using LHCb::Event::momPosCovMatrix; + return momPosCovMatrix( d ); + } }; /** @brief covariance matrix for (x, y, z) */ - struct posCovMatrix : public Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::posCovMatrix; - return posCovMatrix( d ); - } - }; + constexpr auto posCovMatrix = TrivialFunctor{ "posCovMatrix", []( auto const& d ) { + using LHCb::Event::posCovMatrix; + return posCovMatrix( d ); + } }; /** @brief covariance matrix for (px, py, pz, pe) */ - struct momCovMatrix : public Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::momCovMatrix; - return momCovMatrix( d ); - } - }; + constexpr auto momCovMatrix = TrivialFunctor{ "momCovMatrix", []( auto const& d ) { + using LHCb::Event::momCovMatrix; + return momCovMatrix( d ); + } }; - struct PPHasMuonInfo : Predicate { - bool operator()( LHCb::ProtoParticle const& pp ) const { return pp.muonPID(); } - bool operator()( LHCb::ProtoParticle const* pp ) const { return pp && ( *this )( *pp ); } - }; + constexpr auto PPHasMuonInfo = + TrivialPredicate{ "PPHasMuon", []( LHCb::ProtoParticle const& pp ) -> bool { return pp.muonPID(); }, + []( LHCb::ProtoParticle const* pp ) -> bool { return pp && pp->muonPID(); } }; - struct PPHasRich : Predicate { - bool operator()( LHCb::ProtoParticle const& pp ) const { return pp.richPID(); } - bool operator()( LHCb::ProtoParticle const* pp ) const { return pp && ( *this )( *pp ); } - }; + constexpr auto PPHasRich = + TrivialPredicate{ "PPHasRich", []( LHCb::ProtoParticle const& pp ) -> bool { return pp.richPID(); }, + []( LHCb::ProtoParticle const* pp ) -> bool { return pp && pp->richPID(); } }; /** * @brief Check if the "TriggerResult_t" object is TOS */ - using IsTos = detail::IsTrigCategory; + constexpr auto IsTos = TrivialPredicate{ "IsTOS", &LHCb::detail::TisTosResult_t::TOS }; /** * @brief Check if the "TriggerResult_t" object is TIS */ - using IsTis = detail::IsTrigCategory; + constexpr auto IsTis = TrivialPredicate{ "IsTIS", &LHCb::detail::TisTosResult_t::TIS }; + + /** + * @brief Check if the "TriggerResult_t" object is TUS + */ + constexpr auto IsTus = TrivialPredicate{ "IsTUS", &LHCb::detail::TisTosResult_t::TUS }; /** @brief Check if the particle is a basic particle (not composite) */ - struct IsBasicParticle : public Predicate { - template - auto operator()( Particle const& particle ) const { - return Sel::Utils::deref_if_ptr( particle ).isBasicParticle(); - } - }; + constexpr auto IsBasicParticle = TrivialPredicate{ + "IsBasicParticle", []( const auto& p ) -> decltype( p.isBasicParticle() ) { return p.isBasicParticle(); }, + []( const auto* p ) -> decltype( p->isBasicParticle() ) { return p && p->isBasicParticle(); } }; } // namespace Functors::Particle diff --git a/Phys/FunctorCore/include/Functors/Simulation.h b/Phys/FunctorCore/include/Functors/Simulation.h index f19cf5ff252216bb3effe2c86354b787708941b0..2bdf7246be55d62a6dd58b23cd3f33606c47602f 100644 --- a/Phys/FunctorCore/include/Functors/Simulation.h +++ b/Phys/FunctorCore/include/Functors/Simulation.h @@ -47,12 +47,6 @@ namespace Functors::Simulation { return check_mask( value, m_mask ); } - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, - "The functor Functors::Simulation::CheckMask can only apply to int object" ); - } - private: int m_mask; }; @@ -60,65 +54,32 @@ namespace Functors::Simulation { /** * @brief Get the particle ID object of a particle */ - struct Particle_Id_Obj final : Function { - constexpr auto name() const { return "Particle_Id_Obj"; } - - template - auto operator()( Particle const& p ) const -> decltype( Sel::Utils::deref_if_ptr( p ).particleID() ) { - return Sel::Utils::deref_if_ptr( p ).particleID(); - } - - void operator()( ... ) const { - throw GaudiException( - "Unsupported argument to Particle_Id_Obj functor -- argument does not have a `particleID()` functions", - __PRETTY_FUNCTION__, StatusCode::FAILURE ); - } - }; + constexpr auto Particle_Id_Obj = + TrivialFunctor{ "Particle_Id_Obj", []( auto const& p ) -> decltype( p.particleID() ) { return p.particleID(); }, + []( auto const& p ) -> decltype( p->particleID() ) { return p->particleID(); } }; /** @brief Particle ID of LHCb::Particle or LHCb::MCParticle. * Can be used together with F.MAP_INPUT and MC association relations table to obtain the TRUEID*/ - struct Particle_Id : public Function { - /* "name" to improve error messages. */ - constexpr auto name() const { return "Particle_Id"; } - - template - auto operator()( Particle const& p ) const { - using LHCb::Event::pid; - return pid( p ); - } - }; + constexpr auto Particle_Id = TrivialFunctor{ "Particle_Id", []( auto const& p ) { + using LHCb::Event::pid; + return pid( p ); + } }; /** * @brief return true if either LHCb::Particle or LHCb::MCParticle is hadron*/ - struct IsHadron : Predicate { - constexpr auto name() const { return "IsHadron"; } - - bool operator()( const LHCb::ParticleID& id ) const { return id.isHadron(); } - }; + constexpr auto IsHadron = TrivialPredicate{ "IsHadron", &LHCb::ParticleID::isHadron }; /** * @brief return true if either LHCb::Particle or LHCb::MCParticle is meson*/ - struct IsMeson : Predicate { - constexpr auto name() const { return "IsMeson"; } - - bool operator()( const LHCb::ParticleID& id ) const { return id.isMeson(); } - }; + constexpr auto IsMeson = TrivialPredicate{ "IsMeson", &LHCb::ParticleID::isMeson }; /** * @brief return true if either LHCb::Particle or LHCb::MCParticle is baryon*/ - struct IsBaryon : Predicate { - constexpr auto name() const { return "IsBaryon"; } - - bool operator()( const LHCb::ParticleID& id ) const { return id.isBaryon(); } - }; + constexpr auto IsBaryon = TrivialPredicate{ "IsBaryon", &LHCb::ParticleID::isBaryon }; /** * @brief return true if either LHCb::Particle or LHCb::MCParticle is lepton*/ - struct IsLepton : Predicate { - constexpr auto name() const { return "IsLepton"; } - - bool operator()( const LHCb::ParticleID& id ) const { return id.isLepton(); } - }; + constexpr auto IsLepton = TrivialPredicate{ "IsLepton", &LHCb::ParticleID::isLepton }; /** * @brief Returns if particle contains a given quark*/ @@ -141,8 +102,12 @@ namespace Functors::Simulation { } template - bool operator()( Particle const& p ) const { - return std::invoke( m_fun, Sel::Utils::deref_if_ptr( p ).particleID() ); + bool operator()( Particle const& p ) const + requires requires( Particle const& p, bool ( LHCb::ParticleID::*f )() const ) { + ( Sel::Utils::deref_if_ptr( p ).particleID().*f )(); + } + { + return ( Sel::Utils::deref_if_ptr( p ).particleID().*m_fun )(); } private: @@ -157,18 +122,7 @@ namespace Functors::Simulation { * * @see Functors::Simulation::Category */ - struct Category : public Function { - /* "name" to improve error messages. */ - static constexpr auto name() { return "Category"; } - - auto operator()( int const i ) const { return i; } - - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, - "The functor Functors::Simulation::CheckMask can only apply to int object" ); - } - }; + constexpr auto Category = TrivialFunctor{ "Category", []( int const i ) { return i; } }; namespace MC { /** @@ -176,20 +130,14 @@ namespace Functors::Simulation { * an MC Particle, which contains the bitwise information. */ - struct Property : public Function { + struct Property_t : public Function { constexpr auto name() const { return "MC::Property"; } auto operator()( const LHCb::MCProperty& mc_track_info, const LHCb::MCParticle& mc_particle ) const { - Functors::Optional result{ std::nullopt }; - if ( mc_particle.particleID().threeCharge() != 0 ) { result = mc_track_info.property( &mc_particle ); } - return result; - } - - // template - template - auto operator()( const T1& p1, const T2& p2 ) const -> decltype( ( *this )( *p1, *p2 ) ) { - return ( *this )( *p1, *p2 ); + return ( mc_particle.particleID().threeCharge() != 0 ) + ? Functors::Optional{ mc_track_info.property( &mc_particle ) } + : std::nullopt; } // template @@ -203,14 +151,8 @@ namespace Functors::Simulation { auto operator()( const T1& p1, const T2& p2 ) const -> decltype( ( *this )( *p1, p2 ) ) { return ( *this )( *p1, p2 ); } - - template - auto operator()( Data... ) const { - static_assert( - detail::always_false_v, - "The functor Functors::Simulation::MC::Property can only apply to (LHCb::MCProperty, LHCb::MCParticle)" ); - } }; + constexpr auto Property = Property_t{}; /** * @brief ChargeReconstructible, return the reconstructible category @@ -228,102 +170,72 @@ namespace Functors::Simulation { * 6 = Reconstructible as a VELO charged track * */ - struct ChargeReconstructible : public Function { - static constexpr auto name() { return "MC::ChargeReconstructible"; } - auto operator()( int property ) const { - - using Functors::detail::check_mask; - auto rec = IMCReconstructible::RecCategory::NoClassification; - - if ( property ) { - /// Acceptance - auto inAcc = ( check_mask( property, MCTrackInfo::flagMasks::maskAccT ) || - check_mask( property, MCTrackInfo::flagMasks::maskAccUT ) || - check_mask( property, MCTrackInfo::flagMasks::maskAccVelo ) ); - - /// Category - if ( inAcc ) { - if ( check_mask( property, MCTrackInfo::flagMasks::maskHasVeloAndT ) ) - rec = IMCReconstructible::RecCategory::ChargedLong; - else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasVelo ) && - check_mask( property, MCTrackInfo::flagMasks::maskHasUT ) ) - rec = IMCReconstructible::RecCategory::ChargedUpstream; - else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasT ) && - check_mask( property, MCTrackInfo::flagMasks::maskHasUT ) ) - rec = IMCReconstructible::RecCategory::ChargedDownstream; - else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasVelo ) ) - rec = IMCReconstructible::RecCategory::ChargedVelo; - else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasT ) ) - rec = IMCReconstructible::RecCategory::ChargedTtrack; - } else - rec = IMCReconstructible::RecCategory::OutsideAcceptance; - } - - return rec; - } - - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, - "The functor Functors::Simulation::MC::ChargeReconstructible can only apply to int object" ); - } - }; + constexpr auto ChargeReconstructible = + TrivialFunctor{ "MC::ChargeReconstructible", []( int property ) { + using Functors::detail::check_mask; + auto rec = IMCReconstructible::RecCategory::NoClassification; + if ( property ) { + /// Acceptance + auto inAcc = ( check_mask( property, MCTrackInfo::flagMasks::maskAccT ) || + check_mask( property, MCTrackInfo::flagMasks::maskAccUT ) || + check_mask( property, MCTrackInfo::flagMasks::maskAccVelo ) ); + + /// Category + if ( inAcc ) { + if ( check_mask( property, MCTrackInfo::flagMasks::maskHasVeloAndT ) ) + rec = IMCReconstructible::RecCategory::ChargedLong; + else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasVelo ) && + check_mask( property, MCTrackInfo::flagMasks::maskHasUT ) ) + rec = IMCReconstructible::RecCategory::ChargedUpstream; + else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasT ) && + check_mask( property, MCTrackInfo::flagMasks::maskHasUT ) ) + rec = IMCReconstructible::RecCategory::ChargedDownstream; + else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasVelo ) ) + rec = IMCReconstructible::RecCategory::ChargedVelo; + else if ( check_mask( property, MCTrackInfo::flagMasks::maskHasT ) ) + rec = IMCReconstructible::RecCategory::ChargedTtrack; + } else + rec = IMCReconstructible::RecCategory::OutsideAcceptance; + } + return rec; + } }; /** * @brief functor accessing the parent MCParticle * @note The grandparent or ancestors can be accessed by chainning more Parent functors. */ - struct Mother : public Function { - - constexpr auto name() const { return "MC::Mother"; } - - auto operator()( const LHCb::MCParticle& mcp ) const { - auto mother = mcp.mother(); - return mother ? Functors::Optional{ mother } : std::nullopt; - } - - auto operator()( const LHCb::MCVertex& mcv ) const { - auto mother = mcv.mother(); - return mother ? Functors::Optional{ mother } : std::nullopt; - } - - template - auto operator()( const T* p ) const { - return Functors::and_then( p, *this ); - } - - template - auto operator()( Data... ) const { - static_assert( - detail::always_false_v, - "The functor Functors::Simulation::MC::Mother can only apply to LHCb::MCParticle or LHCb::MCVertex" ); - } - }; + constexpr auto Mother = GenericFunctor{ + "MC::Mother", + []( const LHCb::MCParticle& mcp ) { + auto mother = mcp.mother(); + return mother ? Functors::Optional{ mother } : std::nullopt; // FIXME: optional pointer is a semantic stutter + }, + []( const LHCb::MCVertex& mcv ) { + auto mother = mcv.mother(); + return mother ? Functors::Optional{ mother } : std::nullopt; // FIXME: optional pointer is a semantic stutter + } }; /** * @brief functor accessing the origin vertex of a MCParticle * @note this functor does currently the same as Track::ReferencePoint as the referencePoint * of a MCParticle is its originVertex */ - inline constexpr auto OriginVertex = - Functors::MemberFn{ &LHCb::MCParticle::originVertex, "MCParticle::originVertex" }; + constexpr auto OriginVertex = + Functors::GenericFunctor{ "MCParticle::originVertex", &LHCb::MCParticle::originVertex }; /** * @brief functor accessing the primary vertex of a MCParticle */ - inline constexpr auto PrimaryVertex = - Functors::MemberFn{ &LHCb::MCParticle::primaryVertex, "MCParticle::primaryVertex" }; + constexpr auto PrimaryVertex = + Functors::GenericFunctor{ "MCParticle::primaryVertex", &LHCb::MCParticle::primaryVertex }; /** * @brief functor accessing the true tagging information of a MCParticle */ - struct OriginFlag : public Function { - constexpr auto name() const { return "MC::OriginFlag"; } - - auto operator()( const LHCb::MCParticle* tMC, const LHCb::MCParticle* bMC ) const { - return LHCb::FlavourTagging::originType( *bMC, *tMC ); - } - }; + constexpr auto OriginFlag = + TrivialFunctor{ "MC::OriginFlag", []( const LHCb::MCParticle* tMC, const LHCb::MCParticle* bMC ) { + return LHCb::FlavourTagging::originType( *bMC, *tMC ); + } }; /** * @brief This functor return the first longlived ancestor of a MCParticle @@ -350,18 +262,12 @@ namespace Functors::Simulation { if ( pProp && pProp->lifetime() > m_minLifetime ) break; parent = parent->mother(); } - return parent ? Functors::Optional{ parent } : std::nullopt; + return parent ? Functors::Optional{ parent } + : std::nullopt; // FIXME: wrapping a pointer in an optional is a semantic stutter } auto operator()( const LHCb::MCParticle* p ) const { return Functors::and_then( p, *this ); } - template - auto operator()( Data... ) const { - static_assert( - detail::always_false_v, - "The functor Functors::Simulation::MC::FirstLongLivedAncestor can only apply to LHCb::MCParticle" ); - } - private: const double m_minLifetime; std::optional> m_ppSvc; @@ -370,27 +276,15 @@ namespace Functors::Simulation { /** * @brief functor accessing the lifetime of a MCParticle */ - struct LifeTime : public Function { - constexpr auto name() const { return "MC::LifeTime"; } - - Functors::Optional operator()( const LHCb::MCParticle& mcp ) const { - const auto* end_vertex = mcp.goodEndVertex(); - const auto* origin_vertex = mcp.originVertex(); - if ( !end_vertex || !origin_vertex ) return std::nullopt; - - const auto trueDist = end_vertex->position() - origin_vertex->position(); - const auto trueP = mcp.momentum(); - return ( trueP.M() * trueDist.Dot( trueP.Vect() ) / trueP.Vect().mag2() ) / Gaudi::Units::c_light; - } - - auto operator()( const LHCb::MCParticle* p ) const { return Functors::and_then( p, *this ); } - - template - auto operator()( Data... ) const { - static_assert( detail::always_false_v, - "The functor Functors::Simulation::MC::LifeTime can only apply to LHCb::MCParticle" ); - } - }; + constexpr auto LifeTime = GenericFunctor{ + "MC::LifeTime", []( const LHCb::MCParticle& mcp ) -> Functors::Optional { + const auto* end_vertex = mcp.goodEndVertex(); + const auto* origin_vertex = mcp.originVertex(); + if ( !end_vertex || !origin_vertex ) return std::nullopt; + const auto trueDist = end_vertex->position() - origin_vertex->position(); + const auto trueP = mcp.momentum(); + return ( trueP.M() * trueDist.Dot( trueP.Vect() ) / trueP.Vect().mag2() ) / Gaudi::Units::c_light; + } }; } // namespace MC @@ -398,49 +292,49 @@ namespace Functors::Simulation { /** * @brief get all primary vertices from the MCHeader */ - inline constexpr auto AllPVs = Functors::MemberFn{ &LHCb::MCHeader::primaryVertices, "MCHeader::AllPVs" }; + constexpr auto AllPVs = Functors::TrivialFunctor{ "MCHeader::AllPVs", &LHCb::MCHeader::primaryVertices }; /** * @brief get the event time of the MCHeader */ - inline constexpr auto EvtTime = Functors::MemberFn{ &LHCb::MCHeader::evtTime, "MCHeader::EvtTime" }; + constexpr auto EvtTime = Functors::TrivialFunctor{ "MCHeader::EvtTime", &LHCb::MCHeader::evtTime }; /** * @brief get the event number of the MCHeader */ - inline constexpr auto EvtNumber = Functors::MemberFn{ &LHCb::MCHeader::evtNumber, "MCHeader::EvtNumber" }; + constexpr auto EvtNumber = Functors::TrivialFunctor{ "MCHeader::EvtNumber", &LHCb::MCHeader::evtNumber }; /** * @brief get the run number of the MCHeader */ - inline constexpr auto RunNumber = Functors::MemberFn{ &LHCb::MCHeader::runNumber, "MCHeader::RunNumber" }; + constexpr auto RunNumber = Functors::TrivialFunctor{ "MCHeader::RunNumber", &LHCb::MCHeader::runNumber }; } // namespace MCHeader namespace MCVertex { /** * @brief get the time of a MCVertex. */ - inline constexpr auto Time = Functors::MemberFn{ &LHCb::MCVertex::time, "MCVertex::Time" }; + constexpr auto Time = Functors::GenericFunctor{ "MCVertex::Time", &LHCb::MCVertex::time }; /** * @brief get the type of a MCVertex. */ - inline constexpr auto Type = Functors::MemberFn{ &LHCb::MCVertex::type, "MCVertex::Type" }; + constexpr auto Type = Functors::GenericFunctor{ "MCVertex::Type", &LHCb::MCVertex::type }; /** * @brief returns true if the MCVertex is a primary vertex. */ - inline constexpr auto IsPrimary = Functors::MemberFn{ &LHCb::MCVertex::isPrimary, "MCVertex::IsPrimary" }; + constexpr auto IsPrimary = Functors::GenericFunctor{ "MCVertex::IsPrimary", &LHCb::MCVertex::isPrimary }; /** * @brief returns true if the MCVertex is a decay vertex. */ - inline constexpr auto IsDecay = Functors::MemberFn{ &LHCb::MCVertex::isDecay, "MCVertex::IsDecay" }; + constexpr auto IsDecay = Functors::GenericFunctor{ "MCVertex::IsDecay", &LHCb::MCVertex::isDecay }; /** * @brief functor accessing the decay products of a MCVertex */ - inline constexpr auto Products = Functors::MemberFn{ &LHCb::MCVertex::products, "MCVertex::Products" }; + constexpr auto Products = Functors::GenericFunctor{ "MCVertex::Products", &LHCb::MCVertex::products }; } // namespace MCVertex diff --git a/Phys/FunctorCore/include/Functors/TES.h b/Phys/FunctorCore/include/Functors/TES.h index 8e80eca713090030f704064a62cc270fa851a4d4..700993d45617e61da08bab50b80b215477ba13ec 100644 --- a/Phys/FunctorCore/include/Functors/TES.h +++ b/Phys/FunctorCore/include/Functors/TES.h @@ -29,30 +29,17 @@ #include namespace Functors::detail { - struct SizeOf : public Function { - /** Make some error messages more informative. */ - static constexpr auto name() { return "TES::SizeOf"; } - - /** Try and deduce the size of the given object. - * - * @todo include an if constexpr check that the DataObject type, which may - * have been explicitly specified as some other type, has a .size() - * method and just call it if so. - */ - template - int operator()( DataObject const& obj ) const { - if constexpr ( Sel::Utils::has_size_v ) { - return obj.size(); - } else { - auto input_ptr = &obj; // so we don't have to catch exceptions from dynamic_cast - auto container = dynamic_cast( input_ptr ); - if ( container ) { return container->numberOfObjects(); } - auto anydata = dynamic_cast( input_ptr ); - if ( anydata ) { return anydata->size().value_or( -1 ); } - return -1; - } - } - }; + constexpr auto SizeOf = + TrivialFunctor{ "TES::SizeOf", []( const auto& d ) -> decltype( d.size() ) { return d.size(); }, + []( const DataObject& d ) -> int { + if ( auto container = dynamic_cast( &d ); container ) { + return container->numberOfObjects(); + } + if ( auto anydata = dynamic_cast( &d ); anydata ) { + return anydata->size().value_or( -1 ); + } + return -1; + } }; template class DecReportsCachedFilter { @@ -98,27 +85,27 @@ namespace Functors::detail { */ namespace Functors::TES { /** @brief Get run number from ODIN */ - inline constexpr auto RunNumber = Functors::MemberFn{ &LHCb::ODIN::runNumber, "Odin::runNumber" }; + constexpr auto RunNumber = Functors::TrivialFunctor{ "Odin::runNumber", &LHCb::ODIN::runNumber }; /** @brief Get event number from ODIN */ - inline constexpr auto EventNumber = Functors::MemberFn{ &LHCb::ODIN::eventNumber, "Odin::eventNumber" }; + constexpr auto EventNumber = Functors::TrivialFunctor{ "Odin::eventNumber", &LHCb::ODIN::eventNumber }; /** @brief Get event type from ODIN */ - inline constexpr auto EventType = Functors::MemberFn{ &LHCb::ODIN::eventType, "Odin::eventType" }; + constexpr auto EventType = Functors::TrivialFunctor{ "Odin::eventType", &LHCb::ODIN::eventType }; /** @brief Get the bunch crossing ID from ODIN. */ - inline constexpr auto BunchCrossingID = Functors::MemberFn{ &LHCb::ODIN::bunchId, "Odin::bunchId" }; + constexpr auto BunchCrossingID = Functors::TrivialFunctor{ "Odin::bunchId", &LHCb::ODIN::bunchId }; /** @brief Get the bunch crossing type from ODIN. */ - inline constexpr auto BunchCrossingType = - Functors::MemberFn{ &LHCb::ODIN::bunchCrossingType, "Odin::bunchCrossingType" }; + constexpr auto BunchCrossingType = + Functors::TrivialFunctor{ "Odin::bunchCrossingType", &LHCb::ODIN::bunchCrossingType }; /** @brief Get the Odin TCK from ODIN. */ - inline constexpr auto OdinTCK = - Functors::MemberFn{ &LHCb::ODIN::triggerConfigurationKey, "Odin::triggerConfigurationKey" }; + constexpr auto OdinTCK = + Functors::TrivialFunctor{ "Odin::triggerConfigurationKey", &LHCb::ODIN::triggerConfigurationKey }; /** @brief Get the GPS time from ODIN. */ - inline constexpr auto GpsTime = Functors::MemberFn{ &LHCb::ODIN::gpsTime, "Odin::gpsTime" }; + constexpr auto GpsTime = Functors::TrivialFunctor{ "Odin::gpsTime", &LHCb::ODIN::gpsTime }; /** @brief Get information from RecSummary object. */ struct RecSummaryInfo : public Function { @@ -140,15 +127,7 @@ namespace Functors::TES { }; /** @brief Get the trigger configuration key (TCK) from the DecReports*/ - struct SelectionTCK : public Function { - /** Make some error messages more informative. */ - static constexpr auto name() { return "TES::SelectionTCK"; } - - template - auto operator()( DecReports const& dec ) const { - return dec.configuredTCK(); - } - }; + constexpr auto SelectionTCK = TrivialFunctor{ "TES::SelectionTCK", &LHCb::HltDecReports::configuredTCK }; /** @brief Get a dictionary containing decision of list of selections lines from DecReports. */ class SelectionDecision : public Predicate { @@ -213,19 +192,18 @@ namespace Functors::TES { /** @brief Key of the KeyedObject (i.e. LHCb::Particle or LHCb::MCParticle). * Could be used together with F.MAP_INPUT and MC association relations table to get the TRUEKEY from MC association*/ - struct ObjectKey : public Function { - /* "name" to improve error messages. */ - constexpr auto name() const { return "ObjectKey"; } - - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).key(); - } - }; + // FIXME: use GenericFunctor, and deal with the fallout due to returning optional in case of a pointer argument + constexpr auto ObjectKey = + TrivialFunctor{ "ObjectKey", []( auto const& d ) -> decltype( d.key() ) { return d.key(); }, + []( auto const& d ) -> decltype( d->key() ) { return d->key(); } }; /* @brief Returns the number of hits in the muon system station, region, and quarter specified */ - struct NHitsInMuon : public Function { + class NHitsInMuon final : public Function { + unsigned int ref_station; + unsigned int ref_region; + + public: NHitsInMuon( unsigned int station, unsigned int region ) : ref_station( station ), ref_region( region ) { assert( station < 4 && region < 4 && "Station or region not suppported." ); } @@ -233,12 +211,8 @@ namespace Functors::TES { int operator()( LHCb::Pr::Hits const& muon_hits ) const { auto const& hits = muon_hits.hits( ref_station ); return std::count_if( hits.begin(), hits.end(), - [this]( const auto& hit ) { return hit.region() == this->ref_region; } ); + [r = ref_region]( const auto& hit ) { return hit.region() == r; } ); } - - protected: - unsigned int ref_station; - unsigned int ref_region; }; } // namespace Functors::TES diff --git a/Phys/FunctorCore/include/Functors/TrackLike.h b/Phys/FunctorCore/include/Functors/TrackLike.h index 59fbe2a8d52c08f03ff40ad8c445b39ee5a4e6a1..4fafed823457ccb11a3e8224e8bff9989525d750 100644 --- a/Phys/FunctorCore/include/Functors/TrackLike.h +++ b/Phys/FunctorCore/include/Functors/TrackLike.h @@ -23,10 +23,8 @@ #include "GaudiKernel/GaudiException.h" #include "GaudiKernel/System.h" #include "GaudiKernel/Vector4DTypes.h" -#include "GaudiKernel/detected.h" #include "Kernel/HitPattern.h" #include "MCInterfaces/IMCReconstructed.h" -#include "SelKernel/ParticleAccessors.h" #include "SelKernel/Utilities.h" #include "SelKernel/VertexRelation.h" #include "TrackInterfaces/ITrackExtrapolator.h" @@ -48,66 +46,19 @@ namespace Functors::Track::detail { template - constexpr bool is_proto_particle = - std::is_same_v>>>; - + auto chi2PerDoF( T const& x ) -> decltype( x.chi2PerDof() ) { + return x.chi2PerDof(); + } template - constexpr bool is_legacy_track = std::is_same_v>>>; + auto chi2PerDoF( T const& x ) -> decltype( x.chi2() / x.nDoF() ) { + return x.chi2() / x.nDoF(); + } /* * Helper for ProbNN */ enum struct Pid { electron, muon, pion, kaon, proton, deuteron, ghost }; - /** @brief helpers for probNN - */ - template - struct has_probNN { - template - using check_for_probNN_id = decltype( std::declval().template probNN() ); - template - static constexpr bool value = Gaudi::cpp17::is_detected_v; - }; - - template - constexpr bool has_probNN_v = has_probNN::template value; - - template - constexpr auto probNN( const T& d ) { - if constexpr ( is_legacy_particle ) { - auto const* pp = Sel::Utils::deref_if_ptr( d ).proto(); - return ( !pp || !pp->globalChargedPID() ) ? probNN( *( pp->globalChargedPID() ) ) : std::nullopt; - } else { - Functors::Optional output = std::nullopt; - switch ( pid ) { - case Pid::electron: - output = d.ProbNNe(); - break; - case Pid::muon: - output = d.ProbNNmu(); - break; - case Pid::pion: - output = d.ProbNNpi(); - break; - case Pid::kaon: - output = d.ProbNNk(); - break; - case Pid::proton: - output = d.ProbNNp(); - break; - case Pid::deuteron: - output = d.ProbNNd(); - break; - case Pid::ghost: - output = d.ProbNNghost(); - break; - default: - throw std::domain_error{ "impossible PID type" }; - } - return output.value() != LHCb::GlobalChargedPID::DefaultProbNN ? output : std::nullopt; - } - } - template [[gnu::always_inline]] inline auto impactParameterSquared( StatePos_t const& state_pos, StateDir_t const& state_dir, VertexPos_t const& vertex ) { @@ -222,12 +173,8 @@ namespace Functors::Track { /** * @brief Retrieve const Container with pointers to all the states */ - struct States : public Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).states(); - } - }; + constexpr auto States = + GenericFunctor{ "States", []( auto const& d ) -> decltype( d.states() ) { return d.states(); } }; /** * @brief Access state on v1 or v3 track by location. @@ -238,15 +185,20 @@ namespace Functors::Track { static constexpr auto name() { return "StateAt"; } StateAt( LHCb::Event::Enum::State::Location location ) : m_loc{ location } {} - StateAt( std::string location ) { parse( m_loc, location ).ignore(); } + StateAt( std::string location ) { parse( m_loc, location ).orThrow( "Unknown Location", __PRETTY_FUNCTION__ ); } auto operator()( const LHCb::Event::v1::Track& track ) const { const auto* state = track.stateAt( m_loc ); - return state ? Functors::Optional{ *state } : std::nullopt; + return state ? Functors::Optional{ *state } : std::nullopt; // FIXME: an optional pointer is a semantic stutter } template - auto operator()( const Track& track ) const { + auto operator()( const Track& track ) const + requires requires( const Track& t, LHCb::Event::Enum::State::Location l ) { + t.has_state( l ); + t.state( l ); + } + { return track.has_state( m_loc ) ? Functors::Optional{ track.state( m_loc ) } : std::nullopt; } @@ -260,118 +212,86 @@ namespace Functors::Track { * @brief Access LHCbIDs of track. * */ - struct LHCbIDs : public Function { - template - auto operator()( Data const& d ) const -> decltype( auto ) { - return Sel::Utils::deref_if_ptr( d ).lhcbIDs(); - } - }; + constexpr auto LHCbIDs = + GenericFunctor{ "LHCbIDs", []( auto const& d ) -> decltype( d.lhcbIDs() ) { return d.lhcbIDs(); } }; /** * @brief Access HitPattern of LHCbIDs. * */ - struct HitPattern : Function { - template - auto operator()( Data const& d ) const { - return LHCb::HitPattern( d ); - } - }; + constexpr auto HitPattern = TrivialFunctor{ "HitPattern", []( auto const& d ) { return LHCb::HitPattern( d ); } }; /** * @brief Access number of A-side VP hits on HitPattern. * */ constexpr auto nVPHitsA = - chain( Functors::MemberFn{ &LHCb::HitPattern::numVeloA, "HitPattern::numVeloA" }, HitPattern{}, LHCbIDs{} ); + chain( Functors::TrivialFunctor{ "HitPattern::numVeloA", &LHCb::HitPattern::numVeloA }, HitPattern, LHCbIDs ); /** * @brief Access number of c-side VP hits on HitPattern. * */ constexpr auto nVPHitsC = - chain( Functors::MemberFn{ &LHCb::HitPattern::numVeloC, "HitPattern::numVeloC" }, HitPattern{}, LHCbIDs{} ); + chain( Functors::TrivialFunctor{ "HitPattern::numVeloC", &LHCb::HitPattern::numVeloC }, HitPattern, LHCbIDs ); /** * @brief Acces number of overlap VP hits on HitPattern. * */ - constexpr auto nVPOverlap = - chain( Functors::MemberFn{ &LHCb::HitPattern::numVeloStationsOverlap, "HitPattern::numVeloStationsOverlap" }, - HitPattern{}, LHCbIDs{} ); + constexpr auto nVPOverlap = chain( + Functors::TrivialFunctor{ "HitPattern::numVeloStationsOverlap", &LHCb::HitPattern::numVeloStationsOverlap }, + HitPattern, LHCbIDs ); /** * @brief referencePoint, as defined by the referencePoint() accessor. * @note referencePoint is the position at which the object has its threeMomentum * defined */ - struct ReferencePoint : Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::referencePoint; - return referencePoint( d ); - } - }; + constexpr auto ReferencePoint = TrivialFunctor{ "ReferencePoint", []( auto const& d ) { + using LHCb::Event::referencePoint; + return referencePoint( d ); + } }; /** * @brief The TrackState is the first state on the track. * */ - struct TrackState : Function { - template - auto operator()( Data const& track ) const { - using LHCb::Event::trackState; - return trackState( track ); - } - }; + constexpr auto TrackState = TrivialFunctor{ "TrackState", []( auto const& track ) { + using LHCb::Event::trackState; + return trackState( track ); + } }; /** @brief slopes vector, as defined by the slopes() accessor. */ - struct Slopes : Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::slopes; - return slopes( d ); - } - }; + constexpr auto Slopes = TrivialFunctor{ "Slopes", []( auto const& d ) { + using LHCb::Event::slopes; + return slopes( d ); + } }; /** @brief FourMomentum vector e.g. (px, py, pz, E) */ - struct FourMomentum : public Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::fourMomentum; - return fourMomentum( d ); - } - }; + constexpr auto FourMomentum = TrivialFunctor{ "FourMomentum", []( auto const& d ) { + using LHCb::Event::fourMomentum; + return fourMomentum( d ); + } }; /** @brief ThreeMomentum vector e.g. (px, py, pz) */ - struct ThreeMomentum : Function { - template - auto operator()( Data const& d ) const { - using LHCb::Event::threeMomentum; - return threeMomentum( d ); - } - }; + constexpr auto ThreeMomentum = TrivialFunctor{ "ThreeMomentum", []( auto const& d ) { + using LHCb::Event::threeMomentum; + return threeMomentum( d ); + } }; /** @brief Return covariance matrix of input */ - struct Covariance : Function { - template - decltype( auto ) operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).covariance(); - } - }; + constexpr auto Covariance = + GenericFunctor{ "Covariance", []( auto const& d ) -> decltype( d.covariance() ) { return d.covariance(); } }; /** @brief Charge, as defined by the charge() accessor. */ - struct Charge : Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).charge(); - } - }; + constexpr auto Charge = + GenericFunctor{ "Charge", []( auto const& d ) -> decltype( d.charge() ) { return d.charge(); } }; /** @brief HasBremAdded, as defined by the HasBremAdded accessor. */ @@ -419,12 +339,7 @@ namespace Functors::Track { /** @brief Number of degrees of freedom, as defined by the nDoF accessor. */ - struct nDoF : public Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).nDoF(); - } - }; + constexpr auto nDoF = GenericFunctor{ "nDoF", []( auto const& d ) -> decltype( d.nDoF() ) { return d.nDoF(); } }; /** @brief Get tracks from vertex fit */ @@ -453,21 +368,16 @@ namespace Functors::Track { * accessor is used. If a track is not present but a vertex is the vertex's * accessor is used. */ - struct Chi2PerDoF : public Function { - template - auto operator()( Data&& d ) const { - if constexpr ( is_legacy_particle ) { - auto pp = Sel::Utils::deref_if_ptr( d ).proto(); - auto trk = pp ? pp->track() : nullptr; - auto ev = Sel::Utils::deref_if_ptr( d ).endVertex(); - return trk ? ( Functors::Optional{ Sel::get::chi2PerDoF( Sel::Utils::deref_if_ptr( trk ) ) } ) - : ( ev ? Functors::Optional{ Sel::get::chi2PerDoF( Sel::Utils::deref_if_ptr( ev ) ) } - : std::nullopt ); - } else { - return Sel::get::chi2PerDoF( Sel::Utils::deref_if_ptr( d ) ); - } - } - }; + constexpr auto Chi2PerDoF = GenericFunctor{ + "Chi2PerDoF", []( auto const& d ) -> decltype( detail::chi2PerDoF( d ) ) { return detail::chi2PerDoF( d ); }, + []( LHCb::Particle const& d ) { + auto pp = d.proto(); + auto trk = ( pp ? pp->track() : nullptr ); + auto ev = d.endVertex(); + return trk ? Functors::Optional{ detail::chi2PerDoF( *trk ) } + : ev ? Functors::Optional{ detail::chi2PerDoF( *ev ) } + : std::nullopt; + } }; /** @brief chi^2, as defined by the chi2 accessor. * @@ -475,42 +385,26 @@ namespace Functors::Track { * accessor is used. If a track is not present but a vertex is the vertex's * accessor is used. */ - struct Chi2 : public Function { - template - auto operator()( Data&& d ) const { - if constexpr ( is_legacy_particle ) { - auto pp = Sel::Utils::deref_if_ptr( d ).proto(); - auto trk = pp ? pp->track() : nullptr; - auto ev = Sel::Utils::deref_if_ptr( d ).endVertex(); - return trk ? Functors::Optional{ Sel::Utils::deref_if_ptr( trk ).chi2() } - : ( ev ? Functors::Optional{ Sel::Utils::deref_if_ptr( ev ).chi2() } : std::nullopt ); - } else { - return Sel::Utils::deref_if_ptr( d ).chi2(); - } - } - }; + constexpr auto Chi2 = GenericFunctor{ + "Chi2", + []( LHCb::Particle const& d ) { + auto pp = d.proto(); + auto trk = ( pp ) ? pp->track() : nullptr; + auto ev = d.endVertex(); + return trk ? Functors::Optional{ trk->chi2() } : ev ? Functors::Optional{ ev->chi2() } : std::nullopt; + }, + []( auto const& d ) -> decltype( d.chi2() ) { return d.chi2(); } }; /** @brief q/p, as defined by the qOverP accessor. */ - struct QoverP : public Function { - template - auto operator()( Data const& d ) const { - if constexpr ( detail::is_legacy_track ) { - return Sel::Utils::deref_if_ptr( d ).firstState().qOverP(); - } else { - return Sel::Utils::deref_if_ptr( d ).qOverP(); - } - } - }; + constexpr auto QoverP = GenericFunctor{ + "QoverP", []( const auto& t ) -> decltype( t.firstState().qOverP() ) { return t.firstState().qOverP(); }, + []( const auto& t ) -> decltype( t.qOverP() ) { return t.qOverP(); } }; /** @brief Ghost probability, as defined by the ghostProbability accessor. */ - struct GhostProbability : public Function { - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).ghostProbability(); - } - }; + constexpr auto GhostProbability = GenericFunctor{ + "GhostProbability", []( auto const& d ) -> decltype( d.ghostProbability() ) { return d.ghostProbability(); } }; class CombDLL : public Function { detail::Pid m_pid; @@ -519,220 +413,202 @@ namespace Functors::Track { constexpr CombDLL( detail::Pid pid ) : m_pid{ pid } {} template - auto operator()( T const& d ) const { - if constexpr ( is_legacy_particle ) { - return Functors::and_then( Sel::Utils::deref_if_ptr( d ).proto(), *this ); - } else if constexpr ( detail::is_proto_particle ) { - return Functors::and_then( Sel::Utils::deref_if_ptr( d ).globalChargedPID(), *this ); - } else { - Functors::Optional dll = std::nullopt; + auto operator()( const T& d ) const -> decltype( d.CombDLLe() ) { + switch ( m_pid ) { + case detail::Pid::electron: + return d.CombDLLe(); + case detail::Pid::muon: + return d.CombDLLmu(); + case detail::Pid::pion: + return d.CombDLLpi(); + case detail::Pid::kaon: + return d.CombDLLk(); + case detail::Pid::proton: + return d.CombDLLp(); + case detail::Pid::deuteron: + return d.CombDLLd(); + default: + throw std::domain_error{ "impossible PID type" }; + } + __builtin_unreachable(); + } + + template + auto operator()( const T* data ) const -> decltype( Functors::and_then( data, *this ) ) { + return Functors::and_then( data, *this ); + } + auto operator()( const LHCb::ProtoParticle& pp ) const { + return Functors::and_then( pp.globalChargedPID(), *this ); + } + auto operator()( const LHCb::Particle& p ) const { return Functors::and_then( p.proto(), *this ); } + }; + + /** @brief PIDmu, PIDp, PIDe, PIDk, PIDpi, as defined by the corresponding CombDLL variable + */ + constexpr auto PIDmu = CombDLL{ detail::Pid::muon }; + constexpr auto PIDp = CombDLL{ detail::Pid::proton }; + constexpr auto PIDe = CombDLL{ detail::Pid::electron }; + constexpr auto PIDk = CombDLL{ detail::Pid::kaon }; + constexpr auto PIDpi = CombDLL{ detail::Pid::pion }; + + /** @brief ProbNN definition + */ + class ProbNN : public Function { + detail::Pid m_pid; + + public: + constexpr ProbNN( detail::Pid pid ) : m_pid{ pid } {} + + auto operator()( const LHCb::GlobalChargedPID& d ) const { + float prb = [&] { switch ( m_pid ) { case detail::Pid::electron: - dll = d.CombDLLe(); - break; + return d.ProbNNe(); case detail::Pid::muon: - dll = d.CombDLLmu(); - break; + return d.ProbNNmu(); case detail::Pid::pion: - dll = d.CombDLLpi(); - break; + return d.ProbNNpi(); case detail::Pid::kaon: - dll = d.CombDLLk(); - break; + return d.ProbNNk(); case detail::Pid::proton: - dll = d.CombDLLp(); - break; + return d.ProbNNp(); case detail::Pid::deuteron: - dll = d.CombDLLd(); - break; - default: - throw std::domain_error{ "impossible PID type" }; + return d.ProbNNd(); + case detail::Pid::ghost: + return d.ProbNNghost(); } - return dll; - } + __builtin_unreachable(); + }(); + return prb != LHCb::GlobalChargedPID::DefaultProbNN ? Functors::Optional{ prb } : std::nullopt; } - }; - - /** @brief PIDmu, PIDp, PIDe, PIDk, PIDpi, as defined by the corresponding CombDLL variable - */ - inline constexpr auto PIDmu = CombDLL{ detail::Pid::muon }; - inline constexpr auto PIDp = CombDLL{ detail::Pid::proton }; - inline constexpr auto PIDe = CombDLL{ detail::Pid::electron }; - inline constexpr auto PIDk = CombDLL{ detail::Pid::kaon }; - inline constexpr auto PIDpi = CombDLL{ detail::Pid::pion }; - /** @brief ProbNN templated definition - */ - template - struct ProbNN : public Function { template - auto operator()( const T& d ) const { - if constexpr ( detail::has_probNN_v>>> ) { - return Sel::Utils::deref_if_ptr( d ).template probNN(); - } else if constexpr ( Functors::detail::has_proto_v>>> ) { - return Functors::and_then( Sel::Utils::deref_if_ptr( d ).proto(), *this ); - } else if constexpr ( detail::is_proto_particle ) { - auto gpid = Sel::Utils::deref_if_ptr( d ).globalChargedPID(); - return gpid ? detail::probNN( *gpid ) : std::nullopt; - } else { - throw GaudiException{ "The type T neither has a `proto()` member function nor a `probNN`() member function " - "-- sorry, not supported", - "Functors::Track::ProbNN::operator()", StatusCode::FAILURE }; + auto operator()( const T& d ) const -> decltype( d.template probNN() ) { + switch ( m_pid ) { + case detail::Pid::electron: + return d.template probNN(); + case detail::Pid::muon: + return d.template probNN(); + case detail::Pid::pion: + return d.template probNN(); + case detail::Pid::kaon: + return d.template probNN(); + case detail::Pid::proton: + return d.template probNN(); + case detail::Pid::deuteron: + return d.template probNN(); + case detail::Pid::ghost: + return d.template probNN(); + default: + throw std::domain_error{ "impossible PID type" }; } + __builtin_unreachable(); + } + + template + auto operator()( const T* data ) const -> decltype( Functors::and_then( data, *this ) ) { + return Functors::and_then( data, *this ); + } + auto operator()( const LHCb::Particle& p ) const { + return Functors::and_then( p.proto(), + static_cast( + &LHCb::ProtoParticle::globalChargedPID ), + *this ); } }; /** @brief The explicit definition for the probNN quantities - * the interpreter doesn't like that. See - * https://gitlab.cern.ch/lhcb/Rec/-/merge_requests/2471#note_4863872 - * - * constexpr auto PROBNN_D = ProbNN{}; - * constexpr auto PROBNN_E = ProbNN{}; - * constexpr auto PROBNN_GHOST = ProbNN{}; - * constexpr auto PROBNN_K = ProbNN{}; - * constexpr auto PROBNN_MU = ProbNN{}; - * constexpr auto PROBNN_PI = ProbNN{}; - * constexpr auto PROBNN_P = ProbNN{}; - */ - /** @brief The explicit definition for the probNN quantities - * Warning: these are types, so you need a {} to get an instance. */ - using PROBNN_D_t = ProbNN; - using PROBNN_E_t = ProbNN; - using PROBNN_GHOST_t = ProbNN; - using PROBNN_K_t = ProbNN; - using PROBNN_MU_t = ProbNN; - using PROBNN_PI_t = ProbNN; - using PROBNN_P_t = ProbNN; + constexpr auto PROBNN_D = ProbNN{ detail::Pid::deuteron }; + constexpr auto PROBNN_E = ProbNN{ detail::Pid::electron }; + constexpr auto PROBNN_GHOST = ProbNN{ detail::Pid::ghost }; + constexpr auto PROBNN_K = ProbNN{ detail::Pid::kaon }; + constexpr auto PROBNN_MU = ProbNN{ detail::Pid::muon }; + constexpr auto PROBNN_PI = ProbNN{ detail::Pid::pion }; + constexpr auto PROBNN_P = ProbNN{ detail::Pid::proton }; /** @brief nHits, as defined by the nHits accessor. */ - struct nHits : public Function { - static constexpr auto name() { return "nHits"; } - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).nHits(); - } - }; + constexpr auto nHits = GenericFunctor{ "nHits", []( const auto& d ) -> decltype( d.nHits() ) { return d.nHits(); } }; /** @brief number of VP hits */ - struct nVPHits : public Function { - static constexpr auto name() { return "nVPHits"; } - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).nVPHits(); - } - }; + constexpr auto nVPHits = + GenericFunctor{ "nVPHits", []( const auto& d ) -> decltype( d.nHits() ) { return d.nVPHits(); } }; /** @brief number of UT hits */ - struct nUTHits : public Function { - static constexpr auto name() { return "nUTHits"; } - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).nUTHits(); - } - }; + constexpr auto nUTHits = + GenericFunctor{ "nUTHits", []( const auto& d ) -> decltype( d.nUTHits() ) { return d.nUTHits(); } }; /** @brief number of FT hits */ - struct nFTHits : public Function { - static constexpr auto name() { return "nFTHits"; } - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).nFTHits(); - } - }; + constexpr auto nFTHits = + GenericFunctor{ "nFTHits", []( const auto& d ) -> decltype( d.nFTHits() ) { return d.nFTHits(); } }; /** @brief Track history */ - struct History : public Function { - static constexpr auto name() { return "History"; } - template - auto operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).history(); - } - }; + constexpr auto History = + GenericFunctor{ "History", []( const auto& d ) -> decltype( d.history() ) { return d.history(); } }; /** @brief Track flag */ - struct Flag : public Function { - static constexpr auto name() { return "Flag"; } - template - LHCb::Event::Enum::Track::Flag operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).flag(); - } - }; + constexpr auto Flag = GenericFunctor{ "Flag", []( const auto& d ) -> decltype( d.flag() ) { return d.flag(); } }; + + class HasTrackFlag : public Predicate { + LHCb::Event::Enum::Track::Flag m_f; - template - struct HasTrackFlag : public Predicate { + public: + constexpr HasTrackFlag( LHCb::Event::Enum::Track::Flag f ) : m_f{ f } {} static constexpr auto name() { return "HasTrackFlag"; } + template - bool operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).checkFlag( f ); + bool operator()( Data const& d ) const + requires requires( Data const& d, LHCb::Event::Enum::Track::Flag f ) { + Sel::Utils::deref_if_ptr( d ).checkFlag( f ); + } + { + return Sel::Utils::deref_if_ptr( d ).checkFlag( m_f ); } }; + constexpr auto IsClone = HasTrackFlag{ LHCb::Event::Enum::Track::Flag::Clone }; + constexpr auto IsSelected = HasTrackFlag{ LHCb::Event::Enum::Track::Flag::Selected }; + constexpr auto IsInvalid = HasTrackFlag{ LHCb::Event::Enum::Track::Flag::Invalid }; /** @brief Track type */ - struct Type : public Function { - static constexpr auto name() { return "Type"; } - template - LHCb::Event::Enum::Track::Type operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).type(); - } - }; - - class IsTrackType : public Predicate { - LHCb::Event::Enum::Track::Type m_t; + constexpr auto Type = GenericFunctor{ "Type", []( const auto& d ) -> decltype( d.type() ) { return d.type(); } }; - public: - constexpr IsTrackType( LHCb::Event::Enum::Track::Type t ) : m_t{ t } {} - - static constexpr auto name() { return "IsTrackType"; } - template - bool operator()( Data const& d ) const { - return Sel::Utils::deref_if_ptr( d ).type() == m_t; - } - }; - constexpr auto IsLong = IsTrackType{ LHCb::Event::Enum::Track::Type::Long }; - constexpr auto IsDownstream = IsTrackType{ LHCb::Event::Enum::Track::Type::Downstream }; - constexpr auto IsUpstream = IsTrackType{ LHCb::Event::Enum::Track::Type::Upstream }; - constexpr auto IsTtrack = IsTrackType{ LHCb::Event::Enum::Track::Type::Ttrack }; - constexpr auto IsVelo = IsTrackType{ LHCb::Event::Enum::Track::Type::Velo }; - constexpr auto IsVeloBackward = IsTrackType{ LHCb::Event::Enum::Track::Type::VeloBackward }; + constexpr auto IsLong = ( Type == LHCb::Event::Enum::Track::Type::Long ); + constexpr auto IsDownstream = ( Type == LHCb::Event::Enum::Track::Type::Downstream ); + constexpr auto IsUpstream = ( Type == LHCb::Event::Enum::Track::Type::Upstream ); + constexpr auto IsTtrack = ( Type == LHCb::Event::Enum::Track::Type::Ttrack ); + constexpr auto IsVelo = ( Type == LHCb::Event::Enum::Track::Type::Velo ); + constexpr auto IsVeloBackward = ( Type == LHCb::Event::Enum::Track::Type::VeloBackward ); /** @brief Track hasT, the input of this functor must be the track type */ - struct HasT : public Predicate { - static constexpr auto name() { return "HasT"; } - constexpr auto operator()( LHCb::Event::Enum::Track::Type t ) const { return hasT( t ); } - }; + constexpr auto HasT = TrivialPredicate{ "HasT", []( LHCb::Event::Enum::Track::Type t ) { return hasT( t ); } }; /** @brief Track hasUT, the input of this functor must be the track type */ - struct HasUT : public Predicate { - static constexpr auto name() { return "HasUT"; } - constexpr auto operator()( LHCb::Event::Enum::Track::Type t ) const { return hasUT( t ); } - }; + constexpr auto HasUT = TrivialPredicate{ "HasUT", []( LHCb::Event::Enum::Track::Type t ) { return hasUT( t ); } }; /** @brief Track hasVelo, the input of this functor must be the track type */ - struct HasVelo : public Predicate { - static constexpr auto name() { return "HasVelo"; } - constexpr auto operator()( LHCb::Event::Enum::Track::Type t ) const { return hasVelo( t ); } - }; + constexpr auto HasVelo = + TrivialPredicate{ "HasVelo", []( LHCb::Event::Enum::Track::Type t ) { return hasVelo( t ); } }; /** @brief Number of expected Velo clusters from VELO 3D pattern recognition */ - struct nPRVelo3DExpect : public Function { - static constexpr auto name() { return "nPRVelo3DExpect"; } - template - auto operator()( Data const& d ) const { - return (int)Sel::Utils::deref_if_ptr( d ).info( LHCb::Event::Enum::Track::AdditionalInfo::nPRVelo3DExpect, -1. ); - } - }; + + constexpr auto nPRVelo3DExpect = GenericFunctor{ + "nPRVelo3DExpect", + []( auto const& d ) -> decltype( static_cast( std::nearbyint( + d.info( LHCb::Event::Enum::Track::AdditionalInfo::nPRVelo3DExpect, -1. ) ) ) ) { + return static_cast( + std::nearbyint( d.info( LHCb::Event::Enum::Track::AdditionalInfo::nPRVelo3DExpect, -1. ) ) ); + } }; /** * @brief MC_Reconstructed, return the reconstructed category @@ -742,31 +618,21 @@ namespace Functors::Track { * For possible values of IMCReconstructed::RecCategory, see IMCReconstructed.h * */ - struct MC_Reconstructed : public Function { - static constexpr auto name() { return "MC_Reconstructed"; } - template - IMCReconstructed::RecCategory operator()( Data const& d ) const { - if constexpr ( is_legacy_particle ) { - const auto* pp = Sel::Utils::deref_if_ptr( d ).proto(); - return get_reconstructed_category( pp ); - } else { - const auto* rec = &Sel::Utils::deref_if_ptr( d ); - return get_reconstructed_category( rec ); - }; - } - - private: + namespace detail { template - IMCReconstructed::RecCategory get_reconstructed_category( const T* rec ) const { - if ( !rec ) return IMCReconstructed::RecCategory::NotReconstructed; - - if ( !rec->charge() ) { /// Neutral particle - return IMCReconstructed::RecCategory::Neutral; + IMCReconstructed::RecCategory get_reconstructed_category( const T* rec ) + requires requires { + rec->charge(); + rec->track(); } + { + if ( !rec ) return IMCReconstructed::RecCategory::NotReconstructed; + /// Neutral particle + if ( !rec->charge() ) return IMCReconstructed::RecCategory::Neutral; + /// Charged const auto* track = rec->track(); if ( track && !track->checkFlag( LHCb::Track::Flags::Clone ) ) { - LHCb::Event::Enum::Track::Type t{ track->type() }; - switch ( t ) { + switch ( track->type() ) { case LHCb::Event::Enum::Track::Type::Long: return IMCReconstructed::RecCategory::ChargedLong; case LHCb::Event::Enum::Track::Type::Downstream: @@ -786,53 +652,49 @@ namespace Functors::Track { } return IMCReconstructed::RecCategory::NotReconstructed; } - }; + } // namespace detail - /** @brief Wrapper around Particle/ChargedBasic/Track to access brem corrected information - */ - struct Bremsstrahlung : Function { - template - requires( !std::is_pointer_v && !std::is_rvalue_reference_v ) - auto operator()( Data&& d ) const { - return LHCb::Event::Bremsstrahlung::BremsstrahlungWrapper>{ d }; - } - template - auto operator()( Data const* d ) const { - return LHCb::Event::Bremsstrahlung::BremsstrahlungWrapper{ *d }; - } - }; + constexpr auto MC_Reconstructed = + GenericFunctor{ "MC_Reconstructed", + []( LHCb::Particle const& d ) -> IMCReconstructed::RecCategory { + return detail::get_reconstructed_category( d.proto() ); + }, + []( auto const& d ) -> decltype( detail::get_reconstructed_category( &d ) ) { + return detail::get_reconstructed_category( &d ); + } }; - /** @brief Vector of ADC values of UT clusters on track - */ - struct UTHitADCs : public Function { - static constexpr auto name() { return "UTHitADCs"; } - - auto operator()( const LHCb::Event::v1::Track& track ) const { - // get the UT hits on the track - const auto& cls = track.utClusters(); - std::vector adcs; - adcs.reserve( cls.size() ); - std::transform( cls.begin(), cls.end(), std::back_inserter( adcs ), - []( const auto& cl ) { return cl.clusterCharge(); } ); - return adcs; - } - auto operator()( const LHCb::Event::v1::Track* track ) const { return Functors::and_then( track, *this ); } - }; - - /** @brief Vector of sizes of UT clusters on track + /** @brief Wrapper around Particle/ChargedBasic/Track to access brem corrected information */ - struct UTHitSizes : public Function { - static constexpr auto name() { return "UTHitSizes"; } + constexpr auto Bremsstrahlung = GenericFunctor{ + "Bremsstrahlung", []( Data&& d ) requires( std::is_lvalue_reference_v && + !std::is_pointer_v> ){ + return LHCb::Event::Bremsstrahlung::BremsstrahlungWrapper>{ d }; +} // namespace Functors::Track +} +; - auto operator()( const LHCb::Event::v1::Track& track ) const { - // get the UT hits on the track - const auto& cls = track.utClusters(); - std::vector sizes; - sizes.reserve( cls.size() ); - std::transform( cls.begin(), cls.end(), std::back_inserter( sizes ), []( const auto& cl ) { return cl.size(); } ); - return sizes; - } - auto operator()( const LHCb::Event::v1::Track* track ) const { return Functors::and_then( track, *this ); } - }; +/** @brief Vector of ADC values of UT clusters on track + */ +constexpr auto UTHitADCs = GenericFunctor{ "UTHitADCs", []( const LHCb::Event::v1::Track& track ) { + // get the UT hits on the track + const auto& cls = track.utClusters(); + std::vector adcs; + adcs.reserve( cls.size() ); + std::transform( cls.begin(), cls.end(), std::back_inserter( adcs ), + []( const auto& cl ) { return cl.clusterCharge(); } ); + return adcs; + } }; + +/** @brief Vector of sizes of UT clusters on track + */ +constexpr auto UTHitSizes = GenericFunctor{ "UTHitSizes", []( const LHCb::Event::v1::Track& track ) { + // get the UT hits on the track + const auto& cls = track.utClusters(); + std::vector sizes; + sizes.reserve( cls.size() ); + std::transform( cls.begin(), cls.end(), std::back_inserter( sizes ), + []( const auto& cl ) { return cl.size(); } ); + return sizes; + } }; } // namespace Functors::Track diff --git a/Phys/FunctorCore/include/Functors/Utilities.h b/Phys/FunctorCore/include/Functors/Utilities.h index 20edb77b7d7a92439e83b0ec7f9aa02859c4244c..ff422f7a28ccdfaf992a28bd8e5191a57e3dfeef 100644 --- a/Phys/FunctorCore/include/Functors/Utilities.h +++ b/Phys/FunctorCore/include/Functors/Utilities.h @@ -16,7 +16,6 @@ #include "Gaudi/Algorithm.h" #include "GaudiKernel/DataObjectHandle.h" #include "GaudiKernel/System.h" -#include "GaudiKernel/detected.h" #include #include @@ -30,12 +29,12 @@ namespace Functors::detail { /** Return the value of obj.name() if that exists, otherwise try to demangle * the type name. */ template - std::string get_name( Derived const& obj ) { - if constexpr ( requires { obj.name(); } ) { - return obj.name(); - } else { - return System::typeinfoName( typeid( Derived ) ); - } + auto get_name( Derived const& obj ) -> decltype( obj.name() ) { + return obj.name(); + } + template + std::string get_name( Derived const& ) { + return System::typeinfoName( typeid( Derived ) ); } /** Default type of the TES container of PVs. */ diff --git a/Phys/FunctorCore/python/Functors/__init__.py b/Phys/FunctorCore/python/Functors/__init__.py index e171b74963f733fa4d7c841ad0610b17b9897cd2..95d7d5e04920634ac04c3ecbd848e4b8b24dcaa1 100644 --- a/Phys/FunctorCore/python/Functors/__init__.py +++ b/Phys/FunctorCore/python/Functors/__init__.py @@ -10,7 +10,7 @@ ############################################################################### import functools from array import array -from typing import List, Union +from typing import List, Optional, Union from GaudiKernel import SystemOfUnits from PyConf.dataflow import DataHandle @@ -123,22 +123,9 @@ ADDRESSOF = Functor( "Return address of input. E.g. for pointer comparison", ) -_FORWARDARGS = Functor( - "_FORWARDARGS", - "Common::ForwardArgs", - "Forward all arguments or a specific one as indicated by index", - TemplateParams=[ - ( - "index", - "Nth argument to forward. If not specified all arguments will be forwarded.", - lambda x: str(x), - ) - ], -) - -FORWARDARGS = setComposedFunctor( - _FORWARDARGS, +FORWARDARGS = Functor( "FORWARDARGS", + "Common::ForwardArgs", """Forward all the arguments. It can be used in binding operation for composed functors with argument. While binding, one (or more) argument is fixed and all the other will be forwarded. Example: @@ -146,9 +133,9 @@ FORWARDARGS = setComposedFunctor( """, ) -FORWARDARG0 = setComposedFunctor( - _FORWARDARGS(index=0), +FORWARDARG0 = Functor( "FORWARDARG0", + "Common::ForwardArg0", """ Forward the first argument. @@ -156,9 +143,9 @@ FORWARDARG0 = setComposedFunctor( """, ) -FORWARDARG1 = setComposedFunctor( - _FORWARDARGS(index=1), +FORWARDARG1 = Functor( "FORWARDARG1", + "Common::ForwardArg1", """ Forward the second argument @@ -167,9 +154,9 @@ FORWARDARG1 = setComposedFunctor( """, ) -FORWARDARG2 = setComposedFunctor( - _FORWARDARGS(index=2), +FORWARDARG2 = Functor( "FORWARDARG2", + "Common::ForwardArg2", """ Forward the third argument @@ -180,7 +167,7 @@ FORWARDARG2 = setComposedFunctor( # FIXME to avoid fixing all ADL problems TOLINALG = Functor( - "TOLINALG", "Common::ToLinAlg", "trafo gaudi/root classes to linalg vecs." + "TOLINALG", "Common::ToLinAlg", "convert gaudi/root classes to linalg vecs." ) X_COORDINATE = Functor( @@ -216,7 +203,6 @@ NVPHITSA = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) NVPHITSC = Functor( @@ -227,7 +213,6 @@ NVPHITSC = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) NVPOVERLAP = Functor( @@ -238,7 +223,6 @@ NVPOVERLAP = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) EXTRAPOLATE_TRACK = Functor( @@ -405,13 +389,11 @@ MATH_VALUE = Functor( "MATH_VALUE", "LHCbMath::ValueWithError::Value", "Returns the value of Gaudi::Math::ValueWithError", - isInstance=True, ) MATH_ERROR = Functor( "MATH_ERROR", "LHCbMath::ValueWithError::Error", "Returns the error of Gaudi::Math::ValueWithError", - isInstance=True, ) MATH_SCALAR_MOMENTUM = Functor( "MATH_SCALAR_MOMENTUM", @@ -428,32 +410,28 @@ PARTICLE_PARAMS_FLIGHT_DISTANCE = Functor( "PARTICLE_PARAMS_FLIGHT_DISTANCE", "LHCbMath::ParticleParams::flightDistance", "Returns the flight distance of Gaudi::Math::ParticleParams", - isInstance=True, ) PARTICLE_PARAMS_CTAU = Functor( "PARTICLE_PARAMS_CTAU", "LHCbMath::ParticleParams::ctau", "Returns the c*tau of Gaudi::Math::ParticleParams", - isInstance=True, ) PARTICLE_PARAMS_LEN_POS_COV = Functor( "PARTICLE_PARAMS_LEN_POS_COV", "LHCbMath::ParticleParams::lenPosCov", 'Returns the "Matrix" with correlation errors between position and decay length from Gaudi::Math::ParticleParams', - isInstance=True, ) PARTICLE_PARAMS_LEN_MOM_COV = Functor( "PARTICLE_PARAMS_LEN_MOM_COV", "LHCbMath::ParticleParams::lenMomCov", 'Returns the "Matrix" with correlation errors between momentum and decay length from Gaudi::Math::ParticleParams', - isInstance=True, ) def template_list_arg_formatter(args: list): """Format a list for use as template arguments""" # return "a1,a2,a3..." - return ", ".join([str(a) for a in args]) + return ", ".join(str(a) for a in args) def TES(datahandles: Union[DataHandle, List[DataHandle]]) -> BoundFunctor: @@ -521,20 +499,14 @@ def CALL(Row: int, Col: int): Row: row of element Col: column of element """ - return CALL._F(Args=[Row, Col]) + return CALL._F(Args=(Row, Col)) CALL._F = Functor( "CALL", "Common::Call", "Invoke call operator with integer values, e.g. to retrieve (i, j)th element of a covariance matrix.", - TemplateParams=[ - ( - "Args", - "Integer values to pass into the operator()", - template_list_arg_formatter, - ) - ], + Params=[("Args", "Integer values to pass into the operator()", tuple)], ) @@ -1050,23 +1022,20 @@ HASBREM = Functor( """Has non-zero brem momentum-recovery energy. Functor's call operator expects a particle-like object.""", - isInstance=True, ) HASBREMADDED = Functor( "HASBREMADDED", "Track::HasBremAdded", """Has non-zero brem momentum-recovery energy added (using Particle class flag). - Functor's call operator expects a particle-like object in v1 event model.""", + isInstance=False, ) - INECAL = Functor( "INECAL", "PID::InEcal", """In Ecal acceptance. Functor's call operator expects a particle-like object.""", - isInstance=True, ) INHCAL = Functor( "INHCAL", @@ -1074,7 +1043,6 @@ INHCAL = Functor( """In Hcal acceptance. Functor's call operator expects a particle-like object.""", - isInstance=True, ) INBREM = Functor( "INBREM", @@ -1082,7 +1050,6 @@ INBREM = Functor( """In Brem acceptance. Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMENERGY = Functor( "BREMENERGY", @@ -1090,7 +1057,6 @@ BREMENERGY = Functor( """Brem momentum-recovery energy. Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMBENDCORR = Functor( "BREMBENDCORR", @@ -1098,7 +1064,6 @@ BREMBENDCORR = Functor( """Correction factor accounting for bending biases in track due to brem. Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMPIDE = Functor( "BREMPIDE", @@ -1106,7 +1071,6 @@ BREMPIDE = Functor( """Brem-based DLL for electron-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) ECALPIDE = Functor( "ECALPIDE", @@ -1114,7 +1078,6 @@ ECALPIDE = Functor( """Ecal-based DLL for electron-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) ECALPIDMU = Functor( "ECALPIDMU", @@ -1122,7 +1085,6 @@ ECALPIDMU = Functor( """Ecal-based DLL for mu-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) HCALPIDE = Functor( "HCALPIDE", @@ -1130,7 +1092,6 @@ HCALPIDE = Functor( """Hcal-based DLL for electron-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) HCALPIDMU = Functor( "HCALPIDMU", @@ -1138,7 +1099,6 @@ HCALPIDMU = Functor( """Hcal-based DLL for mu-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_E = Functor( "RICH_DLL_E", @@ -1146,7 +1106,6 @@ RICH_DLL_E = Functor( """Rich-based DLL for electron-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_MU = Functor( "RICH_DLL_MU", @@ -1154,7 +1113,6 @@ RICH_DLL_MU = Functor( """Rich-based DLL for mu-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_P = Functor( "RICH_DLL_P", @@ -1162,7 +1120,6 @@ RICH_DLL_P = Functor( """Rich-based DLL for proton-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_K = Functor( "RICH_DLL_K", @@ -1170,7 +1127,6 @@ RICH_DLL_K = Functor( """Rich-based DLL for kaon-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_PI = Functor( "RICH_DLL_PI", @@ -1178,7 +1134,6 @@ RICH_DLL_PI = Functor( """Rich-based DLL for pion-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_D = Functor( "RICH_DLL_D", @@ -1186,7 +1141,6 @@ RICH_DLL_D = Functor( """Rich-based DLL for deuteron-ID. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_DLL_BT = Functor( "RICH_DLL_BT", @@ -1194,7 +1148,6 @@ RICH_DLL_BT = Functor( """Rich-based DLL for below threshold tracks. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_SCALED_DLL_E = Functor( "RICH_SCALED_DLL_E", @@ -1204,7 +1157,6 @@ RICH_SCALED_DLL_E = Functor( For usage in combined DLLs (with other subdetectors). Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_SCALED_DLL_MU = Functor( "RICH_SCALED_DLL_MU", @@ -1214,7 +1166,6 @@ RICH_SCALED_DLL_MU = Functor( For usage in combined DLLs (with other subdetectors). Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH1_GAS_USED = Functor( "RICH1_GAS_USED", @@ -1222,7 +1173,6 @@ RICH1_GAS_USED = Functor( """Rich 1 gas flag. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH2_GAS_USED = Functor( "RICH2_GAS_USED", @@ -1230,7 +1180,6 @@ RICH2_GAS_USED = Functor( """Rich 2 gas flag. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_THRESHOLD_EL = Functor( "RICH_THRESHOLD_EL", @@ -1238,7 +1187,6 @@ RICH_THRESHOLD_EL = Functor( """Rich threshold for electrons. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_THRESHOLD_KA = Functor( "RICH_THRESHOLD_KA", @@ -1246,7 +1194,6 @@ RICH_THRESHOLD_KA = Functor( """Rich threshold for kaons. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_THRESHOLD_MU = Functor( "RICH_THRESHOLD_MU", @@ -1254,7 +1201,6 @@ RICH_THRESHOLD_MU = Functor( """Rich threshold for muons. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_THRESHOLD_PI = Functor( "RICH_THRESHOLD_PI", @@ -1262,7 +1208,6 @@ RICH_THRESHOLD_PI = Functor( """Rich threshold for pions. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_THRESHOLD_PR = Functor( "RICH_THRESHOLD_PR", @@ -1270,7 +1215,6 @@ RICH_THRESHOLD_PR = Functor( """Rich threshold for protons. Functor's call operator expects a particle-like object.""", - isInstance=True, ) RICH_THRESHOLD_DE = Functor( "RICH_THRESHOLD_DE", @@ -1278,7 +1222,6 @@ RICH_THRESHOLD_DE = Functor( """Rich threshold for deuterons. Functor's call operator expects a particle-like object.""", - isInstance=True, ) ELECTRONSHOWEREOP = Functor( "ELECTRONSHOWEREOP", @@ -1286,7 +1229,6 @@ ELECTRONSHOWEREOP = Functor( """Electron energy/momentum with track-based cell selection. Functor's call operator expects a particle-like object.""", - isInstance=True, ) CLUSTERMATCH_CHI2 = Functor( "CLUSTERMATCH", @@ -1301,7 +1243,6 @@ ELECTRONMATCH_CHI2 = Functor( """CaloID estimator : 3D chi2 for Track/CaloHypo(e) matching (charged). Functor's call operator expects a particle-like object.""", - isInstance=True, ) CALOCELLID_ALL = Functor( "CALOCELLID_ALL", @@ -1309,7 +1250,6 @@ CALOCELLID_ALL = Functor( """Retrieve bitwise information (32bits) of Calo CellID. 0 is invalid/unavailable (see Detector/Calo/include/Detector/Calo/CaloCellID.h) """, - isInstance=True, ) _BREMHYPOID = Functor( "_BREMHYPOID", @@ -1317,7 +1257,6 @@ _BREMHYPOID = Functor( """CellID for CaloHypo (photon) associated to track for brem recovery Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMHYPOID = setComposedFunctor( CALOCELLID_ALL @ _BREMHYPOID, @@ -1333,7 +1272,6 @@ BREMHYPOMATCH_CHI2 = Functor( """2D chi2 of CaloHypo (photon) associated to track for brem recovery Functor's call operator expects a particle-like object.""", - isInstance=True, ) ELECTRONENERGY = Functor( "ELECTRONENERGY", @@ -1341,7 +1279,6 @@ ELECTRONENERGY = Functor( """Cluster energy associated to CaloHypo (charged) Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMHYPOENERGY = Functor( "BREMHYPOENERGY", @@ -1349,7 +1286,6 @@ BREMHYPOENERGY = Functor( """Energy of CaloHypo (photon) associated to track for brem recovery. Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMHYPODELTAX = Functor( "BREMHYPODELTAX", @@ -1357,7 +1293,6 @@ BREMHYPODELTAX = Functor( """Test statistic of being first-state like of CaloHypo (photon) for brem recovery Functor's call operator expects a particle-like object.""", - isInstance=True, ) BREMTRACKBASEDENERGY = Functor( "BREMTRACKBASEDENERGY", @@ -1365,7 +1300,6 @@ BREMTRACKBASEDENERGY = Functor( """Track-based brem energy determination Functor's call operator expects a particle-like object.""", - isInstance=True, ) _ELECTRONID = Functor( "_ELECTRONID", @@ -1373,7 +1307,6 @@ _ELECTRONID = Functor( """CellID associated to CaloHypo seed (electron hypo) Functor's call operator expects a particle-like object.""", - isInstance=True, ) ELECTRONID = setComposedFunctor( CALOCELLID_ALL @ _ELECTRONID, @@ -1390,7 +1323,6 @@ HCALEOP = Functor( """Hcal energy deposit over momentum (track) Functor's call operator expects a particle-like object.""", - isInstance=True, ) _CLUSTERID = Functor( "_CLUSTERID", @@ -1398,7 +1330,6 @@ _CLUSTERID = Functor( """CellID of the best matching cluster for a given reconstructed track. Functor's call operator expects a particle-like object.""", - isInstance=True, ) CLUSTERID = setComposedFunctor( CALOCELLID_ALL @ _CLUSTERID, @@ -1414,7 +1345,6 @@ ELECTRONSHOWERDLL = Functor( """Summed per-cell E/p DLL (electron versus pion) with track-based cell selection and energy estimation. Functor's call operator expects a particle-like object.""", - isInstance=True, ) NDOF = Functor("NDOF", "Track::nDoF", "Number of degrees of freedom [for chi2]") PVTRACKS = Functor("PVTRACKS", "Track::PVtracks", "Tracks from vertex fit") @@ -1441,7 +1371,11 @@ GHOSTPROB = setComposedFunctor( ) ### Track Event -TRACKTYPE = Functor("TRACKTYPE", "Track::Type", "Track type.") +TRACKTYPE = Functor( + "TRACKTYPE", + "Track::Type", + "Track type.", +) _TRACKHAST = Functor("TRACKHAST", "Track::HasT", "Track has T.") _TRACKHASUT = Functor("TRACKHASUT", "Track::HasUT", "Track has UT.") _TRACKHASVELO = Functor("TRACKHASVELO", "Track::HasVelo", "Track has Velo.") @@ -1483,7 +1417,6 @@ TRACKISLONG = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) TRACKISDOWNSTREAM = Functor( "TRACKISDOWNSTREAM", @@ -1492,7 +1425,6 @@ TRACKISDOWNSTREAM = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) TRACKISUPSTREAM = Functor( "TRACKISUPSTREAM", @@ -1501,7 +1433,6 @@ TRACKISUPSTREAM = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) TRACKISTTRACK = Functor( "TRACKISTTRACK", @@ -1510,7 +1441,6 @@ TRACKISTTRACK = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) TRACKISVELO = Functor( "TRACKISVELO", @@ -1519,7 +1449,6 @@ TRACKISVELO = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) TRACKISVELOBACKWARD = Functor( "TRACKISVELOBACKWARD", @@ -1528,7 +1457,6 @@ TRACKISVELOBACKWARD = Functor( Functor's call operator expects a track-like object. """, - isInstance=True, ) TRACKFLAG = Functor( @@ -1542,7 +1470,7 @@ TRACKFLAG = Functor( TRACKISINVALID = Functor( "TRACKISINVALID", - "Track::HasTrackFlag", + "Track::IsInvalid", """Track flag contains Invalid Functor's call operator expects a track-like object. @@ -1550,7 +1478,7 @@ TRACKISINVALID = Functor( ) TRACKISCLONE = Functor( "TRACKISCLONE", - "Track::HasTrackFlag", + "Track::IsClone", """Track flag contains Clone Functor's call operator expects a track-like object. @@ -1558,7 +1486,7 @@ TRACKISCLONE = Functor( ) TRACKISSELECTED = Functor( "TRACKISSELECTED", - "Track::HasTrackFlag", + "Track::IsSelected", """Track flag contains Selected Functor's call operator expects a track-like object. @@ -1571,7 +1499,6 @@ VELOMATCHIP = Functor( """ IP of VELO track to the endvertex of a composite charged particle reconstructed with downstream tracks as defined in https://inspirehep.net/literature/2768765. """, - isInstance=True, ) VELOMATCHCHI2 = Functor( @@ -1580,7 +1507,6 @@ VELOMATCHCHI2 = Functor( """ Chi2 of VELO track when matching it to a composite charged particle reconstructed with downstream tracks as defined in https://inspirehep.net/literature/2768765. """, - isInstance=True, ) ### Number of hits on track @@ -1664,6 +1590,7 @@ PPHASRICH = Functor( Note: FIXME """, ) + PPHASMUONINFO = Functor( "PPHASMUONINFO", "Particle::PPHasMuonInfo", @@ -1676,7 +1603,7 @@ PPHASMUONINFO = Functor( # generic ALL = Functor("ALL", "AcceptAll", "Accept everything; always evaluates to 'true'.") NONE = Functor("NONE", "AcceptNone", "Accept nothing; always evaluates to 'false'.") -IDENTITY = Functor("IDENTITY", "Identity_t", "Returns the same value.") +IDENTITY = Functor("IDENTITY", "Identity", "Returns the same value.") COLUMN = Functor( "COLUMN", "Column_t", @@ -1716,12 +1643,12 @@ MAX = Functor( ) -def CHILD(Index: int, Functor=None): +def CHILD(Index: int, Functor: Optional[BoundFunctor] = None): """Apply functor on a child.""" - # and now for some backwards compatibility... - if Functor is None or type(Functor) == type(FORWARDARGS): + if Functor is None or Functor.name() == FORWARDARGS.name(): return CHILD._F(Index) else: + # nllow for some backwards compatibility... return Functor @ CHILD._F(Index) @@ -1733,9 +1660,13 @@ CHILD._F = Functor( ) -def SUBCOMB(Functor: BoundFunctor, Indices: list): +def SUBCOMB(Indices: list, Functor: Optional[BoundFunctor] = None): """Apply a functor to a subcombination obtained from the decay produces of a composite particle""" - return Functor @ SUBCOMB._F(Indices=Indices) + if Functor is None or Functor.name() == FORWARDARGS.name(): + return SUBCOMB._F(Indices=Indices) + else: + # nllow for some backwards compatibility... + return Functor @ SUBCOMB._F(Indices=Indices) SUBCOMB._F = Functor( @@ -2022,7 +1953,12 @@ HAS_CHARM = setComposedFunctor( ) PID_MU = setComposedFunctor( - VALUE_OR(NaN) @ Functor("_PID_MU", "Track::PIDmu", "CombDLLmu.", isInstance=True), + VALUE_OR(NaN) + @ Functor( + "_PID_MU", + "Track::PIDmu", + "CombDLLmu.", + ), "PID_MU", """ Gives measure of the muon mass hypothesis relative to the pion hypotesis. @@ -2033,7 +1969,12 @@ General information on PID could be found at the following `TWiki page >> import Functors as F >>> F.REQUIRE_CLOSE(F.PT, 1000.) - ('Functors::bind( ::Functors::Common::RequireClose( /* The absolute difference between two numbers */ float{1e-34}, /* The relative difference between two numbers */ float{1e-08} ), Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), float{1000.0} )', ['float{1e-34}', 'float{1e-08}', 'float{1000.0}'], '_REQUIRE_CLOSE(AbsDiff=1e-34, RelDiff=1e-08).bind( ( RHO_COORDINATE @ THREEMOMENTUM ), 1000.0 )') + ('Functors::bind( ::Functors::Common::RequireClose( /* The absolute difference between two numbers */ float{1e-34}, /* The relative difference between two numbers */ float{1e-08} ), Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ), float{1000.0} )', ['float{1e-34}', 'float{1e-08}', 'float{1000.0}'], '_REQUIRE_CLOSE(AbsDiff=1e-34, RelDiff=1e-08).bind( ( RHO_COORDINATE @ THREEMOMENTUM ), 1000.0 )') >>> F.REQUIRE_CLOSE(F.MASS, F.PDG_MASS("J/psi(1S)")) - ('Functors::bind( ::Functors::Common::RequireClose( /* The absolute difference between two numbers */ float{1e-34}, /* The relative difference between two numbers */ float{1e-08} ), ::Functors::Composite::Mass{}, Functors::chain( ::Functors::Composite::Mass{}, ::Functors::Particle::ParticlePropertyUser( /* ID to check */ std::string{"J/psi(1S)"} ) ) )', ['float{1e-34}', 'float{1e-08}', 'std::string{"J/psi(1S)"}'], '_REQUIRE_CLOSE(AbsDiff=1e-34, RelDiff=1e-08).bind( MASS, ( MASS @ PARTICLE_PROPERTY(particle_name=J/psi(1S)) ) )') + ('Functors::bind( ::Functors::Common::RequireClose( /* The absolute difference between two numbers */ float{1e-34}, /* The relative difference between two numbers */ float{1e-08} ), ::Functors::Composite::Mass, Functors::chain( ::Functors::Composite::Mass, ::Functors::Particle::ParticlePropertyUser( /* ID to check */ std::string{"J/psi(1S)"} ) ) )', ['float{1e-34}', 'float{1e-08}', 'std::string{"J/psi(1S)"}'], '_REQUIRE_CLOSE(AbsDiff=1e-34, RelDiff=1e-08).bind( MASS, ( MASS @ PARTICLE_PROPERTY(particle_name=J/psi(1S)) ) )') """ return REQUIRE_CLOSE._F(AbsDiff=AbsDiff, RelDiff=RelDiff).bind(F1, F2) @@ -3784,10 +3714,12 @@ def ALLPV_FD(Vertices: DataHandle): Args: Vertices (DataHandle): the input primary vertices """ - MAG_DIST = MAGNITUDE @ ( - ENDVERTEX_POS @ FORWARDARG1 - TOLINALG @ POSITION @ FORWARDARG0 - ) - return MAP(MAG_DIST).bind(TES(Vertices), FORWARDARGS) + return MAP(ALLPV_FD._F).bind(TES(Vertices), FORWARDARGS) + + +ALLPV_FD._F = MAGNITUDE @ ( + ENDVERTEX_POS @ FORWARDARG1 - TOLINALG @ POSITION @ FORWARDARG0 +) def TaggingDecision(FTags: DataHandle, TaggerName: Union[str, int]): @@ -3864,11 +3796,13 @@ def MC_PROPERTY(mc_track_info: DataHandle): Args: mc_track_info: DataHandle of the MC track info """ - return Functor( - "_MC_PROPERTY", "Simulation::MC::Property", "Retrieve the MCProperty object." - ).bind(TES(mc_track_info), FORWARDARGS) + return MC_PROPERTY._F.bind(TES(mc_track_info), FORWARDARGS) +MC_PROPERTY._F = Functor( + "MC_PROPERTY", "Simulation::MC::Property", "Retrieve the MCProperty object." +) + MC_TRACKINFO = Functor( "MC_TRACKINFO", "Simulation::CheckMask", @@ -4369,43 +4303,37 @@ DELHCB = Functor( ) FILL_NUMBER = setComposedFunctor( - Functor("_FILL_NUMBER", "Detector::FillNumber", "", isInstance=True) @ DELHCB, + Functor("_FILL_NUMBER", "Detector::FillNumber", "") @ DELHCB, "FILL_NUMBER", "Get the fill number from the LHC conditions.", ) LHC_ENERGY = setComposedFunctor( - Functor("_LHC_ENERGY", "Detector::LHCEnergy", "", isInstance=True) @ DELHCB, + Functor("_LHC_ENERGY", "Detector::LHCEnergy", "") @ DELHCB, "LHC_ENERGY", "Get the LHC beam energy.", ) LHCB_CLOCKPHASE = setComposedFunctor( - Functor("_LHCB_CLOCKPHASE", "Detector::LHCbClockPhase", "", isInstance=True) - @ DELHCB, + Functor("_LHCB_CLOCKPHASE", "Detector::LHCbClockPhase", "") @ DELHCB, "LHCB_CLOCKPHASE", "Get the LHCb clock phase from the LHC conditions.", ) SMOG_INJECTION_MODE = setComposedFunctor( - Functor("_SMOG_INJECTION_MODE", "Detector::SMOGInjectionMode", "", isInstance=True) - @ DELHCB, + Functor("_SMOG_INJECTION_MODE", "Detector::SMOGInjectionMode", "") @ DELHCB, "SMOG_INJECTION_MODE", "Get the SMOG injection mode from the Online conditions.", ) SMOG_INJECTED_GAS = setComposedFunctor( - Functor("_SMOG_INJECTED_GAS", "Detector::SMOGInjectedGas", "", isInstance=True) - @ DELHCB, + Functor("_SMOG_INJECTED_GAS", "Detector::SMOGInjectedGas", "") @ DELHCB, "SMOG_INJECTED_GAS", "Get the SMOG injected gas from the Online conditions.", ) SMOG_STABLE_INJECTION = setComposedFunctor( - Functor( - "_SMOG_STABLE_INJECTION", "Detector::SMOGStableInjection", "", isInstance=True - ) - @ DELHCB, + Functor("_SMOG_STABLE_INJECTION", "Detector::SMOGStableInjection", "") @ DELHCB, "SMOG_STABLE_INJECTION", "Get the SMOG stable injection flag from the Online conditions.", ) diff --git a/Phys/FunctorCore/python/Functors/grammar.py b/Phys/FunctorCore/python/Functors/grammar.py index 61fa2b14e37f74984a23985d7d76cef4f5a5a8a8..1e5631a6bb05ae2aa1dad324c99abbc4a5f4154a 100644 --- a/Phys/FunctorCore/python/Functors/grammar.py +++ b/Phys/FunctorCore/python/Functors/grammar.py @@ -587,7 +587,7 @@ def Functor( Params=[], TemplateParams=[], AllowMultiplePositionalArguments=False, - isInstance=False, + isInstance=None, ): """Create a new Functor class and return an instance of it. @@ -732,10 +732,9 @@ def Functor( template_arguments = "" if len(kwargs): raise Exception("Unknown parameters were provided: " + repr(kwargs)) - cpp_str = "{name}{template_params}( {args} )".format( - name=self._cppname, - template_params=template_arguments, - args=", ".join(cpp_arguments), + cpp_args = "( {} )".format(", ".join(cpp_arguments)) if cpp_arguments else "" + cpp_str = "{name}{template_params}{args}".format( + name=self._cppname, template_params=template_arguments, args=cpp_args ) repr_str = "{name}({args})".format( name=representation, @@ -780,8 +779,15 @@ def Functor( ) has_args = len(Params) > 0 or len(TemplateParams) > 0 - if isInstance and has_args: - raise Exception("instances, by their nature, cannot have any arguments!") + if isInstance and len(Params) > 0: + raise Exception( + "Instances, by their nature, cannot have any (non template) arguments!" + ) + if isInstance is None: + isInstance = ( + len(Params) == 0 + ) # default to instance for functor without parameters + cdict = { "__doc__": brief_docs, "__call__": call_with_args if has_args else call_without_args, diff --git a/Phys/FunctorCore/python/Functors/math.py b/Phys/FunctorCore/python/Functors/math.py index 77c6ed579eaefcbcc36d207a86a89016aa6db79b..50a7eb0ebecc1479de05643b212c31d5a0347c26 100644 --- a/Phys/FunctorCore/python/Functors/math.py +++ b/Phys/FunctorCore/python/Functors/math.py @@ -24,7 +24,7 @@ def log(functor): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.log(PT) > 1.0 - ('operator>( ::Functors::math::log( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) ), float{1.0} )', ['float{1.0}'], '( ::Functors::math::log( ( RHO_COORDINATE @ THREEMOMENTUM ) ) > 1.0 )') + ('operator>( ::Functors::math::log( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) ), float{1.0} )', ['float{1.0}'], '( ::Functors::math::log( ( RHO_COORDINATE @ THREEMOMENTUM ) ) > 1.0 )') """ return WrappedBoundFunctor(top_level_namespace + "math::log", functor) @@ -37,7 +37,7 @@ def exp(functor): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.exp(PT) - ('::Functors::math::exp( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) )', '::Functors::math::exp( ( RHO_COORDINATE @ THREEMOMENTUM ) )') + ('::Functors::math::exp( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) )', '::Functors::math::exp( ( RHO_COORDINATE @ THREEMOMENTUM ) )') """ return WrappedBoundFunctor(top_level_namespace + "math::exp", functor) @@ -50,7 +50,7 @@ def pow(functor, power): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.pow(PT, 0.2) - ('::Functors::math::pow( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), float{0.2} )', ['float{0.2}'], '::Functors::math::pow( ( RHO_COORDINATE @ THREEMOMENTUM ), 0.2 )') + ('::Functors::math::pow( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ), float{0.2} )', ['float{0.2}'], '::Functors::math::pow( ( RHO_COORDINATE @ THREEMOMENTUM ), 0.2 )') """ return WrappedBoundFunctor(top_level_namespace + "math::pow", functor, power) @@ -63,7 +63,7 @@ def similarity(vec, cov_matrix): >>> import Functors.math as fmath >>> from Functors import THREEMOMENTUM, THREE_MOM_COV_MATRIX, P >>> fmath.similarity(THREEMOMENTUM/P, THREE_MOM_COV_MATRIX) - ('::Functors::math::similarity( operator/( ::Functors::Track::ThreeMomentum{}, Functors::chain( ::Functors::Common::Magnitude{}, ::Functors::Track::ThreeMomentum{} ) ), ::Functors::Particle::threeMomCovMatrix{} )', '::Functors::math::similarity( ( THREEMOMENTUM / ( MAGNITUDE @ THREEMOMENTUM ) ), THREE_MOM_COV_MATRIX )') + ('::Functors::math::similarity( operator/( ::Functors::Track::ThreeMomentum, Functors::chain( ::Functors::Common::Magnitude, ::Functors::Track::ThreeMomentum ) ), ::Functors::Particle::threeMomCovMatrix )', '::Functors::math::similarity( ( THREEMOMENTUM / ( MAGNITUDE @ THREEMOMENTUM ) ), THREE_MOM_COV_MATRIX )') """ return WrappedBoundFunctor( top_level_namespace + "math::similarity", vec, cov_matrix @@ -78,7 +78,7 @@ def sign(functor): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.sign(PT) > 0 - ('operator>( ::Functors::math::sign( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) ), int{0} )', ['int{0}'], '( ::Functors::math::sign( ( RHO_COORDINATE @ THREEMOMENTUM ) ) > 0 )') + ('operator>( ::Functors::math::sign( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) ), int{0} )', ['int{0}'], '( ::Functors::math::sign( ( RHO_COORDINATE @ THREEMOMENTUM ) ) > 0 )') """ return WrappedBoundFunctor(top_level_namespace + "math::sign", functor) @@ -91,7 +91,7 @@ def sqrt(functor): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.sqrt(PT) - ('::Functors::math::sqrt( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) )', '::Functors::math::sqrt( ( RHO_COORDINATE @ THREEMOMENTUM ) )') + ('::Functors::math::sqrt( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) )', '::Functors::math::sqrt( ( RHO_COORDINATE @ THREEMOMENTUM ) )') """ return WrappedBoundFunctor(top_level_namespace + "math::sqrt", functor) @@ -104,7 +104,7 @@ def arccos(functor): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.arccos(PT) - ('::Functors::math::arccos( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) )', '::Functors::math::arccos( ( RHO_COORDINATE @ THREEMOMENTUM ) )') + ('::Functors::math::arccos( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) )', '::Functors::math::arccos( ( RHO_COORDINATE @ THREEMOMENTUM ) )') """ return WrappedBoundFunctor(top_level_namespace + "math::arccos", functor) @@ -117,7 +117,7 @@ def where(condition, functor_a, functor_b): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.where(PT > 0.5, 2 * PT, PT) - ('::Functors::math::where( operator>( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), float{0.5} ), operator*( int{2}, Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) ), Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) )', ['float{0.5}', 'int{2}'], '::Functors::math::where( ( ( RHO_COORDINATE @ THREEMOMENTUM ) > 0.5 ), ( 2 * ( RHO_COORDINATE @ THREEMOMENTUM ) ), ( RHO_COORDINATE @ THREEMOMENTUM ) )') + ('::Functors::math::where( operator>( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ), float{0.5} ), operator*( int{2}, Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) ), Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) )', ['float{0.5}', 'int{2}'], '::Functors::math::where( ( ( RHO_COORDINATE @ THREEMOMENTUM ) > 0.5 ), ( 2 * ( RHO_COORDINATE @ THREEMOMENTUM ) ), ( RHO_COORDINATE @ THREEMOMENTUM ) )') """ return WrappedBoundFunctor( top_level_namespace + "math::where", condition, functor_a, functor_b @@ -132,7 +132,7 @@ def abs(functor): >>> import Functors.math as fmath >>> from Functors import PT >>> fmath.abs(PT) - ('::Functors::math::abs( Functors::chain( ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) )', '::Functors::math::abs( ( RHO_COORDINATE @ THREEMOMENTUM ) )') + ('::Functors::math::abs( Functors::chain( ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) )', '::Functors::math::abs( ( RHO_COORDINATE @ THREEMOMENTUM ) )') """ return WrappedBoundFunctor(top_level_namespace + "math::abs", functor) @@ -147,7 +147,7 @@ def in_range(min_val, functor, max_val): >>> import Functors.math as fmath >>> from Functors import MASS >>> fmath.in_range(1500, MASS, 2500) - ('::Functors::math::in_range( int{1500}, ::Functors::Composite::Mass{}, int{2500} )', ['int{1500}', 'int{2500}'], '::Functors::math::in_range( 1500, MASS, 2500 )') + ('::Functors::math::in_range( int{1500}, ::Functors::Composite::Mass, int{2500} )', ['int{1500}', 'int{2500}'], '::Functors::math::in_range( 1500, MASS, 2500 )') """ return WrappedBoundFunctor( top_level_namespace + "math::in_range", min_val, functor, max_val diff --git a/Phys/FunctorCore/tests/options/test_functors_tested.py b/Phys/FunctorCore/tests/options/test_functors_tested.py index 97c82204fd8f1d33580da001dff01f74581e489f..f2a679f6115f262aa4f52bab9092a15591b036ab 100644 --- a/Phys/FunctorCore/tests/options/test_functors_tested.py +++ b/Phys/FunctorCore/tests/options/test_functors_tested.py @@ -25,10 +25,8 @@ def error(msg): # just add everything which is not tested for now. exceptions = [ - "Functors::Adapters::ConvertToPOD", "Functors::Adapters::Maximum", "Functors::Adapters::Minimum", - "Functors::Adapters::SubCombination", "Functors::Combination::Charge", "Functors::Combination::CosAngleBetweenDecayProducts", "Functors::Combination::DistanceOfClosestApproach", @@ -46,10 +44,8 @@ exceptions = [ "Functors::Composite::ComputeDecayLengthSignificance", "Functors::Composite::FlightDistanceChi2ToVertex", "Functors::Composite::MassWithHypotheses", - "Functors::Composite::MotherTrajectoryDistanceOfClosestApproachChi2", "Functors::Examples::GreaterThan", "Functors::Examples::ThorBeatsLoki", - "Functors::MVA", "Functors::Track::Covariance", "Functors::Track::QoverP", "Functors::Track::Flag", @@ -58,15 +54,13 @@ exceptions = [ "Functors::Track::UTHitSizes", "Functors::Track::Extrapolate", "Functors::Common::UnitVector", - "Functors::Common::Call", "Functors::Common::Dot", "Functors::Common::NormedDot", "Functors::Common::ImpactParameterChi2ToVertex", "Functors::Common::Mean", "Functors::Common::Median", - "Functors::Decay::FindMCDecay", "Functors::Column_t", - "Functors::Identity_t", + "Functors::Identity", "Functors::Particle::ParticlePropertyUser", "Functors::PID::RichThresholdDe", "Functors::PID::RichThresholdKa", @@ -74,7 +68,6 @@ exceptions = [ "Functors::PID::RichThresholdPi", "Functors::PID::RichThresholdPr", "Functors::Detector::DeLHCb", - "Functors::Detector::LHCbClockPhase", "Functors::Track::LHCbIDs", "Functors::Track::HitPattern", # these last two are false positives: they _are_ tested, but this code doesn't recognize it... ] diff --git a/Phys/FunctorCore/tests/refs/example_test.ref b/Phys/FunctorCore/tests/refs/example_test.ref index bfd819ce0cc1f22ec5ed58005ed90fa29fd6548c..7ec8983eeaa9e25de7b5415215d75a347e284c52 100644 --- a/Phys/FunctorCore/tests/refs/example_test.ref +++ b/Phys/FunctorCore/tests/refs/example_test.ref @@ -9,17 +9,17 @@ FunctorFactory INFO Writing cpp files for 5 functors split in 1 files FunctorFactory INFO Compilation will use 1 jobs. ApplicationMgr INFO Application Manager Started successfully name0 INFO 'Cuts':[ ] -name0 INFO 'Cut':"('::Functors::AcceptAll{}', 'ALL')" +name0 INFO 'Cut':"('::Functors::AcceptAll', 'ALL')" name0 INFO Result: 1 -name1 INFO 'Cuts':[ [ "('::Functors::Examples::TimesTwo{}', 'TIMESTWO')" , "('::Functors::Examples::ThorBeatsLoki{}', 'TBL')" ] , [ "('Functors::all_of( ::Functors::Examples::GreaterThan( /* reference value */ float{2.0} ), ::Functors::Examples::GreaterThan( /* reference value */ float{4.0} ) )', ['float{2.0}','float{4.0}'], '( GREATERTHAN(v=2.0) & GREATERTHAN(v=4.0) )')" ] ] -name1 INFO 'Cut':"('::Functors::Examples::ThorBeatsLoki{}', 'TBL')" +name1 INFO 'Cuts':[ [ "('::Functors::Examples::TimesTwo', 'TIMESTWO')" , "('::Functors::Examples::ThorBeatsLoki', 'TBL')" ] , [ "('Functors::all_of( ::Functors::Examples::GreaterThan( /* reference value */ float{2.0} ), ::Functors::Examples::GreaterThan( /* reference value */ float{4.0} ) )', ['float{2.0}','float{4.0}'], '( GREATERTHAN(v=2.0) & GREATERTHAN(v=4.0) )')" ] ] +name1 INFO 'Cut':"('::Functors::Examples::ThorBeatsLoki', 'TBL')" name1 INFO Result: 1 Gaudi::Examples... INFO executing IntDataProducer, storing 7 into SomeInt name2 INFO 'Cut':"('::Functors::Examples::GreaterThan( /* reference value */ float{8.0} )', ['float{8.0}'], 'GREATERTHAN(v=8.0)')" name2 INFO Result: 0 -name3 INFO 'Cut':"('Functors::all_of( ::Functors::Examples::GreaterThan( /* reference value */ float{8.0} ), ::Functors::Examples::ThorBeatsLoki{} )', ['float{8.0}'], '( GREATERTHAN(v=8.0) & TBL )')" +name3 INFO 'Cut':"('Functors::all_of( ::Functors::Examples::GreaterThan( /* reference value */ float{8.0} ), ::Functors::Examples::ThorBeatsLoki )', ['float{8.0}'], '( GREATERTHAN(v=8.0) & TBL )')" name3 INFO Result: 0 -name4 INFO 'Cut':"('operator>( ::Functors::Examples::TimesTwo{}, int{10} )', ['int{10}'], '( TIMESTWO > 10 )')" +name4 INFO 'Cut':"('operator>( ::Functors::Examples::TimesTwo, int{10} )', ['int{10}'], '( TIMESTWO > 10 )')" name4 INFO Result: 1 ApplicationMgr INFO Application Manager Stopped successfully EventLoopMgr INFO Histograms converted successfully according to request. diff --git a/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp b/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp index 056eadbd5ae019c6f9765a2a79f790d9ec29db85..017630ab8021194676d122e43bf1b1df26848f1a 100644 --- a/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp +++ b/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp @@ -78,15 +78,16 @@ using soa_composite = decltype( *std::declval().s // to save ourselfes a lot of writing we use mp_product below a lot. // mp_product calls invoke_result_t for each combination of the list of functors and provided arguments // see mp_product doc: https://www.boost.org/doc/libs/master/libs/mp11/doc/html/mp11.html#mp_productf_l -using test1 = mp_product, +using test1 = mp_product, mp_append, ptr_and_ref>>; -using test2 = mp_product, +using test2 = mp_product, mp_append, mp_list>>; using test3 = - mp_product, + mp_product, mp_append, mp_list>>; // @@ -102,21 +103,24 @@ using composed_t = template using apply_vec_accessors_to = - mp_list, composed_t, composed_t, - composed_t, composed_t, composed_t, - composed_t>; + mp_list, composed_t, + composed_t, composed_t, + composed_t, composed_t, + composed_t>; using all_vec_accessors = - mp_flatten>>; + mp_flatten>>; using test4 = mp_product, mp_append, ptr_and_ref>>; -using mom4_accessors = - mp_list, composed_t, - composed_t, composed_t, - composed_t>; +using mom4_accessors = mp_list, + composed_t, + composed_t, + composed_t, + composed_t>; // FIXME fourmomentum is broken for v1 Track as it returns a 3-mom Gaudi::XYZVector using test5 = mp_product, @@ -137,31 +141,30 @@ using IPCHI2PV_ptr = decltype( Sel::Utils::impactParameterChi2( std::declval() ) ); using ip = - mp_product, mp_list const>, + mp_product, + mp_list const>, mp_append, ptr_and_ref>>; using ipchi2 = - mp_product, + mp_product, ptr_and_ref, mp_append, ptr_and_ref>>; using ipchi2_to_vtx = - mp_product, + mp_product, mp_list, mp_append, ptr_and_ref>>; -using pid = mp_product, +using pid = mp_product, mp_append, ptr_and_ref>>; -using muonpid = mp_product< - std::invoke_result_t, - mp_list, - mp_append, ptr_and_ref>>; - -using probnn = mp_product, - ptr_and_ref>; +using muonpid = + mp_product, + mp_append, ptr_and_ref>>; // For more complex functors it is easier to do them one by one, otherwise // compilation errors might kill us :( @@ -169,17 +172,18 @@ using probnn = mp_product; -using fdchi2_2 = - std::invoke_result_t; -using fdchi2_3 = - std::invoke_result_t; -using fdchi2_4 = std::invoke_result_t; +using fdchi2_2 = std::invoke_result_t; +using fdchi2_3 = std::invoke_result_t; -using fdchi2_5 = - std::invoke_result_t; -using fdchi2_6 = std::invoke_result_t; +using fdchi2_4 = std::invoke_result_t; +using fdchi2_5 = std::invoke_result_t; +using fdchi2_6 = + std::invoke_result_t; // // CorrectedMass( vertex, composite ) @@ -209,19 +213,19 @@ using cmerr5 = std::invoke_result_t, LHCb::Particle const&>; -using cmbt2 = std::invoke_result_t, LHCb::Particle const&>; // // MassWithHypotheses( vertices, composite ) // -using mh_1 = std::invoke_result_t, LHCb::Particle const&>; -using mh_2 = std::invoke_result_t, LHCb::Particle const*>; -using mh_3 = std::invoke_result_t, - LHCb::ParticleCombination const&>; +using mh_1 = std::invoke_result_t; +using mh_2 = std::invoke_result_t; +using mh_3 = + std::invoke_result_t const&>; // FIXME can't iterate over Sel::ParticleCombination -> no begin & end // using mh_4 = std::invoke_result_t, // Sel::ParticleCombinationN const& >; @@ -232,9 +236,9 @@ using mh_3 = std::invoke_result_t; -using m_2 = std::invoke_result_t; -using m_3 = std::invoke_result_t; +using m_1 = std::invoke_result_t; +using m_2 = std::invoke_result_t; +using m_3 = std::invoke_result_t; // FIXME charged basic doesn't support mass2() // using m_4 = std::invoke_result_t; @@ -242,19 +246,20 @@ using m_3 = std::invoke_result_t; // Liftetime & DLS // -using l_1 = std::invoke_result_t; using l_1 = - std::invoke_result_t; -using l_1 = std::invoke_result_t; - -using dls_1 = std::invoke_result_t; -using dls_2 = std::invoke_result_t; +using l_1 = std::invoke_result_t; +using l_1 = std::invoke_result_t; + +using dls_1 = std::invoke_result_t; +using dls_2 = std::invoke_result_t; -using dls_3 = std::invoke_result_t; +using dls_3 = std::invoke_result_t; -auto chi2perdof_func = Functors::chain( FF::ValueOr{ 0. }, FT::Chi2PerDoF{}, FP::GetTrack{} ); +auto chi2perdof_func = Functors::chain( FF::ValueOr{ 0. }, FT::Chi2PerDoF, FP::GetTrack ); using chi2perdof_prepared = decltype( chi2perdof_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); using chi2perdof_1 = std::invoke_result_t; using chi2perdof_2 = std::invoke_result_t; @@ -263,7 +268,7 @@ using chi2perdof_3 = std::invoke_result_t; using chi2perdof_5 = std::invoke_result_t; -auto chi2_func = Functors::chain( FF::ValueOr{ 0. }, FT::Chi2{}, FP::GetTrack{} ); +auto chi2_func = Functors::chain( FF::ValueOr{ 0. }, FT::Chi2, FP::GetTrack ); using chi2_prepared = decltype( chi2_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); using chi2_1 = std::invoke_result_t; using chi2_2 = std::invoke_result_t; @@ -272,31 +277,30 @@ using chi2_3 = std::invoke_result_t; using chi2_4 = std::invoke_result_t; using chi2_5 = std::invoke_result_t; -auto PT = Functors::chain( ::FC::Rho_Coordinate{}, ::FT::ThreeMomentum{} ); +auto PT = Functors::chain( ::FC::Rho_Coordinate, ::FT::ThreeMomentum ); // Test for ALLPV_FD // // create an instance of ALLPV flight distance functor (obtained from functor.code() in python) auto allpv_fd_func = // bind map and TES functors with forwarding the arguments - Functors::bind( - FF::Map( /* The functor to map over a range. */ - // chain magnitude and flight distance functor - Functors::chain( - // get magnitude of the flight distance vector - FC::Magnitude{}, - // subtract the vertex position from the particle position - operator-( - // vertex position: LHCb::Vertex -> Gaudi::XYZPoint -> vec3 - // Arg1: LHCb::Vertex - Functors::chain( FC::ToLinAlg{}, FC::Position{}, FC::EndVertex{}, FC::ForwardArgs<1>() ), - // end vertex of particle: LHCb::Particle -> Gaudi::XYZPoint -> vec3 - // Arg0: LHCb::Particle - Functors::chain( FC::ToLinAlg{}, FC::Position{}, FC::ForwardArgs<0>() ) ) ) ), - // get TES object and forward it - FC::TES( - /* List of DataHandles */ std::vector{ std::string{ "FakeLocation" } } ), - FC::ForwardArgs<>{} ); + Functors::bind( FF::Map( /* The functor to map over a range. */ + // chain magnitude and flight distance functor + Functors::chain( + // get magnitude of the flight distance vector + FC::Magnitude, + // subtract the vertex position from the particle position + operator-( + // vertex position: LHCb::Vertex -> Gaudi::XYZPoint -> vec3 + // Arg1: LHCb::Vertex + Functors::chain( FC::ToLinAlg, FC::Position, FC::EndVertex, FC::ForwardArg1 ), + // end vertex of particle: LHCb::Particle -> Gaudi::XYZPoint -> vec3 + // Arg0: LHCb::Particle + Functors::chain( FC::ToLinAlg, FC::Position, FC::ForwardArg0 ) ) ) ), + // get TES object and forward it + FC::TES( + /* List of DataHandles */ std::vector{ std::string{ "FakeLocation" } } ), + FC::ForwardArgs ); // get the type of the prepared functor that is returned when calling prepare() on the above functor using allpv_fd_func_type = decltype( allpv_fd_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); @@ -308,14 +312,14 @@ using allpv_fd_func_result_type = std::invoke_result_t Gaudi::XYZPoint -> vec3 - FF::Map( Functors::chain( FC::ToLinAlg{}, FC::Position{} ) ), + FF::Map( Functors::chain( FC::ToLinAlg, FC::Position ) ), // get TES object and forward it FC::TES( /* List of DataHandles */ std::vector{ std::string{ "FakeLocation" } } ) ), - FC::ForwardArgs<>{} ); + FC::ForwardArgs ); // get the type of the prepared functor that is returned when calling prepare() on the above functor using allpv_ip_func_type = decltype( allpv_ip_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); // get the result_type of invoking the allpv_ip_func_type with inputs. @@ -325,9 +329,9 @@ using allpv_ip_func_result_type = std::invoke_result_t>( /* List of DataHandles */ std::vector{ std::string{ "FakeLocation" } } ); -auto SUMCONE = Functors::chain( ::FF::ValueOr( /* The default value. */ 0.0f ), ::FF::Sum{}, - ::FF::Map( /* The functor to map over a range. */ Functors::chain( PT, ::FC::To{} ) ), - Functors::bind( ::FC::Relations{}, RELS, ::FC::ForwardArgs<>() ) ); +auto SUMCONE = Functors::chain( ::FF::ValueOr( /* The default value. */ 0.0f ), ::FF::Sum, + ::FF::Map( /* The functor to map over a range. */ Functors::chain( PT, ::FC::To ) ), + Functors::bind( ::FC::Relations, RELS, ::FC::ForwardArgs ) ); // TEST ASYM FUNCTOR auto asym_func = ( PT - SUMCONE ) / ( PT + SUMCONE ); using asym_func_type = decltype( asym_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); @@ -341,10 +345,10 @@ auto npvs_func = Functors::chain( using npvs_func_type = decltype( npvs_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); // get the result_type of functors reading RecSummary using npvs_func_res_type = std::invoke_result_t; -using inmuon_1 = std::invoke_result_t; +using inmuon_1 = std::invoke_result_t; // Create an instance for FIND_DECAY functor -auto find_decay_func = Functors::chain( PT, ::Functors::Decay::FindDecay( /* Decay descriptor */ "[B0 -> K+ pi-]CC" ) ); +auto find_decay_func = Functors::chain( PT, ::Functors::Decay::FindDecay( "[B0 -> K+ pi-]CC" ) ); // get the type of the prepared functor using find_decay_func_type = decltype( find_decay_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); // get the result_type of invoking the find_decay_func_type with inputs. @@ -393,15 +397,15 @@ using map_find_mc_decay_range_func_result_type = std::invoke_result_t; auto test_mintree = - Functors::chain( ::FF::Min{}, ::FF::Map( /* The functor to map over a range. */ PT ), - ::Functors::Filter( /* Predicate to filter the container with. */ ::Functors::AcceptAll{} ), + Functors::chain( ::FF::Min, ::FF::Map( /* The functor to map over a range. */ PT ), + ::Functors::Filter( /* Predicate to filter the container with. */ ::Functors::AcceptAll ), ::Functors::Adapters::DescendantsFromComposite{} ); using test_mintree_type = decltype( test_mintree.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); using test_mintree_result_type = std::invoke_result_t; using test_mintree_result_type2 = std::invoke_result_t; -auto const ID = ::Functors::Simulation::Particle_Id{}; -auto const MASS = ::Functors::Composite::Mass{}; +auto const ID = ::Functors::Simulation::Particle_Id; +auto const MASS = ::Functors::Composite::Mass; auto const PIPLUS = ::Functors::Particle::ParticlePropertyUser( /* ID to check */ "pi+" ); auto test_is_id = Functors::chain( ID, PIPLUS ) == ID; diff --git a/Phys/FunctorCore/tests/src/TestFunctors.cpp b/Phys/FunctorCore/tests/src/TestFunctors.cpp index cff2fabc8eb809d0a8c036ea3edb6049abe65902..528241a4357d1241718850c07b5f15860748ecb3 100644 --- a/Phys/FunctorCore/tests/src/TestFunctors.cpp +++ b/Phys/FunctorCore/tests/src/TestFunctors.cpp @@ -85,10 +85,15 @@ struct ETA_Count : public Functors::Function { } }; +template +auto trivial_prepare( F const& f ) { + return [g = f.prepare( EventContext{}, Functors::TopLevelInfo{} )]( const auto&... i ) { return g( true, i... ); }; +} + // Check that functors can be instantiated BOOST_AUTO_TEST_CASE( test_creating_functors ) { - [[maybe_unused]] Functors::AcceptAll ALL; - [[maybe_unused]] auto ip_gt_10 = Functors::Common::ImpactParameter(); + [[maybe_unused]] auto ALL = Functors::AcceptAll; + [[maybe_unused]] auto ip_gt_10 = Functors::Common::ImpactParameter; } struct DummyState { @@ -214,13 +219,13 @@ Tracks make_tracks() { } using Functors::Filter; -auto const PT = chain( Functors::Common::Rho_Coordinate{}, Functors::Track::ThreeMomentum{} ); -auto const PZ = chain( Functors::Common::Z_Coordinate{}, Functors::Track::ThreeMomentum{} ); -auto const ETA = chain( Functors::Common::Eta_Coordinate{}, Functors::Track::Slopes{} ); -auto const ENDVERTEX_POS = chain( Functors::Common::Position{}, Functors::Common::EndVertex{} ); -auto const END_VX = chain( Functors::Common::X_Coordinate{}, ENDVERTEX_POS ); -auto const END_VY = chain( Functors::Common::Y_Coordinate{}, ENDVERTEX_POS ); -auto const END_VZ = chain( Functors::Common::Z_Coordinate{}, ENDVERTEX_POS ); +auto const PT = chain( Functors::Common::Rho_Coordinate, Functors::Track::ThreeMomentum ); +auto const PZ = chain( Functors::Common::Z_Coordinate, Functors::Track::ThreeMomentum ); +auto const ETA = chain( Functors::Common::Eta_Coordinate, Functors::Track::Slopes ); +auto const ENDVERTEX_POS = chain( Functors::Common::Position, Functors::Common::EndVertex ); +auto const END_VX = chain( Functors::Common::X_Coordinate, ENDVERTEX_POS ); +auto const END_VY = chain( Functors::Common::Y_Coordinate, ENDVERTEX_POS ); +auto const END_VZ = chain( Functors::Common::Z_Coordinate, ENDVERTEX_POS ); // check we can define and access RICH DLL values BOOST_AUTO_TEST_CASE( test_rich_dll ) { @@ -265,7 +270,7 @@ BOOST_AUTO_TEST_CASE( test_rich_dll ) { // check we can apply an IsMuon cut to some tracks BOOST_AUTO_TEST_CASE( test_ptcut ) { - TrackFunctor ISMUON{ Filter{ Functors::PID::IsMuon{} } }; + TrackFunctor ISMUON{ Filter{ Functors::PID::IsMuon } }; auto tracks = make_tracks(); auto filtered_tracks = ISMUON( tracks ); BOOST_CHECK_EQUAL( tracks.size(), 3 ); @@ -273,7 +278,7 @@ BOOST_AUTO_TEST_CASE( test_ptcut ) { } // check we can apply an InMuon cut to some tracks BOOST_AUTO_TEST_CASE( test_inmuon ) { - TrackFunctor INMUON{ Filter{ Functors::PID::InAcceptance{} } }; + TrackFunctor INMUON{ Filter{ Functors::PID::InAcceptance } }; auto tracks = make_tracks(); auto filtered_tracks = INMUON( tracks ); BOOST_CHECK_EQUAL( tracks.size(), 3 ); @@ -282,7 +287,7 @@ BOOST_AUTO_TEST_CASE( test_inmuon ) { using SelOfDummy = Pr::Selection; BOOST_AUTO_TEST_CASE( test_ptcut_inmuon ) { - Functors::Functor INMUON{ Filter{ Functors::PID::InAcceptance{} } }; + Functors::Functor INMUON{ Filter{ Functors::PID::InAcceptance } }; auto tracks = make_tracks(); Pr::Selection track_sel{ tracks }; auto filtered_track_sel = INMUON( track_sel ); @@ -291,7 +296,7 @@ BOOST_AUTO_TEST_CASE( test_ptcut_inmuon ) { } BOOST_AUTO_TEST_CASE( test_ptcut_selection ) { - Functors::Functor ISMUON{ Filter{ Functors::PID::IsMuon{} } }; + Functors::Functor ISMUON{ Filter{ Functors::PID::IsMuon } }; auto tracks = make_tracks(); Pr::Selection track_sel{ tracks }; auto filtered_track_sel = ISMUON( track_sel ); @@ -328,8 +333,8 @@ BOOST_AUTO_TEST_CASE( test_predicate_from_function ) { auto one_track_functor() { // This is the full Run2 Hlt1TrackMVA expression, but we can't actually test using it because it has data // dependencies. ProbNN cuts have then been added by https://gitlab.cern.ch/lhcb/Rec/-/merge_requests/2471 - Functors::Track::GhostProbability GHOSTPROB; - Functors::Track::Chi2PerDoF CHI2PERDOF; + const auto GHOSTPROB = Functors::Track::GhostProbability; + const auto CHI2PERDOF = Functors::Track::Chi2PerDoF; auto MinPT = 1.f; auto MaxPT = 25.f; @@ -338,19 +343,19 @@ auto one_track_functor() { // generated via python. One would never actually write the below in c++ auto f_min_ipchi2_cut = Functors::bind( - ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameterChi2{}, MinIPChi2 ) ), + ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameterChi2, MinIPChi2 ) ), ::Functors::Common::TES( std::vector{ std::string{ PV_loc } } ), - ::Functors::Common::ForwardArgs{} ); + ::Functors::Common::ForwardArgs ); auto f_min_ipchi2 = - Functors::chain( ::Functors::Functional::Min{}, - Functors::bind( ::Functors::Functional::Map( ::Functors::Common::ImpactParameterChi2{} ), + Functors::chain( ::Functors::Functional::Min, + Functors::bind( ::Functors::Functional::Map( ::Functors::Common::ImpactParameterChi2 ), ::Functors::Common::TES( std::vector{ std::string{ PV_loc } } ), - ::Functors::Common::ForwardArgs{} ) ); + ::Functors::Common::ForwardArgs ) ); TrackFunctor one_track = Filter{ - ( CHI2PERDOF < 2.f ) & ( GHOSTPROB < 0.3f ) & ( Functors::Track::PROBNN_PI_t{} > 0.1f ) & + ( CHI2PERDOF < 2.f ) & ( GHOSTPROB < 0.3f ) & ( Functors::Track::PROBNN_PI > 0.1f ) & ( ( ( PT > MaxPT ) & f_min_ipchi2_cut ) | ( Functors::math::in_range( MinPT, PT, MaxPT ) & ( Functors::math::log( f_min_ipchi2 ) > ( 1.0 / Functors::math::pow( PT - 1.0, 2 ) + @@ -377,6 +382,9 @@ void testOnParticles( std::vector const& codes, Fun fun ) { } // test BOOST_CHECK( ( cut( parts ) ).empty() ); + if constexpr ( std::is_pointer_v ) { + for ( auto& p : parts ) delete p; + } } template void testPointerAndObject( std::vector const& codes, Fun fun ) { @@ -386,13 +394,12 @@ void testPointerAndObject( std::vector const& codes, Fun fun ) { BOOST_AUTO_TEST_CASE( test_ai_functors ) { // test probNN - testPointerAndObject( std::vector{ 13, 211, 321 }, - all_of( Functors::Track::PROBNN_MU_t{} > 0.1f, Functors::Track::PROBNN_E_t{} > 0.1f, - Functors::Track::PROBNN_P_t{} > 0.1f, Functors::Track::PROBNN_K_t{} > 0.1f, - Functors::Track::PROBNN_PI_t{} > 0.1f, Functors::Track::PROBNN_D_t{} > 0.1f, - Functors::Track::PROBNN_GHOST_t{} < 0.8f ) ); + testPointerAndObject( { 13, 211, 321 }, all_of( Functors::Track::PROBNN_MU > 0.1f, Functors::Track::PROBNN_E > 0.1f, + Functors::Track::PROBNN_P > 0.1f, Functors::Track::PROBNN_K > 0.1f, + Functors::Track::PROBNN_PI > 0.1f, Functors::Track::PROBNN_D > 0.1f, + Functors::Track::PROBNN_GHOST < 0.8f ) ); // test neutral functors - testPointerAndObject( std::vector{ 22, 111 }, + testPointerAndObject( { 22, 111 }, all_of( Functors::Neutral::IsPhoton > 0.5f, Functors::Neutral::IsNotH > 0.1f, Functors::Neutral::ShowerShape<0.f, Functors::Neutral::NeutralE19> 0.3f, Functors::chain( Functors::PID::CaloCellID::All, Functors::Neutral::NeutralID ) > 1.0f, @@ -402,13 +409,13 @@ BOOST_AUTO_TEST_CASE( test_ai_functors ) { // test calo and rich track functors testPointerAndObject( - std::vector{ 11, 22, 211 }, + { 11, 22, 211 }, all_of( Functors::PID::HasBrem, Functors::Track::HasBremAdded{}, Functors::PID::InEcal, Functors::chain( Functors::PID::CaloCellID::All, Functors::PID::ClusterID ) > 0, Functors::PID::InHcal, Functors::PID::InBrem, Functors::PID::BremEnergy > 0.f, Functors::PID::BremBendCorr > 0.f, Functors::PID::BremPIDe > 0.f, Functors::PID::EcalPIDe > 0.f, Functors::PID::EcalPIDmu > 0.f, Functors::PID::HcalPIDe > 0.f, Functors::PID::HcalPIDmu > 0.f, Functors::PID::ElectronShowerEoP > 0.f, - Functors::PID::ElectronShowerDLL > 0.f, Functors::PID::ClusterMatch{} > 0.f, + Functors::PID::ElectronShowerDLL > 0.f, Functors::PID::ClusterMatch > 0.f, Functors::PID::ElectronMatch > 0.f, Functors::PID::BremHypoMatch > 0.f, Functors::PID::ElectronEnergy > 0.f, Functors::PID::BremHypoEnergy > 0.f, Functors::PID::BremHypoDeltaX > 0.f, @@ -426,12 +433,12 @@ BOOST_AUTO_TEST_CASE( test_ai_functors ) { } BOOST_AUTO_TEST_CASE( test_1trackmva_functor ) { - Functors::Track::GhostProbability GHOSTPROB; - Functors::Track::Chi2PerDoF CHI2PERDOF; - auto MinPT = 1.f; - auto MaxPT = 25.f; - auto MinIPChi2 = 7.4f; - TrackFunctor pt_squared_cut = Filter{ Functors::math::pow( PT, 2 ) > 2.f }; + const auto GHOSTPROB = Functors::Track::GhostProbability; + const auto CHI2PERDOF = Functors::Track::Chi2PerDoF; + auto MinPT = 1.f; + auto MaxPT = 25.f; + auto MinIPChi2 = 7.4f; + TrackFunctor pt_squared_cut = Filter{ Functors::math::pow( PT, 2 ) > 2.f }; // This has had ETA put in place of MINIPCHI2 so it should actually be able to run... TrackFunctor one_track_simple = Filter{ ( CHI2PERDOF < 2.f ) & ( GHOSTPROB < 0.3f ) & @@ -446,39 +453,35 @@ BOOST_AUTO_TEST_CASE( test_1trackmva_functor ) { BOOST_AUTO_TEST_CASE( test_general_track_functor ) { - auto prepared_call = []( auto& functor, auto const& input ) { - return functor.prepare( EventContext{}, Functors::TopLevelInfo{} )( true, input ); - }; - - Functors::Track::Type TYPE; - Functors::Track::HasT HAST; - Functors::Track::HasUT HASUT; - Functors::Track::HasVelo HASVELO; - Functors::Track::History HISTORY; - Functors::Track::nFTHits NFTHITS; - Functors::Track::nUTHits NUTHITS; - Functors::Track::nVPHits NVPHITS; - Functors::Track::nHits NHITS; - Functors::Track::nDoF NDOF; - Functors::Track::Chi2 CHI2; - Functors::Track::MC_Reconstructed MC_RECONSTRUCTED; - Functors::Track::States STATES; - Functors::Particle::GetTrack GETTRACK; - Functors::Track::ReferencePoint REFERENCEPOINT; - auto const ISTTRACK = Functors::Track::IsTtrack; - auto const ISDOWNSTREAM = Functors::Track::IsDownstream; - auto const ISUPSTREAM = Functors::Track::IsUpstream; - auto const ISLONG = Functors::Track::IsLong; - auto const ISVELO = Functors::Track::IsVelo; - auto const ISVELOBACKWARD = Functors::Track::IsVeloBackward; - Functors::Track::HasTrackFlag ISINVALID; - Functors::Track::HasTrackFlag ISSELECTED; - Functors::Track::HasTrackFlag ISCLONE; - auto const NVPHITSA = Functors::Track::nVPHitsA; - auto const NVPHITSC = Functors::Track::nVPHitsC; - auto const NVPOVERLAP = Functors::Track::nVPOverlap; - - Functors::Functional::CastTo CAST_TO_INT; + auto const TYPE = Functors::Track::Type; + auto const HAST = Functors::Track::HasT; + auto const HASUT = Functors::Track::HasUT; + auto const HASVELO = Functors::Track::HasVelo; + auto const HISTORY = Functors::Track::History; + auto const NFTHITS = Functors::Track::nFTHits; + auto const NUTHITS = Functors::Track::nUTHits; + auto const NVPHITS = Functors::Track::nVPHits; + auto const NHITS = Functors::Track::nHits; + auto const NDOF = Functors::Track::nDoF; + auto const CHI2 = Functors::Track::Chi2; + auto const MC_RECONSTRUCTED = Functors::Track::MC_Reconstructed; + auto const STATES = Functors::Track::States; + auto const GETTRACK = Functors::Particle::GetTrack; + auto const REFERENCEPOINT = Functors::Track::ReferencePoint; + auto const ISTTRACK = trivial_prepare( Functors::Track::IsTtrack ); + auto const ISDOWNSTREAM = trivial_prepare( Functors::Track::IsDownstream ); + auto const ISUPSTREAM = trivial_prepare( Functors::Track::IsUpstream ); + auto const ISLONG = trivial_prepare( Functors::Track::IsLong ); + auto const ISVELO = trivial_prepare( Functors::Track::IsVelo ); + auto const ISVELOBACKWARD = trivial_prepare( Functors::Track::IsVeloBackward ); + auto const ISINVALID = Functors::Track::IsInvalid; + auto const ISSELECTED = Functors::Track::IsSelected; + auto const ISCLONE = Functors::Track::IsClone; + auto const NVPHITSA = trivial_prepare( Functors::Track::nVPHitsA ); + auto const NVPHITSC = trivial_prepare( Functors::Track::nVPHitsC ); + auto const NVPOVERLAP = trivial_prepare( Functors::Track::nVPOverlap ); + + auto const CAST_TO_INT = Functors::Functional::CastTo; BOOST_CHECK_EQUAL( CAST_TO_INT( true ), 1 ); BOOST_CHECK_EQUAL( CAST_TO_INT( false ), 0 ); @@ -503,9 +506,9 @@ BOOST_AUTO_TEST_CASE( test_general_track_functor ) { BOOST_CHECK_EQUAL( NHITS( track ), 12 ); BOOST_CHECK_EQUAL( NDOF( track ), 1 ); BOOST_CHECK_EQUAL( CHI2( track ), 1.f ); - BOOST_CHECK_EQUAL( prepared_call( NVPHITSA, track ), 1 ); - BOOST_CHECK_EQUAL( prepared_call( NVPHITSC, track ), 2 ); - BOOST_CHECK_EQUAL( prepared_call( NVPOVERLAP, track ), 1 ); + BOOST_CHECK_EQUAL( NVPHITSA( track ), 1 ); + BOOST_CHECK_EQUAL( NVPHITSC( track ), 2 ); + BOOST_CHECK_EQUAL( NVPOVERLAP( track ), 1 ); DummyReconstructedObject rec{ 1, &track }; BOOST_CHECK_EQUAL( MC_RECONSTRUCTED( rec ), 1 ); @@ -515,12 +518,12 @@ BOOST_AUTO_TEST_CASE( test_general_track_functor ) { track.addToStates( &state_0 ); BOOST_CHECK_EQUAL( REFERENCEPOINT( STATES( track ).front() ).x().cast(), 0 ); - Functors::Track::StateAt STATE_AT{ LHCb::State::Location::FirstMeasurement }; - Functors::Track::StateAt STATE_AT_CTB{ "ClosestToBeam" }; - Functors::Track::TrackState FIRST_STATE{}; - Functors::Common::Position POS{}; - Functors::Common::X_Coordinate X{}; - auto v1track = LHCb::Event::v1::Track{}; + Functors::Track::StateAt STATE_AT{ LHCb::State::Location::FirstMeasurement }; + Functors::Track::StateAt STATE_AT_CTB{ "ClosestToBeam" }; + auto const FIRST_STATE = Functors::Track::TrackState; + const auto POS = Functors::Common::Position; + const auto X = Functors::Common::X_Coordinate; + auto v1track = LHCb::Event::v1::Track{}; v1track.addToStates( LHCb::State{ { 1, 2, 3, 4, 5 }, 6, LHCb::State::Location::FirstMeasurement } ); BOOST_CHECK_EQUAL( X( POS( ( STATE_AT( v1track ).value() ) ) ), 1 ); @@ -532,9 +535,9 @@ BOOST_AUTO_TEST_CASE( test_general_track_functor ) { } BOOST_AUTO_TEST_CASE( test_brem_functors ) { - auto const BREM = Functors::Track::Bremsstrahlung{}; + auto const BREM = Functors::Track::Bremsstrahlung; auto const PZ_WITH_BREM = chain( PZ, BREM ); - auto const MASS_WITH_BREM = chain( Functors::Composite::Mass{}, BREM ); + auto const MASS_WITH_BREM = chain( Functors::Composite::Mass, BREM ); auto prepared_call = []( auto& functor, auto const& input ) { return functor.prepare( EventContext{}, Functors::TopLevelInfo{} )( true, input ); @@ -584,11 +587,11 @@ BOOST_AUTO_TEST_CASE( test_brem_functors ) { } BOOST_AUTO_TEST_CASE( test_muonPID_functors ) { - Functors::PID::IsMuonTight ISMUONTIGHT; - Functors::PID::MuonChi2Corr MUONCHI2CORR; - Functors::PID::MuonLLMu MUONLLMU; - Functors::PID::MuonLLBg MUONLLBG; - Functors::PID::MuonCatBoost MUONCATBOOST; + const auto ISMUONTIGHT = Functors::PID::IsMuonTight; + const auto MUONCHI2CORR = Functors::PID::MuonChi2Corr; + const auto MUONLLMU = Functors::PID::MuonLLMu; + const auto MUONLLBG = Functors::PID::MuonLLBg; + const auto MUONCATBOOST = Functors::PID::MuonCatBoost; DummyTrack track{ 10.f, 10.f, true, true }; BOOST_CHECK_EQUAL( ISMUONTIGHT( track ), false ); @@ -616,10 +619,10 @@ BOOST_AUTO_TEST_CASE( test_reconstructible_functor ) { mc_property.setProperty( mc_particles( 2 ), property_2 ); // Build functor - Functors::Simulation::MC::Property MC_PROPERTY; - Functors::Simulation::CheckMask CHECKMASK{ MCTrackInfo::flagMasks::maskHasVelo }; - Functors::Simulation::MC::ChargeReconstructible CHARGE_RECONSTRUCTIBLE; - Functors::Simulation::Category CATEGORY; + const auto MC_PROPERTY = Functors::Simulation::MC::Property; + Functors::Simulation::CheckMask CHECKMASK{ MCTrackInfo::flagMasks::maskHasVelo }; + const auto CHARGE_RECONSTRUCTIBLE = Functors::Simulation::MC::ChargeReconstructible; + const auto CATEGORY = Functors::Simulation::Category; // Test BOOST_CHECK_EQUAL( MC_PROPERTY( mc_property, mc_particles( 1 ) ), property_1 ); @@ -653,39 +656,39 @@ BOOST_AUTO_TEST_CASE( test_short_circuiting ) { BOOST_AUTO_TEST_CASE( test_scalar_functors ) { auto f_min_ip_cut = - Functors::bind( ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameter{}, -.1 ) ), - Functors::chain( ::Functors::Functional::Map( Functors::chain( ::Functors::Common::ToLinAlg{}, - ::Functors::Common::Position{} ) ), + Functors::bind( ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameter, -.1 ) ), + Functors::chain( ::Functors::Functional::Map( Functors::chain( ::Functors::Common::ToLinAlg, + ::Functors::Common::Position ) ), ::Functors::Common::TES( std::vector{ std::string{ "path/to/pvs" } } ) ), - ::Functors::Common::ForwardArgs{} ); + ::Functors::Common::ForwardArgs ); BOOST_CHECK_THROW( TrackFunctor{ Filter{ f_min_ip_cut } }( make_tracks() ), GaudiException ); auto f_min_ip_cut_recvtx = Functors::bind( - ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameter{}, -.1 ) ), - Functors::chain( ::Functors::Functional::Map( - Functors::chain( ::Functors::Common::ToLinAlg{}, ::Functors::Common::Position{} ) ), - ::Functors::Common::TES( std::vector{ std::string{ "path/to/pvs" } } ) ), - ::Functors::Common::ForwardArgs{} ); + ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameter, -.1 ) ), + Functors::chain( + ::Functors::Functional::Map( Functors::chain( ::Functors::Common::ToLinAlg, ::Functors::Common::Position ) ), + ::Functors::Common::TES( std::vector{ std::string{ "path/to/pvs" } } ) ), + ::Functors::Common::ForwardArgs ); BOOST_CHECK_THROW( TrackFunctor{ Filter{ f_min_ip_cut_recvtx } }( make_tracks() ), GaudiException ); } BOOST_AUTO_TEST_CASE( test_vector_functors ) { - Functors::Functional::Reverse REVERSE_RANGE; - Functors::Functional::Front FRONT; - std::vector vec_int{ 1, 2, 3, 4, 5 }; + auto const REVERSE_RANGE = Functors::Functional::Reverse; + auto const FRONT = Functors::Functional::Front; + std::vector vec_int{ 1, 2, 3, 4, 5 }; BOOST_CHECK_EQUAL( FRONT( REVERSE_RANGE( vec_int ) ), 5 ); using VT = LHCb::Pr::Velo::Tracks; auto f_min_ip_cut = - Functors::bind( ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameter{}, 0.1 ) ), - Functors::chain( ::Functors::Functional::Map( Functors::chain( ::Functors::Common::ToLinAlg{}, - ::Functors::Common::Position{} ) ), + Functors::bind( ::Functors::Functional::MapAllOf( operator>( ::Functors::Common::ImpactParameter, 0.1 ) ), + Functors::chain( ::Functors::Functional::Map( Functors::chain( ::Functors::Common::ToLinAlg, + ::Functors::Common::Position ) ), ::Functors::Common::TES( std::vector{ std::string{ "path/to/pvs" } } ) ), - ::Functors::Common::ForwardArgs{} ); + ::Functors::Common::ForwardArgs ); BOOST_CHECK_THROW( Functors::Functor{ Filter{ f_min_ip_cut } }( VT{} ), GaudiException ); } @@ -709,7 +712,7 @@ using TrackFunction = Functors::Functor; using TrackPredicate = Functors::Functor; BOOST_AUTO_TEST_CASE( test_single_object_functions ) { DummyTrack track{ 5.f, 1.f, false, false }; // pT, eta, InMuon, IsMuon - TrackPredicate inacceptance{ Functors::PID::InAcceptance{} }, ismuon{ Functors::PID::IsMuon{} }; + TrackPredicate inacceptance{ Functors::PID::InAcceptance }, ismuon{ Functors::PID::IsMuon }; TrackFunction pT{ PT }, eta{ ETA }; BOOST_CHECK_EQUAL( pT( track ), track.pt() ); BOOST_CHECK_CLOSE( eta( track ), track.pseudoRapidity(), 0.0001 ); @@ -724,7 +727,7 @@ struct InfoStruct { BOOST_AUTO_TEST_CASE( test_mva_functor ) { using namespace Functors; auto mva = MVA( { { "MatrixnetFile", std::string{ "paramfile://data/Hlt1TwoTrackMVA.mx" } } }, - MVAInput( "chi2", Track::Chi2PerDoF{} ), MVAInput( "fdchi2", ETA ), + MVAInput( "chi2", Track::Chi2PerDoF ), MVAInput( "fdchi2", ETA ), MVAInput( "sumpt", Adapters::Accumulate{ PT } ), MVAInput( "nlt16", ETA ) ); TopLevelInfo top_level; mva.bind( top_level ); @@ -821,7 +824,7 @@ struct Prepare_Helper : public Functors::Function { Prepare_Helper( std::size_t& executions, std::size_t& preparations ) : m_executions{ executions }, m_preparations{ preparations } {} - auto prepare() const { + auto prepare( EventContext const&, Functors::TopLevelInfo const& ) const { m_preparations++; return [this]() { this->m_executions++; }; } @@ -847,7 +850,7 @@ BOOST_AUTO_TEST_CASE( test_preparation ) { } struct PrepareWithTopLevel : public Functors::Function { - auto prepare( Functors::TopLevelInfo const& top_level ) const { + auto prepare( EventContext const&, Functors::TopLevelInfo const& top_level ) const { return [ptr = top_level.algorithm()]() { return ptr; }; } }; @@ -997,7 +1000,7 @@ BOOST_AUTO_TEST_CASE( test_variant_adapters ) { // have the nHits() accessor demanded by the functor. // Use an adapter to specify which members of the variant are OK - Functors::Functor func{ Adapter( Functors::Track::nHits{} ) }; + Functors::Functor func{ Adapter( Functors::Track::nHits ) }; // Use the adapter on a charged Particle, this should work: BOOST_CHECK_EQUAL( func( p_charged ), Charged{}.nHits() ); @@ -1007,20 +1010,20 @@ BOOST_AUTO_TEST_CASE( test_variant_adapters ) { func( p_composite ); BOOST_CHECK( false ); // should never get here } catch ( GaudiException& e ) { - BOOST_CHECK( e.message() == "detail::Adapter blocked call with type Composite" ); + BOOST_CHECK( e.message().find( "blocked call with type Composite" ) != e.message().npos ); } // Use an adapter that has a fallback instead of throwing a runtime error auto default_nhits = 0; Functors::Functor func_default{ - DefaultAdapter( Functors::Track::nHits{}, Functors::detail::promote( default_nhits ) ) }; + DefaultAdapter( Functors::Track::nHits, Functors::detail::promote( default_nhits ) ) }; BOOST_CHECK_EQUAL( func_default( p_charged ), Charged{}.nHits() ); BOOST_CHECK_EQUAL( func_default( p_composite ), default_nhits ); // Try with a cut instead Functors::Functor cut{ - DefaultAdapter( Functors::Track::nHits{} > 3, Functors::AcceptNone{} ) }; + DefaultAdapter( Functors::Track::nHits > 3, Functors::AcceptNone ) }; BOOST_CHECK( cut( p_charged ) ); BOOST_CHECK( !cut( p_composite ) ); @@ -1148,28 +1151,28 @@ BOOST_AUTO_TEST_CASE( test_relation_table ) { // Functor applying cut on another particle // @todo implement the generic case once the specific one works - auto const empty_range = Functors::Common::Relations{}( empty_table, parts( 0 ) ); - auto const range0 = Functors::Common::Relations{}( table, parts( 0 ) ); - auto const range0_size = Functors::detail::SizeOf{}( range0.value() ); + auto const empty_range = Functors::Common::Relations( empty_table, parts( 0 ) ); + auto const range0 = Functors::Common::Relations( table, parts( 0 ) ); + auto const range0_size = Functors::detail::SizeOf( range0.value() ); BOOST_CHECK( !empty_range.has_value() ); BOOST_CHECK_EQUAL( range0.value().size(), 1 ); BOOST_CHECK_EQUAL( range0_size, 1 ); - auto from = Functors::chain( Functors::Common::From{}, Functors::Functional::Front{}, Functors::Common::Relations{} ); + auto from = Functors::chain( Functors::Common::From, Functors::Functional::Front, Functors::Common::Relations ); auto from_p = from.prepare( evtCtx, top_level ); BOOST_CHECK_EQUAL( from_p( true, table, parts( 0 ) ), parts( 0 ) ); BOOST_CHECK_EQUAL( from_p( true, table, parts( 1 ) ), parts( 1 ) ); BOOST_CHECK_EQUAL( from_p( true, table, parts( 2 ) ), parts( 2 ) ); - auto to = Functors::chain( Functors::Common::To{}, Functors::Functional::Front{}, Functors::Common::Relations{} ); + auto to = Functors::chain( Functors::Common::To, Functors::Functional::Front, Functors::Common::Relations ); auto to_p = to.prepare( evtCtx, top_level ); BOOST_CHECK_EQUAL( to_p( true, table, parts( 0 ) ), parts( 1 ) ); BOOST_CHECK_EQUAL( to_p( true, table, parts( 1 ) ), parts( 2 ) ); BOOST_CHECK_EQUAL( to_p( true, table, parts( 2 ) ), parts( 0 ) ); auto const tmp = - Functors::chain( PT, Functors::Common::To{}, Functors::Functional::Front{}, Functors::Common::Relations{} ); + Functors::chain( PT, Functors::Common::To, Functors::Functional::Front, Functors::Common::Relations ); auto const tmp_p = tmp.prepare( evtCtx, top_level ); auto check_empty = tmp_p( true, empty_table, parts( 1 ) ); auto p0 = tmp_p( true, table, parts( 2 ) ); @@ -1190,9 +1193,9 @@ BOOST_AUTO_TEST_CASE( test_relation_table_array ) { auto parts = make_parts(); // Create three dummay particles RelationTable table = make_relations( parts ); - auto const range = Functors::Common::Relations{}( table, parts( 0 ) ); + auto const range = Functors::Common::Relations( table, parts( 0 ) ); BOOST_CHECK( range.has_value() ); - auto const pt_to = Functors::chain( PT, Functors::Common::To{} ); + auto const pt_to = Functors::chain( PT, Functors::Common::To ); auto const pt_to_map = Functors::Functional::Map( pt_to ); auto const prepped = pt_to_map.prepare( evtCtx, top_level ); auto const result = prepped( true, range.value() ); @@ -1235,10 +1238,10 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { IsolationTable empty_table; auto const front_weight = - Functors::chain( Functors::Common::Weight{}, Functors::Functional::Front{}, Functors::Common::Relations{} ); + Functors::chain( Functors::Common::Weight, Functors::Functional::Front, Functors::Common::Relations ); auto const front_weight_prepped = front_weight.prepare( evtCtx, top_level ); auto const back_weight = - Functors::chain( Functors::Common::Weight{}, Functors::Functional::Back{}, Functors::Common::Relations{} ); + Functors::chain( Functors::Common::Weight, Functors::Functional::Back, Functors::Common::Relations ); auto const back_weight_prepped = back_weight.prepare( evtCtx, top_level ); auto w0 = front_weight_prepped( true, table, parts( 2 ) ); auto w1 = back_weight_prepped( true, table, parts( 2 ) ); @@ -1249,13 +1252,13 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { BOOST_CHECK( LHCb::Utils::as_arithmetic( w1.value() ) > fake_w1_min && LHCb::Utils::as_arithmetic( w1.value() ) < fake_w1_max ); - auto const pt_to_min_weight_entry = Functors::chain( - PT, Functors::Common::To{}, Functors::Functional::EntryWithMinRelatedValueOf( Functors::Common::Weight{} ), - Functors::Common::Relations{} ); + auto const pt_to_min_weight_entry = + Functors::chain( PT, Functors::Common::To, Functors::Functional::MinElement( Functors::Common::Weight ), + Functors::Common::Relations ); auto const pt_to_min_weight_entry_prepped = pt_to_min_weight_entry.prepare( evtCtx, top_level ); - auto const pt_to_max_weight_entry = Functors::chain( - PT, Functors::Common::To{}, Functors::Functional::EntryWithMaxRelatedValueOf( Functors::Common::Weight{} ), - Functors::Common::Relations{} ); + auto const pt_to_max_weight_entry = + Functors::chain( PT, Functors::Common::To, Functors::Functional::MaxElement( Functors::Common::Weight ), + Functors::Common::Relations ); auto const pt_to_max_weight_entry_prepped = pt_to_max_weight_entry.prepare( evtCtx, top_level ); auto empty_test = pt_to_min_weight_entry_prepped( true, empty_table, parts( 0 ) ); auto empty_test2 = pt_to_max_weight_entry_prepped( true, empty_table, parts( 1 ) ); @@ -1268,26 +1271,26 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { BOOST_CHECK( LHCb::Utils::as_arithmetic( pt_wmin.value() ) < 100 ); BOOST_CHECK( LHCb::Utils::as_arithmetic( pt_wmax.value() ) > 100 ); - auto const value_or_pt_to_min_weight_entry = Functors::chain( - Functors::Functional::ValueOr{ 0 }, PT, Functors::Common::To{}, - Functors::Functional::EntryWithMinRelatedValueOf( Functors::Common::Weight{} ), Functors::Common::Relations{} ); + auto const value_or_pt_to_min_weight_entry = + Functors::chain( Functors::Functional::ValueOr{ 0 }, PT, Functors::Common::To, + Functors::Functional::MinElement( Functors::Common::Weight ), Functors::Common::Relations ); auto const value_or_pt_to_min_weight_entry_prepped = value_or_pt_to_min_weight_entry.prepare( evtCtx, top_level ); auto value_or_empty_test = value_or_pt_to_min_weight_entry_prepped( true, empty_table, parts( 0 ) ); BOOST_CHECK( LHCb::Utils::as_arithmetic( value_or_empty_test ) == 0 ); - auto const relation = Functors::Common::Relations{}( table, parts( 1 ) ); + auto const relation = Functors::Common::Relations( table, parts( 1 ) ); BOOST_CHECK( relation.has_value() ); - auto pt_to = chain( PT, Functors::Common::To{} ); + auto pt_to = chain( PT, Functors::Common::To ); auto const pt_to_map = Functors::Functional::Map( pt_to ); auto const prepped = pt_to_map.prepare( evtCtx, top_level ); auto const mapcone = prepped( true, relation.value() ); - auto sumcone = Functors::Functional::Sum{}( mapcone ); - auto mincone = Functors::Functional::Min{}( mapcone ); - auto maxcone = Functors::Functional::Max{}( mapcone ); - auto nincone = Functors::detail::SizeOf{}( relation.value() ); + auto sumcone = Functors::Functional::Sum( mapcone ); + auto mincone = Functors::Functional::Min( mapcone ); + auto maxcone = Functors::Functional::Max( mapcone ); + auto nincone = Functors::detail::SizeOf( relation.value() ); BOOST_CHECK( LHCb::Utils::as_arithmetic( sumcone ) > fake_sum_pt_min && LHCb::Utils::as_arithmetic( sumcone ) < fake_sum_pt_max ); @@ -1297,9 +1300,9 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { LHCb::Utils::as_arithmetic( mincone ) < fake_min_pt_max ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( nincone ), 2 ); - auto sum = chain( Functors::Functional::Sum{}, Functors::Functional::Map( pt_to ) ); - auto p1_pt = chain( PT, Functors::Common::ForwardArgs<0>{} ); - auto p1_cone_pt = chain( sum, Functors::Common::ForwardArgs<1>{} ); + auto sum = chain( Functors::Functional::Sum, Functors::Functional::Map( pt_to ) ); + auto p1_pt = chain( PT, Functors::Common::ForwardArg0 ); + auto p1_cone_pt = chain( sum, Functors::Common::ForwardArg1 ); auto tmp = ( p1_pt - p1_cone_pt ) / ( p1_pt + p1_cone_pt ); auto asym_p = tmp.prepare( evtCtx, top_level ); auto asym = asym_p( true, parts( 1 ), relation.value() ); @@ -1455,16 +1458,16 @@ BOOST_AUTO_TEST_CASE( test_cov_matrix_functors ) { v2_posMomCovMatrix, {}, {}, {} ); // Define functors - EventContext const evtCtx; - Functors::TopLevelInfo const top_level; - Functors::Particle::momCovMatrix MOM_COV_MATRIX; - Functors::Particle::posCovMatrix POS_COV_MATRIX; - Functors::Particle::threeMomCovMatrix THREE_MOM_COV_MATRIX; - Functors::Particle::momPosCovMatrix MOM_POS_COV_MATRIX; - Functors::Particle::threeMomPosCovMatrix THREE_MOM_POS_COV_MATRIX; - Functors::Track::ThreeMomentum THREEMOMENTUM; - auto const P = chain( Functors::Common::Magnitude{}, THREEMOMENTUM ); - auto PERR2 = Functors::math::similarity( THREEMOMENTUM / P, THREE_MOM_COV_MATRIX ); + EventContext const evtCtx; + Functors::TopLevelInfo const top_level; + auto const MOM_COV_MATRIX = Functors::Particle::momCovMatrix; + auto const POS_COV_MATRIX = Functors::Particle::posCovMatrix; + auto const THREE_MOM_COV_MATRIX = Functors::Particle::threeMomCovMatrix; + auto const MOM_POS_COV_MATRIX = Functors::Particle::momPosCovMatrix; + auto const THREE_MOM_POS_COV_MATRIX = Functors::Particle::threeMomPosCovMatrix; + auto const THREEMOMENTUM = Functors::Track::ThreeMomentum; + auto const P = chain( Functors::Common::Magnitude, THREEMOMENTUM ); + auto PERR2 = Functors::math::similarity( THREEMOMENTUM / P, THREE_MOM_COV_MATRIX ); // Expected result auto mom_cov_matrix = LHCb::LinAlg::convert( v1_momCovMatrix ); @@ -1573,28 +1576,40 @@ BOOST_AUTO_TEST_CASE( test_decaytime_functor ) { auto& pv = vertices.emplace_back(); pv.setCovMatrix( poscov ); - Functors::Composite::Lifetime l{}; - /*auto const lifetime =*/l( pv, part ); + auto lt = Functors::Composite::Lifetime; + /*auto const lifetime =*/lt( pv, part ); } BOOST_AUTO_TEST_CASE( test_mc_prompt ) { // Prepare functors using MC_FIRST_LONGLIVED_ANCESTOR = Functors::Simulation::MC::FirstLongLivedAncestor; - using HAS_VALUE = Functors::Functional::HasValue; + const auto HAS_VALUE = Functors::Functional::HasValue; using VALUE_OR = Functors::Functional::ValueOr; - using PARTICLE_ID = Functors::Simulation::Particle_Id; - using OBJECT_KEY = Functors::TES::ObjectKey; + const auto PARTICLE_ID = Functors::Simulation::Particle_Id; + const auto OBJECT_KEY = Functors::TES::ObjectKey; // Sice the F.MC_FIRST_LONGLIVED_ANCESTOR needs ParticlePropertySvc from Gaudi Application, it can not be truely // tested, here we just check that it at least compiles. - const auto MC_ISPROMPT = chain( HAS_VALUE{}, MC_FIRST_LONGLIVED_ANCESTOR{} ); - const auto MC_LONGLIVED_ID = chain( VALUE_OR{ 0 }, PARTICLE_ID{}, MC_FIRST_LONGLIVED_ANCESTOR{} ); - const auto MC_LONGLIVED_KEY = chain( VALUE_OR{ -1 }, OBJECT_KEY{}, MC_FIRST_LONGLIVED_ANCESTOR{} ); + const auto MC_ISPROMPT = chain( HAS_VALUE, MC_FIRST_LONGLIVED_ANCESTOR{} ); + const auto MC_LONGLIVED_ID = chain( VALUE_OR{ 0 }, PARTICLE_ID, MC_FIRST_LONGLIVED_ANCESTOR{} ); + const auto MC_LONGLIVED_KEY = chain( VALUE_OR{ -1 }, OBJECT_KEY, MC_FIRST_LONGLIVED_ANCESTOR{} ); // Test the F.HAS_VALUE - Functors::Optional valid_optional{ 0 }, invalid_optional{ std::nullopt }; - BOOST_CHECK_EQUAL( HAS_VALUE{}( valid_optional ), true ); - BOOST_CHECK_EQUAL( HAS_VALUE{}( invalid_optional ), false ); + Functors::Optional valid_optional{ 0 }; + BOOST_CHECK_EQUAL( HAS_VALUE( valid_optional ), true ); + Functors::Optional invalid_optional{ std::nullopt }; + BOOST_CHECK_EQUAL( HAS_VALUE( invalid_optional ), false ); + Functors::Optional default_optional{}; + BOOST_CHECK_EQUAL( HAS_VALUE( default_optional ), false ); + void* void_ptr = nullptr; + BOOST_CHECK_EQUAL( HAS_VALUE( void_ptr ), false ); + int i = 0; + BOOST_CHECK_EQUAL( HAS_VALUE( &i ), true ); + BOOST_CHECK_EQUAL( HAS_VALUE( static_cast( &i ) ), true ); + BOOST_CHECK_EQUAL( HAS_VALUE( nullptr ), false ); + std::optional valid_std_optional{ 0 }; + BOOST_CHECK_EQUAL( HAS_VALUE( valid_std_optional ), true ); + BOOST_CHECK_EQUAL( HAS_VALUE( std::nullopt ), false ); } BOOST_AUTO_TEST_CASE( test_mcorr_functors ) { @@ -1627,11 +1642,11 @@ BOOST_AUTO_TEST_CASE( test_mcorr_functors ) { pv.setPosition( Gaudi::XYZPoint{ 0.0, 0.0, 0.0 } ); pv.setCovMatrix( poscov ); - Functors::Composite::CorrectedMass mc{}; - auto const mcorr_parr = mc( pv, B0_parr ); - auto const mcorr_perp = mc( pv, B0_perp ); - Functors::Composite::CorrectedMassError mce; - auto const mcorrerr_perp = mce( pv, B0_perp ); + auto const mc = Functors::Composite::CorrectedMass{}; + auto const mcorr_parr = mc( pv, B0_parr ); + auto const mcorr_perp = mc( pv, B0_perp ); + auto const mce = Functors::Composite::CorrectedMassError{}; + auto const mcorrerr_perp = mce( pv, B0_perp ); const double bmass = 5.e3; const double truemcorr = 0.; @@ -1730,38 +1745,38 @@ BOOST_AUTO_TEST_CASE( test_mc_functors ) { // get the functors to retrieve various information const EventContext evtCtx; const Functors::TopLevelInfo top_level; - const auto PARTICLE_ID = Functors::Simulation::Particle_Id{}; - const auto OBJECT_KEY = Functors::TES::ObjectKey{}; - const auto MOTHER = Functors::Simulation::MC::Mother{}; - const auto LIFETIME = Functors::Simulation::MC::LifeTime{}; - const auto P4 = Functors::Track::FourMomentum{}; - const auto GM_P4 = chain( Functors::Track::FourMomentum{}, MOTHER, MOTHER ); - const auto GM_MRF = Functors::bind( Functors::LHCbMath::boost_to{}, GM_P4, chain( P4, MOTHER ) ); - const auto CHILD_MRF = Functors::bind( Functors::LHCbMath::boost_to{}, P4, chain( P4, MOTHER ) ); - const auto CHILD_MRF_REV = Functors::bind( Functors::LHCbMath::boost_from{}, CHILD_MRF, chain( P4, MOTHER ) ); - const auto HELICITY_ANGLE = Functors::bind( Functors::LHCbMath::normed_dot_3dim{}, GM_MRF, CHILD_MRF ); - const auto VTX_TIME = Functors::Simulation::MCVertex::Time; - const auto VTX_TYPE = Functors::Simulation::MCVertex::Type; - const auto VTX_ISPRIMARY = Functors::Simulation::MCVertex::IsPrimary; - const auto VTX_ISDECAY = Functors::Simulation::MCVertex::IsDecay; - const auto VTX_PRODUCTS = Functors::Simulation::MCVertex::Products; - auto const PX = chain( Functors::Common::X_Coordinate{}, Functors::Track::ThreeMomentum{} ); - auto const PY = chain( Functors::Common::Y_Coordinate{}, Functors::Track::ThreeMomentum{} ); - auto const PZ = chain( Functors::Common::Z_Coordinate{}, Functors::Track::ThreeMomentum{} ); - auto const E = chain( Functors::Common::E_Coordinate{}, Functors::Track::FourMomentum{} ); - auto const P = chain( Functors::Common::Magnitude{}, Functors::Track::ThreeMomentum{} ); - const auto TRUEORIGINVERTEX_X = - chain( Functors::Common::X_Coordinate{}, Functors::Common::Position{}, Functors::Simulation::MC::OriginVertex ); + const auto PARTICLE_ID = Functors::Simulation::Particle_Id; + const auto OBJECT_KEY = Functors::TES::ObjectKey; + const auto MOTHER = Functors::Simulation::MC::Mother; + const auto LIFETIME = Functors::Simulation::MC::LifeTime; + const auto P4 = Functors::Track::FourMomentum; + const auto GM_P4 = chain( Functors::Track::FourMomentum, MOTHER, MOTHER ); + const auto GM_MRF = bind( Functors::LHCbMath::boost_to, GM_P4, chain( P4, MOTHER ) ); + const auto CHILD_MRF = bind( Functors::LHCbMath::boost_to, P4, chain( P4, MOTHER ) ); + const auto CHILD_MRF_REV = bind( Functors::LHCbMath::boost_from, CHILD_MRF, chain( P4, MOTHER ) ); + const auto HELICITY_ANGLE = bind( Functors::LHCbMath::normed_dot_3dim, GM_MRF, CHILD_MRF ); + const auto VTX_TIME = Functors::Simulation::MCVertex::Time; + const auto VTX_TYPE = Functors::Simulation::MCVertex::Type; + const auto VTX_ISPRIMARY = Functors::Simulation::MCVertex::IsPrimary; + const auto VTX_ISDECAY = Functors::Simulation::MCVertex::IsDecay; + const auto VTX_PRODUCTS = Functors::Simulation::MCVertex::Products; + auto const PX = chain( Functors::Common::X_Coordinate, Functors::Track::ThreeMomentum ); + auto const PY = chain( Functors::Common::Y_Coordinate, Functors::Track::ThreeMomentum ); + auto const PZ = chain( Functors::Common::Z_Coordinate, Functors::Track::ThreeMomentum ); + auto const E = chain( Functors::Common::E_Coordinate, Functors::Track::FourMomentum ); + auto const P = chain( Functors::Common::Magnitude, Functors::Track::ThreeMomentum ); + const auto TRUEORIGINVERTEX_X = + chain( Functors::Common::X_Coordinate, Functors::Common::Position, Functors::Simulation::MC::OriginVertex ); const auto TRUEORIGINVERTEX_Y = - chain( Functors::Common::Y_Coordinate{}, Functors::Common::Position{}, Functors::Simulation::MC::OriginVertex ); + chain( Functors::Common::Y_Coordinate, Functors::Common::Position, Functors::Simulation::MC::OriginVertex ); const auto TRUEORIGINVERTEX_Z = - chain( Functors::Common::Z_Coordinate{}, Functors::Common::Position{}, Functors::Simulation::MC::OriginVertex ); + chain( Functors::Common::Z_Coordinate, Functors::Common::Position, Functors::Simulation::MC::OriginVertex ); const auto TRUEPV_X = - chain( Functors::Common::X_Coordinate{}, Functors::Common::Position{}, Functors::Simulation::MC::PrimaryVertex ); + chain( Functors::Common::X_Coordinate, Functors::Common::Position, Functors::Simulation::MC::PrimaryVertex ); const auto TRUEPV_Y = - chain( Functors::Common::Y_Coordinate{}, Functors::Common::Position{}, Functors::Simulation::MC::PrimaryVertex ); + chain( Functors::Common::Y_Coordinate, Functors::Common::Position, Functors::Simulation::MC::PrimaryVertex ); const auto TRUEPV_Z = - chain( Functors::Common::Z_Coordinate{}, Functors::Common::Position{}, Functors::Simulation::MC::PrimaryVertex ); + chain( Functors::Common::Z_Coordinate, Functors::Common::Position, Functors::Simulation::MC::PrimaryVertex ); const auto TRUEENDVERTEX_X = END_VX.prepare( evtCtx, top_level ); const auto TRUEENDVERTEX_Y = END_VY.prepare( evtCtx, top_level ); const auto TRUEENDVERTEX_Z = END_VZ.prepare( evtCtx, top_level ); @@ -1840,9 +1855,9 @@ BOOST_AUTO_TEST_CASE( test_mc_functors ) { BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEPV_Y, mcp ) ), pp_pos.Y() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEPV_Z, mcp ) ), pp_pos.Z() ); - BOOST_CHECK_EQUAL( Functors::Track::ReferencePoint{}( momcp ).x().cast(), 0 ); - BOOST_CHECK_EQUAL( Functors::Track::ReferencePoint{}( momcp ).y().cast(), 0 ); - BOOST_CHECK_EQUAL( Functors::Track::ReferencePoint{}( momcp ).z().cast(), 0 ); + BOOST_CHECK_EQUAL( Functors::Track::ReferencePoint( momcp ).x().cast(), 0 ); + BOOST_CHECK_EQUAL( Functors::Track::ReferencePoint( momcp ).y().cast(), 0 ); + BOOST_CHECK_EQUAL( Functors::Track::ReferencePoint( momcp ).z().cast(), 0 ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( MC_MOTHER_KEY, mcp ).value_or( -1 ) ), momcp.key() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( MC_MOTHER_ID, mcp ).value_or( 0 ) ), muon.pid() ); @@ -1944,40 +1959,40 @@ BOOST_AUTO_TEST_CASE( test_tes_func ) { sel_dec.setConfiguredTCK( hlt_tck ); // test operator() of Functors::details::OdinInfo - const auto op_RUNNUMBER = Functors::TES::RunNumber; - const auto op_EVENTNUMBER = Functors::TES::EventNumber; - const auto op_EVENTTYPE = Functors::TES::EventType; - const auto op_BUNCHROSSING_ID = Functors::TES::BunchCrossingID; - const auto op_BUNCHROSSING_TYPE = Functors::TES::BunchCrossingType; - const auto op_ODINTCK = Functors::TES::OdinTCK; - const auto op_GPSTIME = Functors::TES::GpsTime; + const auto op_RUNNUMBER = Functors::TES::RunNumber; + const auto op_EVENTNUMBER = Functors::TES::EventNumber; + const auto op_EVENTTYPE = Functors::TES::EventType; + const auto op_BUNCHCROSSING_ID = Functors::TES::BunchCrossingID; + const auto op_BUNCHCROSSING_TYPE = Functors::TES::BunchCrossingType; + const auto op_ODINTCK = Functors::TES::OdinTCK; + const auto op_GPSTIME = Functors::TES::GpsTime; // conduct checks BOOST_CHECK_EQUAL( op_RUNNUMBER( odin ), fake_runNum ); BOOST_CHECK_EQUAL( op_EVENTNUMBER( odin ), fake_evtNum ); BOOST_CHECK_EQUAL( op_EVENTTYPE( odin ), fake_evtType ); - BOOST_CHECK_EQUAL( op_BUNCHROSSING_ID( odin ), fake_bunchId ); - BOOST_CHECK_EQUAL( op_BUNCHROSSING_TYPE( odin ), fake_bunchType ); + BOOST_CHECK_EQUAL( op_BUNCHCROSSING_ID( odin ), fake_bunchId ); + BOOST_CHECK_EQUAL( op_BUNCHCROSSING_TYPE( odin ), fake_bunchType ); BOOST_CHECK_EQUAL( op_ODINTCK( odin ), fake_odinTck ); BOOST_CHECK_EQUAL( op_GPSTIME( odin ), fake_gpsTime ); // test decreport functions taking dummy location std::vector tup = { "Line1Decision", "Line2Decision", "Line3Decision" }; - auto op_DECISION_1 = + const auto op_DECISION_1 = Functors::chain( Functors::Functional::ValueOr{ false }, Functors::TES::SelectionDecision{ tup[0] } ); - auto op_DECISION_2 = + const auto op_DECISION_2 = Functors::chain( Functors::Functional::ValueOr{ false }, Functors::TES::SelectionDecision{ tup[1] } ); - auto op_DECISION_3 = + const auto op_DECISION_3 = Functors::chain( Functors::Functional::ValueOr{ false }, Functors::TES::SelectionDecision{ tup[2] } ); - auto op_DECISION_4 = + const auto op_DECISION_4 = Functors::chain( Functors::Functional::ValueOr{ false }, ( Functors::TES::SelectionDecision{ tup[0] } ) & ( Functors::TES::SelectionDecision{ tup[2] } ) ); - auto op_DECISION_5 = + const auto op_DECISION_5 = Functors::chain( Functors::Functional::ValueOr{ false }, ( Functors::TES::SelectionDecision{ tup[0] } ) | ( Functors::TES::SelectionDecision{ tup[2] } ) ); - auto op_DECISION_6 = + const auto op_DECISION_6 = Functors::chain( Functors::Functional::ValueOr{ false }, ( Functors::TES::SelectionDecision{ tup[0] } ) | ( Functors::TES::SelectionDecision{ tup[1] } ) ); - Functors::TES::SelectionTCK op_TCK{}; + const auto op_TCK = Functors::TES::SelectionTCK; // checks BOOST_CHECK_EQUAL( op_TCK( sel_dec ), hlt_tck ); BOOST_CHECK_EQUAL( op_DECISION_1.prepare( evtCtx, top_level )( true, sel_dec ), static_cast( line1_dec ) ); @@ -2006,7 +2021,7 @@ BOOST_AUTO_TEST_CASE( test_tes_func ) { BOOST_CHECK_EQUAL( op_RE_DECISION_FILTER2( sel_dec ), true ); // test operator() of Functors::TES::SizeOf - Functors::detail::SizeOf op_size; + const auto op_size = Functors::detail::SizeOf; BOOST_CHECK_EQUAL( op_size( tup ), tup.size() ); } @@ -2019,7 +2034,7 @@ BOOST_AUTO_TEST_CASE( test_functional_functors ) { pvs.emplace_back( Gaudi::XYZPoint( 1, 2, 3 ) ); pvs.emplace_back( Gaudi::XYZPoint( 3, 2, 1 ) ); - auto x_pos = chain( Functors::Common::X_Coordinate{}, Functors::Common::Position{} ); + auto x_pos = chain( Functors::Common::X_Coordinate, Functors::Common::Position ); auto mapped_x_pos = Functors::Functional::Map( x_pos ); @@ -2027,12 +2042,12 @@ BOOST_AUTO_TEST_CASE( test_functional_functors ) { auto x = prepped( true, pvs ); - BOOST_CHECK_EQUAL( Functors::Functional::Front{}( x ), 1 ); + BOOST_CHECK_EQUAL( Functors::Functional::Front( x ), 1 ); - BOOST_CHECK_EQUAL( Functors::Functional::Back{}( x ), 3 ); + BOOST_CHECK_EQUAL( Functors::Functional::Back( x ), 3 ); // Let's do a check of a mapped IP functor - auto f_ip = Functors::Common::ImpactParameter{}; + auto f_ip = Functors::Common::ImpactParameter; auto mapped_ip = Functors::Functional::Map( f_ip ); auto p_mapped_ip = mapped_ip.prepare( evtCtx, top_level ); @@ -2054,8 +2069,8 @@ BOOST_AUTO_TEST_CASE( test_functional_functors ) { BOOST_CHECK( ( first_ip > 0.81649 && first_ip < 0.81650 ) ); BOOST_CHECK_EQUAL( tmp[1].cast(), 0 ); - auto min = Functors::Functional::Min{}; - auto max = Functors::Functional::Max{}; + auto min = Functors::Functional::Min; + auto max = Functors::Functional::Max; std::vector vec{ 1.1, 2.2, 3.3, 1.5, 0.9, 1.0 }; @@ -2176,18 +2191,18 @@ BOOST_AUTO_TEST_CASE( check_binary_functors ) { auto parts = make_parts(); auto tracks = make_tracks(); - auto eta = chain( Functors::Common::Eta_Coordinate{}, Functors::Track::Slopes{} ); - auto phi = chain( Functors::Common::Phi_Coordinate{}, Functors::Track::Slopes{} ); + auto eta = chain( Functors::Common::Eta_Coordinate, Functors::Track::Slopes ); + auto phi = chain( Functors::Common::Phi_Coordinate, Functors::Track::Slopes ); - auto eta0 = chain( eta, Functors::Common::ForwardArgs<0>{} ); - auto eta1 = chain( eta, Functors::Common::ForwardArgs<1>{} ); + auto eta0 = chain( eta, Functors::Common::ForwardArg0 ); + auto eta1 = chain( eta, Functors::Common::ForwardArg1 ); - auto phi0 = chain( phi, Functors::Common::ForwardArgs<0>{} ); - auto phi1 = chain( phi, Functors::Common::ForwardArgs<1>{} ); + auto phi0 = chain( phi, Functors::Common::ForwardArg0 ); + auto phi1 = chain( phi, Functors::Common::ForwardArg1 ); auto diff_eta = eta0 - eta1; auto diff_phi = phi0 - phi1; - auto dphi_adj = chain( Functors::Common::AdjustAngle{}, diff_phi ); + auto dphi_adj = chain( Functors::Common::AdjustAngle, diff_phi ); auto deta_p = diff_eta.prepare( evtCtx, top_level ); auto dphi_p = dphi_adj.prepare( evtCtx, top_level ); @@ -2198,14 +2213,14 @@ BOOST_AUTO_TEST_CASE( check_binary_functors ) { auto delta_r2 = diff_eta * diff_eta + dphi_adj * dphi_adj; auto dr2_p = delta_r2.prepare( evtCtx, top_level ); auto dr2 = dr2_p( true, tracks[0], tracks[1] ); - auto delta_r = chain( Functors::Common::Sqrt{}, delta_r2 ); + auto delta_r = chain( Functors::Common::Sqrt, delta_r2 ); auto dr_p = delta_r.prepare( evtCtx, top_level ); auto dr = dr_p( true, tracks[0], tracks[1] ); - auto mom0 = chain( Functors::Track::FourMomentum{}, Functors::Common::ForwardArgs<0>{} ); - auto mom1 = chain( Functors::Track::FourMomentum{}, Functors::Common::ForwardArgs<1>{} ); + auto mom0 = chain( Functors::Track::FourMomentum, Functors::Common::ForwardArg0 ); + auto mom1 = chain( Functors::Track::FourMomentum, Functors::Common::ForwardArg1 ); - auto comb_mass = chain( Functors::Composite::Mass{}, ( mom0 + mom1 ) ); + auto comb_mass = chain( Functors::Composite::Mass, ( mom0 + mom1 ) ); auto cmass_p = comb_mass.prepare( evtCtx, top_level ); auto cmass = cmass_p( true, parts( 0 ), parts( 1 ) ); @@ -2235,9 +2250,9 @@ BOOST_AUTO_TEST_CASE( check_binary_functors ) { decayvertex.setCovMatrix( poscov ); part.setPosCovMatrix( poscov ); - const auto& best_pv_p0 = Functors::Common::BestPV{}( pvs, part0 ); - auto refpv_ipchi2 = Functors::Common::ImpactParameterChi2{}( best_pv_p0, part ); - auto ownpv_ipchi2 = Functors::Common::ImpactParameterChi2ToOwnPV{}( part ); + const auto& best_pv_p0 = Functors::Common::BestPV( pvs, part0 ); + auto refpv_ipchi2 = Functors::Common::ImpactParameterChi2( best_pv_p0, part ); + auto ownpv_ipchi2 = Functors::Common::ImpactParameterChi2ToOwnPV( part ); BOOST_CHECK( LHCb::Utils::as_arithmetic( deta ) < fake_delta_eta ); BOOST_CHECK( LHCb::Utils::as_arithmetic( dphi ) < fake_delta_phi ); @@ -2247,8 +2262,9 @@ BOOST_AUTO_TEST_CASE( check_binary_functors ) { LHCb::Utils::as_arithmetic( cmass ) < fake_comb_mass_max ); BOOST_CHECK( LHCb::Utils::as_arithmetic( refpv_ipchi2 ) > fake_ref_part_pv_ipchi2 ); BOOST_CHECK( LHCb::Utils::as_arithmetic( ownpv_ipchi2 ) > fake_ref_part_pv_ipchi2 ); - BOOST_CHECK( Functors::Common::OwnPV{}( part )->position() == pvs.front().position() ); - BOOST_CHECK( Functors::Common::HasOwnPV{}( part ) == true ); + BOOST_CHECK_EQUAL( Functors::Common::OwnPV( part )->position(), pvs.front().position() ); + BOOST_CHECK_EQUAL( Functors::Common::OwnPV( part )->position(), pvs.front().position() ); + BOOST_CHECK_EQUAL( Functors::Common::HasOwnPV( part ), true ); } BOOST_AUTO_TEST_CASE( test_flatten_functor ) { @@ -2404,12 +2420,12 @@ BOOST_AUTO_TEST_CASE( test_quark_content_functor ) { const auto HAS_BOTTOM = Functors::Simulation::HasQuark( "b" ); const auto HAS_CHARM = Functors::Simulation::HasQuark( "c" ); - const auto IS_HADRON = Functors::Simulation::IsHadron{}; - const auto IS_MESON = Functors::Simulation::IsMeson{}; - const auto IS_BARYON = Functors::Simulation::IsBaryon{}; - const auto IS_LEPTON = Functors::Simulation::IsLepton{}; + const auto IS_HADRON = Functors::Simulation::IsHadron; + const auto IS_MESON = Functors::Simulation::IsMeson; + const auto IS_BARYON = Functors::Simulation::IsBaryon; + const auto IS_LEPTON = Functors::Simulation::IsLepton; - const auto PARTICLE_ID_OBJ = Functors::Simulation::Particle_Id_Obj{}; + const auto PARTICLE_ID_OBJ = Functors::Simulation::Particle_Id_Obj; const auto B_plus_id_obj = PARTICLE_ID_OBJ( B_plus ); BOOST_CHECK_EQUAL( B_plus_id_obj.pid(), 521 ); @@ -2430,31 +2446,29 @@ BOOST_AUTO_TEST_CASE( test_quark_content_functor ) { BOOST_AUTO_TEST_CASE( test_flat_vector_functor ) { // test to check flatten vector functor // vector of vector of float and integer - std::vector> vec_float = { { 1.0, 2.0, 3.0 }, { 4.0, 5.0, 6.0 }, { 7.0, 8.0, 9.0 } }; - std::vector> vec_int = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + std::vector> vec_float = { { 1.0, 2.0, 3.0 }, { 4.0, 5.0, 6.0 }, { 7.0, 8.0, 9.0 } }; + std::vector vec_float_flat = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0 }; - const auto FLATTEN_VECTOR = Functors::Common::Flatten{}; - const auto CAST_TO_FLOAT = Functors::Functional::CastTo{}; - auto flat_float = FLATTEN_VECTOR( vec_float ); - auto flat_int = FLATTEN_VECTOR( vec_int ); + std::vector> vec_int = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + std::vector vec_int_flat = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + auto flat_float = Functors::Common::Flatten( vec_float ); + auto flat_int = Functors::Common::Flatten( vec_int ); // check the flattened vectors - BOOST_CHECK_EQUAL( flat_float.size(), 9 ); - BOOST_CHECK_EQUAL( flat_int.size(), 9 ); - BOOST_CHECK_EQUAL( flat_float[0], 1.0 ); - BOOST_CHECK_EQUAL( flat_int[0], 1 ); - BOOST_CHECK_EQUAL( flat_float[5], 6.0 ); - BOOST_CHECK_EQUAL( flat_int[5], 6 ); + BOOST_CHECK_EQUAL_COLLECTIONS( flat_float.begin(), flat_float.end(), vec_float_flat.begin(), vec_float_flat.end() ); + BOOST_CHECK_EQUAL_COLLECTIONS( flat_int.begin(), flat_int.end(), vec_int_flat.begin(), vec_int_flat.end() ); - BOOST_CHECK_EQUAL( CAST_TO_FLOAT( flat_int[2] ), flat_float[2] ); + BOOST_CHECK_EQUAL( Functors::Functional::CastTo( flat_int[2] ), flat_float[2] ); } BOOST_AUTO_TEST_CASE( check_addressof_functor ) { - int a = 10; - auto func = Functors::Common::AddressOf{}; - auto ptr = func( a ); - BOOST_CHECK( ptr == &a ); - BOOST_CHECK( *ptr == a ); + int a = 10; + BOOST_CHECK_EQUAL( Functors::Common::AddressOf( a ), &a ); + BOOST_CHECK_EQUAL( Functors::Common::AddressOf( &a ), &a ); + // should not compile - but how to check that? + // auto ptr = &a ; + // Functors::Common::AddressOf( &ptr); } struct DbgVal final { @@ -2496,7 +2510,7 @@ BOOST_AUTO_TEST_CASE( check_lifetime_and_forwarding_logic ) { EventContext const evtCtx; Functors::TopLevelInfo top_level; - auto add_3 = Functors::bind( Functors::Examples::AddInputs{}, Functors::Examples::PlusN{ 5 }, + auto add_3 = Functors::bind( Functors::Examples::AddInputs, Functors::Examples::PlusN{ 5 }, Functors::Examples::PlusN{ 3 }, Functors::Examples::PlusN{ 1 } ); auto p_add_3 = add_3.prepare( evtCtx, top_level ); @@ -2504,10 +2518,10 @@ BOOST_AUTO_TEST_CASE( check_lifetime_and_forwarding_logic ) { auto res = p_add_3( true, 1 ); BOOST_CHECK_EQUAL( res, 12 ); - auto add_fwd = Functors::bind( Functors::Examples::AddInputs{}, - Functors::chain( Functors::Common::ForwardArgs<>{}, Functors::Examples::PlusN{ 5 }, - Functors::Common::ForwardArgs<>{} ), - Functors::Examples::PlusN{ 3 } ); + auto add_fwd = Functors::bind( + Functors::Examples::AddInputs, + Functors::chain( Functors::Common::ForwardArgs, Functors::Examples::PlusN{ 5 }, Functors::Common::ForwardArgs ), + Functors::Examples::PlusN{ 3 } ); auto p_add_fwd = add_fwd.prepare( evtCtx, top_level ); @@ -2529,7 +2543,7 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { // OptReturn returns a number if called with true else an empty Functors::Optional - auto opt_times_two = Functors::chain( Functors::Examples::TimesTwo{}, Functors::Examples::OptReturn{ 10 } ); + auto opt_times_two = Functors::chain( Functors::Examples::TimesTwo, Functors::Examples::OptReturn{ 10 } ); auto p_opt_times_two = opt_times_two.prepare( evtCtx, top_level ); @@ -2542,7 +2556,7 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { BOOST_CHECK( !res2.has_value() ); // Test that binding of functors with optional return also works. - auto add_3_opt = Functors::bind( Functors::Examples::AddInputs{}, Functors::Examples::OptReturn{ 5 }, + auto add_3_opt = Functors::bind( Functors::Examples::AddInputs, Functors::Examples::OptReturn{ 5 }, Functors::Examples::OptReturn{ 3 }, Functors::Examples::OptReturn{ 1 } ); auto p_add_3_opt = add_3_opt.prepare( evtCtx, top_level ); @@ -2553,10 +2567,10 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { BOOST_CHECK( !res4.has_value() ); // bigger test that has 3 functors that discconected from each other can return an empty optional - auto opt0 = Functors::chain( Functors::Examples::OptReturn{ 5 }, Functors::Common::ForwardArgs<0>{} ); - auto opt1 = Functors::chain( Functors::Examples::OptReturn{ 3 }, Functors::Common::ForwardArgs<1>{} ); - auto opt2 = Functors::chain( Functors::Examples::OptReturn{ 1 }, Functors::Common::ForwardArgs<2>{} ); - auto add_opts = Functors::bind( Functors::Examples::AddInputs{}, opt0, opt1, opt2 ); + auto opt0 = Functors::chain( Functors::Examples::OptReturn{ 5 }, Functors::Common::ForwardArg0 ); + auto opt1 = Functors::chain( Functors::Examples::OptReturn{ 3 }, Functors::Common::ForwardArg1 ); + auto opt2 = Functors::chain( Functors::Examples::OptReturn{ 1 }, Functors::Common::ForwardArg2 ); + auto add_opts = Functors::bind( Functors::Examples::AddInputs, opt0, opt1, opt2 ); auto p_add_opts = add_opts.prepare( evtCtx, top_level ); auto res5 = p_add_opts( true, true, true, true ); @@ -2587,8 +2601,8 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { BOOST_CHECK_EQUAL( res13, 10 ); BOOST_CHECK_EQUAL( res14, 123 ); - auto long_val_or = Functors::chain( Functors::Functional::ValueOr{ 123 }, Functors::Examples::TimesTwo{}, - Functors::Examples::TimesTwo{}, Functors::Examples::OptReturn{ 10 } ); + auto long_val_or = Functors::chain( Functors::Functional::ValueOr{ 123 }, Functors::Examples::TimesTwo, + Functors::Examples::TimesTwo, Functors::Examples::OptReturn{ 10 } ); auto p_long_val_or = long_val_or.prepare( evtCtx, top_level ); @@ -2636,10 +2650,10 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { LHCb::LinAlg::Vec3 vec_a{ 1.f, 2.f, 3.f }, vec_b{ 4.f, 5.f, 6.f }; auto test_operators_4 = - Functors::chain( Functors::Functional::ValueOr{ 123.f }, Functors::Common::Magnitude{}, + Functors::chain( Functors::Functional::ValueOr{ 123.f }, Functors::Common::Magnitude, Functors::Examples::OptReturn{ vec_a } + Functors::Examples::OptReturn{ vec_b } ); auto test_operators_5 = - Functors::chain( Functors::Functional::ValueOr{ 123.f }, Functors::Common::Magnitude{}, + Functors::chain( Functors::Functional::ValueOr{ 123.f }, Functors::Common::Magnitude, Functors::Examples::OptReturn{ vec_a } - Functors::Examples::OptReturn{ vec_b } ); auto p_test_operators_4 = test_operators_4.prepare( evtCtx, top_level ); auto p_test_operators_5 = test_operators_5.prepare( evtCtx, top_level ); @@ -2702,7 +2716,7 @@ BOOST_AUTO_TEST_CASE( test_arithmetic_functor ) { EventContext const evtCtx; Functors::TopLevelInfo top_level; - auto opt_abs = Functors::chain( Functors::Common::Abs{}, Functors::Examples::OptReturn{ -42 } ); + auto opt_abs = Functors::chain( Functors::Common::Abs, Functors::Examples::OptReturn{ -42 } ); auto p_opt_abs = opt_abs.prepare( evtCtx, top_level ); @@ -2715,8 +2729,8 @@ BOOST_AUTO_TEST_CASE( test_get_proto_functor ) { // create protoparticle LHCb::ProtoParticle proto; - Functors::Particle::PPHasMuonInfo PPHASMUON; - Functors::Particle::PPHasRich PPHASRICH; + const auto PPHASMUON = Functors::Particle::PPHasMuonInfo; + const auto PPHASRICH = Functors::Particle::PPHasRich; BOOST_CHECK_EQUAL( PPHASMUON( proto ), false ); BOOST_CHECK_EQUAL( PPHASRICH( proto ), false ); @@ -2740,8 +2754,8 @@ BOOST_AUTO_TEST_CASE( test_get_track_functor ) { LHCb::Particle charged_basic; charged_basic.setProto( &proto ); // get track from functor for v1 - auto TRACK = Functors::Particle::GetTrack{}; - auto THREEMOMENTUM = Functors::Track::ThreeMomentum{}; + auto TRACK = Functors::Particle::GetTrack; + auto THREEMOMENTUM = Functors::Track::ThreeMomentum; auto trck_func = TRACK( charged_basic ).value(); auto trck_func_threemom = THREEMOMENTUM( trck_func ); // Check that the result is correct... allow for tiny numerical tolerance: 1e-6 relative @@ -2804,9 +2818,9 @@ BOOST_AUTO_TEST_CASE( test_get_track_functor ) { // the following tests accessing weights (ExtraTags) of RelationTable1D/2D using // the Weight and Get functors. - auto WEIGHT = Functors::Common::Weight{}; - auto GET_0 = Functors::Common::Get<0>{}; - auto MIN = Functors::Functional::MinElementNotZero{}; + const auto WEIGHT = Functors::Common::Weight; + const auto GET_0 = Functors::Common::Get<0>; + const auto MIN = Functors::Functional::MinElementNotZero; struct Val1 : LHCb::Event::int_field {}; struct Val2 : LHCb::Event::float_field {}; const auto reltracks = v3::generate_tracks( 2 * SIMDWrapper::best::types::size, unique_id_gen, 1, zn ); @@ -2845,7 +2859,7 @@ BOOST_AUTO_TEST_CASE( test_Value_ValueOrDict ) { std::map map_default = { { "a", -1 }, { "b", -1 } }; // test Value - auto val = Functors::chain( Functors::Functional::Value{}, Functors::Examples::OptReturn{ map } ); + auto val = Functors::chain( Functors::Functional::Value, Functors::Examples::OptReturn{ map } ); auto p_val = val.prepare( evtCtx, top_level ); auto funval = p_val( true, true ); BOOST_CHECK_THROW( p_val( true, false ), GaudiException ); @@ -2951,40 +2965,39 @@ BOOST_AUTO_TEST_CASE( test_tree_functors ) { auto basic = ::Functors::Adapters::BasicsFromComposite{}( B0 ); BOOST_CHECK_EQUAL_COLLECTIONS( basic.begin(), basic.end(), basic_expected.begin(), basic_expected.end() ); - auto const& MINTREE = Functors::chain( - ::Functors::Functional::Min{}, + auto const MINTREE = Functors::chain( + ::Functors::Functional::Min, ::Functors::Functional::Map( /* The functor to map over a range. */ Functors::chain( - ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) ), + ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) ), ::Functors::Filter( /* Predicate to filter the container with. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), ::Functors::Adapters::DescendantsFromComposite{} ); - auto const& MAXTREE = Functors::chain( - ::Functors::Functional::Max{}, + auto const MAXTREE = Functors::chain( + ::Functors::Functional::Max, ::Functors::Functional::Map( /* The functor to map over a range. */ Functors::chain( - ::Functors::Common::Rho_Coordinate{}, ::Functors::Track::ThreeMomentum{} ) ), + ::Functors::Common::Rho_Coordinate, ::Functors::Track::ThreeMomentum ) ), ::Functors::Filter( /* Predicate to filter the container with. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), ::Functors::Adapters::DescendantsFromComposite{} ); - auto const& NINTREE = Functors::chain( - ::Functors::detail::SizeOf{}, + auto const NINTREE = Functors::chain( + ::Functors::detail::SizeOf, ::Functors::Filter( /* Predicate to filter the container with. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), ::Functors::Adapters::DescendantsFromComposite{} ); - auto const& INTREE = Functors::chain( + auto const INTREE = Functors::chain( ::Functors::Functional::MapAnyOf( /* The predicate functor to map over a range. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), ::Functors::Adapters::DescendantsFromComposite{} ); - auto const& SHARE_TRACKS = operator==( - Functors::chain( ::Functors::Particle::GetTrack{}, ::Functors::Particle::GetProtoParticle{}, - ::Functors::Common::ForwardArgs<0>() ), - Functors::chain( ::Functors::Particle::GetTrack{}, ::Functors::Particle::GetProtoParticle{}, - ::Functors::Common::ForwardArgs<1>() ) ); + auto const SHARE_TRACKS = ( Functors::chain( ::Functors::Particle::GetTrack, ::Functors::Particle::GetProtoParticle, + ::Functors::Common::ForwardArg0 ) == + Functors::chain( ::Functors::Particle::GetTrack, ::Functors::Particle::GetProtoParticle, + ::Functors::Common::ForwardArg1 ) ); - auto const& FIND_IN_TREE = Functors::bind( - ::Functors::Functional::MapAnyOf( SHARE_TRACKS ), - Functors::chain( ::Functors::Adapters::BasicsFromComposite{}, ::Functors::Common::ForwardArgs<0>() ), - ::Functors::Common::ForwardArgs<1>() ); + auto const& FIND_IN_TREE = + Functors::bind( ::Functors::Functional::MapAnyOf( SHARE_TRACKS ), + Functors::chain( ::Functors::Adapters::BasicsFromComposite{}, ::Functors::Common::ForwardArg0 ), + ::Functors::Common::ForwardArg1 ); auto mintree_prepped = MINTREE.prepare( evtCtx, top_level ); auto maxtree_prepped = MAXTREE.prepare( evtCtx, top_level ); @@ -3017,24 +3030,24 @@ BOOST_AUTO_TEST_CASE( test_tree_functors ) { BOOST_CHECK_EQUAL( grandchildren[4]->particleID().pid(), -211 ); // is the second entry a pi- BOOST_CHECK_EQUAL( grandchildren[5]->particleID().pid(), -211 ); // is the third entry a pi- - auto const& CHILD_NINGENERATION = Functors::chain( - ::Functors::detail::SizeOf{}, + auto const CHILD_NINGENERATION = Functors::chain( + ::Functors::detail::SizeOf, ::Functors::Filter( /* Predicate to filter the container with. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), CHILD ); - auto const& CHILD_INGENERATION = Functors::chain( + auto const CHILD_INGENERATION = Functors::chain( ::Functors::Functional::MapAnyOf( /* The predicate functor to map over a range. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), CHILD ); - auto const& GCHILD_NINGENERATION = Functors::chain( - ::Functors::detail::SizeOf{}, + auto const GCHILD_NINGENERATION = Functors::chain( + ::Functors::detail::SizeOf, ::Functors::Filter( /* Predicate to filter the container with. */ operator>( - Functors::chain( ::Functors::Common::X_Coordinate{}, ::Functors::Track::ThreeMomentum{} ), 200 ) ), + Functors::chain( ::Functors::Common::X_Coordinate, ::Functors::Track::ThreeMomentum ), 200 ) ), GCHILD ); - auto const& GCHILD_INGENERATION = Functors::chain( - ::Functors::Functional::MapAnyOf( /* The predicate functor to map over a range. */ ::Functors::AcceptAll{} ), + auto const GCHILD_INGENERATION = Functors::chain( + ::Functors::Functional::MapAnyOf( /* The predicate functor to map over a range. */ ::Functors::AcceptAll ), GCHILD ); auto child_ningeneration_prepped = CHILD_NINGENERATION.prepare( evtCtx, top_level ); @@ -3047,7 +3060,7 @@ BOOST_AUTO_TEST_CASE( test_tree_functors ) { BOOST_CHECK_EQUAL( gchild_ningeneration_prepped( true, B0 ), 2 ); BOOST_CHECK_EQUAL( gchild_ingeneration_prepped( true, B0 ), true ); - Functors::Particle::IsBasicParticle ISBASICPARTICLE; + const auto ISBASICPARTICLE = Functors::Particle::IsBasicParticle; BOOST_CHECK_EQUAL( ISBASICPARTICLE( B0 ), false ); BOOST_CHECK_EQUAL( ISBASICPARTICLE( children[0] ), false ); BOOST_CHECK_EQUAL( ISBASICPARTICLE( grandchildren[0] ), true ); @@ -3058,14 +3071,15 @@ BOOST_AUTO_TEST_CASE( test_tistos_functors ) { using optional_map_t = Functors::Optional; using RelationTable_P2Map_t = LHCb::Relation1D; using VALUE_FROM_DICT = Functors::Functional::ValueFromDict; - using IS_TIS = Functors::Particle::IsTis; - using IS_TOS = Functors::Particle::IsTos; - using TO = Functors::Common::To; - using FRONT = Functors::Functional::Front; - using RELATIONS = Functors::Common::Relations; - using CAST_TO_INT = Functors::Functional::CastTo; + const auto IS_TIS = Functors::Particle::IsTis; + const auto IS_TOS = Functors::Particle::IsTos; + const auto TO = Functors::Common::To; + const auto FRONT = Functors::Functional::Front; + const auto RELATIONS = Functors::Common::Relations; + const auto CAST_TO_INT = Functors::Functional::CastTo; using VALUE_OR_INT = Functors::Functional::ValueOr; using VALUE_OR_BOOL = Functors::Functional::ValueOr; + EventContext const evtCtx; Functors::TopLevelInfo const top_level; @@ -3084,26 +3098,22 @@ BOOST_AUTO_TEST_CASE( test_tistos_functors ) { RelationTable_P2Map_t table; table.relate( parts( 0 ), tisTosMap ).ignore(); // Create composed functors for various scenarious - auto const MAP_TO_RELATED = Functors::chain( TO{}, FRONT{}, RELATIONS{} ); + auto const MAP_TO_RELATED = Functors::chain( TO, FRONT, RELATIONS ); // for integer outputs (tupling) - auto const tmp_l1_istos_int = - Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TOS{}, VALUE_FROM_DICT{ "Line1" }, - MAP_TO_RELATED ); // all correct - auto const tmp_l1_istis_int = - Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TIS{}, VALUE_FROM_DICT{ "Line1" }, - MAP_TO_RELATED ); // all correct - auto const tmp_l2_istos_int = - Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TOS{}, VALUE_FROM_DICT{ "Line2" }, - MAP_TO_RELATED ); // all correct - auto const tmp_l2_istis_int = - Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TIS{}, VALUE_FROM_DICT{ "Line2" }, - MAP_TO_RELATED ); // all correct - auto const tmp_wrong1_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TOS{}, VALUE_FROM_DICT{ "Line3" }, - MAP_TO_RELATED ); // wrong line name - auto const tmp_wrong2_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TOS{}, VALUE_FROM_DICT{ "Line2" }, - MAP_TO_RELATED ); // no trigger info for particle two - auto const tmp_wrong3_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT{}, IS_TOS{}, VALUE_FROM_DICT{ "Line3" }, - MAP_TO_RELATED ); // wrong line name and no trigger info + auto const tmp_l1_istos_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TOS, VALUE_FROM_DICT{ "Line1" }, + MAP_TO_RELATED ); // all correct + auto const tmp_l1_istis_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TIS, VALUE_FROM_DICT{ "Line1" }, + MAP_TO_RELATED ); // all correct + auto const tmp_l2_istos_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TOS, VALUE_FROM_DICT{ "Line2" }, + MAP_TO_RELATED ); // all correct + auto const tmp_l2_istis_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TIS, VALUE_FROM_DICT{ "Line2" }, + MAP_TO_RELATED ); // all correct + auto const tmp_wrong1_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TOS, VALUE_FROM_DICT{ "Line3" }, + MAP_TO_RELATED ); // wrong line name + auto const tmp_wrong2_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TOS, VALUE_FROM_DICT{ "Line2" }, + MAP_TO_RELATED ); // no trigger info for particle two + auto const tmp_wrong3_int = Functors::chain( VALUE_OR_INT{ -1 }, CAST_TO_INT, IS_TOS, VALUE_FROM_DICT{ "Line3" }, + MAP_TO_RELATED ); // wrong line name and no trigger info auto val_l1_istos_int = tmp_l1_istos_int.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct auto val_l1_istis_int = tmp_l1_istis_int.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct auto val_l2_istos_int = tmp_l2_istos_int.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct @@ -3122,18 +3132,18 @@ BOOST_AUTO_TEST_CASE( test_tistos_functors ) { BOOST_CHECK_EQUAL( val_wrong3_int, -1 ); // same as above but for booleans useful for trigger cuts auto const tmp_l1_istos_bool = - Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS{}, VALUE_FROM_DICT{ "Line1" }, MAP_TO_RELATED ); // all correct + Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS, VALUE_FROM_DICT{ "Line1" }, MAP_TO_RELATED ); // all correct auto const tmp_l1_istis_bool = - Functors::chain( VALUE_OR_BOOL{ false }, IS_TIS{}, VALUE_FROM_DICT{ "Line1" }, MAP_TO_RELATED ); // all correct + Functors::chain( VALUE_OR_BOOL{ false }, IS_TIS, VALUE_FROM_DICT{ "Line1" }, MAP_TO_RELATED ); // all correct auto const tmp_l2_istos_bool = - Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS{}, VALUE_FROM_DICT{ "Line2" }, MAP_TO_RELATED ); // all correct + Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS, VALUE_FROM_DICT{ "Line2" }, MAP_TO_RELATED ); // all correct auto const tmp_l2_istis_bool = - Functors::chain( VALUE_OR_BOOL{ false }, IS_TIS{}, VALUE_FROM_DICT{ "Line2" }, MAP_TO_RELATED ); // all correct - auto const tmp_wrong1_bool = Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS{}, VALUE_FROM_DICT{ "Line3" }, - MAP_TO_RELATED ); // wrong line name - auto const tmp_wrong2_bool = Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS{}, VALUE_FROM_DICT{ "Line2" }, + Functors::chain( VALUE_OR_BOOL{ false }, IS_TIS, VALUE_FROM_DICT{ "Line2" }, MAP_TO_RELATED ); // all correct + auto const tmp_wrong1_bool = + Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS, VALUE_FROM_DICT{ "Line3" }, MAP_TO_RELATED ); // wrong line name + auto const tmp_wrong2_bool = Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS, VALUE_FROM_DICT{ "Line2" }, MAP_TO_RELATED ); // no trigger info for particle two - auto const tmp_wrong3_bool = Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS{}, VALUE_FROM_DICT{ "Line3" }, + auto const tmp_wrong3_bool = Functors::chain( VALUE_OR_BOOL{ false }, IS_TOS, VALUE_FROM_DICT{ "Line3" }, MAP_TO_RELATED ); // wrong line name and no trigger info auto val_l1_istos_bool = tmp_l1_istos_bool.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct auto val_l1_istis_bool = tmp_l1_istis_bool.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct @@ -3175,8 +3185,8 @@ BOOST_AUTO_TEST_CASE( test_lhcb_math_functors ) { Gaudi::Vector4 mom( 0.2 * GeV, 1 * GeV, 0.5 * GeV, 5 * GeV ); Gaudi::Math::LorentzVectorWithError P4{ mom, covMatrix }; - Functors::LHCbMath::scalarMomentum SCALAR_MOMENTUM; - Functors::LHCbMath::invariantMass INVARIANT_MASS; + auto const SCALAR_MOMENTUM = Functors::LHCbMath::scalarMomentum; + auto const INVARIANT_MASS = Functors::LHCbMath::invariantMass; BOOST_CHECK_EQUAL( SCALAR_MOMENTUM( P4 ), P4.scalarMomentum() ); BOOST_CHECK_EQUAL( INVARIANT_MASS( P4 ), P4.invariantMass() ); @@ -3218,9 +3228,9 @@ BOOST_AUTO_TEST_CASE( test_require_close ) { B0.setDaughters( B0_children ); // define the functors and prepare them - auto const PT = chain( Functors::Common::Rho_Coordinate{}, Functors::Track::ThreeMomentum{} ); - const auto CHILD1_PT = chain( PT, Functors::Adapters::Child{ 1 } ); - const auto CHILD2_PT = chain( PT, Functors::Adapters::Child{ 2 } ); + auto const PT = chain( Functors::Common::Rho_Coordinate, Functors::Track::ThreeMomentum ); + const auto CHILD1_PT = chain( PT, Functors::Adapters::Child{ 1 } ); + const auto CHILD2_PT = chain( PT, Functors::Adapters::Child{ 2 } ); auto const _REQUIRE_CLOSE = Functors::Common::RequireClose( 1e-34f, 1e-07f ); auto const REQUIRE_CLOSE = Functors::bind( _REQUIRE_CLOSE, CHILD1_PT, CHILD2_PT ); EventContext const evtCtx; @@ -3232,10 +3242,13 @@ BOOST_AUTO_TEST_CASE( test_require_close ) { } BOOST_AUTO_TEST_CASE( test_mc_originflag ) { - Functors::Simulation::MC::OriginFlag of; - const LHCb::MCParticle mc1{}; - const LHCb::MCParticle mc2{}; + const auto of = Functors::Simulation::MC::OriginFlag; + const LHCb::MCParticle mc1{}; + const LHCb::MCParticle mc2{}; BOOST_CHECK_EQUAL( LHCb::FlavourTagging::originTagCodes::Prompt_From_SignalB_PV, of( &mc1, &mc2 ) ); + // BOOST_CHECK_EQUAL( LHCb::FlavourTagging::originTagCodes::Prompt_From_SignalB_PV, of( mc1, mc2 ) ); + // BOOST_CHECK_EQUAL( LHCb::FlavourTagging::originTagCodes::Prompt_From_SignalB_PV, of( mc1, &mc2 ) ); + // BOOST_CHECK_EQUAL( LHCb::FlavourTagging::originTagCodes::Prompt_From_SignalB_PV, of( &mc1, mc2 ) ); } BOOST_AUTO_TEST_CASE( test_muon_nhits ) { @@ -3279,8 +3292,8 @@ BOOST_AUTO_TEST_CASE( test_get_pvtracks ) { EventContext const evtCtx; Functors::TopLevelInfo const top_level; - Functors::AcceptAll ALL; - auto const ISVELOBACKWARD = Functors::Track::IsVeloBackward; + auto const ALL = Functors::AcceptAll; + auto const ISVELOBACKWARD = Functors::Track::IsVeloBackward; auto const& COUNTIF_ALL = Functors::chain( ::Functors::Functional::CountIf( ALL ), PVTRACKS ); diff --git a/Phys/SelKernel/include/SelKernel/ParticleAccessors.h b/Phys/SelKernel/include/SelKernel/ParticleAccessors.h deleted file mode 100644 index 593f50fe03f962fd0b7f66bda6f1c6baa8706008..0000000000000000000000000000000000000000 --- a/Phys/SelKernel/include/SelKernel/ParticleAccessors.h +++ /dev/null @@ -1,30 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2020 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 -#include "LHCbMath/MatVec.h" -#include "SelKernel/ParticleTraits.h" -/** @namespace Sel::get - * @brief Free-standing helper functions for extracting physical variables - * - * This namespace collects helper functions for operations such like "get the - * energy of this object" that can perform some compile-time type - * introspection and support a range of different argument types. - */ -namespace Sel::get { - template - auto chi2PerDoF( T const& x ) { - if constexpr ( type_traits::has_chi2PerDoF_v ) { - return x.chi2PerDoF(); - } else { - return x.chi2() / x.nDoF(); - } - } -} // namespace Sel::get diff --git a/Phys/SelKernel/include/SelKernel/ParticleCombination.h b/Phys/SelKernel/include/SelKernel/ParticleCombination.h index 7b61cca798738e2f2fbf72fd04420dab210cf43d..99acea04bec63f29c2b0d93d8338ceeb41f0297c 100644 --- a/Phys/SelKernel/include/SelKernel/ParticleCombination.h +++ b/Phys/SelKernel/include/SelKernel/ParticleCombination.h @@ -10,6 +10,7 @@ \*****************************************************************************/ #pragma once #include "Event/TrackVertexUtils.h" +#include "GaudiKernel/detected.h" #include #include @@ -157,12 +158,19 @@ namespace Sel::detail { template using first_t = std::tuple_element_t<0, std::tuple>; + /** Helper to determine if the given type has a static mask_true() method. */ + template + using has_static_mask_true_ = decltype( T::mask_true() ); + + template + inline constexpr bool has_static_mask_true_v = Gaudi::cpp17::is_detected_v; + template struct mask_true_helper {}; template struct mask_true_helper> { static constexpr auto _() { - static_assert( ( Sel::Utils::has_static_mask_true_v && ... ) ); + static_assert( ( has_static_mask_true_v && ... ) ); using mask_true_t = std::common_type_t; return mask_true_t{ first_t::mask_true() }; } diff --git a/Phys/SelKernel/include/SelKernel/ParticleTraits.h b/Phys/SelKernel/include/SelKernel/ParticleTraits.h deleted file mode 100644 index 8372779c23376a7c67bdd3ead274ae81135a8e42..0000000000000000000000000000000000000000 --- a/Phys/SelKernel/include/SelKernel/ParticleTraits.h +++ /dev/null @@ -1,109 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2020 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 -#include "GaudiKernel/detected.h" - -/** @namespace Sel::type_traits - * @brief Type traits for particle-like types. - * - * This namespace holds a collection of compile-time tests for different - * accessors. They are typically used in `if constexpr` expressions inside - * the free-standing helper functions in the Sel::get namespace. - */ -namespace Sel::type_traits { - namespace detail { - template - using has_chi2PerDoF = decltype( std::declval().chi2PerDoF() ); - - template - using has_closestToBeamState = decltype( std::declval().closestToBeamState() ); - - template - using has_e = decltype( std::declval().e() ); - - template - using has_endVertex = decltype( std::declval().endVertex() ); - - template - using has_momentum = decltype( std::declval().momentum() ); - - template - using has_momCovMatrix = decltype( std::declval().momCovMatrix() ); - - template - using has_momPosCovMatrix = decltype( std::declval().momPosCovMatrix() ); - - template - using has_posCovMatrix = decltype( std::declval().posCovMatrix() ); - - template - using has_px = decltype( std::declval().px() ); - - template - using has_py = decltype( std::declval().py() ); - - template - using has_pz = decltype( std::declval().pz() ); - - template - using has_threeMomentum = decltype( std::declval().threeMomentum() ); - - template - using has_threeMomCovMatrix = decltype( std::declval().threeMomCovMatrix() ); - - template - using has_threeMomPosCovMatrix = decltype( std::declval().threeMomPosCovMatrix() ); - } // namespace detail - - template - inline constexpr bool has_chi2PerDoF_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_closestToBeamState_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_e_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_endVertex_v = Gaudi::cpp17::is_detected_v; - - /** This should mean 4-momentum. - */ - template - inline constexpr bool has_momentum_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_momCovMatrix_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_momPosCovMatrix_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_posCovMatrix_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_px_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_py_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_pz_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_threeMomentum_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_threeMomCovMatrix_v = Gaudi::cpp17::is_detected_v; - - template - inline constexpr bool has_threeMomPosCovMatrix_v = Gaudi::cpp17::is_detected_v; -} // namespace Sel::type_traits diff --git a/Phys/SelKernel/include/SelKernel/Utilities.h b/Phys/SelKernel/include/SelKernel/Utilities.h index 2facbfd921bbcff5a1722ef7bae4bf3ae9b51740..9942a99fec59190361dc77cc5acdf0a80ea66530 100644 --- a/Phys/SelKernel/include/SelKernel/Utilities.h +++ b/Phys/SelKernel/include/SelKernel/Utilities.h @@ -16,14 +16,11 @@ #include "Event/State.h" #include "Event/TrackVertexUtils.h" #include "Event/Track_v3.h" +#include "GaudiKernel/GenericMatrixTypes.h" +#include "GaudiKernel/SmartRef.h" #include "LHCbMath/MatVec.h" #include "LHCbMath/MatrixTransforms.h" #include "LHCbMath/MatrixUtils.h" -#include "SelKernel/ParticleTraits.h" - -#include "GaudiKernel/GenericMatrixTypes.h" -#include "GaudiKernel/SmartRef.h" -#include "GaudiKernel/detected.h" #include @@ -36,25 +33,7 @@ namespace LHCb { class VertexBase; } // namespace LHCb -namespace Functors { - template - constexpr bool is_legacy_particle = - std::is_same_v>>>; -} // namespace Functors - namespace Sel::Utils { - /** Helper to determine if the given type has a static mask_true() method. */ - template - using has_static_mask_true_ = decltype( T::mask_true() ); - - template - inline constexpr bool has_static_mask_true_v = Gaudi::cpp17::is_detected_v; - - template - using has_dType = typename T::dType; - - template - inline constexpr bool has_dType_v = Gaudi::cpp17::is_detected_v; /** Define plain bool versions that mirror the functions defined for * SIMDWrapper's mask_v types. These are useful when writing generic @@ -99,33 +78,6 @@ namespace Sel::Utils { } } - /** Helper to determine if the given type has a bestPV() method. */ - template - using has_bestPV_ = decltype( std::declval().bestPV() ); - - template - inline constexpr bool has_bestPV_v = Gaudi::cpp17::is_detected_v; - - /** Helper to determine if the given type has a size() method, to determine if one deals with a int_v or int. */ - template - using has_size_ = decltype( std::declval().size() ); - - template - inline constexpr bool has_size_v = Gaudi::cpp17::is_detected_v; - - template - constexpr bool is_lhcb_vertexbase = std::is_base_of_v; - - inline constexpr auto get_track_from_particle = []( auto const& p ) { - auto const* pp = deref_if_ptr( p ).proto(); - return pp ? pp->track() : nullptr; - }; - - inline constexpr auto get_track_property_from_particle = []( auto const& p, auto&& accessor, auto&& invalid ) { - auto const* trk = get_track_from_particle( p ); - return trk ? accessor( trk ) : invalid; - }; - // TODO: make sure this predicate becomes obsolete by moving the 'dispatch' code // into the relevant event model classes -- and the code to which it dispatches // (which is written in terms of more basic quantities like positions, directions, @@ -136,9 +88,6 @@ namespace Sel::Utils { template constexpr auto isBasicParticle_v = std::remove_pointer_t>::isBasicParticle; - template - constexpr auto hasTrack_v = std::remove_pointer_t>::hasTrack; - /** Helpers for dispatching to the right fdchi2 calculation. */ template auto flightDistanceChi2( Vertex1 const& v1, Vertex2 const& v2 ) { diff --git a/Phys/SelKernel/include/SelKernel/VertexRelation.h b/Phys/SelKernel/include/SelKernel/VertexRelation.h index 90bdf2413cbe3296674818fae5c7c8eaae62ea0b..7cced2eadc8a765d2d9ed9d069394207b5ce8441 100644 --- a/Phys/SelKernel/include/SelKernel/VertexRelation.h +++ b/Phys/SelKernel/include/SelKernel/VertexRelation.h @@ -223,7 +223,7 @@ namespace Sel { */ template auto getBestPVRel( Object const& obj, VContainer const& vertices ) { - if constexpr ( Utils::has_bestPV_v ) { + if constexpr ( requires { obj.bestPV(); } ) { auto rel = obj.bestPV(); // TODO: replace this with a check that rel is compatible with vertices if ( ( true ) ) { return rel; } @@ -252,7 +252,7 @@ namespace Sel { throw GaudiException{ "Invalid vertex index", "Sel::getBestPV", StatusCode::FAILURE }; } // index could be int or int_v, if it's int_v, size should be one for v1 Particle - if constexpr ( Sel::Utils::has_size_v ) { // FIXME has_size -> is_int_v + if constexpr ( requires { index.size(); } ) { // FIXME has_size -> is_int_v assert( index.size() == 1 ); return to_pointer( vertices[index.cast()] ); } else { @@ -282,7 +282,7 @@ namespace Sel { } // index could be int or int_v, if it's int_v, we need // to return multiple vertices - if constexpr ( Sel::Utils::has_size_v ) { // FIXME has_size -> is_int_v + if constexpr ( requires { index.size(); } ) { // FIXME has_size -> is_int_v if constexpr ( index.size() > 1 ) { std::array idxs; index.store( idxs ); diff --git a/Phys/SelTools/include/SelTools/DistanceCalculator.h b/Phys/SelTools/include/SelTools/DistanceCalculator.h index 261dbcf942b0450a8ebb70f2507a53e60398566a..2d3c139b448cd3db79634c071d14a075100030a7 100644 --- a/Phys/SelTools/include/SelTools/DistanceCalculator.h +++ b/Phys/SelTools/include/SelTools/DistanceCalculator.h @@ -29,23 +29,20 @@ namespace { - template - using has_posSlopeCovariance = decltype( std::declval().posSlopeCovariance() ); - - template - inline constexpr bool has_posSlopeCovariance_v = Gaudi::cpp17::is_detected_v; - /** Extract a new_dim x new_dim symmetric matrix from another symmetric * matrix, starting at offset {start_row_col, start_row_col}. */ template struct sub_sym { + template auto operator()( LHCb::LinAlg::MatSym const& mat ) const { return mat.template sub, start_row_col, start_row_col>(); } + template using SMatrixSym = ROOT::Math::SMatrix>; + template auto operator()( SMatrixSym const& mat ) const { return mat.template Sub>( start_row_col, start_row_col ); @@ -55,13 +52,15 @@ namespace { /** Extract the 4x4 position-slope covariance of a state. */ template - decltype( auto ) posSlopeCovariance( T const& x ) { - if constexpr ( has_posSlopeCovariance_v ) { - return x.posSlopeCovariance(); - } else { - return sub_sym<0, 4>{}( x.covariance() ); - } + auto posSlopeCovariance( T const& x ) -> decltype( x.posSlopeCovariance() ) { + return x.posSlopeCovariance(); + } + + template + auto posSlopeCovariance( T const& x ) -> decltype( sub_sym<0, 4>{}( x.covariance() ) ) { + return sub_sym<0, 4>{}( x.covariance() ); } + } // namespace namespace Sel { diff --git a/Phys/VertexFit/include/VertexFit/ParticleVertexFitter.h b/Phys/VertexFit/include/VertexFit/ParticleVertexFitter.h index dbeb1d88659f9f7788dd4c372b1ad10ab94d29e1..98cdc194a3ef73ec51a3b9bf2ea603f6ef87c6c0 100644 --- a/Phys/VertexFit/include/VertexFit/ParticleVertexFitter.h +++ b/Phys/VertexFit/include/VertexFit/ParticleVertexFitter.h @@ -9,7 +9,6 @@ * or submit itself to any jurisdiction. * \*****************************************************************************/ #pragma once -#include "SelKernel/ParticleAccessors.h" #include "SelKernel/ParticleCombination.h" #include "SelKernel/Utilities.h" #include "SelTools/State4.h" @@ -90,9 +89,9 @@ namespace { /// Determine the child type for a given proxy template - struct child_type_for_proxy - : child_type_for_conditions, Sel::Utils::hasTrack_v, - Sel::Utils::canBeExtrapolatedDownstream_v> {}; + struct child_type_for_proxy : child_type_for_conditions, + std::remove_pointer_t>::hasTrack, + Sel::Utils::canBeExtrapolatedDownstream_v> {}; /// Child type for a given proxy template diff --git a/Pr/PrMCTools/src/PrVeloHeavyFlavourTrackingChecker.cpp b/Pr/PrMCTools/src/PrVeloHeavyFlavourTrackingChecker.cpp index 0eea2b06d93ef1746e8145b674b4ab743736b8cc..0a1c5047d77c3ce883d30119b5b7e074f204f07c 100644 --- a/Pr/PrMCTools/src/PrVeloHeavyFlavourTrackingChecker.cpp +++ b/Pr/PrMCTools/src/PrVeloHeavyFlavourTrackingChecker.cpp @@ -407,7 +407,7 @@ void PrVeloHeavyFlavourTrackingChecker::operator()( MCParticles const& mcparts, float ipchi2 = -1.f; if ( pion && has_track ) { auto pv = LHCb::bestPV( pvs, *pion ); - ip = ImpactParameter{}( ToLinAlg{}( Position{}( pv ) ), pion ).cast(); + ip = ImpactParameter( ToLinAlg( Position( pv ) ), pion ).cast(); ipchi2 = impactParameterChi2( pion, pv ).cast(); } sc &= tuple->column( compbase + pbase + "match", (bool)pion );