ClusterParamsBuilder_tool.cc
Go to the documentation of this file.
1 /**
2  * @file ClusterParamsBuilder.cc
3  *
4  * @brief A tool to select good clusters and fill their output parameters
5  *
6  */
7 
8 // Framework Includes
10 #include "fhiclcpp/ParameterSet.h"
11 
12 // LArSoft includes
17 
18 // std includes
19 #include <iostream>
20 #include <memory>
21 
22 namespace lar_cluster3d {
23 
24 /**
25  * @brief ClusterParamsBuilder class definiton
26  */
28 {
29 public:
30  /**
31  * @brief Constructor
32  *
33  * @param pset
34  */
35  explicit ClusterParamsBuilder(fhicl::ParameterSet const &pset);
36 
37  /**
38  * @brief Destructor
39  */
40  virtual ~ClusterParamsBuilder();
41 
42  void configure(const fhicl::ParameterSet&) override;
43 
44  /**
45  * @brief Given the results of running DBScan, format the clusters so that they can be
46  * easily transferred back to the larsoft world
47  *
48  * @param hitPairClusterMap map between view and a list of 3D hits
49  * @param clusterParametersList a container for our candidate 3D clusters
50  * @param rejectionFraction Used for determine "hit purity" when rejecting clusters
51  *
52  * The last two parameters are passed through to the FillClusterParams method
53  */
54  void BuildClusterInfo(reco::ClusterParametersList& clusterParametersList) const override;
55 
56  /**
57  * @brief Fill the cluster parameters (expose to outside world for case of splitting/merging clusters)
58  *
59  * @param ClusterParameters The cluster parameters container to be modified
60  * @param Hit2DToClusterMap Map to keep track of 2D hit to cluster association
61  * @param double minimum fraction of unique hits
62  * @param double maximum fraction of "lost" hits
63  */
64 
67  double minUniqueFrac = 0.,
68  double maxLostFrac=1.) const override;
69 
70 private:
71 
72  /**
73  * @brief Is a cluster "good" and worth keeping?
74  *
75  * @param ClusterParameters The cluster parameters of cluster to be checked
76  * @param Hit2DToClusterMap Map to keep track of 2D hit to cluster association
77  */
78 
80 
82 
84 
85  /**
86  * @brief Data members to follow
87  */
91 
92  PrincipalComponentsAlg m_pcaAlg; // For running Principal Components Analysis
93 };
94 
95 
96 //------------------------------------------------------------------------------------------------------------------------------------------
97 // implementation follows
98 
100  m_pcaAlg(pset.get<fhicl::ParameterSet>("PrincipalComponentsAlg"))
101 {
102  this->configure(pset);
103 }
104 
105 //------------------------------------------------------------------------------------------------------------------------------------------
106 
108 {
109 }
110 
111 //------------------------------------------------------------------------------------------------------------------------------------------
112 
114 {
115  m_clusterMinHits = pset.get<size_t>("ClusterMinHits", 3 );
116  m_clusterMinUniqueFraction = pset.get<double>("ClusterMinUniqueFraction", 0.5 );
117  m_clusterMaxLostFraction = pset.get<double>("ClusterMaxLostFraction", 0.5 );
118 
119  return;
120 }
121 
123 {
124  /**
125  * @brief Given a list of a list of candidate cluster hits, build these out into the intermediate
126  * 3D cluster objects to pass to the final stage
127  *
128  * Note that this routine will also reject unworthy clusters, in particular those that share too
129  * many hits with other clusters. The criteria is that a larger cluster (more hits) will be superior
130  * to a smaller one, if the smaller one shares too many hits with the larger it is zapped.
131  * *** THIS IS AN AREA FOR CONTINUED STUDY ***
132  */
133  // This is a remote possibility but why not check?
134  if (!clusterParametersList.empty())
135  {
136  // We want to order our clusters on by largest (most number hits) to smallest. So, we'll loop through the clusters,
137  // weeding out the unwanted ones and keep track of things in a set of "good" clusters which we'll order
138  // by cluster size.
139  clusterParametersList.sort();
140 
141  // The smallest clusters are now at the end, drop those off the back that are less than the mininum necessary
142  while(!clusterParametersList.empty() && clusterParametersList.back().getHitPairListPtr().size() < m_clusterMinHits) clusterParametersList.pop_back();
143 
144  // The next step is to build out a mapping of all 2D hits to clusters
145  // Keep track of where the hits get distributed...
146  reco::Hit2DToClusterMap hit2DToClusterMap;
147 
148  reco::ClusterParametersList::iterator clusterItr = clusterParametersList.begin();
149 
150 // for(auto& clusterParams : clusterParametersList)
151 // {
152 // for(const auto& hit3D : clusterParams.getHitPairListPtr())
153 // {
154 // for(const auto& hit2D : hit3D->getHits())
155 // {
156 // if (!hit2D) continue;
157 //
158 // hit2DToClusterMap[hit2D][&clusterParams].insert(hit3D);
159 // }
160 // }
161 // }
162 
163  // Ok, spin through again to remove ambiguous hits
164  // for(auto& clusterParams : clusterParametersList) PruneAmbiguousHits(clusterParams,hit2DToClusterMap);
165 
166  // What remains is an order set of clusters, largest first
167  // Now go through and obtain cluster parameters
168 // clusterItr = clusterParametersList.begin();
169 
170 // while(clusterItr != clusterParametersList.end())
171 // {
172 // // Dereference for ease...
173 // reco::ClusterParameters& clusterParams = *clusterItr;
174 //
175 // // Do the actual work of filling the parameters
176 // FillClusterParams(clusterParams, hit2DToClusterMap, m_clusterMinUniqueFraction, m_clusterMaxLostFraction);
177 //
178 // // If this cluster is rejected then the parameters will be empty
179 // if (clusterParams.getClusterParams().empty() || !clusterParams.getFullPCA().getSvdOK())
180 // {
181 // clusterItr = clusterParametersList.erase(clusterItr);
182 // }
183 // else clusterItr++;
184 // }
185 
186  while(clusterItr != clusterParametersList.end())
187  {
188  // Dereference for ease...
189  reco::ClusterParameters& clusterParams = *clusterItr;
190 
191  if (keepThisCluster(clusterParams, hit2DToClusterMap))
192  {
193  storeThisCluster(clusterParams, hit2DToClusterMap);
194  clusterItr++;
195  }
196  else clusterItr = clusterParametersList.erase(clusterItr);
197  }
198  }
199 
200  return;
201 }
202 
204 {
205  // Try to keep simple by looking at the 2D hits associated to the cluster and checking to see how many, by plane, are already
206  // in use. Reject clusters where too many hits are shared.
207 
208  bool keepThisCluster = false;
209 
210  // Define some handy data structures for counting the number of times hits get used and shared
211  using HitCountMap = std::unordered_map<const reco::ClusterHit2D*,int>;
212  using PlaneHitCountMapVec = std::vector<HitCountMap>;
213 
214  PlaneHitCountMapVec totalPlaneHitCountMapVec(3); // counts total number of hits
215  PlaneHitCountMapVec sharedPlaneHitCountMapVec(3); // this is the number shared with a bigger cluster
216  PlaneHitCountMapVec uniquePlaneHitCountMapVec(3); // this is the number unique to this cluster (so far)
217 
218  // Go through the hits and check usage...
219  for(const auto& hit3D : clusterParams.getHitPairListPtr())
220  {
221  for(const auto& hit2D : hit3D->getHits())
222  {
223  if (!hit2D) continue;
224 
225  size_t hitPlane = hit2D->WireID().Plane;
226 
227  totalPlaneHitCountMapVec[hitPlane][hit2D]++;
228 
229  reco::Hit2DToClusterMap::const_iterator hit2DToClusIter = hit2DToClusterMap.find(hit2D);
230 
231  if (hit2DToClusIter != hit2DToClusterMap.end())
232  {
233  sharedPlaneHitCountMapVec[hitPlane][hit2D]++;
234  }
235  else uniquePlaneHitCountMapVec[hitPlane][hit2D]++;
236  }
237  }
238 
239  // First try... look at fractions of unique hits each plane
240  std::vector<float> uniqueFractionVec(3,0.);
241 
242  for(size_t idx = 0; idx < 3; idx++)
243  {
244  if (!totalPlaneHitCountMapVec[idx].empty()) uniqueFractionVec[idx] = float(uniquePlaneHitCountMapVec[idx].size()) / float(totalPlaneHitCountMapVec[idx].size());
245  }
246 
247  float overallFraction = uniqueFractionVec[0] * uniqueFractionVec[1] * uniqueFractionVec[2];
248  float maxFraction = *std::max_element(uniqueFractionVec.begin(),uniqueFractionVec.end());
249 
250  if (maxFraction > 0.9 || overallFraction > 0.2) keepThisCluster = true;
251 
252  return keepThisCluster;
253 }
254 
256 {
257  // See if we can avoid duplicates by temporarily transferring to a set
258  std::unordered_set<const reco::ClusterHit2D*> hitSet;
259 
260  // first task is to mark the hits and update the hit to cluster mapping
261  for(const auto& hit3D : clusterParams.getHitPairListPtr())
262  {
263  for(const auto& hit2D : hit3D->getHits())
264  {
265  if (!hit2D) continue;
266 
267  hit2DToClusterMap[hit2D][&clusterParams].insert(hit3D);
268  hitSet.insert(hit2D);
269  }
270  }
271 
272  // First stage of feature extraction runs here
273  m_pcaAlg.PCAAnalysis_3D(clusterParams.getHitPairListPtr(), clusterParams.getFullPCA());
274 
275  // Must have a valid pca
276  if (clusterParams.getFullPCA().getSvdOK())
277  {
278  // Set the skeleton PCA to make sure it has some value
279  clusterParams.getSkeletonPCA() = clusterParams.getFullPCA();
280 
281  // Add the "good" hits to our cluster parameters
282  for(const auto& hit2D : hitSet)
283  {
284  hit2D->setStatusBit(reco::ClusterHit2D::USED);
285  clusterParams.UpdateParameters(hit2D);
286  }
287  }
288 
289  return;
290 }
291 
293  reco::Hit2DToClusterMap& hit2DToClusterMap,
294  double minUniqueFrac,
295  double maxLostFrac) const
296 {
297  /**
298  * @brief Given a list of hits fill out the remaining parameters for this cluster and evaluate the
299  * candidate's worthiness to achieve stardom in the event display
300  */
301  // Recover the HitPairListPtr from the input clusterParams (which will be the
302  // only thing that has been provided)
303  reco::HitPairListPtr& hitPairVector = clusterParams.getHitPairListPtr();
304 
305  // To be sure, we should clear the other data members
306  clusterParams.getClusterParams().clear();
307  clusterParams.getFullPCA() = reco::PrincipalComponents();
308 
309  // A test of the emergency broadcast system...
310  // FindBestPathInCluster(clusterParams);
311  // CheckHitSorting(clusterParams);
312 
313  // See if we can avoid duplicates by temporarily transferring to a set
314  std::set<const reco::ClusterHit2D*> hitSet;
315 
316  // Ultimately we want to keep track of the number of unique 2D hits in this cluster
317  // So use a vector (by plane) of sets of hits
318  std::vector<size_t> planeHit2DVec;
319  std::vector<size_t> planeUniqueHit2DVec;
320 
321  planeHit2DVec.resize(3);
322  planeUniqueHit2DVec.resize(3);
323 
324  // Map from 2D hits to associated 3D hits
325  reco::Hit2DToHit3DListMap& hit2DToHit3DListMap = clusterParams.getHit2DToHit3DListMap();
326 
327  // The map from 2D to 3D hits will contain unique entries for 2D hits so we can do some quick accounting here
328  for(const auto& hitMapPair : hit2DToHit3DListMap)
329  {
330  size_t plane = hitMapPair.first->WireID().Plane;
331 
332  planeHit2DVec[plane] += hitMapPair.second.size();
333  if (!(hitMapPair.first->getStatusBits() & reco::ClusterHit2D::USED)) planeUniqueHit2DVec[plane] += hitMapPair.second.size();
334  }
335 
336  // Get totals
337  int numTotalHits(0);
338  int numUniqueHits(0);
339 
340  // Also consider the number of hits shared on a given view...
341  std::vector<float> uniqueHitFracVec(3,0.);
342  int nPlanesWithHits(0);
343  int nPlanesWithUniqueHits(0);
344  size_t minPlane(0);
345  size_t minPlaneCnt = planeUniqueHit2DVec[0];
346 
347  // Loop through the planes
348  for(int idx = 0; idx < 3; idx++)
349  {
350  // numerology
351  numTotalHits += planeHit2DVec[idx];
352  numUniqueHits += planeUniqueHit2DVec[idx];
353 
354  if (planeHit2DVec[idx] > 0) nPlanesWithHits++;
355  if (planeUniqueHit2DVec[idx] > 0) nPlanesWithUniqueHits++;
356 
357  // Compute the fraction of unique hits in this plane
358  uniqueHitFracVec[idx] = float(planeUniqueHit2DVec[idx]) / std::max(float(planeHit2DVec[idx]),float(1.));
359 
360  // Finding the plane with the fewest hits
361  if (planeHit2DVec[idx] < minPlaneCnt)
362  {
363  minPlaneCnt = planeHit2DVec[idx];
364  minPlane = idx;
365  }
366  }
367 
368  // If we have something left then at this point we make one more check
369  // This check is intended to weed out clusters made from isolated groups of ambiguous hits which
370  // really belong to a larger cluster
371  if (numUniqueHits > 0.25 * numTotalHits && nPlanesWithHits > 1 && nPlanesWithUniqueHits > 1)
372  {
373  // Sorts lowest to highest
374  std::sort(uniqueHitFracVec.begin(),uniqueHitFracVec.end());
375 
376  float acceptRatio = 0.;
377 
378  if(uniqueHitFracVec[0] * uniqueHitFracVec[1] > 0.25) acceptRatio = 1.;
379 
380  float uniqueFraction = uniqueHitFracVec[0] * uniqueHitFracVec[1] * uniqueHitFracVec[2];
381 
382  // Arbitrary rejection criteria... need to understand
383  if (uniqueFraction > 0.6 && acceptRatio > 0.)
384  {
385  // Create a list to hold 3D hits which are already in use (criteria below)
386  reco::HitPairListPtr usedHitPairList;
387 
388 // std::cout << "--------> Starting 3D hit removal, # 2D hits/plane: " << planeHit2DVec[0] << "/" << planeHit2DVec[1] << "/" << planeHit2DVec[2] << std::endl;
389 
390  // Have survived laugh test, do final processing...
391  // In this first loop go through all the 2D hits and identify the 3D hits that are candidates for deletion
392  for(auto& pair : hit2DToHit3DListMap)
393  {
394  // Check to see if this can happen
395  if (pair.second.empty())
396  {
397  std::cout << "<<<<<< no matching 3D hits for reco hit in final hit processing >>>>>>" << std::endl;
398  continue;
399  }
400 
401  // Which plane for this hit?
402  size_t hitPlane = pair.first->WireID().Plane;
403 
404  // Only reject hits on the planes not the fewest 2D hits and really only do this if more than a couple
405  if (hitPlane != minPlane && pair.second.size() > 2)
406  {
407  // If this hit is associated to a number of 3D hits then do some arbitration
408  // Start by sorting the 3D hits by "significance"
409  // --> Really should do this by the significance of adding the hit we are looking at?
410  //pair.second.sort([hitPlane](const auto& left, const auto& right){return left->getHitDelTSigVec()[hitPlane] < right->getHitDelTSigVec()[hitPlane];});
411  pair.second.sort([](const auto& left, const auto& right){return left->getHitChiSquare() < right->getHitChiSquare();});
412 
413  ////std::cout << "~~~~> Checking hit removal, # matches: " << pair.second.size() << ", first params: " << pair.second.front()->getHitDelTSigVec()[hitPlane] << ", last params: "<< pair.second.back()->getHitDelTSigVec()[hitPlane];
414  //std::cout << "~~~~> Checking hit removal, # matches: " << pair.second.size() << ", first params: " << pair.second.front()->getHitChiSquare() << ", last params: "<< pair.second.back()->getHitChiSquare();
415 
416  // From sorted list, determine a rejection value to eliminate bad hits
417  //float cutDeltaTSig = std::min(2.0,std::max(0.5, double((pair.second.front()->getHitDelTSigVec()[hitPlane]))));
418  float cutDeltaTSig = std::min(2.0,std::max(0.5, double(pair.second.front()->getHitChiSquare())));
419 
420  //std::cout << ", cutDeltaTSig: " << cutDeltaTSig;
421 
422  cutDeltaTSig = 10.;
423 
424  // And here go through the process of eliminating it
425  //reco::HitPairListPtr::iterator firstBadHitItr = std::find_if(pair.second.begin(),pair.second.end(),[hitPlane,cutDeltaTSig](const auto& hitPtr){return hitPtr->getHitDelTSigVec()[hitPlane] > cutDeltaTSig;});
426  reco::HitPairListPtr::iterator firstBadHitItr = std::find_if(pair.second.begin(),pair.second.end(),[cutDeltaTSig](const auto& hitPtr){return hitPtr->getHitChiSquare() > cutDeltaTSig;});
427 
428  // We need to worry about cutting too many hits... use this loop to try to expand the range in a reasonable fashion
429 // while(std::distance(pair.second.begin(),firstBadHitItr) < int(pair.second.size()/3) && cutDeltaTSig < 0.5)
430 // {
431 // float candDeltaTSig = (*firstBadHitItr)->getHitDelTSigVec()[hitPlane];
432 //
433 // if (candDeltaTSig > 2. * cutDeltaTSig) break;
434 //
435 // firstBadHitItr++;
436 // cutDeltaTSig = candDeltaTSig;
437 // }
438 
439  reco::HitPairListPtr rejectCandList;
440 
441  std::copy(firstBadHitItr,pair.second.end(),std::back_inserter(rejectCandList));
442 
443  //std::cout << ", bad hits: " << rejectCandList.size() << std::endl;
444 
445  // Remove the 3D hits from all the lists
446  for(const auto& hit3D : rejectCandList)
447  {
448  bool rejectThisHit(true);
449  std::vector<std::pair<reco::HitPairListPtr&,reco::HitPairListPtr::iterator>> deleteVec;
450 
451  for(const auto& hit2D : hit3D->getHits())
452  {
453  // Watch for null hit (dead channels)
454  if (!hit2D) continue;
455 
456  reco::HitPairListPtr& removeHitList = hit2DToHit3DListMap[hit2D];
457 
458  // Don't allow all the 3D hits associated to this 2D hit to be rejected?
459  if (removeHitList.size() < 2)
460  {
461  //std::cout << " ---> remove list too small, size: " << removeHitList.size() << " for hit: " << hit2D << ", pair.first: " << pair.first << std::endl;
462  rejectThisHit = false;
463  break;
464  }
465 
466  reco::HitPairListPtr::iterator removeItr = std::find(removeHitList.begin(),removeHitList.end(),hit3D);
467 
468  if (removeItr != removeHitList.end()) deleteVec.emplace_back(removeHitList,removeItr);
469  //else std::cout << "======>> Did not find 3D hit to remove from list for 2D hit! <<+++++++++" << std::endl;
470  }
471 
472  if (rejectThisHit)
473  {
474  for(auto& rejectPair : deleteVec) rejectPair.first.erase(rejectPair.second);
475 
476  usedHitPairList.push_back(hit3D);
477  }
478  }
479  }
480 
481  hitSet.insert(pair.first);
482  }
483 
484  // Now we go through the list of candidates and delete those which are unworthy of being processed...
485  if (!usedHitPairList.empty())
486  {
487  // Loop through the hits watching out for double counting
488  const reco::ClusterHit3D* lastHit3D = 0;
489 
490  for(const auto& hit3D : usedHitPairList)
491  {
492  if (hit3D == lastHit3D) continue;
493 
494  reco::HitPairListPtr::iterator hit3DItr = std::find(hitPairVector.begin(),hitPairVector.end(),hit3D);
495 
496  if (hit3DItr != hitPairVector.end())
497  {
498  // Mark the hit
499  hit3D->setStatusBit(reco::ClusterHit3D::REJECTEDHIT);
500 
501  // Remove from the cluster's hit container
502  hitPairVector.erase(hit3DItr);
503 
504  // If the clustering algorithm includes edges then need to get rid of those as well
505  if (!clusterParams.getHit3DToEdgeMap().empty())
506  {
507  reco::Hit3DToEdgeMap& edgeMap = clusterParams.getHit3DToEdgeMap();
508 
509  edgeMap.erase(edgeMap.find(hit3D));
510  }
511  }
512 
513  lastHit3D = hit3D;
514  }
515 // removeUsedHitsFromMap(clusterParams, usedHitPairList, hit2DToClusterMap);
516  }
517 
518  // First stage of feature extraction runs here
519  m_pcaAlg.PCAAnalysis_3D(hitPairVector, clusterParams.getFullPCA());
520 
521  // Must have a valid pca
522  if (clusterParams.getFullPCA().getSvdOK())
523  {
524  // Set the skeleton PCA to make sure it has some value
525  clusterParams.getSkeletonPCA() = clusterParams.getFullPCA();
526 
527  // Add the "good" hits to our cluster parameters
528  for(const auto& hit2D : hitSet)
529  {
530  hit2D->setStatusBit(reco::ClusterHit2D::USED);
531  clusterParams.UpdateParameters(hit2D);
532  }
533  }
534  }
535  }
536 
537  return;
538 }
539 
541  reco::HitPairListPtr& usedHitPairList,
542  reco::Hit2DToClusterMap& hit2DToClusterMap) const
543 {
544  // Clean up our hit to cluster map
545  for(const auto& hit3D : usedHitPairList)
546  {
547  for(const auto& hit2D : hit3D->getHits())
548  {
549  if (!hit2D) continue;
550 
551  reco::Hit2DToClusterMap::iterator hitToClusMapItr = hit2DToClusterMap.find(hit2D);
552 
553  // I am pretty sure this can't happen but let's check anyway...
554  if (hitToClusMapItr == hit2DToClusterMap.end())
555  {
556  std::cout << "*********** COULD NOT FIND ENTRY FOR 2D HIT! **************" << std::endl;
557  break;
558  }
559 
560  // Ok, the same hit can be shared in the same cluster so must be careful here
561  // First loop over clusters looking for match
562  reco::ClusterToHitPairSetMap::iterator clusToHit3DMapItr = hitToClusMapItr->second.find(&clusterParams);
563 
564  // This also can't happen
565  if (clusToHit3DMapItr == hitToClusMapItr->second.end())
566  {
567  std::cout << "************ DUCK! THE SKY HAS FALLEN!! *********" << std::endl;
568  break;
569  }
570 
571  // If this hit is shared by more than one 3D hit then pick the right one
572  if (clusToHit3DMapItr->second.size() > 1)
573  {
574  reco::HitPairSetPtr::iterator hit3DItr = clusToHit3DMapItr->second.find(hit3D);
575 
576  clusToHit3DMapItr->second.erase(hit3DItr);
577  }
578  else
579  hitToClusMapItr->second.erase(clusToHit3DMapItr);
580 
581  }
582  }
583 
584  return;
585 }
586 
588 } // namespace lar_cluster3d
bool keepThisCluster(reco::ClusterParameters &, const reco::Hit2DToClusterMap &) const
Is a cluster "good" and worth keeping?
intermediate_table::iterator iterator
void configure(const fhicl::ParameterSet &) override
bool getSvdOK() const
Definition: Cluster3D.h:244
ClusterParamsBuilder(fhicl::ParameterSet const &pset)
Constructor.
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
void PCAAnalysis_3D(const reco::HitPairListPtr &hitPairList, reco::PrincipalComponents &pca, bool skeletonOnly=false) const
void BuildClusterInfo(reco::ClusterParametersList &clusterParametersList) const override
Given the results of running DBScan, format the clusters so that they can be easily transferred back ...
reco::PrincipalComponents & getSkeletonPCA()
Definition: Cluster3D.h:478
reco::Hit2DToHit3DListMap & getHit2DToHit3DListMap()
Definition: Cluster3D.h:475
Hit has been rejected for any reason.
Definition: Cluster3D.h:99
reco::Hit3DToEdgeMap & getHit3DToEdgeMap()
Definition: Cluster3D.h:479
intermediate_table::const_iterator const_iterator
reco::HitPairListPtr & getHitPairListPtr()
Definition: Cluster3D.h:476
reco::PlaneToClusterParamsMap & getClusterParams()
Definition: Cluster3D.h:474
void removeUsedHitsFromMap(reco::ClusterParameters &, reco::HitPairListPtr &, reco::Hit2DToClusterMap &) const
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
size_t m_clusterMinHits
Data members to follow.
reco::PrincipalComponents & getFullPCA()
Definition: Cluster3D.h:477
ClusterParamsBuilder class definiton.
void storeThisCluster(reco::ClusterParameters &, reco::Hit2DToClusterMap &) const
T get(std::string const &key) const
Definition: ParameterSet.h:271
std::unordered_map< const reco::ClusterHit2D *, reco::HitPairListPtr > Hit2DToHit3DListMap
Definition: Cluster3D.h:348
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:335
void UpdateParameters(const reco::ClusterHit2D *hit)
Definition: Cluster3D.h:452
static int max(int a, int b)
Definition of data types for geometry description.
void FillClusterParams(reco::ClusterParameters &, reco::Hit2DToClusterMap &, double minUniqueFrac=0., double maxLostFrac=1.) const override
Fill the cluster parameters (expose to outside world for case of splitting/merging clusters) ...
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
T copy(T const &v)
std::unordered_map< const reco::ClusterHit2D *, ClusterToHitPairSetMap > Hit2DToClusterMap
Definition: Cluster3D.h:511
ClusterParamsBuilder class definiton.
std::unordered_map< const reco::ClusterHit3D *, reco::EdgeList > Hit3DToEdgeMap
Definition: Cluster3D.h:347
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
std::list< ClusterParameters > ClusterParametersList
Definition: Cluster3D.h:404
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
QTextStream & endl(QTextStream &s)