# Add vectorised track combiner

Brief summary: add a vectorised track combiner `CombineTracksSIMD`

(which produces `v2::Composites`

), and a whole bunch of other related changes to selection/functor code to enable this.

`CombineTracksSIMD`

:

- Implements generic
`N`

-body combinations from a single input container of tracks, producing`v2::Composites`

- The combiner has to be explicitly instantiated for each input container type,
`N`

and target vector backend. The output type`v2::Composites`

erases all of these details. - If a relevant functor cache is available, the combination generation, combination cut(s), vertex fit and vertex/parent cut are all explicitly vectorised. If no cache is available, the cuts are JIT compiled and the algorithm falls back to scalar calculation.
- Vertex fit implementation is lifted from
`ThOrParticleCombiner`

, thanks @nnolte :)

Converters:

- Add
`LHCb::Converters::Composites::ToVectorOfRecVertex<T>`

algorithm for converting`v2::Composites`

to a vector of vertices, for use in the SelReports code

Functor interface changes:

- Store whether a functor with JIT compiled or loaded from the functor cache.
- Add
`getFunctors()`

method to`with_functors`

mixin to return multiple decoded functors at once. - Add
`Functors::mask_arg_t`

tag type; this can be used to tag that the following (second) argument is a mask that gives the validity of the remaining arguments:`Functor<Output( mask_arg_t, mask_v const&, Input const& )>`

. This is useful when`Input`

is some type representing a vector of values. - Drop
`BPVIPCHI2STATE`

functor - Make the
`CompositeMass`

functor return`p.momentum().M()`

instead of`p.measuredMass()`

when applied to a`v1::Particle`

- Make the
`COMB`

functor [reconstructing a "combination" object from a "composite"] compatible with a runtime-variable number of heterogeneous child types & vectorised instantiation - Make the
`MVA`

functor support vectorised instantiation; the calculation of inputs is vectorised, but evaluation of the classifier is [masked] scalar. (We should really get some faster MVA implementations here!) - Add
`POD`

functor (meaning Plain Old Data, but perhaps someone would like to suggest a better name) that wraps the new`Sel::Utils::as_arithmetic`

helper. This converts objects representing scalar values into plain C++ types (e.g.`SIMDWrapper::scalar::int_v`

->`int`

). This is a step on the way to retiring the "unwrapping" functionality of`LHCb::Pr::Zip`

.`POD`

can be automatically added as a wrapper around a functor expression to make it yield a type that e.g.`TTree`

can understand.

Selection utilities changes:

- Add
`Sel::Utils::hmin`

,`Sel::Utils::hmax`

,`Sel::Utils::as_arithmetic`

helpers for writing generic code that handles both plain C++ types and e.g.`SIMDWrapper`

int/float types. - Add various helpers for writing generic code, e.g.
`Sel::vector::dot{}( a, b )`

takes the dot product of vectors`a`

and`b`

, abstracting away some API inconsistencies between different vector types in the codebase - Reorganise various type trait helpers, e.g.
`Sel::type_traits::has_eta_v<T>`

queries whether an object of type`T`

has an`eta()`

method - Add
`Sel::Utils::stateDOCA( s1, s2 )`

helper for calculating the distance of closest approach between two states of distinct type. This is copied from`LHCb::TrackVertexUtils::doca`

to avoid the unfortunate issue that calling`LHCb::TrackVertexUtils::doca`

with two arguments of different types despatches to the calculation of DOCA between a state and a point (a state has x/y/z accessors, so this is not a compile error!)

Event model changes:

- Add
`v2::Composites`

-compatible accessors to`TrackCompactVertex`

- Prefer
`static_assert( std::numeric_limits<T>::is_specialized )`

and`std::numeric_limits<T>`

now`SIMDWrapper`

supports`std::numeric_limits`

Internal functor changes:

- Pass
`Functors::TopLevelInfo&`

to internal functor bind methods instead of`Gaudi::Algorithm*`

, making it easier to expose more helper functionality; add a helper to avoid hitting https://its.cern.ch/jira/browse/GAUDI-1023 when multiple functors need to access the same service - Add some missing inheritance from
`Function`

and`Predicate`

- Use demangled
`typeid( T ).name()`

in some error messages - Minor code improvements/cleanups.
- Support explicit masks in functors. If a functor defines
`constexpr static bool requires_explicit_mask = true`

then it will be invoked with a mask as its first argument, which gives the validity of the remaining arguments. Make this change in the various adapter functors. - Use explicit mask support in
`MINIP[CHI2]CUT`

functors, where the mask can be used to short-circuit earlier.

To be tested with LHCb!2650 (merged) and Moore!562 (merged)

cc: @nnolte

Edited by Olli Lupton