From 7bd099758fd6e6fa4590e259bf524ca493245297 Mon Sep 17 00:00:00 2001 From: Sascha Stahl <sascha.stahl@cern.ch> Date: Sun, 5 May 2019 23:04:05 +0200 Subject: [PATCH] add soa track selector --- Pr/PrAlgorithms/src/PrFilter.cpp | 111 +++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/Pr/PrAlgorithms/src/PrFilter.cpp b/Pr/PrAlgorithms/src/PrFilter.cpp index f1c0b8927..7cfe14437 100644 --- a/Pr/PrAlgorithms/src/PrFilter.cpp +++ b/Pr/PrAlgorithms/src/PrFilter.cpp @@ -20,12 +20,23 @@ #include "boost/algorithm/string/join.hpp" #include <vector> +#include "SOAContainer/SOAContainer.h" +#include "SOAExtensions/ZipContainer.h" +#include "SOAExtensions/ZipSelection.h" +#include "Event/TrackSkin.h" + namespace { // Just shorthand for below template <typename T> using FilterTransform = Gaudi::Functional::MultiTransformerFilter<std::tuple<Pr::Selection<T>>( Pr::Selection<T> const& )>; + // Just shorthand for below + using SOATracks = Zipping::ZipContainer<decltype( + SOA::make_soaview<LHCb::Event::v2::TrackSkin>( std::declval<const std::vector<LHCb::Event::v2::Track>&>() ) )>; + using SOAFilterTransform = Gaudi::Functional::MultiTransformerFilter<std::tuple<Zipping::ExportedSelection<>>( + SOATracks const&, Zipping::ExportedSelection<> const& )>; + // Helper class used to collect the type names we need to construct LoKi functors for various objects template <typename T> struct TypeHelper {}; @@ -49,6 +60,16 @@ namespace { constexpr static auto DefaultFunctorCode = "~TrALL"; constexpr static auto FunctorFactoryName = "LoKi::Hybrid::Pr::TrackFunctorFactory/PrTrackFunctorFactory:PUBLIC"; }; + // LoKi type names for Filter<v2::Track> + template <> + struct TypeHelper<SOATracks> { + using Predicate = LoKi::Pr::TrackTypes::TrCut; + using FunctorFactory = LoKi::Pr::ITrackFunctorFactory; + using BooleanConstant = LoKi::BasicFunctors<LoKi::Pr::TrackType const*>::BooleanConstant; + constexpr static auto DefaultFunctorCode = "~TrALL"; + constexpr static auto FunctorFactoryName = "LoKi::Hybrid::Pr::TrackFunctorFactory/PrTrackFunctorFactory:PUBLIC"; + }; + } // namespace namespace Pr { @@ -138,4 +159,94 @@ namespace Pr { DECLARE_COMPONENT_WITH_ID( Filter<LHCb::Event::v1::Track>, "PrFilter__Track_v1" ) DECLARE_COMPONENT_WITH_ID( Filter<LHCb::Event::v2::Track>, "PrFilter__Track_v2" ) + + + /** @class SOAFilter PrFilter.cpp + * + * SOAFilter<T> applies a selection to an input Selection<T> and returns a new Selection<T> object. + * + * @tparam T The selected object type (e.g. Track, Particle, ...). By contruction this is not copied, as the + * input/output type Selection<T> is just a view of some other underlying storage. + */ + + class SOAFilter final : public SOAFilterTransform { + public: + using SOAFilterTransform::debug; + using SOAFilterTransform::msgLevel; + + SOAFilter( const std::string& name, ISvcLocator* pSvcLocator ) + : SOAFilterTransform( name, pSvcLocator, {KeyValue{"InputTracks", ""}, KeyValue{"InputSelection", ""}}, {"OutputSelection", ""} ) {} + + std::tuple<bool, Zipping::ExportedSelection<>> operator()( SOATracks const& in, + Zipping::ExportedSelection<> const& sel ) const override { + auto selected_input = Zipping::SelectionView<decltype( in )>{&in, sel}; + auto buffer = m_cutEff.buffer(); + auto pred_with_counter = [this, &buffer]( auto const& x ) { + auto dec = this->m_pred( &(x.track()) ); + buffer += dec; // record selection efficiency + return dec; + }; + + // Make a new Selection by applying an extra cut to 'in' + auto filtered = selected_input.select( pred_with_counter ); + + // For use in the control flow: did we select anything? + auto filter_pass = !filtered.empty(); + + return {filter_pass, std::move( filtered )}; + } + + StatusCode initialize() override { + auto sc = SOAFilterTransform::initialize(); + decode(); + return sc; + } + + private: + // Counter for recording cut retention statistics + mutable Gaudi::Accumulators::BinomialCounter<> m_cutEff{this, "Cut selection efficiency"}; + + // Boilerplate to load a LoKi filter predicate + // These two flags are used to ensure that the values of both 'Code' and 'Preambulo' have been loaded before we try + // to decode the functor + bool m_code_updated{false}; + bool m_preambulo_updated{false}; + + // This is the functor cut string + Gaudi::Property<std::string> m_code{this, "Code", TypeHelper<SOATracks>::DefaultFunctorCode, [this]( auto& ) { + this->m_code_updated = true; + if ( this->FSMState() < Gaudi::StateMachine::INITIALIZED ) return; + if ( !this->m_preambulo_updated ) return; + this->decode(); + }}; + + // Finally we can set a list of preambulo statements + Gaudi::Property<std::vector<std::string>> m_preambulo{this, "Preambulo", {}, [this]( auto& ) { + this->m_preambulo_updated = true; + if ( this->FSMState() < Gaudi::StateMachine::INITIALIZED ) + return; + if ( !this->m_code_updated ) return; + this->decode(); + }}; + + // Use the TypeHelper template defined above to choose the right types/defaults based on the template parameter T + ToolHandle<typename TypeHelper<SOATracks>::FunctorFactory> m_factory{this, "Factory", TypeHelper<SOATracks>::FunctorFactoryName}; + typename TypeHelper<SOATracks>::Predicate m_pred = typename TypeHelper<SOATracks>::BooleanConstant( false ); + + void decode() { + if ( msgLevel( MSG::DEBUG ) ) debug() << "decoding " << m_code.value() << endmsg; + m_factory.retrieve().ignore(); + StatusCode sc = m_factory->get( m_code.value(), m_pred, boost::algorithm::join( m_preambulo.value(), "\n" ) ); + if ( sc.isFailure() ) { + throw GaudiException{"Failure to decode: " + m_code.value(), "Pr::Filter<T>", StatusCode::FAILURE}; + } + m_factory.release().ignore(); + m_code_updated = false; + m_preambulo_updated = false; + if ( msgLevel( MSG::DEBUG ) ) debug() << "decoded " << m_code.value() << endmsg; + } + }; + //using SOATrackFilter = SOAFilter<SOATracks>; + DECLARE_COMPONENT_WITH_ID( SOAFilter, "PrFilter__SOATracks" ) + } // namespace Pr -- GitLab