From ee6abe1d9d42f2acab85383c9d2a09e01b840192 Mon Sep 17 00:00:00 2001 From: Gerhard Raven <gerhard.raven@nikhef.nl> Date: Fri, 28 Feb 2025 10:08:55 +0000 Subject: [PATCH] Require a first `mask_arg_t` argument on prepared functor calls with masks --- Phys/FunctorCore/include/Functors/Adapters.h | 2 +- Phys/FunctorCore/include/Functors/Core.h | 7 +- Phys/FunctorCore/include/Functors/Function.h | 20 +- .../FunctorCore/include/Functors/Functional.h | 28 +- Phys/FunctorCore/include/Functors/MVA.h | 2 +- .../tests/src/InstantiateFunctors.cpp | 92 ++++--- Phys/FunctorCore/tests/src/TestFunctors.cpp | 256 ++++++++++-------- 7 files changed, 218 insertions(+), 189 deletions(-) diff --git a/Phys/FunctorCore/include/Functors/Adapters.h b/Phys/FunctorCore/include/Functors/Adapters.h index 2b5b140737f..8c589c6150a 100644 --- a/Phys/FunctorCore/include/Functors/Adapters.h +++ b/Phys/FunctorCore/include/Functors/Adapters.h @@ -47,7 +47,7 @@ namespace Functors::detail { auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { if constexpr ( requires_explicit_mask ) { - return [f = detail::prepared( m_transform, evtCtx, top_level ), r = m_reduce]( auto const& mask, + return [f = detail::prepared( m_transform, evtCtx, top_level ), r = m_reduce]( mask_arg_t, auto const& mask, auto const& collection ) { using LHCb::Event::decayProducts; return Sel::transform_reduce( decayProducts( collection ), LHCb::cxx::bind_front( f, mask_arg, mask ), r ); diff --git a/Phys/FunctorCore/include/Functors/Core.h b/Phys/FunctorCore/include/Functors/Core.h index b84eca2ca91..9fbcfc1d73a 100644 --- a/Phys/FunctorCore/include/Functors/Core.h +++ b/Phys/FunctorCore/include/Functors/Core.h @@ -204,7 +204,7 @@ namespace Functors { get_value( std::forward<Args>( args ) )... ) } : std::nullopt; } else if constexpr ( requires_explicit_mask ) { - return LHCb::invoke_or_visit( f, std::forward<Mask>( mask ), std::forward<Args>( args )... ); + return LHCb::invoke_or_visit( f, mask_arg, std::forward<Mask>( mask ), std::forward<Args>( args )... ); } else { return LHCb::invoke_or_visit( f, std::forward<Args>( args )... ); } @@ -220,7 +220,8 @@ namespace Functors { f, get_value( std::forward<Args>( args ) )... ) } : std::nullopt; } else if constexpr ( requires_explicit_mask ) { - return LHCb::invoke_or_visit( f, loop_mask( static_cast<std::remove_reference_t<Args>&>( args )... ), + return LHCb::invoke_or_visit( f, mask_arg, + loop_mask( static_cast<std::remove_reference_t<Args>&>( args )... ), std::forward<Args>( args )... ); } else { return LHCb::invoke_or_visit( f, std::forward<Args>( args )... ); @@ -381,6 +382,8 @@ namespace Functors { .invoke = []( void const* p, EventContext const& evtCtx, TopLevelInfo const& top_level, InputType... input ) -> result_type { // Prepare and call in one go, avoiding the overhead of .prepare + static_assert( + requires( F const& f, InputType... in ) { detail::prepared( f, evtCtx, top_level )( in... ); } ); return static_cast<result_type>( detail::prepared( *static_cast<const F*>( p ), evtCtx, top_level )( input... ) ); }, diff --git a/Phys/FunctorCore/include/Functors/Function.h b/Phys/FunctorCore/include/Functors/Function.h index 0da4569cbd6..4caada4b9f7 100644 --- a/Phys/FunctorCore/include/Functors/Function.h +++ b/Phys/FunctorCore/include/Functors/Function.h @@ -329,7 +329,7 @@ namespace Functors { TopLevelInfo const& top_level, F const&... f ) { static_assert( sizeof...( f ) > 1 ); - return [... pf = prepared( f, evtCtx, top_level )]( auto mask, auto&&... input ) { + return [... pf = prepared( f, evtCtx, top_level )]( mask_arg_t, auto mask, auto&&... input ) { using Sel::Utils::any; // for the scalar case // Operator{}( ... ) would not short-circuit in this case // Short circuit vectorised cuts as well as scalar ones -- use a fold expression do to so, @@ -344,7 +344,7 @@ namespace Functors { template <typename, FunctorPredicate F0, FunctorPredicate F1> LHCB_FUNCTORS_INLINE constexpr auto prepare_( std::logical_or<>, EventContext const& evtCtx, TopLevelInfo const& top_level, F0 const& f0, F1 const& f1 ) { - return [f0 = prepared( f0, evtCtx, top_level ), f1 = prepared( f1, evtCtx, top_level )]( auto mask, + return [f0 = prepared( f0, evtCtx, top_level ), f1 = prepared( f1, evtCtx, top_level )]( mask_arg_t, auto mask, auto&&... input ) { // Operator{}( ... ) would not short-circuit in this case // we start with 'first' set to all entries that should _not_ be checked, and then @@ -375,7 +375,7 @@ namespace Functors { template <typename, FunctorFunction... F> LHCB_FUNCTORS_INLINE constexpr auto prepare_( composition::chain, EventContext const& evtCtx, TopLevelInfo const& top_level, F const&... f ) { - return [... pf = prepared( f, evtCtx, top_level )]<typename... Input>( auto mask, + return [... pf = prepared( f, evtCtx, top_level )]<typename... Input>( mask_arg_t, auto mask, Input&&... input ) -> decltype( auto ) { using for_chain_only::operator<<=; return ( LHCb::cxx::bind_front( pf, mask_arg, mask ) <<= ... <<= @@ -387,7 +387,7 @@ namespace Functors { LHCB_FUNCTORS_INLINE constexpr auto prepare_( composition::bind, EventContext const& evtCtx, TopLevelInfo const& top_level, F0 const& f0, F const&... f ) { return [f0 = prepared( f0, evtCtx, top_level ), ... pf = prepared( f, evtCtx, top_level )]<typename... Input>( - auto mask, Input&&... input ) -> decltype( auto ) { + mask_arg_t, auto mask, Input&&... input ) -> decltype( auto ) { return f0( mask_arg, mask, fwd_as_flattened_tuple( pf( mask_arg, mask, std::forward<Input>( input )... )... ) ); }; }; @@ -395,7 +395,7 @@ namespace Functors { template <typename NewBase, typename Operator, FunctorFunction... F> LHCB_FUNCTORS_INLINE constexpr auto prepare_( Operator op, EventContext const& evtCtx, TopLevelInfo const& top_level, const F&... f ) { - return [op = std::move( op ), ... pf = prepared( f, evtCtx, top_level )]( auto mask, + return [op = std::move( op ), ... pf = prepared( f, evtCtx, top_level )]( mask_arg_t, auto mask, auto&&... input ) -> decltype( auto ) { // Evaluate all the functors and let the given Operator combine the results. return [&op]<typename... I>( I&&... i ) { @@ -428,6 +428,11 @@ namespace Functors { template <typename NewBase, typename Operator, typename Fs> struct Composed : NewBase { + /** Flag that this functor explicitly receives/handles a mask giving the + * current validity of the arguments. + */ + constexpr static bool requires_explicit_mask = true; + constexpr Composed( Operator op, Fs fs ) : m_fs{ std::move( fs ) }, m_op{ std::move( op ) } {} /** Prepare the composite functor for use: return a new lambda that @@ -460,11 +465,6 @@ namespace Functors { apply( [&top_level]( auto&... f ) { ( detail::bind( f, top_level ), ... ); }, m_fs ); } - /** Flag that this functor explicitly receives/handles a mask giving the - * current validity of the arguments. - */ - constexpr static bool requires_explicit_mask = true; - private: Fs m_fs; LHCB_HAS_NO_UNIQUE_ADDRESS Operator m_op; diff --git a/Phys/FunctorCore/include/Functors/Functional.h b/Phys/FunctorCore/include/Functors/Functional.h index 29b1619407b..637f2318f91 100644 --- a/Phys/FunctorCore/include/Functors/Functional.h +++ b/Phys/FunctorCore/include/Functors/Functional.h @@ -35,12 +35,12 @@ 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, std::ranges::range auto const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]<std::ranges::range Range>( + mask_arg_t, auto mask, Range const& range, auto const&... input ) { using std::ranges::begin; using std::ranges::end; - static_assert( std::is_invocable_v<decltype( pf ), decltype( mask_arg ), decltype( mask ), - decltype( *begin( range ) ), decltype( input )...> ); + static_assert( std::is_invocable_v<decltype( pf ), mask_arg_t, decltype( mask ), + std::ranges::range_value_t<Range>, decltype( input )...> ); using result_t = std::remove_cvref_t<decltype( pf( mask_arg, mask, *begin( range ), input... ) )>; std::vector<result_t> out; out.reserve( range.size() ); @@ -50,11 +50,11 @@ namespace Functors::Functional { return out; }; } else { - return [pf = detail::prepared( m_f, evtCtx, top_level )]( std::ranges::range auto const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]<std::ranges::range Range>( Range const& range, + auto const&... input ) { using std::ranges::begin; using std::ranges::end; - static_assert( std::is_invocable_v<decltype( pf ), decltype( *begin( range ) ), decltype( input )...> ); + static_assert( std::is_invocable_v<decltype( pf ), std::ranges::range_value_t<Range>, decltype( input )...> ); using result_t = std::remove_cvref_t<decltype( pf( *begin( range ), input... ) )>; std::vector<result_t> out; out.reserve( range.size() ); @@ -89,7 +89,7 @@ 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 )]<std::ranges::range Range>( - auto mask, Range const& range, auto const&... input ) { + mask_arg_t, auto mask, Range const& range, auto const&... input ) { using Sel::Utils::all; // the logic here is the same as in `prepare_(std::logical_or<>, ... )` auto done = !mask; @@ -130,7 +130,7 @@ namespace Functors::Functional { auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { if constexpr ( requires_explicit_mask ) { return [f = detail::prepared( m_f, evtCtx, top_level )]<std::ranges::range Range>( - auto mask, Range const& range, auto const&... input ) { + mask_arg_t, auto mask, Range const& range, auto const&... input ) { for ( auto const& item : range ) { using Sel::Utils::none; mask = mask && f( mask_arg, mask, item, input... ); @@ -256,8 +256,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, std::ranges::range auto const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( + mask_arg_t, auto mask, std::ranges::range auto const& range, auto const&... input ) { using std::ranges::begin; using std::ranges::end; using std::next; @@ -319,8 +319,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, std::ranges::range auto const& range, - auto const&... input ) { + return [pf = detail::prepared( m_f, evtCtx, top_level )]( + mask_arg_t, auto mask, std::ranges::range auto const& range, auto const&... input ) { using std::ranges::begin; using std::ranges::end; using std::next; @@ -514,7 +514,7 @@ namespace Functors::Functional { auto prepare( EventContext const& evtCtx, TopLevelInfo const& top_level ) const { if constexpr ( requires_explicit_mask ) { return [predicate = detail::prepared( m_predicate, evtCtx, top_level )]<std::ranges::range Range>( - auto mask, Range const& range ) { + mask_arg_t, auto mask, Range const& range ) { return std::ranges::count_if( range, LHCb::cxx::bind_front( predicate, mask_arg, mask ) ); }; } else { diff --git a/Phys/FunctorCore/include/Functors/MVA.h b/Phys/FunctorCore/include/Functors/MVA.h index 9811fc7b344..18d8f025540 100644 --- a/Phys/FunctorCore/include/Functors/MVA.h +++ b/Phys/FunctorCore/include/Functors/MVA.h @@ -75,7 +75,7 @@ namespace Functors { // 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, + return [this, ... pf = detail::prepared( fns, evtCtx, top_level )]( mask_arg_t, 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, diff --git a/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp b/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp index 017630ab802..144734b7ab5 100644 --- a/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp +++ b/Phys/FunctorCore/tests/src/InstantiateFunctors.cpp @@ -17,11 +17,12 @@ #include <boost/test/unit_test.hpp> using namespace boost::mp11; -namespace FT = Functors::Track; -namespace FPID = Functors::PID; -namespace FC = Functors::Common; -namespace FF = Functors::Functional; -namespace FP = Functors::Particle; +namespace FT = Functors::Track; +namespace FPID = Functors::PID; +namespace FC = Functors::Common; +namespace FF = Functors::Functional; +namespace FP = Functors::Particle; +using mask_arg_t = Functors::mask_arg_t; // // The idea of this file is not to run any given functor but to check that it at least compiles. @@ -112,7 +113,7 @@ using all_vec_accessors = mp_flatten<mp_transform<apply_vec_accessors_to, mp_list<decltype( FT::ReferencePoint ), decltype( FT::ThreeMomentum ), decltype( FT::Slopes )>>>; -using test4 = mp_product<std::invoke_result_t, all_vec_accessors, mp_list<bool>, +using test4 = mp_product<std::invoke_result_t, all_vec_accessors, mp_list<mask_arg_t>, mp_list<bool>, mp_append<mp_list<v3_track, charged_basic>, ptr_and_ref<LHCb::Track const, LHCb::Particle const, LHCb::MCParticle const>>>; @@ -123,7 +124,7 @@ using mom4_accessors = mp_list<composed_t<decltype( FC::X_Coordinate ), decltype composed_t<decltype( FC::E_Coordinate ), decltype( FT::FourMomentum )>>; // FIXME fourmomentum is broken for v1 Track as it returns a 3-mom Gaudi::XYZVector -using test5 = mp_product<std::invoke_result_t, mom4_accessors, mp_list<bool>, +using test5 = mp_product<std::invoke_result_t, mom4_accessors, mp_list<mask_arg_t>, mp_list<bool>, mp_append<mp_list<charged_basic>, ptr_and_ref<LHCb::Particle const, LHCb::MCParticle const>>>; // check this helper works with the specified set of types: @@ -261,21 +262,21 @@ using dls_3 = std::invoke_result_t<decltype( Functors::Composite::ComputeDecayLe 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<chi2perdof_prepared, bool, LHCb::Particle const&>; -using chi2perdof_2 = std::invoke_result_t<chi2perdof_prepared, bool, LHCb::Particle const*>; +using chi2perdof_1 = std::invoke_result_t<chi2perdof_prepared, mask_arg_t, bool, LHCb::Particle const&>; +using chi2perdof_2 = std::invoke_result_t<chi2perdof_prepared, mask_arg_t, bool, LHCb::Particle const*>; // // needed because Chi2PerDof has overloads see Moore#452 -using chi2perdof_3 = std::invoke_result_t<chi2perdof_prepared, bool, LHCb::Particle*>; -using chi2perdof_4 = std::invoke_result_t<chi2perdof_prepared, bool, charged_basic>; -using chi2perdof_5 = std::invoke_result_t<chi2perdof_prepared, bool, soa_composite>; +using chi2perdof_3 = std::invoke_result_t<chi2perdof_prepared, mask_arg_t, bool, LHCb::Particle*>; +using chi2perdof_4 = std::invoke_result_t<chi2perdof_prepared, mask_arg_t, bool, charged_basic>; +using chi2perdof_5 = std::invoke_result_t<chi2perdof_prepared, mask_arg_t, bool, soa_composite>; 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<chi2_prepared, bool, LHCb::Particle const&>; -using chi2_2 = std::invoke_result_t<chi2_prepared, bool, LHCb::Particle const*>; +using chi2_1 = std::invoke_result_t<chi2_prepared, mask_arg_t, bool, LHCb::Particle const&>; +using chi2_2 = std::invoke_result_t<chi2_prepared, mask_arg_t, bool, LHCb::Particle const*>; // // needed because Chi2PerDof has overloads see Moore#452 -using chi2_3 = std::invoke_result_t<chi2_prepared, bool, LHCb::Particle*>; -using chi2_4 = std::invoke_result_t<chi2_prepared, bool, charged_basic>; -using chi2_5 = std::invoke_result_t<chi2_prepared, bool, soa_composite>; +using chi2_3 = std::invoke_result_t<chi2_prepared, mask_arg_t, bool, LHCb::Particle*>; +using chi2_4 = std::invoke_result_t<chi2_prepared, mask_arg_t, bool, charged_basic>; +using chi2_5 = std::invoke_result_t<chi2_prepared, mask_arg_t, bool, soa_composite>; auto PT = Functors::chain( ::FC::Rho_Coordinate, ::FT::ThreeMomentum ); @@ -307,7 +308,7 @@ using allpv_fd_func_type = decltype( allpv_fd_func.prepare( EventContext{}, Func // get the result_type of invoking the allpv_fd_func_type with inputs. // The bool needs to be there since it is a mask to be passed to prepared functor // Then the actual input, in this instance LHCb::Particle const ref. -using allpv_fd_func_result_type = std::invoke_result_t<allpv_fd_func_type, bool, LHCb::Particle const&>; +using allpv_fd_func_result_type = std::invoke_result_t<allpv_fd_func_type, mask_arg_t, bool, LHCb::Particle const&>; // Test for ALLPV_IP // @@ -325,7 +326,7 @@ using allpv_ip_func_type = decltype( allpv_ip_func.prepare( EventContext{}, Func // get the result_type of invoking the allpv_ip_func_type with inputs. // The bool needs to be there since it is a mask to be passed to prepared functor // Then the actual input, in this instance LHCb::Particle const ref. -using allpv_ip_func_result_type = std::invoke_result_t<allpv_ip_func_type, bool, LHCb::Particle const&>; +using allpv_ip_func_result_type = std::invoke_result_t<allpv_ip_func_type, mask_arg_t, bool, LHCb::Particle const&>; auto RELS = ::FC::TES<LHCb::Relation1D<LHCb::Particle, LHCb::Particle>>( /* List of DataHandles */ std::vector{ std::string{ "FakeLocation" } } ); @@ -335,7 +336,7 @@ auto SUMCONE = Functors::chain( ::FF::ValueOr( /* The default value. */ 0.0f ), // TEST ASYM FUNCTOR auto asym_func = ( PT - SUMCONE ) / ( PT + SUMCONE ); using asym_func_type = decltype( asym_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); -using asym_func_result_type = std::invoke_result_t<asym_func_type, bool, LHCb::Particle const&>; +using asym_func_result_type = std::invoke_result_t<asym_func_type, mask_arg_t, bool, LHCb::Particle const&>; // create an instances of functors reading RecSummary auto npvs_func = Functors::chain( @@ -344,7 +345,7 @@ auto npvs_func = Functors::chain( // get the type of the prepared functors reading RecSummary 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<npvs_func_type, bool, LHCb::RecSummary const&>; +using npvs_func_res_type = std::invoke_result_t<npvs_func_type, mask_arg_t, bool, LHCb::RecSummary const&>; using inmuon_1 = std::invoke_result_t<decltype( FPID::InAcceptance ), LHCb::Particle const&>; // Create an instance for FIND_DECAY functor @@ -354,30 +355,36 @@ using find_decay_func_type = decltype( find_decay_func.prepare( EventContext{}, // get the result_type of invoking the find_decay_func_type with inputs. // The bool needs to be there since it is a mask to be passed to prepared functor // Then the actual input is passed forwarding the arguments (LHCb::Particle const ref). -using find_decay_func_result_type = std::invoke_result_t<find_decay_func_type, bool, LHCb::Particle const&>; -using find_decay_func_result_type_ptr = std::invoke_result_t<find_decay_func_type, bool, LHCb::Particle const*>; -using find_decay_func_result_type_non_const = std::invoke_result_t<find_decay_func_type, bool, LHCb::Particle>; +using find_decay_func_result_type = std::invoke_result_t<find_decay_func_type, mask_arg_t, bool, LHCb::Particle const&>; +using find_decay_func_result_type_ptr = + std::invoke_result_t<find_decay_func_type, mask_arg_t, bool, LHCb::Particle const*>; +using find_decay_func_result_type_non_const = + std::invoke_result_t<find_decay_func_type, mask_arg_t, bool, LHCb::Particle>; auto find_mc_decay_func = Functors::chain( PT, ::Functors::Decay::FindMCDecay( /* Decay descriptor */ "[B0 => K+ pi-]CC" ) ); using find_mc_decay_func_type = decltype( find_mc_decay_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); -using find_mc_decay_func_result_type = std::invoke_result_t<find_mc_decay_func_type, bool, LHCb::MCParticle const&>; -using find_mc_decay_func_result_type_ptr = std::invoke_result_t<find_mc_decay_func_type, bool, LHCb::MCParticle const*>; -using find_mc_decay_func_result_type_non_const = std::invoke_result_t<find_mc_decay_func_type, bool, LHCb::MCParticle>; +using find_mc_decay_func_result_type = + std::invoke_result_t<find_mc_decay_func_type, mask_arg_t, bool, LHCb::MCParticle const&>; +using find_mc_decay_func_result_type_ptr = + std::invoke_result_t<find_mc_decay_func_type, mask_arg_t, bool, LHCb::MCParticle const*>; +using find_mc_decay_func_result_type_non_const = + std::invoke_result_t<find_mc_decay_func_type, mask_arg_t, bool, LHCb::MCParticle>; auto map_find_decay_func = Functors::chain( ::FF::Map( /* The functor to map over a range. */ Functors::chain( PT, ::Functors::Decay::FindDecay( /* Decay descriptor */ "[B0 => K+ pi-]CC" ) ) ), ::FC::TES<LHCb::Particle::ConstVector>( /* List of DataHandles */ std::vector{ std::string{ "FakeLocation" } } ) ); using map_find_decay_func_type = decltype( map_find_decay_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); -using map_find_decay_func_result_type = std::invoke_result_t<map_find_decay_func_type, bool, LHCb::Particle const&>; +using map_find_decay_func_result_type = + std::invoke_result_t<map_find_decay_func_type, mask_arg_t, bool, LHCb::Particle const&>; auto map_find_decay_range_func = Functors::chain( ::FF::Map( /* The functor to map over a range. */ Functors::chain( PT, ::Functors::Decay::FindDecay( /* Decay descriptor */ "[B0 => K+ pi-]CC" ) ) ) ); using map_find_decay_range_func_type = decltype( map_find_decay_range_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); using map_find_decay_range_func_result_type = - std::invoke_result_t<map_find_decay_range_func_type, bool, LHCb::Particle::Range const&>; + std::invoke_result_t<map_find_decay_range_func_type, mask_arg_t, bool, LHCb::Particle::Range const&>; auto map_find_mc_decay_func = Functors::chain( ::FF::Map( /* The functor to map over a range. */ Functors::chain( @@ -387,22 +394,22 @@ auto map_find_mc_decay_func = using map_find_mc_decay_func_type = decltype( map_find_mc_decay_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); using map_find_mc_decay_func_result_type = - std::invoke_result_t<map_find_mc_decay_func_type, bool, LHCb::MCParticle const&>; + std::invoke_result_t<map_find_mc_decay_func_type, mask_arg_t, bool, LHCb::MCParticle const&>; auto map_find_mc_decay_range_func = Functors::chain( ::FF::Map( /* The functor to map over a range. */ Functors::chain( PT, ::Functors::Decay::FindMCDecay( /* Decay descriptor */ "[B0 => K+ pi-]CC" ) ) ) ); using map_find_mc_decay_range_func_type = decltype( map_find_mc_decay_range_func.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); using map_find_mc_decay_range_func_result_type = - std::invoke_result_t<map_find_mc_decay_range_func_type, bool, LHCb::MCParticle::Range const&>; + std::invoke_result_t<map_find_mc_decay_range_func_type, mask_arg_t, bool, LHCb::MCParticle::Range const&>; 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::Adapters::DescendantsFromComposite{} ); using test_mintree_type = decltype( test_mintree.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); -using test_mintree_result_type = std::invoke_result_t<test_mintree_type, bool, LHCb::Particle const&>; -using test_mintree_result_type2 = std::invoke_result_t<test_mintree_type, bool, LHCb::Particle const*>; +using test_mintree_result_type = std::invoke_result_t<test_mintree_type, mask_arg_t, bool, LHCb::Particle const&>; +using test_mintree_result_type2 = std::invoke_result_t<test_mintree_type, mask_arg_t, bool, LHCb::Particle const*>; auto const ID = ::Functors::Simulation::Particle_Id; auto const MASS = ::Functors::Composite::Mass; @@ -410,15 +417,16 @@ auto const PIPLUS = ::Functors::Particle::ParticlePropertyUser( /* ID to check * auto test_is_id = Functors::chain( ID, PIPLUS ) == ID; using test_is_id_type = decltype( test_is_id.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); -using test_is_id_result_type = std::invoke_result_t<test_is_id_type, bool, LHCb::Particle const&>; -using test_is_id_result_type2 = std::invoke_result_t<test_is_id_type, bool, LHCb::Particle const*>; -using test_is_id_result_type3 = std::invoke_result_t<test_is_id_type, bool, LHCb::MCParticle const&>; -using test_is_id_result_type4 = std::invoke_result_t<test_is_id_type, bool, LHCb::MCParticle const*>; - -auto test_delta_mass = MASS - Functors::chain( MASS, PIPLUS ); -using test_delta_mass_type = decltype( test_delta_mass.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); -using test_delta_mass_result_type = std::invoke_result_t<test_delta_mass_type, bool, LHCb::Particle const&>; -using test_delta_mass_result_type2 = std::invoke_result_t<test_delta_mass_type, bool, LHCb::Particle const*>; +using test_is_id_result_type = std::invoke_result_t<test_is_id_type, mask_arg_t, bool, LHCb::Particle const&>; +using test_is_id_result_type2 = std::invoke_result_t<test_is_id_type, mask_arg_t, bool, LHCb::Particle const*>; +using test_is_id_result_type3 = std::invoke_result_t<test_is_id_type, mask_arg_t, bool, LHCb::MCParticle const&>; +using test_is_id_result_type4 = std::invoke_result_t<test_is_id_type, mask_arg_t, bool, LHCb::MCParticle const*>; + +auto test_delta_mass = MASS - Functors::chain( MASS, PIPLUS ); +using test_delta_mass_type = decltype( test_delta_mass.prepare( EventContext{}, Functors::TopLevelInfo{} ) ); +using test_delta_mass_result_type = std::invoke_result_t<test_delta_mass_type, mask_arg_t, bool, LHCb::Particle const&>; +using test_delta_mass_result_type2 = + std::invoke_result_t<test_delta_mass_type, mask_arg_t, bool, LHCb::Particle const*>; auto test_extrapolate_track = FT::Extrapolate( /* z coordinate */ 50 ); using test_extrapolate_track_type = diff --git a/Phys/FunctorCore/tests/src/TestFunctors.cpp b/Phys/FunctorCore/tests/src/TestFunctors.cpp index 528241a4357..46c47d25e70 100644 --- a/Phys/FunctorCore/tests/src/TestFunctors.cpp +++ b/Phys/FunctorCore/tests/src/TestFunctors.cpp @@ -58,6 +58,7 @@ #include <type_traits> #include <vector> +constexpr auto mask_arg = Functors::mask_arg; static const LHCb::UniqueIDGenerator unique_id_gen; // Define some special functors that have execution counters so that we can @@ -87,7 +88,9 @@ struct ETA_Count : public Functors::Function { template <typename F> auto trivial_prepare( F const& f ) { - return [g = f.prepare( EventContext{}, Functors::TopLevelInfo{} )]( const auto&... i ) { return g( true, i... ); }; + return [g = f.prepare( EventContext{}, Functors::TopLevelInfo{} )]( const auto&... i ) { + return g( mask_arg, true, i... ); + }; } // Check that functors can be instantiated @@ -540,7 +543,7 @@ BOOST_AUTO_TEST_CASE( test_brem_functors ) { 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 ); + return functor.prepare( EventContext{}, Functors::TopLevelInfo{} )( mask_arg, true, input ); }; DummyTrack track{ 10.f, 0.f, true, true, 2.f }; @@ -805,7 +808,7 @@ BOOST_AUTO_TEST_CASE( test_soa_references ) { int i = 0; auto const iterable_tracks = std::array{ tracks1.scalar(), tracks2.scalar() }; for ( auto vertex : vertices.scalar() ) { // will do three iterations... - auto cf_result = prepared( true /* mask */, vertex ); + auto cf_result = prepared( mask_arg, true /* mask */, vertex ); // Get the tracks by hand, so we can check the functor works properly auto const& t1 = iterable_tracks[combinations[i][0][0]][combinations[i][0][1]]; @@ -1161,23 +1164,23 @@ BOOST_AUTO_TEST_CASE( test_relation_table ) { 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 ) ); + BOOST_CHECK_EQUAL( from_p( mask_arg, true, table, parts( 0 ) ), parts( 0 ) ); + BOOST_CHECK_EQUAL( from_p( mask_arg, true, table, parts( 1 ) ), parts( 1 ) ); + BOOST_CHECK_EQUAL( from_p( mask_arg, true, table, parts( 2 ) ), parts( 2 ) ); 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 ) ); + BOOST_CHECK_EQUAL( to_p( mask_arg, true, table, parts( 0 ) ), parts( 1 ) ); + BOOST_CHECK_EQUAL( to_p( mask_arg, true, table, parts( 1 ) ), parts( 2 ) ); + BOOST_CHECK_EQUAL( to_p( mask_arg, true, table, parts( 2 ) ), parts( 0 ) ); auto const tmp = 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 ) ); - auto p1 = tmp_p( true, table, parts( 0 ) ); - auto p2 = tmp_p( true, table, parts( 1 ) ); + auto check_empty = tmp_p( mask_arg, true, empty_table, parts( 1 ) ); + auto p0 = tmp_p( mask_arg, true, table, parts( 2 ) ); + auto p1 = tmp_p( mask_arg, true, table, parts( 0 ) ); + auto p2 = tmp_p( mask_arg, true, table, parts( 1 ) ); BOOST_CHECK( !check_empty.has_value() ); BOOST_CHECK( p0.has_value() ); BOOST_CHECK( p1.has_value() ); @@ -1198,7 +1201,7 @@ BOOST_AUTO_TEST_CASE( test_relation_table_array ) { 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() ); + auto const result = prepped( mask_arg, true, range.value() ); BOOST_CHECK( LHCb::Utils::as_arithmetic( result.size() ) == 1 ); BOOST_CHECK_SMALL( LHCb::Utils::as_arithmetic( result[0] ), std::numeric_limits<float>::min() ); } @@ -1243,8 +1246,8 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { auto const back_weight = 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 ) ); + auto w0 = front_weight_prepped( mask_arg, true, table, parts( 2 ) ); + auto w1 = back_weight_prepped( mask_arg, true, table, parts( 2 ) ); BOOST_CHECK( w0.has_value() ); BOOST_CHECK( w1.has_value() ); BOOST_CHECK( LHCb::Utils::as_arithmetic( w0.value() ) > fake_w0_min && @@ -1260,10 +1263,10 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { 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 ) ); - auto pt_wmin = pt_to_min_weight_entry_prepped( true, table, parts( 2 ) ); - auto pt_wmax = pt_to_max_weight_entry_prepped( true, table, parts( 2 ) ); + auto empty_test = pt_to_min_weight_entry_prepped( mask_arg, true, empty_table, parts( 0 ) ); + auto empty_test2 = pt_to_max_weight_entry_prepped( mask_arg, true, empty_table, parts( 1 ) ); + auto pt_wmin = pt_to_min_weight_entry_prepped( mask_arg, true, table, parts( 2 ) ); + auto pt_wmax = pt_to_max_weight_entry_prepped( mask_arg, true, table, parts( 2 ) ); BOOST_CHECK( !empty_test.has_value() ); BOOST_CHECK( !empty_test2.has_value() ); BOOST_CHECK( pt_wmin.has_value() ); @@ -1276,7 +1279,7 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { 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 ) ); + auto value_or_empty_test = value_or_pt_to_min_weight_entry_prepped( mask_arg, true, empty_table, parts( 0 ) ); BOOST_CHECK( LHCb::Utils::as_arithmetic( value_or_empty_test ) == 0 ); @@ -1285,7 +1288,7 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { 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 const mapcone = prepped( mask_arg, true, relation.value() ); auto sumcone = Functors::Functional::Sum( mapcone ); auto mincone = Functors::Functional::Min( mapcone ); @@ -1305,7 +1308,7 @@ BOOST_AUTO_TEST_CASE( test_relation_table_isolation ) { 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() ); + auto asym = asym_p( mask_arg, true, parts( 1 ), relation.value() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( asym ), fake_asym_pt ); } @@ -1322,7 +1325,7 @@ namespace Functors { Op_Count( std::size_t& counter, std::size_t& scalar_counter, float threshold ) : m_threshold{ threshold }, m_counter{ counter }, m_scalar_counter{ scalar_counter } {} template <typename Data> - auto operator()( bool mask, Data const& x ) const { + auto operator()( mask_arg_t, bool mask, Data const& x ) const { m_scalar_counter += mask; if ( mask ) { return Operator{}( x, m_threshold ); @@ -1333,7 +1336,7 @@ namespace Functors { } template <typename mask_v, typename float_v> - auto operator()( mask_v const& mask, float_v const& x ) const { + auto operator()( mask_arg_t, mask_v const& mask, float_v const& x ) const { m_counter += popcount( mask ); auto const result = Operator{}( x, m_threshold ); std::array<float, float_v::size()> data_to_generate_mask{}; @@ -1393,13 +1396,13 @@ BOOST_AUTO_TEST_CASE( test_mask_logic ) { auto const data = simd_t::float_v{ data_to_generate_float }; // Do some checks using 'mask' and 'data', vector-wise and scalar auto const do_tests = [&]( auto const& obj ) { - auto const vector_res = obj( mask, data ); + auto const vector_res = obj( mask_arg, mask, data ); for ( auto l = 0ul; l < simd_t::size; ++l ) { // Only compare parts of the result that were 'valid' in 'mask' // If the relevant part of 'mask' was zero, then the functor was free // to return any value there. if ( testbit( mask, l ) ) { - auto const scalar_res = obj( true, data_to_generate_float[l] ); + auto const scalar_res = obj( mask_arg, true, data_to_generate_float[l] ); BOOST_CHECK_EQUAL( testbit( vector_res, l ), scalar_res ); } } @@ -1487,7 +1490,8 @@ BOOST_AUTO_TEST_CASE( test_cov_matrix_functors ) { BOOST_CHECK_EQUAL( THREE_MOM_COV_MATRIX( v1_particle )( 0, 0 ).cast(), three_mom_cov_matrix( 0, 0 ).cast() ); BOOST_CHECK_EQUAL( MOM_POS_COV_MATRIX( v1_particle )( 0, 0 ).cast(), mom_pos_cov_matrix( 0, 0 ).cast() ); BOOST_CHECK_EQUAL( THREE_MOM_POS_COV_MATRIX( v1_particle )( 0, 0 ).cast(), three_mom_pos_cov_matrix( 0, 0 ).cast() ); - BOOST_CHECK_EQUAL( PERR2.prepare( evtCtx, top_level )( true, v1_particle ).cast(), expected_similarity.cast() ); + BOOST_CHECK_EQUAL( PERR2.prepare( evtCtx, top_level )( mask_arg, true, v1_particle ).cast(), + expected_similarity.cast() ); // - v2 particle auto v2_particle = v2_particles.scalar()[0]; @@ -1496,7 +1500,8 @@ BOOST_AUTO_TEST_CASE( test_cov_matrix_functors ) { BOOST_CHECK_EQUAL( THREE_MOM_COV_MATRIX( v2_particle )( 0, 0 ).cast(), three_mom_cov_matrix( 0, 0 ).cast() ); BOOST_CHECK_EQUAL( MOM_POS_COV_MATRIX( v2_particle )( 0, 0 ).cast(), mom_pos_cov_matrix( 0, 0 ).cast() ); BOOST_CHECK_EQUAL( THREE_MOM_POS_COV_MATRIX( v2_particle )( 0, 0 ).cast(), three_mom_pos_cov_matrix( 0, 0 ).cast() ); - BOOST_CHECK_EQUAL( PERR2.prepare( evtCtx, top_level )( true, v2_particle ).cast(), expected_similarity.cast() ); + BOOST_CHECK_EQUAL( PERR2.prepare( evtCtx, top_level )( mask_arg, true, v2_particle ).cast(), + expected_similarity.cast() ); } BOOST_AUTO_TEST_CASE( test_child ) { @@ -1547,9 +1552,10 @@ BOOST_AUTO_TEST_CASE( test_vertex_diff_functors ) { const auto Ds_VZ_prepared = Ds_VZ.prepare( evtCtx, top_level ); auto const DELTA_VZ = Ds_VZ - END_VZ; const auto DELTA_VZ_prepared = DELTA_VZ.prepare( evtCtx, top_level ); - BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( END_VZ.prepare( evtCtx, top_level )( true, B0_part ) ), B0_vertex_z ); - BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( Ds_VZ_prepared( true, B0_part ) ), B0_vertex_z + delta_z ); - BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( DELTA_VZ_prepared( true, B0_part ) ), delta_z ); + BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( END_VZ.prepare( evtCtx, top_level )( mask_arg, true, B0_part ) ), + B0_vertex_z ); + BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( Ds_VZ_prepared( mask_arg, true, B0_part ) ), B0_vertex_z + delta_z ); + BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( DELTA_VZ_prepared( mask_arg, true, B0_part ) ), delta_z ); } BOOST_AUTO_TEST_CASE( test_decaytime_functor ) { @@ -1804,7 +1810,7 @@ BOOST_AUTO_TEST_CASE( test_mc_functors ) { BOOST_CHECK_EQUAL( OBJECT_KEY( mcp ), mcp.key() ); auto prepared_call = []( auto& functor, auto const& input ) { - return functor.prepare( EventContext{}, Functors::TopLevelInfo{} )( true, input ); + return functor.prepare( EventContext{}, Functors::TopLevelInfo{} )( mask_arg, true, input ); }; BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( LIFETIME( momcp ).value_or( -1. ) ), lifetime_mother ); @@ -1847,9 +1853,9 @@ BOOST_AUTO_TEST_CASE( test_mc_functors ) { BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEORIGINVERTEX_X, mcp ) ), origin_vertex_pos.X() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEORIGINVERTEX_Y, mcp ) ), origin_vertex_pos.Y() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEORIGINVERTEX_Z, mcp ) ), origin_vertex_pos.Z() ); - BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( TRUEENDVERTEX_X( true, momcp ) ), origin_vertex_pos.X() ); - BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( TRUEENDVERTEX_Y( true, momcp ) ), origin_vertex_pos.Y() ); - BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( TRUEENDVERTEX_Z( true, momcp ) ), origin_vertex_pos.Z() ); + BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( TRUEENDVERTEX_X( mask_arg, true, momcp ) ), origin_vertex_pos.X() ); + BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( TRUEENDVERTEX_Y( mask_arg, true, momcp ) ), origin_vertex_pos.Y() ); + BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( TRUEENDVERTEX_Z( mask_arg, true, momcp ) ), origin_vertex_pos.Z() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEPV_X, mcp ) ), pp_pos.X() ); BOOST_CHECK_EQUAL( LHCb::Utils::as_arithmetic( prepared_call( TRUEPV_Y, mcp ) ), pp_pos.Y() ); @@ -1912,7 +1918,7 @@ BOOST_AUTO_TEST_CASE( test_simd_type_compare ) { auto comp_prepared = composed.prepare( evtCtx, top_level ); // composed functors also need a mask to know which elements to evaluate. auto in_mask = simd_t::mask_true(); - auto mask_f = comp_prepared( in_mask ); + auto mask_f = comp_prepared( mask_arg, in_mask ); // we should get a sse4::mask_v type that has size == 4 BOOST_CHECK_EQUAL( mask_f.size(), 4 ); @@ -1995,12 +2001,14 @@ BOOST_AUTO_TEST_CASE( test_tes_func ) { 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<bool>( line1_dec ) ); - BOOST_CHECK_EQUAL( op_DECISION_2.prepare( evtCtx, top_level )( true, sel_dec ), static_cast<bool>( line2_dec ) ); - BOOST_CHECK_EQUAL( op_DECISION_3.prepare( evtCtx, top_level )( true, sel_dec ), false ); - BOOST_CHECK_EQUAL( op_DECISION_4.prepare( evtCtx, top_level )( true, sel_dec ), false ); - BOOST_CHECK_EQUAL( op_DECISION_5.prepare( evtCtx, top_level )( true, sel_dec ), false ); - BOOST_CHECK_EQUAL( op_DECISION_6.prepare( evtCtx, top_level )( true, sel_dec ), + BOOST_CHECK_EQUAL( op_DECISION_1.prepare( evtCtx, top_level )( mask_arg, true, sel_dec ), + static_cast<bool>( line1_dec ) ); + BOOST_CHECK_EQUAL( op_DECISION_2.prepare( evtCtx, top_level )( mask_arg, true, sel_dec ), + static_cast<bool>( line2_dec ) ); + BOOST_CHECK_EQUAL( op_DECISION_3.prepare( evtCtx, top_level )( mask_arg, true, sel_dec ), false ); + BOOST_CHECK_EQUAL( op_DECISION_4.prepare( evtCtx, top_level )( mask_arg, true, sel_dec ), false ); + BOOST_CHECK_EQUAL( op_DECISION_5.prepare( evtCtx, top_level )( mask_arg, true, sel_dec ), false ); + BOOST_CHECK_EQUAL( op_DECISION_6.prepare( evtCtx, top_level )( mask_arg, true, sel_dec ), static_cast<bool>( line1_dec ) || static_cast<bool>( line2_dec ) ); // test operator() of Functors::TES::SelectionDecision @@ -2040,7 +2048,7 @@ BOOST_AUTO_TEST_CASE( test_functional_functors ) { auto prepped = mapped_x_pos.prepare( evtCtx, top_level ); - auto x = prepped( true, pvs ); + auto x = prepped( mask_arg, true, pvs ); BOOST_CHECK_EQUAL( Functors::Functional::Front( x ), 1 ); @@ -2207,22 +2215,22 @@ BOOST_AUTO_TEST_CASE( check_binary_functors ) { auto deta_p = diff_eta.prepare( evtCtx, top_level ); auto dphi_p = dphi_adj.prepare( evtCtx, top_level ); - auto deta = deta_p( true, tracks[0], tracks[1] ); - auto dphi = dphi_p( true, tracks[0], tracks[1] ); + auto deta = deta_p( mask_arg, true, tracks[0], tracks[1] ); + auto dphi = dphi_p( mask_arg, true, tracks[0], tracks[1] ); 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 dr2 = dr2_p( mask_arg, true, tracks[0], tracks[1] ); 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 dr = dr_p( mask_arg, true, tracks[0], tracks[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 cmass_p = comb_mass.prepare( evtCtx, top_level ); - auto cmass = cmass_p( true, parts( 0 ), parts( 1 ) ); + auto cmass = cmass_p( mask_arg, true, parts( 0 ), parts( 1 ) ); auto part0 = *parts( 0 ); @@ -2515,7 +2523,7 @@ BOOST_AUTO_TEST_CASE( check_lifetime_and_forwarding_logic ) { auto p_add_3 = add_3.prepare( evtCtx, top_level ); - auto res = p_add_3( true, 1 ); + auto res = p_add_3( mask_arg, true, 1 ); BOOST_CHECK_EQUAL( res, 12 ); auto add_fwd = Functors::bind( @@ -2525,15 +2533,15 @@ BOOST_AUTO_TEST_CASE( check_lifetime_and_forwarding_logic ) { auto p_add_fwd = add_fwd.prepare( evtCtx, top_level ); - auto res2 = p_add_fwd( true, 1 ); + auto res2 = p_add_fwd( mask_arg, true, 1 ); BOOST_CHECK_EQUAL( res2, 10 ); // the below is helpfull for debuggin lifetime and perfect forwarding issues (enable printing in DbgVal) - auto res3 = p_add_fwd( true, DbgVal( 10 ) ); + auto res3 = p_add_fwd( mask_arg, true, DbgVal( 10 ) ); BOOST_CHECK_EQUAL( res3.m_value, 28 ); auto val = DbgVal( 5 ); - auto res4 = p_add_fwd( true, val ); + auto res4 = p_add_fwd( mask_arg, true, val ); BOOST_CHECK_EQUAL( res4.m_value, 18 ); } @@ -2548,9 +2556,9 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { auto p_opt_times_two = opt_times_two.prepare( evtCtx, top_level ); // res1 should be 2 * Functors::Optional<int>{10}; - auto res1 = p_opt_times_two( true, true ); + auto res1 = p_opt_times_two( mask_arg, true, true ); // res1 should be 2 * Functors::Optional<int>{}; - auto res2 = p_opt_times_two( true, false ); + auto res2 = p_opt_times_two( mask_arg, true, false ); BOOST_CHECK_EQUAL( res1, 20 ); BOOST_CHECK( !res2.has_value() ); @@ -2560,8 +2568,8 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { Functors::Examples::OptReturn{ 3 }, Functors::Examples::OptReturn{ 1 } ); auto p_add_3_opt = add_3_opt.prepare( evtCtx, top_level ); - auto res3 = p_add_3_opt( true, true ); - auto res4 = p_add_3_opt( true, false ); + auto res3 = p_add_3_opt( mask_arg, true, true ); + auto res4 = p_add_3_opt( mask_arg, true, false ); BOOST_CHECK_EQUAL( res3, 9 ); BOOST_CHECK( !res4.has_value() ); @@ -2573,14 +2581,14 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { 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 ); - auto res6 = p_add_opts( true, false, true, true ); - auto res7 = p_add_opts( true, true, false, true ); - auto res8 = p_add_opts( true, true, true, false ); - auto res9 = p_add_opts( true, false, false, true ); - auto res10 = p_add_opts( true, true, false, false ); - auto res11 = p_add_opts( true, false, true, false ); - auto res12 = p_add_opts( true, false, false, false ); + auto res5 = p_add_opts( mask_arg, true, true, true, true ); + auto res6 = p_add_opts( mask_arg, true, false, true, true ); + auto res7 = p_add_opts( mask_arg, true, true, false, true ); + auto res8 = p_add_opts( mask_arg, true, true, true, false ); + auto res9 = p_add_opts( mask_arg, true, false, false, true ); + auto res10 = p_add_opts( mask_arg, true, true, false, false ); + auto res11 = p_add_opts( mask_arg, true, false, true, false ); + auto res12 = p_add_opts( mask_arg, true, false, false, false ); BOOST_CHECK_EQUAL( res5, 9 ); @@ -2595,8 +2603,8 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { // check the VALUE_OR functor auto val_or = Functors::chain( Functors::Functional::ValueOr{ 123 }, Functors::Examples::OptReturn{ 10 } ); auto p_val_or = val_or.prepare( evtCtx, top_level ); - auto res13 = p_val_or( true, true ); - auto res14 = p_val_or( true, false ); + auto res13 = p_val_or( mask_arg, true, true ); + auto res14 = p_val_or( mask_arg, true, false ); BOOST_CHECK_EQUAL( res13, 10 ); BOOST_CHECK_EQUAL( res14, 123 ); @@ -2606,8 +2614,8 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { auto p_long_val_or = long_val_or.prepare( evtCtx, top_level ); - auto res15 = p_long_val_or( true, true ); - auto res16 = p_long_val_or( true, false ); + auto res15 = p_long_val_or( mask_arg, true, true ); + auto res16 = p_long_val_or( mask_arg, true, false ); BOOST_CHECK_EQUAL( res15, 40 ); BOOST_CHECK_EQUAL( res16, 123 ); @@ -2615,8 +2623,8 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { auto val_or_v = Functors::chain( Functors::Functional::ValueOr{ 123 }, Functors::Examples::OptReturn<SIMDWrapper::scalar::int_v>( 10 ) ); auto p_val_or_v = val_or_v.prepare( evtCtx, top_level ); - auto res17 = p_val_or_v( true, true ); - auto res18 = p_val_or_v( true, false ); + auto res17 = p_val_or_v( mask_arg, true, true ); + auto res18 = p_val_or_v( mask_arg, true, false ); BOOST_CHECK_EQUAL( res17.cast(), 10 ); BOOST_CHECK_EQUAL( res18.cast(), 123 ); @@ -2639,14 +2647,14 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { auto p_test_operators_2 = test_operators_2.prepare( evtCtx, top_level ); auto p_test_operators_3 = test_operators_3.prepare( evtCtx, top_level ); - BOOST_CHECK_EQUAL( p_test_operators_0( true, true ), 10 + 11 ); - BOOST_CHECK_EQUAL( p_test_operators_1( true, true ), 10 - 11 ); - BOOST_CHECK_EQUAL( p_test_operators_2( true, true ), 10 * 11 ); - BOOST_CHECK_EQUAL( p_test_operators_3( true, true ), 10 / 11 ); - BOOST_CHECK_EQUAL( p_test_operators_0( true, false ), 123 ); - BOOST_CHECK_EQUAL( p_test_operators_1( true, false ), 123 ); - BOOST_CHECK_EQUAL( p_test_operators_2( true, false ), 123 ); - BOOST_CHECK_EQUAL( p_test_operators_3( true, false ), 123 ); + BOOST_CHECK_EQUAL( p_test_operators_0( mask_arg, true, true ), 10 + 11 ); + BOOST_CHECK_EQUAL( p_test_operators_1( mask_arg, true, true ), 10 - 11 ); + BOOST_CHECK_EQUAL( p_test_operators_2( mask_arg, true, true ), 10 * 11 ); + BOOST_CHECK_EQUAL( p_test_operators_3( mask_arg, true, true ), 10 / 11 ); + BOOST_CHECK_EQUAL( p_test_operators_0( mask_arg, true, false ), 123 ); + BOOST_CHECK_EQUAL( p_test_operators_1( mask_arg, true, false ), 123 ); + BOOST_CHECK_EQUAL( p_test_operators_2( mask_arg, true, false ), 123 ); + BOOST_CHECK_EQUAL( p_test_operators_3( mask_arg, true, false ), 123 ); LHCb::LinAlg::Vec3<float> vec_a{ 1.f, 2.f, 3.f }, vec_b{ 4.f, 5.f, 6.f }; auto test_operators_4 = @@ -2658,10 +2666,10 @@ BOOST_AUTO_TEST_CASE( check_optional_returns ) { auto p_test_operators_4 = test_operators_4.prepare( evtCtx, top_level ); auto p_test_operators_5 = test_operators_5.prepare( evtCtx, top_level ); - BOOST_CHECK_EQUAL( p_test_operators_4( true, true ), ( vec_a + vec_b ).mag() ); - BOOST_CHECK_EQUAL( p_test_operators_5( true, true ), ( vec_a - vec_b ).mag() ); - BOOST_CHECK_EQUAL( p_test_operators_4( true, false ), 123.f ); - BOOST_CHECK_EQUAL( p_test_operators_5( true, false ), 123.f ); + BOOST_CHECK_EQUAL( p_test_operators_4( mask_arg, true, true ), ( vec_a + vec_b ).mag() ); + BOOST_CHECK_EQUAL( p_test_operators_5( mask_arg, true, true ), ( vec_a - vec_b ).mag() ); + BOOST_CHECK_EQUAL( p_test_operators_4( mask_arg, true, false ), 123.f ); + BOOST_CHECK_EQUAL( p_test_operators_5( mask_arg, true, false ), 123.f ); // // Check value or in LHCb::LinAlg::Vec @@ -2720,7 +2728,7 @@ BOOST_AUTO_TEST_CASE( test_arithmetic_functor ) { auto p_opt_abs = opt_abs.prepare( evtCtx, top_level ); - auto res = p_opt_abs( true, true ); + auto res = p_opt_abs( mask_arg, true, true ); BOOST_CHECK_EQUAL( res, 42 ); } @@ -2861,8 +2869,8 @@ BOOST_AUTO_TEST_CASE( test_Value_ValueOrDict ) { // test Value 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 ); + auto funval = p_val( mask_arg, true, true ); + BOOST_CHECK_THROW( p_val( mask_arg, true, false ), GaudiException ); BOOST_CHECK_EQUAL( funval["a"], 2 ); BOOST_CHECK_EQUAL( funval["b"], 3 ); @@ -2877,8 +2885,8 @@ BOOST_AUTO_TEST_CASE( test_Value_ValueOrDict ) { // doesn't work with type deduction // auto val_or_mine = Functors::Functional::ValueOr{{{ std::string{"a"}, int{-1} }, { std::string{"b"}, int{-1} }}}; auto p_val_or = val_or.prepare( evtCtx, top_level ); - auto funval_or = p_val_or( true, true ); - auto def_funval_or = p_val_or( true, false ); + auto funval_or = p_val_or( mask_arg, true, true ); + auto def_funval_or = p_val_or( mask_arg, true, false ); BOOST_CHECK_EQUAL( funval_or["a"], 2 ); BOOST_CHECK_EQUAL( funval_or["b"], 3 ); BOOST_CHECK_EQUAL( def_funval_or["a"], -1 ); @@ -3006,14 +3014,14 @@ BOOST_AUTO_TEST_CASE( test_tree_functors ) { auto find_in_tree_prepped = FIND_IN_TREE.prepare( evtCtx, top_level ); auto share_tracks_prepped = SHARE_TRACKS.prepare( evtCtx, top_level ); - BOOST_CHECK( LHCb::Utils::as_arithmetic( mintree_prepped( true, B0 ) ) < 500 ); - BOOST_CHECK( LHCb::Utils::as_arithmetic( maxtree_prepped( true, B0 ) ) > 500 ); - BOOST_CHECK_EQUAL( nintree_prepped( true, B0 ), 3 ); - BOOST_CHECK_EQUAL( intree_prepped( true, B0 ), true ); - BOOST_CHECK_EQUAL( find_in_tree_prepped( true, p3, p1 ), true ); - BOOST_CHECK_EQUAL( find_in_tree_prepped( true, p3, p2 ), true ); - BOOST_CHECK_EQUAL( find_in_tree_prepped( true, p3, p4 ), false ); - BOOST_CHECK_EQUAL( share_tracks_prepped( true, p1, p1 ), true ); + BOOST_CHECK( LHCb::Utils::as_arithmetic( mintree_prepped( mask_arg, true, B0 ) ) < 500 ); + BOOST_CHECK( LHCb::Utils::as_arithmetic( maxtree_prepped( mask_arg, true, B0 ) ) > 500 ); + BOOST_CHECK_EQUAL( nintree_prepped( mask_arg, true, B0 ), 3 ); + BOOST_CHECK_EQUAL( intree_prepped( mask_arg, true, B0 ), true ); + BOOST_CHECK_EQUAL( find_in_tree_prepped( mask_arg, true, p3, p1 ), true ); + BOOST_CHECK_EQUAL( find_in_tree_prepped( mask_arg, true, p3, p2 ), true ); + BOOST_CHECK_EQUAL( find_in_tree_prepped( mask_arg, true, p3, p4 ), false ); + BOOST_CHECK_EQUAL( share_tracks_prepped( mask_arg, true, p1, p1 ), true ); auto const& CHILD = ::Functors::Adapters::GenerationFromComposite( 1 ); auto const& GCHILD = ::Functors::Adapters::GenerationFromComposite( 2 ); @@ -3055,10 +3063,10 @@ BOOST_AUTO_TEST_CASE( test_tree_functors ) { auto gchild_ningeneration_prepped = GCHILD_NINGENERATION.prepare( evtCtx, top_level ); auto gchild_ingeneration_prepped = GCHILD_INGENERATION.prepare( evtCtx, top_level ); - BOOST_CHECK_EQUAL( child_ningeneration_prepped( true, B0 ), 1 ); - BOOST_CHECK_EQUAL( child_ingeneration_prepped( true, B0 ), true ); - BOOST_CHECK_EQUAL( gchild_ningeneration_prepped( true, B0 ), 2 ); - BOOST_CHECK_EQUAL( gchild_ingeneration_prepped( true, B0 ), true ); + BOOST_CHECK_EQUAL( child_ningeneration_prepped( mask_arg, true, B0 ), 1 ); + BOOST_CHECK_EQUAL( child_ingeneration_prepped( mask_arg, true, B0 ), true ); + BOOST_CHECK_EQUAL( gchild_ningeneration_prepped( mask_arg, true, B0 ), 2 ); + BOOST_CHECK_EQUAL( gchild_ingeneration_prepped( mask_arg, true, B0 ), true ); const auto ISBASICPARTICLE = Functors::Particle::IsBasicParticle; BOOST_CHECK_EQUAL( ISBASICPARTICLE( B0 ), false ); @@ -3114,15 +3122,20 @@ BOOST_AUTO_TEST_CASE( test_tistos_functors ) { 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 - auto val_l2_istis_int = tmp_l2_istis_int.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct - auto val_wrong1_int = tmp_wrong1_int.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // wrong line name - auto val_wrong2_int = - tmp_wrong2_int.prepare( evtCtx, top_level )( true, table, parts( 1 ) ); // no trigger info for particle two + auto val_l1_istos_int = + tmp_l1_istos_int.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_l1_istis_int = + tmp_l1_istis_int.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_l2_istos_int = + tmp_l2_istos_int.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_l2_istis_int = + tmp_l2_istis_int.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_wrong1_int = + tmp_wrong1_int.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // wrong line name + auto val_wrong2_int = tmp_wrong2_int.prepare( evtCtx, top_level )( mask_arg, true, table, + parts( 1 ) ); // no trigger info for particle two auto val_wrong3_int = tmp_wrong3_int.prepare( evtCtx, top_level )( - true, table, parts( 1 ) ); // wrong line name and no trigger info particle two + mask_arg, true, table, parts( 1 ) ); // wrong line name and no trigger info particle two BOOST_CHECK_EQUAL( val_l1_istos_int, static_cast<int>( Line1res.TOS() ) ); BOOST_CHECK_EQUAL( val_l1_istis_int, static_cast<int>( Line1res.TIS() ) ); BOOST_CHECK_EQUAL( val_l2_istos_int, static_cast<int>( Line2res.TOS() ) ); @@ -3145,15 +3158,20 @@ BOOST_AUTO_TEST_CASE( test_tistos_functors ) { 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" }, 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 - auto val_l2_istos_bool = tmp_l2_istos_bool.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct - auto val_l2_istis_bool = tmp_l2_istis_bool.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // all correct - auto val_wrong1_bool = tmp_wrong1_bool.prepare( evtCtx, top_level )( true, table, parts( 0 ) ); // wrong line name - auto val_wrong2_bool = - tmp_wrong2_bool.prepare( evtCtx, top_level )( true, table, parts( 1 ) ); // no trigger info for particle two + auto val_l1_istos_bool = + tmp_l1_istos_bool.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_l1_istis_bool = + tmp_l1_istis_bool.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_l2_istos_bool = + tmp_l2_istos_bool.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_l2_istis_bool = + tmp_l2_istis_bool.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // all correct + auto val_wrong1_bool = + tmp_wrong1_bool.prepare( evtCtx, top_level )( mask_arg, true, table, parts( 0 ) ); // wrong line name + auto val_wrong2_bool = tmp_wrong2_bool.prepare( evtCtx, top_level )( mask_arg, true, table, + parts( 1 ) ); // no trigger info for particle two auto val_wrong3_bool = tmp_wrong3_bool.prepare( evtCtx, top_level )( - true, table, parts( 1 ) ); // wrong line name and no trigger info particle two + mask_arg, true, table, parts( 1 ) ); // wrong line name and no trigger info particle two BOOST_CHECK_EQUAL( val_l1_istos_bool, Line1res.TOS() ); BOOST_CHECK_EQUAL( val_l1_istis_bool, Line1res.TIS() ); BOOST_CHECK_EQUAL( val_l2_istos_bool, Line2res.TOS() ); @@ -3238,7 +3256,7 @@ BOOST_AUTO_TEST_CASE( test_require_close ) { auto REQUIRE_CLOSE_prepared = REQUIRE_CLOSE.prepare( evtCtx, top_level ); // check that it is equal - BOOST_CHECK_EQUAL( REQUIRE_CLOSE_prepared( true, B0 ), true ); + BOOST_CHECK_EQUAL( REQUIRE_CLOSE_prepared( mask_arg, true, B0 ), true ); } BOOST_AUTO_TEST_CASE( test_mc_originflag ) { @@ -3302,8 +3320,8 @@ BOOST_AUTO_TEST_CASE( test_get_pvtracks ) { auto COUNTIF_ALL_prepped = COUNTIF_ALL.prepare( evtCtx, top_level ); auto COUNTIF_BACKWARDS_prepped = COUNTIF_BACKWARDS.prepare( evtCtx, top_level ); - BOOST_CHECK_EQUAL( COUNTIF_ALL_prepped( true, &recvtx ), 2 ); - BOOST_CHECK_EQUAL( COUNTIF_BACKWARDS_prepped( true, &recvtx ), 1 ); + BOOST_CHECK_EQUAL( COUNTIF_ALL_prepped( mask_arg, true, &recvtx ), 2 ); + BOOST_CHECK_EQUAL( COUNTIF_BACKWARDS_prepped( mask_arg, true, &recvtx ), 1 ); } BOOST_AUTO_TEST_CASE( test_velomatch_functors ) { -- GitLab