Skip to content
Snippets Groups Projects
L1Algo.h 27.79 KiB
/* Copyright (C) 2007-2021 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Maksym Zyzak, Valentina Akishina, Igor Kulakov [committer] */

#ifndef L1Algo_h
#define L1Algo_h

// #define TBB // TODO: Doesn't work now. Renew

/// Debug features
// #define PULLS            // triplets pulls
// #define TRIP_PERFORMANCE // triplets efficiencies
// #define DOUB_PERFORMANCE // doublets efficiencies
// #define DRAW             // event display
#ifdef DRAW
class L1AlgoDraw;
#include "CbmL1Track.h"
#endif
//#define XXX               // time debug
//#define COUNTERS          // diff counters (hits, doublets, ... )

// =====>dispatched<===== // #define MERGE_CLONES
// #define TRACKS_FROM_TRIPLETS_ITERATION kAllPrimIter

//#define HitErrors
//#define GLOBAL
//#define mCBM

// =====>dispatched<===== // #define LAST_ITERATION kAllSecIter
#define FIND_GAPED_TRACKS  // use triplets with gaps
// =====>dispatched<===== // #define USE_RL_TABLE
#ifndef TRACKS_FROM_TRIPLETS
#define EXTEND_TRACKS
#endif
//#define USE_EVENT_NUMBER
//#endif


#include <array>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>

#include "L1Branch.h"
#include "L1Field.h"
#include "L1Grid.h"
#include "L1Hit.h"
#include "L1HitPoint.h"
#include "L1HitsSortHelper.h"
#include "L1InitManager.h"
#include "L1Parameters.h"
#include "L1Portion.h"
#include "L1Station.h"
#include "L1Track.h"
#include "L1TrackPar.h"
#include "L1TrackParFit.h"
#include "L1Triplet.h"
#include "L1Utils.h"
#include "L1Vector.h"

#ifdef _OPENMP
#include "omp.h"
#endif

using std::map;

typedef int Tindex;

#ifdef PULLS
#define TRIP_PERFORMANCE
class L1AlgoPulls;
#endif
#ifdef TRIP_PERFORMANCE
template<Tindex NHits>
class L1AlgoEfficiencyPerformance;
#endif
#ifdef DOUB_PERFORMANCE
template<Tindex NHits>
class L1AlgoEfficiencyPerformance;
#endif

using L1StationsArray_t = std::array<L1Station, L1Constants::size::kMaxNstations>;
using L1MaterialArray_t = std::array<L1Material, L1Constants::size::kMaxNstations>;

/// Central class of L1 tracking
///
class L1Algo {
public:
  L1Algo(unsigned int nThreads = 1);

  L1Algo(const L1Algo&) = delete;
  L1Algo operator=(const L1Algo&) = delete;

  /// Sets a default particle mass for the track fit
  /// it is used during reconstruction
  /// for the multiple scattering and energy loss estimation
  /// \param mass Default particle mass
  void SetDefaultParticleMass(float mass) { fDefaultMass = mass; }

  /// Gets default particle mass
  /// \return particle mass
  float GetDefaultParticleMass() const { return fDefaultMass; }

  /// Gets default particle mass squared
  /// \return particle mass squared
  float GetDefaultParticleMass2() const { return fDefaultMass * fDefaultMass; }


  /// pack station, thread and triplet indices to an unique triplet ID
  static unsigned int PackTripletId(unsigned int Station, unsigned int Thread, unsigned int Triplet)
  {
    //SG!!#ifndef FAST_CODE
    assert(Station < L1Constants::size::kMaxNstations);
    assert(Thread < L1Constants::size::kMaxNthreads);
    assert(Triplet < L1Constants::size::kMaxNtriplets);
    //#endif
    constexpr unsigned int kMoveThread  = L1Constants::size::kTripletBits;
    constexpr unsigned int kMoveStation = L1Constants::size::kTripletBits + L1Constants::size::kThreadBits;
    return (Station << kMoveStation) + (Thread << kMoveThread) + Triplet;
  }

  /// unpack the triplet ID to its station index
  static unsigned int TripletId2Station(unsigned int ID)
  {
    constexpr unsigned int kMoveStation = L1Constants::size::kTripletBits + L1Constants::size::kThreadBits;
    return ID >> kMoveStation;
  }

  /// unpack the triplet ID to its thread index
  static unsigned int TripletId2Thread(unsigned int ID)
  {
    constexpr unsigned int kMoveThread = L1Constants::size::kTripletBits;
    constexpr unsigned int kThreadMask = (1u << L1Constants::size::kThreadBits) - 1u;
    return (ID >> kMoveThread) & kThreadMask;
  }

  /// unpack the triplet ID to its triplet index
  static unsigned int TripletId2Triplet(unsigned int ID)
  {
    constexpr unsigned int kTripletMask = (1u << L1Constants::size::kTripletBits) - 1u;
    return ID & kTripletMask;
  }


  /// pack thread and track indices to an unique track ID
  static int PackTrackId(int Thread, int Track)
  {
    return PackTripletId(0, (unsigned int) Thread, (unsigned int) Track);
  }

  /// unpack the track ID to its thread index
  static int TrackId2Thread(int ID) { return TripletId2Thread((unsigned int) ID); }

  /// unpack the track ID to its track index
  static int TrackId2Track(int ID) { return TripletId2Triplet((unsigned int) ID); }


  L1Vector<L1Triplet> fTriplets[L1Constants::size::kMaxNstations][L1Constants::size::kMaxNthreads] {
    {"L1Algo::fTriplets"}};  // created triplets at station + thread

  // Track candidates created out of adjacent triplets before the final track selection.
  // The candidates may share any amount of hits.
  L1Vector<L1Branch> fTrackCandidates[L1Constants::size::kMaxNthreads] {"L1Algo::fTrackCandidates"};

  Tindex fDupletPortionStopIndex[L1Constants::size::kMaxNstations] {0};  // end of the duplet portions for the station
  L1Vector<Tindex> fDupletPortionSize {"L1Algo::fDupletPortionSize"};    // N duplets in a portion

  /********************************************************************************************/ /**
   * Temporary vectors used by the clone merger 
   * TODO: Probably, the subclass L1TrackMerger for clones merger would help to improve 
   *       readability (S.Zharko)
   ***********************************************************************************************/

  //
  // Vectors that are parallel to fTracks
  //
  /// First station of a track
  L1Vector<unsigned short> fMergerTrackFirstStation {"L1Algo::fMergerTrackFirstStation"};
  /// Last station of a track
  L1Vector<unsigned short> fMergerTrackLastStation {"L1Algo::fMergerTrackLastStation"};
  /// Index of the first hit of a track
  L1Vector<L1HitIndex_t> fMergerTrackFirstHit {"L1Algo::fMergerTrackFirstHit"};
  /// Index of the last hit of a track
  L1Vector<L1HitIndex_t> fMergerTrackLastHit {"L1Algo::fMergerTrackLastHit"};
  /// Index (TODO:??) of a track that can be merge with the given track
  L1Vector<unsigned short> fMergerTrackNeighbour {"L1Algo::fMergerTrackNeighbour"};
  /// Chi2 value of the track merging procedure
  L1Vector<float> fMergerTrackChi2 {"L1Algo::fMergerTrackChi2"};
  /// Flag: is the given track already stored to the output
  L1Vector<char> fMergerTrackIsStored {"L1Algo::fMergerTrackIsStored"};
  /// Flag: is the track a downstream neighbour of another track
  L1Vector<char> fMergerTrackIsDownstreamNeighbour {"L1Algo::fMergerTrackIsDownstreamNeighbour"};
  //
  // Utility vectors
  //
  /// Tracks after the merging procedure
  L1Vector<L1Track> fMergerTracksNew {"L1Algo::fMergerTracksNew"};           // vector of tracks after the merge
  L1Vector<L1HitIndex_t> fMergerRecoHitsNew {"L1Algo::fMergerRecoHitsNew"};  // vector of track hits after the merge


#ifdef DRAW
  L1AlgoDraw* draw {nullptr};
  void DrawRecoTracksTime(const L1Vector<CbmL1Track>& tracks);
#endif

  enum TrackingMode
  {
    kSts,
    kGlobal,
    kMcbm
  };

  void Init(const bool UseHitErrors, const TrackingMode mode, const bool MissingHits);

  void SetData(L1Vector<L1Hit>& Hits_, int nStrips_, L1Vector<unsigned char>& SFlag_,
               const L1HitIndex_t* HitsStartIndex_, const L1HitIndex_t* HitsStopIndex_);

  void PrintHits();

  /// The main procedure - find tracks.
  void CATrackFinder();

  /// Track fitting procedures
  void KFTrackFitter_simple();  // version, which use procedured used during the reconstruction
  void L1KFTrackFitter();       // version from SIMD-KF benchmark

  void L1KFTrackFitterMuch();

  float GetMaxInvMom() const { return fMaxInvMom[0]; }

  /// ----- Input data -----
  // filled in CbmL1::ReadEvent();

  void SetNThreads(unsigned int n);

private:
  int fNstations {0};            ///< number of all detector stations
  int fNstationsBeforePipe {0};  ///< number of stations before pipe (MVD stations in CBM)
  int fNfieldStations {0};       ///< number of stations in the field region
  //alignas(16) L1StationsArray_t fStations {};  ///< array of L1Station objects
  //alignas(16) L1MaterialArray_t fRadThick {};  ///< material for each station
  float fDefaultMass {L1Constants::phys::kMuonMass};  ///< mass of the propagated particle [GeV/c2]

public:
  /// Gets total number of stations used in tracking
  int GetNstations() const { return fNstations; }

  /// Gets number of stations before the pipe (MVD stations in CBM)
  int GetNstationsBeforePipe() const { return fNstationsBeforePipe; }

  /// Gets number of stations situated in field region (MVD + STS in CBM)
  int GetNfieldStations() const { return fNfieldStations; }

  /// Get mc track ID for a hit (debug tool)
  int GetMcTrackIdForHit(int iHit);

  /// Get mc track ID for a hit (debug tool)
  int GetMcTrackIdForUnusedHit(int iHit);

public:
  int fNstrips {0};                                    ///> number of strips
  L1Vector<L1Hit>* vHits {nullptr};                    ///> hits as a combination of front-, backstrips and z-position
  L1Grid vGrid[L1Constants::size::kMaxNstations];      ///> hits as a combination of front-, backstrips and z-position
  L1Grid vGridTime[L1Constants::size::kMaxNstations];  ///>

  L1Vector<unsigned char>* fStripFlag {nullptr};  // information of hits station & using hits in tracks;

  double fCATime {0.};  // time of track finding

  L1Vector<L1Track> fTracks {"L1Algo::fTracks"};           // reconstructed tracks
  L1Vector<L1HitIndex_t> fRecoHits {"L1Algo::fRecoHits"};  // packed hits of reconstructed tracks

  const L1HitIndex_t* HitsStartIndex {nullptr};  // station-bounders in vHits array
  const L1HitIndex_t* HitsStopIndex {nullptr};   // station-bounders in vHits array


  //  L1Branch* pointer;
  unsigned int NHitsIsecAll {0};
  L1Vector<L1Hit> vNotUsedHits_A {"L1Algo::vNotUsedHits_A"};
  L1Vector<L1Hit> vNotUsedHits_B {"L1Algo::vNotUsedHits_B"};
  L1Vector<L1Hit> vNotUsedHits_Buf {"L1Algo::vNotUsedHits_Buf"};
  L1Vector<L1HitPoint> vNotUsedHitsxy_A {"L1Algo::vNotUsedHitsxy_A"};
  L1Vector<L1HitPoint> vNotUsedHitsxy_buf {"L1Algo::vNotUsedHitsxy_buf"};
  L1Vector<L1HitPoint> vNotUsedHitsxy_B {"L1Algo::vNotUsedHitsxy_B"};
  L1Vector<L1Track> fTracks_local[L1Constants::size::kMaxNthreads] {"L1Algo::fTracks_local"};
  L1Vector<L1HitIndex_t> fRecoHits_local[L1Constants::size::kMaxNthreads] {"L1Algo::fRecoHits_local"};

  L1Vector<L1HitIndex_t> RealIHit_v {"L1Algo::RealIHit_v"};
  L1Vector<L1HitIndex_t> RealIHit_v_buf {"L1Algo::RealIHit_v_buf"};
  L1Vector<L1HitIndex_t> RealIHit_v_buf2 {"L1Algo::RealIHit_v_buf2"};

#ifdef _OPENMP
  L1Vector<omp_lock_t> fStripToTrackLock {"L1Algo::fStripToTrackLock"};
#endif

  L1Vector<int> fStripToTrack {"L1Algo::fStripToTrack"};  // strip to track pointers

  int fNThreads {0};
  bool fUseHitErrors {true};
  bool fMissingHits {0};  ///< TODO ???
  TrackingMode fTrackingMode {kSts};

  fvec EventTime[L1Constants::size::kMaxNthreads][L1Constants::size::kMaxNthreads] {{0}};
  fvec Err[L1Constants::size::kMaxNthreads][L1Constants::size::kMaxNthreads] {{0}};


  /// standard sizes of the arrays
  enum
  {
    multiCoeff = 1,  // central - 1, mbias


    coeff = 64 / 4,

    Portion = 1024 / coeff,  // portion of left hits

    MaxPortionDoublets = 10000 / 5 * 64 / 2 / coeff /*/ multiCoeff*/ * 1,
    MaxPortionTriplets = 10000 * 5 * 64 / 2 / coeff /*/ multiCoeff*/ * 1,
    MaxNPortion        = 40 * coeff / multiCoeff,


    MaxArrSize = MaxNPortion * MaxPortionDoublets / L1Constants::size::kMaxNstations
    //200000,  // standart size of big arrays  // mas be 40000 for normal work in cbmroot!
  };


  /// --- data used during finding iterations
  int isec {0};                                       // iteration TODO: to be dispatched (S.Zharko, 21.06.2022)
  const L1CAIteration* fpCurrentIteration {nullptr};  ///< pointer to the current CA track finder iteration

  L1Vector<L1Hit>* vHitsUnused {nullptr};
  L1Vector<L1HitIndex_t>* RealIHitP {nullptr};
  L1Vector<L1HitIndex_t>* RealIHitPBuf {nullptr};
  L1Vector<L1HitPoint>* vHitPointsUnused {nullptr};
  L1HitIndex_t* RealIHit {nullptr};  // index in vHits indexed by index in vHitsUnused

  L1HitIndex_t HitsUnusedStartIndex[L1Constants::size::kMaxNstations + 1] {0};
  L1HitIndex_t HitsUnusedStopIndex[L1Constants::size::kMaxNstations + 1] {0};
  L1HitIndex_t HitsUnusedStartIndexEnd[L1Constants::size::kMaxNstations + 1] {0};
  L1HitIndex_t HitsUnusedStopIndexEnd[L1Constants::size::kMaxNstations + 1] {0};


  L1Vector<int> fHitFirstTriplet {"L1Algo::fHitFirstTriplet"};  /// link hit -> first triplet { hit, *, *}
  L1Vector<int> fHitNtriplets {"L1Algo::fHitNtriplets"};        /// link hit ->n triplets { hit, *, *}


  //  fvec u_front[Portion/fvecLen], u_back[Portion/fvecLen];
  //  fvec zPos[Portion/fvecLen];
  //  fvec fHitTime[Portion/fvecLen];

  nsL1::vector<L1TrackPar>::TSimd fT_3[L1Constants::size::kMaxNthreads];

  L1Vector<L1HitIndex_t> fhitsl_3[L1Constants::size::kMaxNthreads] {"L1Algo::fhitsl_3"};
  L1Vector<L1HitIndex_t> fhitsm_3[L1Constants::size::kMaxNthreads] {"L1Algo::fhitsm_3"};
  L1Vector<L1HitIndex_t> fhitsr_3[L1Constants::size::kMaxNthreads] {"L1Algo::fhitsr_3"};

  nsL1::vector<fvec>::TSimd fu_front3[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd fu_back3[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd fz_pos3[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd fTimeR[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd fTimeER[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd dx[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd dy[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd du[L1Constants::size::kMaxNthreads];
  nsL1::vector<fvec>::TSimd dv[L1Constants::size::kMaxNthreads];


  //   Tindex NHits_l[L1Constants::size::kMaxNstations];
  //   Tindex NHits_l_P[L1Constants::size::kMaxNstations];
  /// ----- Output data -----

  friend class CbmL1;

  /// ----- Hit-point-strips conversion routines ------

  void GetHitCoor(const L1Hit& _h, fscal& _x, fscal& _y, fscal& _z, const L1Station& sta);

  void dUdV_to_dY(const fvec& u, const fvec& v, fvec& _y, const L1Station& sta);

  void dUdV_to_dX(const fvec& u, const fvec& v, fvec& _x, const L1Station& sta);

  void dUdV_to_dXdY(const fvec& u, const fvec& v, fvec& _xy, const L1Station& sta);

  void GetHitCoor(const L1Hit& _h, fscal& _x, fscal& _y, char iS);
  void StripsToCoor(const fscal& u, const fscal& v, fscal& x, fscal& y,
                    const L1Station& sta) const;  // convert strip positions to coordinates
  void StripsToCoor(const fscal& u, const fscal& v, fvec& x, fvec& y,
                    const L1Station& sta) const;  // convert strip positions to coordinates
  void StripsToCoor(const fvec& u, const fvec& v, fvec& x, fvec& y, const L1Station& sta) const;
  L1HitPoint CreateHitPoint(const L1Hit& hit);  // full the hit point by hit information.

  void CreateHitPoint(const L1Hit& hit, L1HitPoint& point);
  inline int PackIndex(const int& a, const int& b, const int& c);

  inline int UnPackIndex(const int& i, int& a, int& b, int& c);
  /// -- Flags routines --
  inline __attribute__((always_inline)) static unsigned char GetFStation(unsigned char flag) { return flag / 4; }
  inline __attribute__((always_inline)) static bool GetFUsed(unsigned char flag) { return (flag & 0x02) != 0; }
  //   bool GetFUsedD  ( unsigned char flag ){ return (flag&0x01)!=0; }


  /// Sets L1Algo parameters object
  /// \param other - reference to the L1Parameters object
  void SetParameters(const L1Parameters& other) { fParameters = other; }
  // TODO: remove it (S.Zharko)

  /// Gets a pointer to the L1Algo parameters object
  const L1Parameters* GetParameters() { return &fParameters; }

  /// Gets a pointer to the L1Algo initialization object
  L1InitManager* GetInitManager() { return &fInitManager; }

private:
  L1Parameters fParameters {};    ///< Object of L1Algo parameters class
  L1InitManager fInitManager {};  ///< Object of L1Algo initialization manager class


  /*********************************************************************************************/ /**
   *                             ------  FUNCTIONAL PART ------
   ************************************************************************************************/

  /// ----- Subroutines used by L1Algo::CATrackFinder() ------

  void CAFindTrack(int ista, L1Branch& best_tr, unsigned char& best_L, fscal& best_chi2, const L1Triplet* curr_trip,
                   L1Branch& curr_tr, unsigned char& curr_L, fscal& curr_chi2, unsigned char min_best_l,
                   L1Branch* new_tr);


  /// Fits track
  /// \param t - track with hits
  /// \param T - track parameters
  /// \param dir - false - forward, true - backward
  /// \param qp0 - momentum for extrapolation
  /// \param initParams - should be params ititialized. 1 - yes.
  void BranchFitterFast(const L1Branch& t, L1TrackPar& T, const bool dir, const fvec qp0 = 0.,
                        const bool initParams = true);

  /// Fits track. more precise than FitterFast
  /// \param t - track with hits
  /// \param T - track parameters
  /// \param dir - false - forward, true - backward
  /// \param qp0 - momentum for extrapolation
  /// \param initParams - should be params ititialized. 1 - yes.
  void BranchFitter(const L1Branch& t, L1TrackPar& T, const bool dir, const fvec qp0 = 0.,
                    const bool initParams = true);

  /// Finds additional hits for already found track
  /// \param t - track with hits
  /// \param T - track params
  /// \param dir - 0 - forward, 1 - backward
  /// \param qp0 - momentum for extrapolation
  void FindMoreHits(L1Branch& t, L1TrackPar& T, const bool dir, const fvec qp0 = 0.0);

  /// Find additional hits for existing track
  /// \return chi2
  fscal BranchExtender(L1Branch& t);

  /// ----- Subroutines used by L1Algo::CAMergeClones() ------
  void InvertCholetsky(fvec a[15]);
  void MultiplySS(fvec const C[15], fvec const V[15], fvec K[5][5]);
  void MultiplyMS(fvec const C[5][5], fvec const V[15], fvec K[15]);
  void MultiplySR(fvec const C[15], fvec const r_in[5], fvec r_out[5]);
  void FilterTracks(fvec const r[5], fvec const C[15], fvec const m[5], fvec const V[15], fvec R[5], fvec W[15],
                    fvec* chi2);
  ///
  void CAMergeClones();


  inline __attribute__((always_inline)) void PackLocation(unsigned int& location, unsigned int& triplet,
                                                          unsigned int iStation, unsigned int& thread)
  {
    location = (triplet << 11) | (thread << 3) | iStation;
  }

  inline __attribute__((always_inline)) void UnPackStation(unsigned int& location, unsigned int& iStation)
  {
    iStation = location & 0x7;
  }

  inline __attribute__((always_inline)) void UnPackThread(unsigned int& location, unsigned int& thread)
  {
    thread = (location >> 3) & 0xFF;
  }

  inline __attribute__((always_inline)) void UnPackTriplet(unsigned int& location, unsigned int& triplet)
  {
    triplet = (location >> 11);
  }

  inline __attribute__((always_inline)) void SetFStation(unsigned char& flag, unsigned int iStation)
  {
    flag = iStation * 4 + (flag % 4);
  }
  inline __attribute__((always_inline)) void SetFUsed(unsigned char& flag) { flag |= 0x02; }
  //   void SetFUsedD   ( unsigned char &flag ){ flag |= 0x01; }
  inline __attribute__((always_inline)) void SetFUnUsed(unsigned char& flag) { flag &= 0xFC; }
  //   void SetFUnUsedD ( unsigned char &flag ){ flag &= 0xFE; }

  /// Prepare the portion of left hits data
  void findSingletsStep0(  // input
    Tindex start_lh, Tindex n1_l, L1HitPoint* Hits_l,
    // output
    fvec* u_front_l, fvec* u_back_l, fvec* zPos_l, L1HitIndex_t* hitsl, fvec* HitTime_l, fvec* HitTimeEr, fvec* Event_l,
    fvec* d_u, fvec* d_v);

  /// Get the field approximation. Add the target to parameters estimation. Propagate to middle station.
  void findSingletsStep1(  // input
    int istal, int istam, Tindex n1_V,

    fvec* u_front_l, fvec* u_back_l, fvec* zPos_l, fvec* HitTime_l, fvec* HitTimeEr,
    // output
    L1TrackPar* T_1, L1FieldRegion* fld_1, fvec* d_u, fvec* d_v);

  /// Find the doublets. Reformat data in the portion of doublets.
  void findDoubletsStep0(  // input
    Tindex n1, const L1Station& stal, const L1Station& stam, L1HitPoint* vHits_m, L1TrackPar* T_1,
    L1HitIndex_t* hitsl_1,

    // output
    Tindex& n2, L1Vector<L1HitIndex_t>& i1_2,

#ifdef DOUB_PERFORMANCE
    L1Vector<L1HitIndex_t>& hitsl_2,
#endif  // DOUB_PERFORMANCE
    L1Vector<L1HitIndex_t>& hitsm_2, fvec* Event, L1Vector<char>& lmDuplets);

  /// Add the middle hits to parameters estimation. Propagate to right station.
  /// Find the triplets (right hit). Reformat data in the portion of triplets.
  void findTripletsStep0(  // input
    L1HitPoint* vHits_r, const L1Station& stam, const L1Station& star,

    int istam, int istar, L1HitPoint* vHits_m, L1TrackPar* T_1, L1FieldRegion* fld_1, L1HitIndex_t* hitsl_1,

    Tindex n2, L1Vector<L1HitIndex_t>& hitsm_2, L1Vector<L1HitIndex_t>& i1_2,

    const L1Vector<char>& mrDuplets,
    // output
    Tindex& n3, nsL1::vector<L1TrackPar>::TSimd& T_3, L1Vector<L1HitIndex_t>& hitsl_3, L1Vector<L1HitIndex_t>& hitsm_3,
    L1Vector<L1HitIndex_t>& hitsr_3, nsL1::vector<fvec>::TSimd& u_front_3, nsL1::vector<fvec>::TSimd& u_back_3,
    nsL1::vector<fvec>::TSimd& z_Pos_3,
    //    nsL1::vector<fvec>::TSimd& dx_,
    //    nsL1::vector<fvec>::TSimd& dy_,
    nsL1::vector<fvec>::TSimd& du_, nsL1::vector<fvec>::TSimd& dv_, nsL1::vector<fvec>::TSimd& timeR,
    nsL1::vector<fvec>::TSimd& timeER);

  /// Add the right hits to parameters estimation.
  void findTripletsStep1(  // input
    Tindex n3_V, const L1Station& star, nsL1::vector<fvec>::TSimd& u_front_3, nsL1::vector<fvec>::TSimd& u_back_3,
    nsL1::vector<fvec>::TSimd& z_Pos_3,
    //    nsL1::vector<fvec>::TSimd& dx_,
    //    nsL1::vector<fvec>::TSimd& dy_,
    nsL1::vector<fvec>::TSimd& du_, nsL1::vector<fvec>::TSimd& dv_, nsL1::vector<fvec>::TSimd& timeR,
    nsL1::vector<fvec>::TSimd& timeER,
    // output
    nsL1::vector<L1TrackPar>::TSimd& T_3);

  /// Refit Triplets.
  void findTripletsStep2(  // input
    Tindex n3, int istal, nsL1::vector<L1TrackPar>::TSimd& T_3, L1Vector<L1HitIndex_t>& hitsl_3,
    L1Vector<L1HitIndex_t>& hitsm_3, L1Vector<L1HitIndex_t>& hitsr_3, int nIterations = 0);

  /// Select triplets. Save them into vTriplets.
  void findTripletsStep3(  // input
    Tindex n3, int istal, int istam, int istar, nsL1::vector<L1TrackPar>::TSimd& T_3, L1Vector<L1HitIndex_t>& hitsl_3,
    L1Vector<L1HitIndex_t>& hitsm_3, L1Vector<L1HitIndex_t>& hitsr_3,
    // output
    Tindex& nstaltriplets);


  /// Find neighbours of triplets. Calculate level of triplets.
  void f5(  // input
    // output
    int* nlevel);


  /// Find doublets on station
  void DupletsStaPort(  // input
    int istal, int istam, Tindex ip, L1Vector<Tindex>& n_g, Tindex* portionStopIndex_,

    // output
    L1TrackPar* T_1, L1FieldRegion* fld_1, L1HitIndex_t* hitsl_1,

    L1Vector<char>& lmDuplets,


    Tindex& n_2, L1Vector<L1HitIndex_t>& i1_2, L1Vector<L1HitIndex_t>& hitsm_2);

  /// Find triplets on station
  void TripletsStaPort(  // input
    int istal, int istam, int istar, Tindex& nstaltriplets, L1TrackPar* T_1, L1FieldRegion* fld_1,
    L1HitIndex_t* hitsl_1,

    Tindex& n_2, L1Vector<L1HitIndex_t>& i1_2, L1Vector<L1HitIndex_t>& hitsm_2,

    const L1Vector<char>& mrDuplets

    // output


  );


  ///  ------ Subroutines used by L1Algo::KFTrackFitter()  ------

  void GuessVec(L1TrackPar& t, fvec* xV, fvec* yV, fvec* zV, fvec* Sy, fvec* wV, int NHits, fvec* zCur = 0);
  void GuessVec(L1TrackParFit& t, fvec* xV, fvec* yV, fvec* zV, fvec* Sy, fvec* wV, int NHits, fvec* zCur = 0,
                fvec* timeV = 0, fvec* w_time = 0);

  void FilterFirst(L1TrackPar& track, fvec& x, fvec& y, L1Station& st);
  void FilterFirst(L1TrackParFit& track, fvec& x, fvec& y, fvec& t, L1Station& st);
  void FilterFirst(L1TrackParFit& track, fvec& x, fvec& y, fvec& t, fvec& t_er, L1Station& st);

  void FilterFirst(L1TrackParFit& track, fvec& x, fvec& y, fvec& t, fvec& t_er, L1Station& st, fvec& dx, fvec& dy,
                   fvec& dxy);
  void FilterFirstL(L1TrackParFit& track, fvec& x, fvec& y, fvec& t, fvec& t_er, L1Station& st, fvec& dx, fvec& dy,
                    fvec& dxy);

#ifdef TBB
  enum
  {
    nthreads = 3,  // number of threads
    nblocks  = 1   // number of stations on one thread
  };

  friend class ParalleledDup;
  friend class ParalleledTrip;
#endif  // TBB
#ifdef TBB2
public:
  Tindex thrId;
#endif  // TBB2
private:
  /// =================================  DATA PART  =================================

  /// ----- Different parameters of CATrackFinder -----

  Tindex fFirstCAstation {0};  //first station used in CA

  // fNFindIterations - set number of interation for trackfinding
  // itetation of finding:
#ifdef FIND_GAPED_TRACKS
  enum
  {
    kFastPrimIter,     // primary fast tracks
    kAllPrimIter,      // primary all tracks
    kAllPrimJumpIter,  // primary tracks with jumped triplets
    kAllSecIter,       // secondary all tracks
    kAllPrimEIter,     // primary all electron tracks
    kAllSecEIter,      // secondary all electron tracks

    kFastPrimJumpIter,  // primary fast tracks with jumped triplets
    kFastPrimIter2,
    kAllSecJumpIter  // secondary tracks with jumped triplets
  };

#ifdef TRACKS_FROM_TRIPLETS
  int fNFindIterations = TRACKS_FROM_TRIPLETS_ITERATION + 1;  // TODO investigate kAllPrimJumpIter & kAllSecJumpIter
#else  // not TRACKS_FROM_TRIPLETS
  int fNFindIterations = -1;  // TODO investigate kAllPrimJumpIter & kAllSecJumpIter
#endif  // TRACKS_FROM_TRIPLETS

#else  // not FIND_GAPED_TRACKS
  enum
  {
    kFastPrimIter = 0,  // primary fast tracks
    kAllPrimIter,       // primary all tracks
    kAllSecIter,        // secondary all tracks
    kFastPrimJumpIter,  // disabled
    kAllPrimJumpIter,   // disabled
    kFastPrimIter2,
    kAllSecJumpIter,
    kAllPrimEIter,
    kAllSecEIter
  };
#endif  // FIND_GAPED_TRACKS

  map<int, int> threadNumberToCpuMap {};

  float fTrackChi2Cut {10.f};
  float fTripletChi2Cut {5.f};  // cut for selecting triplets before collecting tracks.per one DoF
  float fDoubletChi2Cut {5.f};
  float fTimeCut1 {0.f};  // TODO: please, specify "1" and "2" (S.Zharko)
  float fTimeCut2 {0.f};

  /// correction in order to take into account overlaping and iff z. if sort by y then it is max diff between same station's modules (~0.4cm)
  fvec fMaxDZ {L1Utils::kNaN};

  /// parameters which are different for different iterations. Set in the begin of CAL1TrackFinder

  float fPickGather {L1Utils::kNaN};     ///< same for attaching additional hits to track
  float fPickNeighbour {L1Utils::kNaN};  ///< (fPickNeighbour < dp/dp_error)  =>  triplets are neighbours
  fvec fMaxInvMom {L1Utils::kNaN};       ///< max considered q/p for tracks
  fvec fMaxSlopePV {L1Utils::kNaN};      ///< max slope (tx\ty) in prim vertex
  float fMaxSlope {L1Utils::kNaN};       ///< max slope (tx\ty) in 3d hit position of a triplet

  fvec fTargX {L1Utils::kNaN};  ///< target position x coordinate for the current iteration (modifiable)
  fvec fTargY {L1Utils::kNaN};  ///< target position y coordinate for the current iteration (modifiable)
  fvec fTargZ {L1Utils::kNaN};  ///< target position z coordinate for the current iteration (modifiable)

  L1FieldValue fTargB _fvecalignment {};               // field in the target point (modifiable, do not touch!!)
  L1XYMeasurementInfo TargetXYInfo _fvecalignment {};  // target constraint  [cm]


  //  int TripNumThread;

  int fTrackingLevel {2};       // currently not used
  int fGhostSuppression {1};    // currently not used
  float fMomentumCutOff {0.2};  // currently not used

  /// ----- Debug features -----
#ifdef PULLS
  L1AlgoPulls* fL1Pulls;
#endif
#ifdef TRIP_PERFORMANCE
  L1AlgoEfficiencyPerformance<3>* fL1Eff_triplets;
  L1AlgoEfficiencyPerformance<3>* fL1Eff_triplets2;
#endif
#ifdef DOUB_PERFORMANCE
  L1AlgoEfficiencyPerformance<2>* fL1Eff_doublets;
#endif
#ifdef DRAW
  friend class L1AlgoDraw;
#endif
} _fvecalignment;

#endif