Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-01-23 02:42:44

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 
0228     HoTNode& refLastHoTNode();              // for filling up overlap info
0229     const HoTNode& refLastHoTNode() const;  // for dump traversal
0230 
0231     void incOverlapCount() { ++nOverlapHits_; }
0232 
0233     Track exportTrack(bool remove_missing_hits = false) const;
0234 
0235     void resetShortTrack() {
0236       score_ = getScoreWorstPossible();
0237       m_comb_candidate = nullptr;
0238     }
0239 
0240   private:
0241     CombCandidate* m_comb_candidate = nullptr;
0242     HitMatchPair m_overlap_hits;
0243 
0244     // using TrackBase::lastHitIdx_ to point into hit-on-track-node vector of CombCandidate
0245     short int nMissingHits_ = 0;
0246     short int nOverlapHits_ = 0;
0247 
0248     short int nInsideMinusOneHits_ = 0;
0249     short int nTailMinusOneHits_ = 0;
0250 
0251     short int m_origin_index = -1;  // index of origin candidate (used for overlaps in Standard)
0252   };
0253 
0254   inline bool sortByScoreTrackCand(const TrackCand& cand1, const TrackCand& cand2) {
0255     return cand1.score() > cand2.score();
0256   }
0257 
0258   inline float getScoreCand(const track_score_func& score_func,
0259                             const TrackCand& cand1,
0260                             bool penalizeTailMissHits = false,
0261                             bool inFindCandidates = false) {
0262     int nfoundhits = cand1.nFoundHits();
0263     int noverlaphits = cand1.nOverlapHits();
0264     int nmisshits = cand1.nInsideMinusOneHits();
0265     int ntailmisshits = penalizeTailMissHits ? cand1.nTailMinusOneHits() : 0;
0266     float pt = cand1.pT();
0267     float chi2 = cand1.chi2();
0268     // Do not allow for chi2<0 in score calculation
0269     if (chi2 < 0)
0270       chi2 = 0.f;
0271     return score_func(nfoundhits, ntailmisshits, noverlaphits, nmisshits, chi2, pt, inFindCandidates);
0272   }
0273 
0274   // CombCandidate -- a set of candidates from a given seed.
0275 
0276   class CombCandidate {
0277   public:
0278     using trk_cand_vec_type = std::vector<TrackCand, CcAlloc<TrackCand>>;
0279     using allocator_type = CcAlloc<TrackCand>;
0280 
0281     enum SeedState_e { Dormant = 0, Finding, Finished };
0282 
0283     CombCandidate(const allocator_type& alloc) : m_trk_cands(alloc), m_state(Dormant), m_pickup_layer(-1) {}
0284 
0285     // Required by std::uninitialized_fill_n when declaring vector<CombCandidate> in EventOfCombCandidates
0286     CombCandidate(const CombCandidate& o)
0287         : m_trk_cands(o.m_trk_cands),
0288           m_state(o.m_state),
0289           m_pickup_layer(o.m_pickup_layer),
0290           m_lastHitIdx_before_bkwsearch(o.m_lastHitIdx_before_bkwsearch),
0291           m_nInsideMinusOneHits_before_bkwsearch(o.m_nInsideMinusOneHits_before_bkwsearch),
0292           m_nTailMinusOneHits_before_bkwsearch(o.m_nTailMinusOneHits_before_bkwsearch),
0293 #ifdef DUMPHITWINDOW
0294           m_seed_algo(o.m_seed_algo),
0295           m_seed_label(o.m_seed_label),
0296 #endif
0297           m_hots_size(o.m_hots_size),
0298           m_hots(o.m_hots) {
0299     }
0300 
0301     // Required for std::swap().
0302     CombCandidate(CombCandidate&& o)
0303         : m_trk_cands(std::move(o.m_trk_cands)),
0304           m_best_short_cand(std::move(o.m_best_short_cand)),
0305           m_state(o.m_state),
0306           m_pickup_layer(o.m_pickup_layer),
0307           m_lastHitIdx_before_bkwsearch(o.m_lastHitIdx_before_bkwsearch),
0308           m_nInsideMinusOneHits_before_bkwsearch(o.m_nInsideMinusOneHits_before_bkwsearch),
0309           m_nTailMinusOneHits_before_bkwsearch(o.m_nTailMinusOneHits_before_bkwsearch),
0310 #ifdef DUMPHITWINDOW
0311           m_seed_algo(o.m_seed_algo),
0312           m_seed_label(o.m_seed_label),
0313 #endif
0314           m_hots_size(o.m_hots_size),
0315           m_hots(std::move(o.m_hots)) {
0316       // This is not needed as we do EOCC::reset() after EOCCS::resize which
0317       // calls Reset here and all CombCands get cleared.
0318       // However, if at some point we start using this for other purposes this needs
0319       // to be called as well.
0320       // for (auto &tc : *this) tc.setCombCandidate(this);
0321     }
0322 
0323     // Required for std::swap when filtering EventOfCombinedCandidates::m_candidates.
0324     // We do not call clear() on vectors as this will be done via EoCCs reset.
0325     // Probably would be better (clearer) if there was a special function that does
0326     // the swap in here or in EoCCs.
0327     CombCandidate& operator=(CombCandidate&& o) {
0328       m_trk_cands = (std::move(o.m_trk_cands));
0329       m_best_short_cand = std::move(o.m_best_short_cand);
0330       m_state = o.m_state;
0331       m_pickup_layer = o.m_pickup_layer;
0332       m_lastHitIdx_before_bkwsearch = o.m_lastHitIdx_before_bkwsearch;
0333       m_nInsideMinusOneHits_before_bkwsearch = o.m_nInsideMinusOneHits_before_bkwsearch;
0334       m_nTailMinusOneHits_before_bkwsearch = o.m_nTailMinusOneHits_before_bkwsearch;
0335 #ifdef DUMPHITWINDOW
0336       m_seed_algo = o.m_seed_algo;
0337       m_seed_label = o.m_seed_label;
0338 #endif
0339       m_hots_size = o.m_hots_size;
0340       m_hots = std::move(o.m_hots);
0341 
0342       for (auto& tc : m_trk_cands)
0343         tc.setCombCandidate(this);
0344 
0345       return *this;
0346     }
0347 
0348     // std::vector-like interface to access m_trk_cands
0349     bool empty() const { return m_trk_cands.empty(); }
0350     trk_cand_vec_type::size_type size() const { return m_trk_cands.size(); }
0351     void resize(trk_cand_vec_type::size_type count) { m_trk_cands.resize(count); }
0352     TrackCand& operator[](int i) { return m_trk_cands[i]; }
0353     const TrackCand& operator[](int i) const { return m_trk_cands[i]; }
0354     TrackCand& front() { return m_trk_cands.front(); }
0355     const TrackCand& front() const { return m_trk_cands.front(); }
0356     trk_cand_vec_type::reference emplace_back(TrackCand& tc) { return m_trk_cands.emplace_back(tc); }
0357     void clear() { m_trk_cands.clear(); }
0358 
0359     void reset(int max_cands_per_seed, int expected_num_hots) {
0360       std::vector<TrackCand, CcAlloc<TrackCand>> tmp(m_trk_cands.get_allocator());
0361       m_trk_cands.swap(tmp);
0362       m_trk_cands.reserve(max_cands_per_seed);  // we *must* never exceed this
0363 
0364       m_best_short_cand.setScore(getScoreWorstPossible());
0365 
0366       // state and pickup_layer set in importSeed.
0367 
0368       // expected_num_hots is different for CloneEngine and Std, especially as long as we
0369       // instantiate all candidates before purging them.
0370       // ce:  N_layer * N_cands ~~ 20 * 6 = 120
0371       // std: i don't know, maybe double?
0372       m_hots.reserve(expected_num_hots);
0373       m_hots_size = 0;
0374       m_hots.clear();
0375     }
0376 
0377     void importSeed(const Track& seed, const track_score_func& score_func, int region);
0378 
0379     int addHit(const HitOnTrack& hot, float chi2, int prev_idx) {
0380       m_hots.push_back({hot, chi2, prev_idx});
0381       return m_hots_size++;
0382     }
0383 
0384     void mergeCandsAndBestShortOne(const IterationParams& params,
0385                                    const track_score_func& score_func,
0386                                    bool update_score,
0387                                    bool sort_cands);
0388 
0389     void compactifyHitStorageForBestCand(bool remove_seed_hits, int backward_fit_min_hits);
0390     void beginBkwSearch();
0391     void endBkwSearch();
0392 
0393     // Accessors
0394     //-----------
0395     int hotsSize() const { return m_hots_size; }
0396     const HoTNode& hot_node(int i) const { return m_hots[i]; }
0397     HoTNode& hot_node_nc(int i) { return m_hots[i]; }
0398     HitOnTrack hot(int i) const { return m_hots[i].m_hot; }
0399     // Direct access into array for vectorized code in MkFinder
0400     const HoTNode* hotsData() const { return m_hots.data(); }
0401 
0402     const TrackCand& refBestShortCand() const { return m_best_short_cand; }
0403     void setBestShortCand(const TrackCand& tc) { m_best_short_cand = tc; }
0404 
0405     SeedState_e state() const { return m_state; }
0406     void setState(SeedState_e ss) { m_state = ss; }
0407 
0408     int pickupLayer() const { return m_pickup_layer; }
0409 
0410 #ifdef DUMPHITWINDOW
0411     int seed_algo() const { return m_seed_algo; }
0412     int seed_label() const { return m_seed_label; }
0413 #endif
0414 
0415   private:
0416     trk_cand_vec_type m_trk_cands;
0417     TrackCand m_best_short_cand;
0418     SeedState_e m_state : 8;
0419     int m_pickup_layer : 16;
0420     short int m_lastHitIdx_before_bkwsearch = -1;
0421     short int m_nInsideMinusOneHits_before_bkwsearch = -1;
0422     short int m_nTailMinusOneHits_before_bkwsearch = -1;
0423 
0424 #ifdef DUMPHITWINDOW
0425     int m_seed_algo = 0;
0426     int m_seed_label = 0;
0427 #endif
0428     int m_hots_size = 0;
0429     std::vector<HoTNode> m_hots;
0430   };
0431 
0432   //==============================================================================
0433 
0434   inline HitOnTrack TrackCand::getLastHitOnTrack() const { return m_comb_candidate->hot(lastHitIdx_); }
0435 
0436   inline int TrackCand::getLastHitIdx() const { return m_comb_candidate->hot(lastHitIdx_).index; }
0437 
0438   inline int TrackCand::getLastHitLyr() const { return m_comb_candidate->hot(lastHitIdx_).layer; }
0439 
0440   inline int TrackCand::getLastFoundHitLyr() const {
0441     int nh = nTotalHits();
0442     int ch = lastHitIdx_;
0443     int ll = -1;
0444     while (--nh >= 0) {
0445       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0446       if (hot_node.m_hot.index < 0) {
0447         ch = hot_node.m_prev_idx;
0448       } else {
0449         ll = hot_node.m_hot.layer;
0450         break;
0451       }
0452     }
0453     return ll;
0454   }
0455 
0456   inline int TrackCand::getLastFoundPixelHitLyr() const {
0457     int nh = nTotalHits();
0458     int ch = lastHitIdx_;
0459     int ll = -1;
0460     while (--nh >= 0) {
0461       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0462       int tl = hot_node.m_hot.layer;
0463       if (hot_node.m_hot.index < 0 || !((0 <= tl && tl <= 3) || (18 <= tl && tl <= 20) || (45 <= tl && tl <= 47))) {
0464         ch = hot_node.m_prev_idx;
0465       } else if ((0 <= tl && tl <= 3) || (18 <= tl && tl <= 20) || (45 <= tl && tl <= 47)) {
0466         ll = hot_node.m_hot.layer;
0467         break;
0468       }
0469     }
0470     return ll;
0471   }
0472 
0473   inline int TrackCand::nUniqueLayers() const {
0474     int nUL = 0;
0475     int prevL = -1;
0476     int nh = nTotalHits();
0477     int ch = lastHitIdx_;
0478 
0479     while (--nh >= 0) {
0480       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0481       int thisL = hot_node.m_hot.layer;
0482       if (thisL >= 0 && (hot_node.m_hot.index >= 0 || hot_node.m_hot.index == Hit::kHitCCCFilterIdx) &&
0483           thisL != prevL) {
0484         ++nUL;
0485         prevL = thisL;
0486       }
0487       ch = hot_node.m_prev_idx;
0488     }
0489     return nUL;
0490   }
0491 
0492   inline int TrackCand::nHitsByTypeEncoded(const TrackerInfo& trk_inf) const {
0493     int prevL = -1;
0494     bool prevStereo = false;
0495     int nh = nTotalHits();
0496     int ch = lastHitIdx_;
0497     int pix = 0, stereo = 0, mono = 0, matched = 0;
0498     int doubleStereo = -1;
0499     while (--nh >= 0) {
0500       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0501       int thisL = hot_node.m_hot.layer;
0502       if (thisL >= 0 && (hot_node.m_hot.index >= 0 || hot_node.m_hot.index == Hit::kHitCCCFilterIdx)) {
0503         bool cStereo = trk_inf[thisL].is_stereo();
0504         if (trk_inf[thisL].is_pixel())
0505           ++pix;
0506         else if (cStereo) {
0507           ++stereo;
0508           if (thisL == prevL)
0509             doubleStereo = thisL;
0510         } else {
0511           //mono if not pixel, nor stereo - can be matched to stereo
0512           ++mono;
0513           if (prevStereo && thisL == prevL - 1)
0514             ++matched;
0515           else if (thisL == prevL && thisL == doubleStereo - 1)
0516             ++matched;  //doubleMatch, the first is counted early on
0517         }
0518         prevL = thisL;
0519         prevStereo = cStereo;
0520       }
0521       ch = hot_node.m_prev_idx;
0522     }
0523     return pix + 100 * stereo + 10000 * mono + 1000000 * matched;
0524   }
0525 
0526   inline int TrackCand::nLayersByTypeEncoded(const TrackerInfo& trk_inf) const {
0527     int prevL = -1;
0528     bool prevStereo = false;
0529     int nh = nTotalHits();
0530     int ch = lastHitIdx_;
0531     int pix = 0, stereo = 0, mono = 0, matched = 0;
0532     while (--nh >= 0) {
0533       const HoTNode& hot_node = m_comb_candidate->hot_node(ch);
0534       int thisL = hot_node.m_hot.layer;
0535       if (thisL >= 0 && (hot_node.m_hot.index >= 0 || hot_node.m_hot.index == Hit::kHitCCCFilterIdx) &&
0536           thisL != prevL) {
0537         bool cStereo = trk_inf[thisL].is_stereo();
0538         if (trk_inf[thisL].is_pixel())
0539           ++pix;
0540         else if (cStereo)
0541           ++stereo;
0542         else {
0543           //mono if not pixel, nor stereo - can be matched to stereo
0544           ++mono;
0545           if (prevStereo && thisL == prevL - 1)
0546             ++matched;
0547         }
0548         prevL = thisL;
0549         prevStereo = cStereo;
0550       }
0551       ch = hot_node.m_prev_idx;
0552     }
0553     return pix + 100 * stereo + 10000 * mono + 1000000 * matched;
0554   }
0555 
0556   inline HoTNode& TrackCand::refLastHoTNode() { return m_comb_candidate->hot_node_nc(lastHitIdx_); }
0557 
0558   inline const HoTNode& TrackCand::refLastHoTNode() const { return m_comb_candidate->hot_node(lastHitIdx_); }
0559 
0560   //------------------------------------------------------------------------------
0561 
0562   inline void TrackCand::addHitIdx(int hitIdx, int hitLyr, float chi2) {
0563     lastHitIdx_ = m_comb_candidate->addHit({hitIdx, hitLyr}, chi2, lastHitIdx_);
0564 
0565     if (hitIdx >= 0 || hitIdx == Hit::kHitCCCFilterIdx) {
0566       ++nFoundHits_;
0567       chi2_ += chi2;
0568       nInsideMinusOneHits_ += nTailMinusOneHits_;
0569       nTailMinusOneHits_ = 0;
0570     }
0571     //Note that for tracks passing through an inactive module (hitIdx = -7), we do not count the -7 hit against the track when scoring.
0572     else {
0573       ++nMissingHits_;
0574       if (hitIdx == Hit::kHitMissIdx)
0575         ++nTailMinusOneHits_;
0576     }
0577   }
0578 
0579   //==============================================================================
0580 
0581   class EventOfCombCandidates {
0582   public:
0583     EventOfCombCandidates(int size = 0) : m_cc_pool(), m_candidates() {}
0584 
0585     void releaseMemory() {
0586       {  // Get all the destructors called before nuking CcPool.
0587         std::vector<CombCandidate> tmp;
0588         m_candidates.swap(tmp);
0589       }
0590       m_capacity = 0;
0591       m_size = 0;
0592       m_n_seeds_inserted = 0;
0593       m_cc_pool.release();
0594     }
0595 
0596     void reset(int new_capacity, int max_cands_per_seed, int expected_num_hots = 128) {
0597       m_cc_pool.reset(new_capacity * max_cands_per_seed);
0598       if (new_capacity > m_capacity) {
0599         CcAlloc<TrackCand> alloc(&m_cc_pool);
0600         std::vector<CombCandidate> tmp(new_capacity, alloc);
0601         m_candidates.swap(tmp);
0602         m_capacity = new_capacity;
0603       }
0604       for (int s = 0; s < new_capacity; ++s) {
0605         m_candidates[s].reset(max_cands_per_seed, expected_num_hots);
0606       }
0607       for (int s = new_capacity; s < m_capacity; ++s) {
0608         m_candidates[s].reset(0, 0);
0609       }
0610 
0611       m_size = new_capacity;
0612       m_n_seeds_inserted = 0;
0613     }
0614 
0615     void resizeAfterFiltering(int n_removed) {
0616       assert(n_removed <= m_size);
0617       m_size -= n_removed;
0618       m_n_seeds_inserted -= n_removed;
0619     }
0620 
0621     void insertSeed(const Track& seed, const track_score_func& score_func, int region, int pos) {
0622       assert(pos < m_size);
0623 
0624       m_candidates[pos].importSeed(seed, score_func, region);
0625 
0626       ++m_n_seeds_inserted;
0627     }
0628 
0629     void compactifyHitStorageForBestCand(bool remove_seed_hits, int backward_fit_min_hits) {
0630       for (int i = 0; i < m_size; ++i)
0631         m_candidates[i].compactifyHitStorageForBestCand(remove_seed_hits, backward_fit_min_hits);
0632     }
0633 
0634     void beginBkwSearch() {
0635       for (int i = 0; i < m_size; ++i)
0636         m_candidates[i].beginBkwSearch();
0637     }
0638     void endBkwSearch() {
0639       for (int i = 0; i < m_size; ++i)
0640         m_candidates[i].endBkwSearch();
0641     }
0642 
0643     // Accessors
0644     int size() const { return m_size; }
0645 
0646     const CombCandidate& operator[](int i) const { return m_candidates[i]; }
0647     CombCandidate& operator[](int i) { return m_candidates[i]; }
0648     CombCandidate& cand(int i) { return m_candidates[i]; }
0649 
0650     // Direct access for vectorized functions in MkBuilder / MkFinder
0651     const std::vector<CombCandidate>& refCandidates() const { return m_candidates; }
0652     std::vector<CombCandidate>& refCandidates_nc() { return m_candidates; }
0653 
0654   private:
0655     CcPool<TrackCand> m_cc_pool;
0656 
0657     std::vector<CombCandidate> m_candidates;
0658 
0659     int m_capacity = 0;
0660     int m_size = 0;
0661     int m_n_seeds_inserted = 0;
0662   };
0663 
0664 }  // namespace mkfit
0665 
0666 #endif