Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-05-01 22:52:20

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