LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
lar_cluster3d::SkeletonAlg Class Reference

Cluster3D class. More...

#include "SkeletonAlg.h"

Public Member Functions

 SkeletonAlg (fhicl::ParameterSet const &pset)
 Constructor. More...
 
virtual ~SkeletonAlg ()
 Destructor. More...
 
void reconfigure (fhicl::ParameterSet const &pset)
 a handler for the case where the algorithm control parameters are to be reset More...
 
int FindMedialSkeleton (reco::HitPairListPtr &hitPairList) const
 This is intended to find the medial skeleton given a list of input hit pairs. More...
 
void GetSkeletonHits (const reco::HitPairListPtr &inputHitList, reco::HitPairListPtr &skeletonHitList) const
 Return the skeleton hits from the input list. More...
 
void AverageSkeletonPositions (reco::HitPairListPtr &skeletonHitList) const
 Modifies the position of input skeleton hits by averaging along the "best" wire direction. More...
 

Private Member Functions

double FindFirstAndLastWires (std::vector< const reco::ClusterHit3D * > &hitVec, int planeToCheck, int referenceWire, double referenceTicks, int &firstWire, int &lastWire) const
 A function to find the bounding wires in a given view. More...
 

Private Attributes

double m_minimumDeltaTicks
 
double m_maximumDeltaTicks
 
fhicl::ParameterSet m_pset
 

Detailed Description

Cluster3D class.

Definition at line 33 of file SkeletonAlg.h.

Constructor & Destructor Documentation

lar_cluster3d::SkeletonAlg::SkeletonAlg ( fhicl::ParameterSet const &  pset)

Constructor.

Parameters
pset

Definition at line 30 of file SkeletonAlg.cxx.

References reconfigure().

31 {
32  reconfigure(pset);
33 }
void reconfigure(fhicl::ParameterSet const &pset)
a handler for the case where the algorithm control parameters are to be reset
Definition: SkeletonAlg.cxx:43
lar_cluster3d::SkeletonAlg::~SkeletonAlg ( )
virtual

Destructor.

Definition at line 37 of file SkeletonAlg.cxx.

38 {
39 }

Member Function Documentation

void lar_cluster3d::SkeletonAlg::AverageSkeletonPositions ( reco::HitPairListPtr skeletonHitList) const

Modifies the position of input skeleton hits by averaging along the "best" wire direction.

Parameters
skeletonHitList- input list of skeleton hits

Definition at line 331 of file SkeletonAlg.cxx.

References reco::ClusterHit3D::getArclenToPoca(), reco::ClusterHit3D::getAvePeakTime(), reco::ClusterHit3D::getDeltaPeakTime(), reco::ClusterHit3D::getDocaToAxis(), reco::ClusterHit3D::getHitChiSquare(), reco::ClusterHit3D::getHitDelTSigVec(), reco::ClusterHit3D::getHits(), reco::ClusterHit3D::getID(), reco::ClusterHit3D::getPosition(), reco::ClusterHit3D::getSigmaPeakTime(), reco::ClusterHit3D::getStatusBits(), reco::ClusterHit3D::getTotalCharge(), reco::ClusterHit3D::getWireIDs(), reco::ClusterHit3D::REJECTEDHIT, reco::ClusterHit3D::setPosition(), and reco::ClusterHit3D::SKELETONPOSAVE.

Referenced by lar_cluster3d::Cluster3D::findTrackSeeds(), lar_cluster3d::Cluster3D::splitClustersWithHough(), and lar_cluster3d::Cluster3D::splitClustersWithMST().

332 {
333  // NOTE: This method assumes the list being given to it is comprised of skeleton hits
334  // YMMV if you send in a complete hit collection!
335 
336  // Define a mapping between 2D hits and the 3D hits they make
337  typedef std::map<const reco::ClusterHit2D*, std::vector<const reco::ClusterHit3D*> > Hit2DtoHit3DMap;
338 
339  // We want to keep track of this mapping by view
340  Hit2DtoHit3DMap hit2DToHit3DMap[3];
341 
342  // Keep count of the number of skeleton hits selected
343  unsigned int nSkeletonHits(0);
344 
345  // Execute the first loop through the hits to build the map
346  for(const auto& hitPair : skeletonHitList)
347  {
348  // Don't consider points "rejected" earlier
349  if (hitPair->bitsAreSet(reco::ClusterHit3D::REJECTEDHIT)) continue;
350 
351  // Count only those skeleton hits which have not been averaged
352  if (!hitPair->bitsAreSet(reco::ClusterHit3D::SKELETONPOSAVE)) nSkeletonHits++;
353 
354  for(const auto& hit2D : hitPair->getHits())
355  {
356  size_t plane = hit2D->getHit().WireID().Plane;
357 
358  hit2DToHit3DMap[plane][hit2D].push_back(hitPair);
359  }
360  }
361 
362  // Exit early if no skeleton hits to process
363  if (!nSkeletonHits) return;
364 
365  // The list of 3D hits associated to any given 2D hit is most useful to us if it is ordered
366  // So this will loop through entries in the map and do the ordering
367  for(size_t idx = 0; idx < 3; idx++)
368  {
369  for(auto& mapPair : hit2DToHit3DMap[idx])
370  {
371  size_t numHitPairs = mapPair.second.size();
372  int planeToCheck = (idx + 1) % 3; // have forgotten reasoning here...
373 
374  if (numHitPairs > 1) std::sort(mapPair.second.begin(), mapPair.second.end(), OrderHitsAlongWire(planeToCheck));
375  }
376  }
377 
378  // Ok, so the basic strategy is not entirely different from that used to build the skeleton hits in the first
379  // place. The idea is to loop through all skeleton hits and then determine the average position for the hit
380  // based on the wire direction with the fewest hits to the edge.
381  // Currently this is a pretty simple minded approach and it would appear that some effort could be spent
382  // here to improve this.
383  // NOTE: the averaging being performed is ONLY in the Y-Z plane since this is where the hit ambiguity
384  // issue arises.
385  reco::HitPairListPtr::iterator hitPairItr = skeletonHitList.begin();
386 
387  for(int bestPlaneVecIdx = 0; bestPlaneVecIdx < 2; bestPlaneVecIdx++)
388  {
389  std::list<reco::ClusterHit3D> tempHitPairList;
390  reco::HitPairListPtr tempHitPairListPtr;
391 
392  std::map<const reco::ClusterHit3D*, const reco::ClusterHit3D*> hit3DToHit3DMap;
393 
394  while(hitPairItr != skeletonHitList.end())
395  {
396  const reco::ClusterHit3D* hit3D = *hitPairItr++;
397 
398  std::vector<std::pair<size_t,size_t> > bestPlaneVec;
399 
400  for(const auto& hit2D : hit3D->getHits())
401  {
402  bestPlaneVec.push_back(std::pair<size_t,size_t>(hit2D->getHit().WireID().Plane,hit2DToHit3DMap[hit2D->getHit().WireID().Plane][hit2D].size()));
403  }
404 
405  std::sort(bestPlaneVec.begin(), bestPlaneVec.end(), OrderBestPlanes());
406 
407  size_t bestPlaneIdx = bestPlaneVec[bestPlaneVecIdx].first;
408  size_t bestPlaneCnt = bestPlaneVec[bestPlaneVecIdx].second;
409 
410  if (bestPlaneCnt > 5) continue;
411 
412  std::vector<const reco::ClusterHit3D*>& hit3DVec = hit2DToHit3DMap[bestPlaneIdx][hit3D->getHits()[bestPlaneIdx]];
413 
414  float avePosition[3] = {hit3D->getPosition()[0],0.,0.};
415 
416  for(const auto& tempHit3D : hit3DVec)
417  {
418  avePosition[1] += tempHit3D->getPosition()[1];
419  avePosition[2] += tempHit3D->getPosition()[2];
420  }
421 
422  avePosition[1] *= 1./double(hit3DVec.size());
423  avePosition[2] *= 1./double(hit3DVec.size());
424 
425  tempHitPairList.emplace_back(reco::ClusterHit3D(hit3D->getID(),
426  hit3D->getStatusBits(),
427  avePosition,
428  hit3D->getTotalCharge(),
429  hit3D->getAvePeakTime(),
430  hit3D->getDeltaPeakTime(),
431  hit3D->getSigmaPeakTime(),
432  hit3D->getHitChiSquare(),
433  hit3D->getDocaToAxis(),
434  hit3D->getArclenToPoca(),
435  hit3D->getHits(),
436  hit3D->getHitDelTSigVec(),
437  hit3D->getWireIDs()));
438 
439  tempHitPairListPtr.push_back(&tempHitPairList.back());
440 
441  hit3DToHit3DMap[tempHitPairListPtr.back()] = hit3D;
442  }
443 
444  for(const auto& pair : hit3DToHit3DMap)
445  {
446  pair.second->setPosition(pair.first->getPosition());
447  pair.second->setStatusBit(reco::ClusterHit3D::SKELETONPOSAVE);
448  }
449  }
450 
451  return;
452 }
intermediate_table::iterator iterator
const std::vector< float > getHitDelTSigVec() const
Definition: Cluster3D.h:159
float getTotalCharge() const
Definition: Cluster3D.h:151
Hit has been rejected for any reason.
Definition: Cluster3D.h:92
float getSigmaPeakTime() const
Definition: Cluster3D.h:154
unsigned int getStatusBits() const
Definition: Cluster3D.h:146
float getDocaToAxis() const
Definition: Cluster3D.h:156
float getAvePeakTime() const
Definition: Cluster3D.h:152
size_t getID() const
Definition: Cluster3D.h:145
std::list< const reco::ClusterHit3D * > HitPairListPtr
Definition: Cluster3D.h:317
const float * getPosition() const
Definition: Cluster3D.h:147
void setPosition(const float *pos) const
Definition: Cluster3D.h:171
const std::vector< geo::WireID > & getWireIDs() const
Definition: Cluster3D.h:160
float getArclenToPoca() const
Definition: Cluster3D.h:157
float getDeltaPeakTime() const
Definition: Cluster3D.h:153
Skeleton hit position averaged.
Definition: Cluster3D.h:99
float getHitChiSquare() const
Definition: Cluster3D.h:155
const ClusterHit2DVec & getHits() const
Definition: Cluster3D.h:158
double lar_cluster3d::SkeletonAlg::FindFirstAndLastWires ( std::vector< const reco::ClusterHit3D * > &  hitVec,
int  planeToCheck,
int  referenceWire,
double  referenceTicks,
int &  firstWire,
int &  lastWire 
) const
private

A function to find the bounding wires in a given view.

Definition at line 49 of file SkeletonAlg.cxx.

References m_maximumDeltaTicks, m_minimumDeltaTicks, max, and min.

Referenced by FindMedialSkeleton().

55 {
56  // In the simple case the first and last wires are simply the front and back of the input vector
57  firstWire = hitVec.front()->getHits()[planeToCheck]->getHit().WireID().Wire;
58  lastWire = hitVec.back()->getHits()[planeToCheck]->getHit().WireID().Wire;
59 
60  double maxDeltaTicks = referenceTicks - hitVec.front()->getHits()[planeToCheck]->getTimeTicks();
61  double minDeltaTicks = referenceTicks - hitVec.back()->getHits()[planeToCheck]->getTimeTicks();
62 
63  if (minDeltaTicks > maxDeltaTicks) std::swap(maxDeltaTicks, minDeltaTicks);
64 
65  double bestDeltaTicks = 1000000.;
66 
67  // Can't have a gap if only one element
68  if (hitVec.size() > 1)
69  {
70  // The issue is that there may be a gap in wires which we need to find.
71  // Reset the last wire
72  lastWire = firstWire;
73 
74  // Keep track of all the deltas
75  double nextBestDeltaTicks = bestDeltaTicks;
76 
77  for(const auto& hitPair : hitVec)
78  {
79  int curWire = hitPair->getHits()[planeToCheck]->getHit().WireID().Wire;
80  double deltaTicks = referenceTicks - hitPair->getHits()[planeToCheck]->getTimeTicks();
81 
82  maxDeltaTicks = std::max(maxDeltaTicks, deltaTicks);
83  minDeltaTicks = std::min(minDeltaTicks, deltaTicks);
84 
85  if (bestDeltaTicks > fabs(deltaTicks))
86  {
87  // By definition, the "next best" is now the current best
88  nextBestDeltaTicks = bestDeltaTicks;
89  bestDeltaTicks = fabs(deltaTicks);
90  }
91  else if (nextBestDeltaTicks > fabs(deltaTicks))
92  {
93  nextBestDeltaTicks = fabs(deltaTicks);
94  }
95 
96  // if gap detected, take action depending on where the input wire is
97  // But remember we need to be willing to accept a 1 wire gap... for efficiency
98  if (fabs(curWire - lastWire) > 2000)
99  {
100  if (referenceWire <= lastWire) break;
101 
102  // Stepped over gap, reset everything
103  firstWire = curWire;
104  maxDeltaTicks = deltaTicks;
105  minDeltaTicks = deltaTicks;
106  bestDeltaTicks = fabs(deltaTicks);
107  nextBestDeltaTicks = bestDeltaTicks;
108  }
109 
110  lastWire = curWire;
111  }
112 
113  bestDeltaTicks = nextBestDeltaTicks;
114  }
115 
116  bestDeltaTicks = std::max(std::min(bestDeltaTicks,m_maximumDeltaTicks), m_minimumDeltaTicks);
117 
118  if (minDeltaTicks * maxDeltaTicks > 0. && bestDeltaTicks > 30.) bestDeltaTicks = 0.;
119 
120  return bestDeltaTicks;
121 }
Int_t max
Definition: plot.C:27
void swap(art::HLTGlobalStatus &lhs, art::HLTGlobalStatus &rhs)
Int_t min
Definition: plot.C:26
int lar_cluster3d::SkeletonAlg::FindMedialSkeleton ( reco::HitPairListPtr hitPairList) const

This is intended to find the medial skeleton given a list of input hit pairs.

Parameters
hitPairList- input list of pointers to internal Cluster3D 3D hits

Definition at line 159 of file SkeletonAlg.cxx.

References reco::ClusterHit3D::EDGEHIT, FindFirstAndLastWires(), reco::ClusterHit2D::getTimeTicks(), reco::ClusterHit3D::REJECTEDHIT, and reco::ClusterHit3D::SKELETONHIT.

160 {
161  // Our mission is to try to find the medial skeletion of the input list of hits
162  // We define that as the set of hit pairs where the pairs share the same hit in a given direction
163  // and the selected medial hit is equal distance from the edges.
164  // The first step in trying to do this is to build a map which relates a give 2D hit to an ordered list of hitpairs using it
165  typedef std::map<const reco::ClusterHit2D*, std::vector<const reco::ClusterHit3D*> > Hit2DtoHit3DMapU;
166 
167  Hit2DtoHit3DMapU hit2DToHit3DMap[3];
168 
169  for(const auto& hitPair : hitPairList)
170  {
171  // Don't consider points "rejected" earlier
172  if (hitPair->bitsAreSet(reco::ClusterHit3D::REJECTEDHIT)) continue;
173 
174  // Don't consider hitPair's with less than 3 hits
175  unsigned status = hitPair->getStatusBits();
176 
177  if ((status & 0x7) != 0x7) continue;
178 
179  for(const auto& hit2D : hitPair->getHits())
180  {
181  size_t plane = hit2D->getHit().WireID().Plane;
182 
183  hit2DToHit3DMap[plane][hit2D].push_back(hitPair);
184  }
185  }
186 
187  // Do an explicit loop through to sort?
188  for(size_t idx = 0; idx < 3; idx++)
189  {
190  for(auto& mapPair : hit2DToHit3DMap[idx])
191  {
192  size_t numHitPairs = mapPair.second.size();
193  int planeToCheck = (idx + 1) % 3; // have forgotten reasoning here...
194 
195  if (numHitPairs > 1) std::sort(mapPair.second.begin(), mapPair.second.end(), OrderHitsAlongWire(planeToCheck));
196  }
197  }
198 
199  // Keep a count of the number of skeleton points to be returned
200  int nSkeletonPoints(0);
201 
202  // The idea is go through all the hits again and determine if they could be "skeleton" elements
203  for(const auto& hitPair : hitPairList)
204  {
205  // Don't consider points "rejected" earlier
206  if (hitPair->bitsAreSet(reco::ClusterHit3D::REJECTEDHIT)) continue;
207 
208  // If a hit pair we skip for now
209  if ((hitPair->getStatusBits() & 0x7) != 7) continue;
210 
211  // Hopefully I am not confusing myself here.
212  // The goal is to know, for a given 3D hit, how many other 3D hits share the 2D hits that it is made of
213  // We want this to be a bit more precise in that we don't count other 3D hits if there is a gap between
214  // the current hit and the one we are comparing.
215  // How do we do this?
216  // We consider each 2D hit comprising the 3D hit in turn... for each 2D hit we have a list of the 3D
217  // hits which share this hit. Note that for the 3D hits to be unique, there must be an equal number of 2D
218  // hits from the other two views. So, to count "wires" to the boundary, we can simply pick one of the other views
219 
220  // so the idea is to through each of the views to determine
221  // a) the difference in distance to the last hit on this wire (in each direction)
222  // b) the number of 3D hits using the 2D hit in the given 3D hit
223  size_t numHitPairs[3] = {0, 0, 0}; // This keeps track of the number of 3D hits a given 2D hit is associated with
224  int deltaWires[3] = {0, 0, 0};
225  double planeDeltaT[3] = {0., 0., 0.};
226  double bestDeltaTicks[3] = {0., 0., 0.};
227  int wireNumByPlane[3] = {int(hitPair->getHits()[0]->getHit().WireID().Wire),
228  int(hitPair->getHits()[1]->getHit().WireID().Wire),
229  int(hitPair->getHits()[2]->getHit().WireID().Wire)};
230 
231  size_t bestPlaneIdx(0);
232 
233  // Initiate the loop over views
234  for(size_t planeIdx = 0; planeIdx < 3; planeIdx++)
235  {
236  const reco::ClusterHit2D* hit2D = hitPair->getHits()[planeIdx];
237  double hit2DTimeTicks = hit2D->getTimeTicks();
238 
239  std::vector<const reco::ClusterHit3D*>& hitVec(hit2DToHit3DMap[planeIdx][hit2D]);
240 
241  numHitPairs[planeIdx] = hitVec.size();
242 
243  if (numHitPairs[planeIdx] > 1)
244  {
245  int planeToCheck = (planeIdx + 1) % 3;
246  int firstWire;
247  int lastWire;
248 
249  bestDeltaTicks[planeIdx] = FindFirstAndLastWires(hitVec,
250  planeToCheck,
251  wireNumByPlane[planeToCheck],
252  hit2DTimeTicks,
253  firstWire,
254  lastWire);
255 
256  int deltaFirst = wireNumByPlane[planeToCheck] - firstWire;
257  int deltaLast = wireNumByPlane[planeToCheck] - lastWire;
258 
259  // If either distance to the first or last wire is zero then we are an edge point
260  if (deltaFirst == 0 || deltaLast == 0) hitPair->setStatusBit(reco::ClusterHit3D::EDGEHIT);
261 
262  deltaWires[planeIdx] = deltaFirst + deltaLast;
263  numHitPairs[planeIdx] = lastWire - firstWire + 1;
264  planeDeltaT[planeIdx] = fabs(hit2DTimeTicks - hitPair->getHits()[planeToCheck]->getTimeTicks());
265  }
266  // Otherwise, by definition, it is both a skeleton point and an edge point
267  else hitPair->setStatusBit(reco::ClusterHit3D::SKELETONHIT | reco::ClusterHit3D::EDGEHIT);
268 
269  if (numHitPairs[planeIdx] < numHitPairs[bestPlaneIdx])
270  {
271  bestPlaneIdx = planeIdx;
272  }
273  }
274 
275  // Make sure a real index was found (which should always happen)
276  if (bestPlaneIdx < 3 && numHitPairs[bestPlaneIdx] > 0)
277  {
278  // Make a sliding value for the width of the core region
279  int maxBestWires = 0.05 * numHitPairs[bestPlaneIdx] + 1;
280 
281  maxBestWires = 5000;
282 
283  // Check condition for a "skeleton" point
284  if (fabs(deltaWires[bestPlaneIdx]) < maxBestWires + 1)
285  {
286 
287  // If exactly in the middle then we are done
288  // Set a bit in the ClusterHit3D word to signify
289 // if (fabs(deltaWires[bestViewIdx]) < maxBestWires || numHitPairs[bestViewIdx] < 3)
290 // hitPair->setStatusBit(reco::ClusterHit3D::SKELETONHIT);
291 
292  // Otherwise we can try to look at the other view
293 // else
294  {
295  // Find the next best view
296  int nextBestIdx = (bestPlaneIdx + 1) % 3;
297 
298  for(size_t idx = 0; idx < 3; idx++)
299  {
300  if (idx == bestPlaneIdx) continue;
301 
302  if (numHitPairs[idx] < numHitPairs[nextBestIdx]) nextBestIdx = idx;
303  }
304 
305  if (nextBestIdx > 2)
306  {
307  std::cout << "***** invalid next best plane: " << nextBestIdx << " *******" << std::endl;
308  continue;
309  }
310 
311  if (planeDeltaT[bestPlaneIdx] < 1.01*bestDeltaTicks[bestPlaneIdx] && planeDeltaT[nextBestIdx] < 6.01*bestDeltaTicks[nextBestIdx])
312  hitPair->setStatusBit(reco::ClusterHit3D::SKELETONHIT);
313  }
314  }
315  }
316 
317  // We want to keep count of "pure" skeleton points only
318  if (hitPair->bitsAreSet(reco::ClusterHit3D::SKELETONHIT) && !hitPair->bitsAreSet(reco::ClusterHit3D::EDGEHIT)) nSkeletonPoints++;
319  }
320 
321  return nSkeletonPoints;
322 }
float getTimeTicks() const
Definition: Cluster3D.h:72
Hit is an "edge" hit.
Definition: Cluster3D.h:94
Hit has been rejected for any reason.
Definition: Cluster3D.h:92
double FindFirstAndLastWires(std::vector< const reco::ClusterHit3D * > &hitVec, int planeToCheck, int referenceWire, double referenceTicks, int &firstWire, int &lastWire) const
A function to find the bounding wires in a given view.
Definition: SkeletonAlg.cxx:49
Hit is a "skeleton" hit.
Definition: Cluster3D.h:93
void lar_cluster3d::SkeletonAlg::GetSkeletonHits ( const reco::HitPairListPtr inputHitList,
reco::HitPairListPtr skeletonHitList 
) const

Return the skeleton hits from the input list.

  • note that this presumes the skeleton hits have been found already
Parameters
inputHitList- input list of pointers to internal Cluster3D 3D hits
skeletonHitList- output list of skeleton hits

Definition at line 324 of file SkeletonAlg.cxx.

References reco::ClusterHit3D::SKELETONHIT.

Referenced by lar_cluster3d::Cluster3D::findTrackSeeds(), lar_cluster3d::Cluster3D::splitClustersWithHough(), and lar_cluster3d::Cluster3D::splitClustersWithMST().

325 {
326  for(const auto& hit3D : inputHitList) if (hit3D->bitsAreSet(reco::ClusterHit3D::SKELETONHIT)) skeletonHitList.emplace_back(hit3D);
327 
328  return;
329 }
Hit is a "skeleton" hit.
Definition: Cluster3D.h:93
void lar_cluster3d::SkeletonAlg::reconfigure ( fhicl::ParameterSet const &  pset)

a handler for the case where the algorithm control parameters are to be reset

Definition at line 43 of file SkeletonAlg.cxx.

References fhicl::ParameterSet::get(), m_maximumDeltaTicks, and m_minimumDeltaTicks.

Referenced by lar_cluster3d::Cluster3D::reconfigure(), and SkeletonAlg().

44 {
45  m_minimumDeltaTicks = pset.get<double>("MinimumDeltaTicks", 0.05);
46  m_maximumDeltaTicks = pset.get<double>("MaximumDeltaTicks", 10.0 );
47 }

Member Data Documentation

double lar_cluster3d::SkeletonAlg::m_maximumDeltaTicks
private

Definition at line 91 of file SkeletonAlg.h.

Referenced by FindFirstAndLastWires(), and reconfigure().

double lar_cluster3d::SkeletonAlg::m_minimumDeltaTicks
private

Definition at line 90 of file SkeletonAlg.h.

Referenced by FindFirstAndLastWires(), and reconfigure().

fhicl::ParameterSet lar_cluster3d::SkeletonAlg::m_pset
private

Definition at line 93 of file SkeletonAlg.h.


The documentation for this class was generated from the following files: