Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:28:17

0001 #ifndef RecoTracker_MkFitCore_interface_TrackStructures_h
0002 #define RecoTracker_MkFitCore_interface_TrackStructures_h
0003 
0004 #include "RecoTracker/MkFitCore/interface/Config.h"
0005 #include "RecoTracker/MkFitCore/interface/Hit.h"
0006 #include "RecoTracker/MkFitCore/interface/Track.h"
0007 #include "RecoTracker/MkFitCore/interface/TrackerInfo.h"
0008 
0009 #include <algorithm>
0010 #include <array>
0011 
0012 namespace mkfit {
0013 
0014   class IterationParams;
0015 
0016   //==============================================================================
0017   // TrackCand, CombinedCandidate and EventOfCombinedCandidates
0018   //==============================================================================
0019 
0020   struct HoTNode {
0021     HitOnTrack m_hot;
0022     float m_chi2;
0023     int m_prev_idx;
0024   };
0025 
0026   struct HitMatch {
0027     int m_hit_idx = -1;
0028     int m_module_id = -1;
0029     float m_chi2 = 1e9;
0030 
0031     void reset() {
0032       m_hit_idx = -1;
0033       m_module_id = -1;
0034       m_chi2 = 1e9;
0035     }
0036   };
0037 
0038   struct HitMatchPair {
0039     HitMatch M[2];
0040 
0041     void reset() {
0042       M[0].reset();
0043       M[1].reset();
0044     }
0045 
0046     void consider_hit_for_overlap(int hit_idx, int module_id, float chi2) {
0047       if (module_id == M[0].m_module_id) {
0048         if (chi2 < M[0].m_chi2) {
0049           M[0].m_chi2 = chi2;
0050           M[0].m_hit_idx = hit_idx;
0051         }
0052       } else if (module_id == M[1].m_module_id) {
0053         if (chi2 < M[1].m_chi2) {
0054           M[1].m_chi2 = chi2;
0055           M[1].m_hit_idx = hit_idx;
0056         }
0057       } else {
0058         if (M[0].m_chi2 > M[1].m_chi2) {
0059           if (chi2 < M[0].m_chi2) {
0060             M[0] = {hit_idx, module_id, chi2};
0061           }
0062         } else {
0063           if (chi2 < M[1].m_chi2) {
0064             M[1] = {hit_idx, module_id, chi2};
0065           }
0066         }
0067       }
0068     }
0069 
0070     HitMatch* find_overlap(int hit_idx, int module_id) {
0071       if (module_id == M[0].m_module_id) {
0072         if (M[1].m_hit_idx >= 0)
0073           return &M[1];
0074       } else if (module_id == M[1].m_module_id) {
0075         if (M[0].m_hit_idx >= 0)
0076           return &M[0];
0077       } else {
0078         if (M[0].m_chi2 <= M[1].m_chi2) {
0079           if (M[0].m_hit_idx >= 0)
0080             return &M[0];
0081         } else {
0082           if (M[1].m_hit_idx >= 0)
0083             return &M[1];
0084         }
0085       }
0086 
0087       return nullptr;
0088     }
0089   };
0090 
0091   // CcPool - CombCandidate Pool and Allocator
0092 
0093   template <class T>
0094   class CcPool {
0095   public:
0096     void reset(std::size_t size) {
0097       if (size > m_mem.size())
0098         m_mem.resize(size);
0099       m_pos = 0;
0100       m_size = size;
0101     }
0102 
0103     void release() {
0104       std::vector<T> tmp;
0105       m_mem.swap(tmp);
0106       m_pos = 0;
0107       m_size = 0;
0108     }
0109 
0110     CcPool(std::size_t size = 0) {
0111       if (size)
0112         reset(size);
0113     }
0114 
0115     T* allocate(std::size_t n) {
0116       if (m_pos + n > m_size)
0117         throw std::bad_alloc();
0118       T* ret = &m_mem[m_pos];
0119       m_pos += n;
0120       return ret;
0121     }
0122 
0123     void deallocate(T* p, std::size_t n) noexcept {
0124       // we do not care, implied deallocation of the whole pool on reset().
0125     }
0126 
0127   private:
0128     std::vector<T> m_mem;
0129     std::size_t m_pos = 0;
0130     std::size_t m_size = 0;
0131   };
0132 
0133   template <class T>
0134   class CcAlloc {
0135   public:
0136     typedef T value_type;
0137 
0138     CcAlloc(CcPool<T>* p) : m_pool(p) {}
0139 
0140     const void* pool_id() const { return m_pool; }
0141 
0142     T* allocate(std::size_t n) { return m_pool->allocate(n); }
0143 
0144     void deallocate(T* p, std::size_t n) noexcept { m_pool->deallocate(p, n); }
0145 
0146   private:
0147     CcPool<T>* m_pool;
0148   };
0149 
0150   template <class T, class U>
0151   bool operator==(const CcAlloc<T>& a, const CcAlloc<U>& b) {
0152     return a.pool_id() == b.pool_id();
0153   }
0154 
0155   //------------------------------------------------------------------------------
0156 
0157   class CombCandidate;
0158 
0159   class TrackCand : public TrackBase {
0160   public:
0161     TrackCand() = default;
0162 
0163     explicit TrackCand(const TrackBase& base, CombCandidate* ccand) : TrackBase(base), m_comb_candidate(ccand) {
0164       // Reset hit counters -- caller has to initialize hits.
0165       lastHitIdx_ = -1;
0166       nFoundHits_ = 0;
0167     }
0168 
0169     // CombCandidate is used as a hit-container for a set of TrackCands originating from
0170     // the same seed and track building functions need this access to be able to add hits
0171     // into this holder class.
0172     // Access is guaranteed to be thread safe as seed ranges pointing into CombCandidate
0173     // vector is assigned to threads doing track-finding and final processing is only done
0174     // when all worker threads have finished.
0175     CombCandidate* combCandidate() const { return m_comb_candidate; }
0176     void setCombCandidate(CombCandidate* cc) { m_comb_candidate = cc; }
0177 
0178     int lastCcIndex() const { return lastHitIdx_; }
0179     int nFoundHits() const { return nFoundHits_; }
0180     int nMissingHits() const { return nMissingHits_; }
0181     int nOverlapHits() const { return nOverlapHits_; }
0182     int nTotalHits() const { return nFoundHits_ + nMissingHits_; }
0183 
0184     void setLastCcIndex(int i) { lastHitIdx_ = i; }
0185     void setNFoundHits(int n) { nFoundHits_ = n; }
0186     void setNMissingHits(int n) { nMissingHits_ = n; }
0187     void setNOverlapHits(int n) { nOverlapHits_ = n; }
0188 
0189     int nInsideMinusOneHits() const { return nInsideMinusOneHits_; }
0190     int nTailMinusOneHits() const { return nTailMinusOneHits_; }
0191 
0192     void setNInsideMinusOneHits(int n) { nInsideMinusOneHits_ = n; }
0193     void setNTailMinusOneHits(int n) { nTailMinusOneHits_ = n; }
0194 
0195     int originIndex() const { return m_origin_index; }
0196     void setOriginIndex(int oi) { m_origin_index = oi; }
0197 
0198     void resetOverlaps() { m_overlap_hits.reset(); }
0199     void considerHitForOverlap(int hit_idx, int module_id, float chi2) {
0200       m_overlap_hits.consider_hit_for_overlap(hit_idx, module_id, chi2);
0201     }
0202     HitMatch* findOverlap(int hit_idx, int module_id) { return m_overlap_hits.find_overlap(hit_idx, module_id); }
0203 
0204     // Inlines after definition of CombCandidate
0205 
0206     HitOnTrack getLastHitOnTrack() const;
0207     int getLastHitIdx() const;
0208     int getLastHitLyr() const;
0209 
0210     // For additional filter
0211     int getLastFoundPixelHitLyr() const;
0212     int getLastFoundHitLyr() const;
0213     int nUniqueLayers() const;
0214 
0215     int nLayersByTypeEncoded(const TrackerInfo& trk_inf) const;
0216     int nHitsByTypeEncoded(const TrackerInfo& trk_inf) const;
0217 
0218     int nPixelDecoded(const int& encoded) const { return encoded % 100; }
0219     int nStereoDecoded(const int& encoded) const { return (encoded / 100) % 100; }
0220     int nMonoDecoded(const int& encoded) const { return (encoded / 10000) % 100; }
0221     int nMatchedDecoded(const int& encoded) const { return encoded / 1000000; }
0222     int nTotMatchDecoded(const int& encoded) const {
0223       return encoded % 100 + (encoded / 100) % 100 + (encoded / 10000) % 100 - encoded / 1000000;
0224     }
0225 
0226     void addHitIdx(int hitIdx, int hitLyr, float chi2);
0227     bool popOverlap();
0228 
0229     HoTNode& refLastHoTNode();              // for filling up overlap info
0230     const HoTNode& refLastHoTNode() const;  // for dump traversal
0231 
0232     void incOverlapCount() { ++nOverlapHits_; }
0233 
0234     Track exportTrack(bool remove_missing_hits = false) const;
0235 
0236     void resetShortTrack() {
0237       score_ = getScoreWorstPossible();
0238       m_comb_candidate = nullptr;
0239     }
0240 
0241   private:
0242     CombCandidate* m_comb_candidate = nullptr;
0243     HitMatchPair m_overlap_hits;
0244 
0245     // using TrackBase::lastHitIdx_ to point into hit-on-track-node vector of CombCandidate
0246     short int nMissingHits_ = 0;
0247     short int nOverlapHits_ = 0;
0248 
0249     short int nInsideMinusOneHits_ = 0;
0250     short int nTailMinusOneHits_ = 0;
0251 
0252     short int m_origin_index = -1;  // index of origin candidate (used for overlaps in Standard)
0253   };
0254 
0255   inline bool sortByScoreTrackCand(const TrackCand& cand1, const TrackCand& cand2) {
0256     return cand1.score() > cand2.score();
0257   }
0258 
0259   inline float getScoreCand(const track_score_func& score_func,
0260                             const TrackCand& cand1,
0261                             bool penalizeTailMissHits = false,
0262                             bool inFindCandidates = false) {
0263     int nfoundhits = cand1.nFoundHits();
0264     int noverlaphits = cand1.nOverlapHits();
0265     int nmisshits = cand1.nInsideMinusOneHits();
0266     int ntailmisshits = penalizeTailMissHits ? cand1.nTailMinusOneHits() : 0;
0267     float pt = cand1.pT();
0268     float chi2 = cand1.chi2();
0269     // Do not allow for chi2<0 in score calculation
0270     if (chi2 < 0)
0271       chi2 = 0.f;
0272     return score_func(nfoundhits, ntailmisshits, noverlaphits, nmisshits, chi2, pt, inFindCandidates);
0273   }
0274 
0275   // CombCandidate -- a set of candidates from a given seed.
0276 
0277   class CombCandidate {
0278   public:
0279     using trk_cand_vec_type = std::vector<TrackCand, CcAlloc<TrackCand>>;
0280     using allocator_type = CcAlloc<TrackCand>;
0281 
0282     enum SeedState_e { Dormant = 0, Finding, Finished };
0283 
0284     CombCandidate(const allocator_type& alloc) : m_trk_cands(alloc), m_state(Dormant), m_pickup_layer(-1) {}
0285 
0286     // Required by std::uninitialized_fill_n when declaring vector<CombCandidate> in EventOfCombCandidates
0287     CombCandidate(const CombCandidate& o)
0288         : m_trk_cands(o.m_trk_cands),
0289           m_state(o.m_state),
0290           m_pickup_layer(o.m_pickup_layer),
0291           m_lastHitIdx_before_bkwsearch(o.m_lastHitIdx_before_bkwsearch),
0292           m_nInsideMinusOneHits_before_bkwsearch(o.m_nInsideMinusOneHits_before_bkwsearch),
0293           m_nTailMinusOneHits_before_bkwsearch(o.m_nTailMinusOneHits_before_bkwsearch),
0294           m_seed_origin_index(o.m_seed_origin_index),
0295           m_hots_size(o.m_hots_size),
0296           m_hots(o.m_hots) {}
0297 
0298     // Required for std::swap().
0299     CombCandidate(CombCandidate&& o)
0300         : m_trk_cands(std::move(o.m_trk_cands)),
0301           m_best_short_cand(std::move(o.m_best_short_cand)),
0302           m_state(o.m_state),
0303           m_pickup_layer(o.m_pickup_layer),
0304           m_lastHitIdx_before_bkwsearch(o.m_lastHitIdx_before_bkwsearch),
0305           m_nInsideMinusOneHits_before_bkwsearch(o.m_nInsideMinusOneHits_before_bkwsearch),
0306           m_nTailMinusOneHits_before_bkwsearch(o.m_nTailMinusOneHits_before_bkwsearch),
0307           m_seed_origin_index(o.m_seed_origin_index),
0308           m_hots_size(o.m_hots_size),
0309           m_hots(std::move(o.m_hots)) {
0310       // This is not needed as we do EOCC::reset() after EOCCS::resize which
0311       // calls Reset here and all CombCands get cleared.
0312       // However, if at some point we start using this for other purposes this needs
0313       // to be called as well.
0314       // for (auto &tc : *this) tc.setCombCandidate(this);
0315     }
0316 
0317     // Required for std::swap when filtering EventOfCombinedCandidates::m_candidates.
0318     // We do not call clear() on vectors as this will be done via EoCCs reset.
0319     // Probably would be better (clearer) if there was a special function that does
0320     // the swap in here or in EoCCs.
0321     CombCandidate& operator=(CombCandidate&& o) {
0322       m_trk_cands = (std::move(o.m_trk_cands));
0323       m_best_short_cand = std::move(o.m_best_short_cand);
0324       m_state = o.m_state;
0325       m_pickup_layer = o.m_pickup_layer;
0326       m_lastHitIdx_before_bkwsearch = o.m_lastHitIdx_before_bkwsearch;
0327       m_nInsideMinusOneHits_before_bkwsearch = o.m_nInsideMinusOneHits_before_bkwsearch;
0328       m_nTailMinusOneHits_before_bkwsearch = o.m_nTailMinusOneHits_before_bkwsearch;
0329       m_seed_origin_index = o.m_seed_origin_index;
0330       m_hots_size = o.m_hots_size;
0331       m_hots = std::move(o.m_hots);
0332 
0333       for (auto& tc : m_trk_cands)
0334         tc.setCombCandidate(this);
0335 
0336       return *this;
0337     }
0338 
0339     // std::vector-like interface to access m_trk_cands
0340     bool empty() const { return m_trk_cands.empty(); }
0341     trk_cand_vec_type::size_type size() const { return m_trk_cands.size(); }
0342     void resize(trk_cand_vec_type::size_type count) { m_trk_cands.resize(count); }
0343     TrackCand& operator[](int i) { return m_trk_cands[i]; }
0344     const TrackCand& operator[](int i) const { return m_trk_cands[i]; }
0345     TrackCand& front() { return m_trk_cands.front(); }
0346     const TrackCand& front() const { return m_trk_cands.front(); }
0347     trk_cand_vec_type::reference emplace_back(TrackCand& tc) { return m_trk_cands.emplace_back(tc); }
0348     void clear() { m_trk_cands.clear(); }
0349 
0350     void reset(int max_cands_per_seed, int expected_num_hots) {
0351       std::vector<TrackCand, CcAlloc<TrackCand>> tmp(m_trk_cands.get_allocator());
0352       m_trk_cands.swap(tmp);
0353       m_trk_cands.reserve(max_cands_per_seed);  // we *must* never exceed this
0354 
0355       m_best_short_cand.setScore(getScoreWorstPossible());
0356 
0357       // state and pickup_layer set in importSeed.
0358 
0359       // expected_num_hots is different for CloneEngine and Std, especially as long as we
0360       // instantiate all candidates before purging them.
0361       // ce:  N_layer * N_cands ~~ 20 * 6 = 120
0362       // std: i don't know, maybe double?
0363       m_hots.reserve(expected_num_hots);
0364       m_hots_size = 0;
0365       m_hots.clear();
0366 
0367       m_lastHitIdx_before_bkwsearch = -1;
0368       m_nInsideMinusOneHits_before_bkwsearch = -1;
0369       m_nTailMinusOneHits_before_bkwsearch = -1;
0370     }
0371 
0372     void importSeed(const Track& seed, int seed_idx, const track_score_func& score_func, int region);
0373 
0374     int addHit(const HitOnTrack& hot, float chi2, int prev_idx) {
0375       m_hots.push_back({hot, chi2, prev_idx});
0376       return m_hots_size++;
0377     }
0378 
0379     void mergeCandsAndBestShortOne(const IterationParams& params,
0380                                    const track_score_func& score_func,
0381                                    bool update_score,
0382                                    bool sort_cands);
0383 
0384     void compactifyHitStorageForBestCand(bool remove_seed_hits, int backward_fit_min_hits);
0385     void beginBkwSearch();
0386     void repackCandPostBkwSearch(int i);
0387     // not needed for CombCand::endBkwSearch(), reinit performed in reset() for a new event.
0388 
0389     // Accessors
0390     //-----------
0391     int hotsSize() const { return m_hots_size; }
0392     const HoTNode& hot_node(int i) const { return m_hots[i]; }
0393     HoTNode& hot_node_nc(int i) { return m_hots[i]; }
0394     HitOnTrack hot(int i) const { return m_hots[i].m_hot; }
0395     // Direct access into array for vectorized code in MkFinder
0396     const HoTNode* hotsData() const { return m_hots.data(); }
0397 
0398     const TrackCand& refBestShortCand() const { return m_best_short_cand; }
0399     void setBestShortCand(const TrackCand& tc) { m_best_short_cand = tc; }
0400 
0401     SeedState_e state() const { return m_state; }
0402     void setState(SeedState_e ss) { m_state = ss; }
0403 
0404     int pickupLayer() const { return m_pickup_layer; }
0405 
0406     int seed_origin_index() const { return m_seed_origin_index; }
0407 
0408   private:
0409     trk_cand_vec_type m_trk_cands;
0410     TrackCand m_best_short_cand;
0411     SeedState_e m_state : 8;
0412     int m_pickup_layer : 16;
0413     short int m_lastHitIdx_before_bkwsearch = -1;
0414     short int m_nInsideMinusOneHits_before_bkwsearch = -1;
0415     short int m_nTailMinusOneHits_before_bkwsearch = -1;
0416     int m_seed_origin_index = -1;  // seed index in the passed-in seed vector
0417     int m_hots_size = 0;
0418     std::vector<HoTNode> m_hots;
0419   };
0420 
0421   //==============================================================================
0422 
0423   inline HitOnTrack TrackCand::getLastHitOnTrack() const { return m_comb_candidate->hot(lastHitIdx_); }
0424 
0425   inline int TrackCand::getLastHitIdx() const { return m_comb_candidate->hot(lastHitIdx_).index; }
0426 
0427   inline int TrackCand::getLastHitLyr() const { return m_comb_candidate->hot(lastHitIdx_).layer; }
0428 
0429   inline int TrackCand::getLastFoundHitLyr() const {
0430     int nh = nTotalHits();
0431     int ch = lastHitIdx_;
0432     int ll = -1;
0433     while (--nh >= 0) {
0434       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0435       if (hot_node.m_hot.index < 0) {
0436         ch = hot_node.m_prev_idx;
0437       } else {
0438         ll = hot_node.m_hot.layer;
0439         break;
0440       }
0441     }
0442     return ll;
0443   }
0444 
0445   inline int TrackCand::getLastFoundPixelHitLyr() const {
0446     int nh = nTotalHits();
0447     int ch = lastHitIdx_;
0448     int ll = -1;
0449     while (--nh >= 0) {
0450       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0451       int tl = hot_node.m_hot.layer;
0452       if (hot_node.m_hot.index < 0 || !((0 <= tl && tl <= 3) || (18 <= tl && tl <= 20) || (45 <= tl && tl <= 47))) {
0453         ch = hot_node.m_prev_idx;
0454       } else if ((0 <= tl && tl <= 3) || (18 <= tl && tl <= 20) || (45 <= tl && tl <= 47)) {
0455         ll = hot_node.m_hot.layer;
0456         break;
0457       }
0458     }
0459     return ll;
0460   }
0461 
0462   inline int TrackCand::nUniqueLayers() const {
0463     int nUL = 0;
0464     int prevL = -1;
0465     int nh = nTotalHits();
0466     int ch = lastHitIdx_;
0467 
0468     while (--nh >= 0) {
0469       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0470       int thisL = hot_node.m_hot.layer;
0471       if (thisL >= 0 && (hot_node.m_hot.index >= 0 || hot_node.m_hot.index == Hit::kHitCCCFilterIdx) &&
0472           thisL != prevL) {
0473         ++nUL;
0474         prevL = thisL;
0475       }
0476       ch = hot_node.m_prev_idx;
0477     }
0478     return nUL;
0479   }
0480 
0481   inline int TrackCand::nHitsByTypeEncoded(const TrackerInfo& trk_inf) const {
0482     int prevL = -1;
0483     bool prevStereo = false;
0484     int nh = nTotalHits();
0485     int ch = lastHitIdx_;
0486     int pix = 0, stereo = 0, mono = 0, matched = 0;
0487     int doubleStereo = -1;
0488     while (--nh >= 0) {
0489       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0490       int thisL = hot_node.m_hot.layer;
0491       if (thisL >= 0 && (hot_node.m_hot.index >= 0 || hot_node.m_hot.index == Hit::kHitCCCFilterIdx)) {
0492         bool cStereo = trk_inf[thisL].is_stereo();
0493         if (trk_inf[thisL].is_pixel())
0494           ++pix;
0495         else if (cStereo) {
0496           ++stereo;
0497           if (thisL == prevL)
0498             doubleStereo = thisL;
0499         } else {
0500           //mono if not pixel, nor stereo - can be matched to stereo
0501           ++mono;
0502           if (prevStereo && thisL == prevL - 1)
0503             ++matched;
0504           else if (thisL == prevL && thisL == doubleStereo - 1)
0505             ++matched;  //doubleMatch, the first is counted early on
0506         }
0507         prevL = thisL;
0508         prevStereo = cStereo;
0509       }
0510       ch = hot_node.m_prev_idx;
0511     }
0512     return pix + 100 * stereo + 10000 * mono + 1000000 * matched;
0513   }
0514 
0515   inline int TrackCand::nLayersByTypeEncoded(const TrackerInfo& trk_inf) const {
0516     int prevL = -1;
0517     bool prevStereo = false;
0518     int nh = nTotalHits();
0519     int ch = lastHitIdx_;
0520     int pix = 0, stereo = 0, mono = 0, matched = 0;
0521     while (--nh >= 0) {
0522       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0523       int thisL = hot_node.m_hot.layer;
0524       if (thisL >= 0 && (hot_node.m_hot.index >= 0 || hot_node.m_hot.index == Hit::kHitCCCFilterIdx) &&
0525           thisL != prevL) {
0526         bool cStereo = trk_inf[thisL].is_stereo();
0527         if (trk_inf[thisL].is_pixel())
0528           ++pix;
0529         else if (cStereo)
0530           ++stereo;
0531         else {
0532           //mono if not pixel, nor stereo - can be matched to stereo
0533           ++mono;
0534           if (prevStereo && thisL == prevL - 1)
0535             ++matched;
0536         }
0537         prevL = thisL;
0538         prevStereo = cStereo;
0539       }
0540       ch = hot_node.m_prev_idx;
0541     }
0542     return pix + 100 * stereo + 10000 * mono + 1000000 * matched;
0543   }
0544 
0545   inline HoTNode& TrackCand::refLastHoTNode() { return m_comb_candidate->hot_node_nc(lastHitIdx_); }
0546 
0547   inline const HoTNode& TrackCand::refLastHoTNode() const { return m_comb_candidate->hot_node(lastHitIdx_); }
0548 
0549   //------------------------------------------------------------------------------
0550 
0551   inline void TrackCand::addHitIdx(int hitIdx, int hitLyr, float chi2) {
0552     lastHitIdx_ = m_comb_candidate->addHit({hitIdx, hitLyr}, chi2, lastHitIdx_);
0553 
0554     if (hitIdx >= 0 || hitIdx == Hit::kHitCCCFilterIdx) {
0555       ++nFoundHits_;
0556       chi2_ += chi2;
0557       nInsideMinusOneHits_ += nTailMinusOneHits_;
0558       nTailMinusOneHits_ = 0;
0559     }
0560     //Note that for tracks passing through an inactive module (hitIdx = -7), we do not count the -7 hit against the track when scoring.
0561     else {
0562       ++nMissingHits_;
0563       if (hitIdx == Hit::kHitMissIdx)
0564         ++nTailMinusOneHits_;
0565     }
0566   }
0567 
0568   inline bool TrackCand::popOverlap() {
0569     auto popHitIdx = getLastHitIdx();
0570     auto popHitLyr = getLastHitLyr();
0571     auto popPrev = refLastHoTNode().m_prev_idx;
0572     auto popChi2 = refLastHoTNode().m_chi2;
0573     // sanity checks first, then just shift lastHitIdx_ to popPrev
0574     if (lastHitIdx_ == 0 || popHitIdx < 0)
0575       return false;
0576     auto prevHitLyr = m_comb_candidate->hot(popPrev).layer;
0577     auto prevHitIdx = m_comb_candidate->hot(popPrev).index;
0578     if (popHitLyr != prevHitLyr || prevHitIdx < 0)
0579       return false;
0580     lastHitIdx_ = popPrev;
0581 
0582     --nFoundHits_;
0583     chi2_ -= popChi2;
0584     --nOverlapHits_;
0585     return true;
0586   }
0587   //==============================================================================
0588 
0589   class EventOfCombCandidates {
0590   public:
0591     EventOfCombCandidates(int size = 0) : m_cc_pool(), m_candidates() {}
0592 
0593     void releaseMemory() {
0594       {  // Get all the destructors called before nuking CcPool.
0595         std::vector<CombCandidate> tmp;
0596         m_candidates.swap(tmp);
0597       }
0598       m_capacity = 0;
0599       m_size = 0;
0600       m_n_seeds_inserted = 0;
0601       m_cc_pool.release();
0602     }
0603 
0604     void reset(int new_capacity, int max_cands_per_seed, int expected_num_hots = 128) {
0605       m_cc_pool.reset(new_capacity * max_cands_per_seed);
0606       if (new_capacity > m_capacity) {
0607         CcAlloc<TrackCand> alloc(&m_cc_pool);
0608         std::vector<CombCandidate> tmp(new_capacity, alloc);
0609         m_candidates.swap(tmp);
0610         m_capacity = new_capacity;
0611       }
0612       for (int s = 0; s < new_capacity; ++s) {
0613         m_candidates[s].reset(max_cands_per_seed, expected_num_hots);
0614       }
0615       for (int s = new_capacity; s < m_capacity; ++s) {
0616         m_candidates[s].reset(0, 0);
0617       }
0618 
0619       m_size = new_capacity;
0620       m_n_seeds_inserted = 0;
0621     }
0622 
0623     void resizeAfterFiltering(int n_removed) {
0624       assert(n_removed <= m_size);
0625       m_size -= n_removed;
0626       m_n_seeds_inserted -= n_removed;
0627     }
0628 
0629     void insertSeed(const Track& seed, int seed_idx, const track_score_func& score_func, int region, int pos) {
0630       assert(pos < m_size);
0631 
0632       m_candidates[pos].importSeed(seed, seed_idx, score_func, region);
0633 
0634       ++m_n_seeds_inserted;
0635     }
0636 
0637     void compactifyHitStorageForBestCand(bool remove_seed_hits, int backward_fit_min_hits) {
0638       for (int i = 0; i < m_size; ++i)
0639         m_candidates[i].compactifyHitStorageForBestCand(remove_seed_hits, backward_fit_min_hits);
0640     }
0641 
0642     void beginBkwSearch() {
0643       for (int i = 0; i < m_size; ++i)
0644         m_candidates[i].beginBkwSearch();
0645       m_cands_in_backward_rep = true;
0646     }
0647     void endBkwSearch() {
0648       // There is no CombCand::endBkwSearch(), setup correctly in CombCand::reset().
0649       m_cands_in_backward_rep = false;
0650     }
0651 
0652     // Accessors
0653     int size() const { return m_size; }
0654 
0655     const CombCandidate& operator[](int i) const { return m_candidates[i]; }
0656     CombCandidate& operator[](int i) { return m_candidates[i]; }
0657     CombCandidate& cand(int i) { return m_candidates[i]; }
0658 
0659     bool cands_in_backward_rep() const { return m_cands_in_backward_rep; }
0660 
0661     // Direct access for vectorized functions in MkBuilder / MkFinder
0662     const std::vector<CombCandidate>& refCandidates() const { return m_candidates; }
0663     std::vector<CombCandidate>& refCandidates_nc() { return m_candidates; }
0664 
0665   private:
0666     CcPool<TrackCand> m_cc_pool;
0667 
0668     std::vector<CombCandidate> m_candidates;
0669 
0670     int m_capacity = 0;
0671     int m_size = 0;
0672     int m_n_seeds_inserted = 0;
0673     bool m_cands_in_backward_rep = false;
0674   };
0675 
0676 }  // namespace mkfit
0677 
0678 #endif